Skip to content

Commit e1e47cf

Browse files
committed
svc/nlb/sg/e2e: scaffold case to test NLG+SG feature
Introduce e2e test case to validate the feature of NLB provisioning with Security Group. The Security Group is provisioned by default on NLB when the global configuration NLBSecurityGroupMode is set to NLBSecurityGroupModeManaged. To do so, the cloud-config must be changed when the test run, and must be restored when finished, so it can't affect other scenarios.
1 parent a2923ca commit e1e47cf

File tree

1 file changed

+129
-13
lines changed

1 file changed

+129
-13
lines changed

tests/e2e/loadbalancer.go

Lines changed: 129 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import (
1717
"context"
1818
"fmt"
1919
"strings"
20+
"time"
2021

2122
. "github.com/onsi/ginkgo/v2"
2223
v1 "k8s.io/api/core/v1"
@@ -43,6 +44,8 @@ var (
4344
clusterNodesSelector string
4445
clusterNodesCount int = 0
4546

47+
cloudConfigHandler *testClusterConfig
48+
4649
// lookupNodeSelectors are valid compute/node/worker selectors commonly used in different kubernetes
4750
// distributions.
4851
lookupNodeSelectors = []string{
@@ -71,11 +74,12 @@ var _ = Describe("[cloud-provider-aws-e2e] loadbalancer", func() {
7174
})
7275

7376
type loadBalancerTestCases struct {
74-
Name string
75-
ResourceSuffix string
76-
Annotations map[string]string
77-
PostConfigService func(cfg *configServiceLB, svc *v1.Service)
78-
PostRunValidation func(cfg *configServiceLB, svc *v1.Service)
77+
Name string
78+
ResourceSuffix string
79+
Annotations map[string]string
80+
PostConfigService func(cfg *configServiceLB, svc *v1.Service)
81+
PostRunValidation func(cfg *configServiceLB, svc *v1.Service)
82+
preCloudConfigUpdate map[string]string
7983
}
8084
cases := []loadBalancerTestCases{
8185
{
@@ -84,14 +88,14 @@ var _ = Describe("[cloud-provider-aws-e2e] loadbalancer", func() {
8488
Annotations: map[string]string{},
8589
},
8690
{
87-
Name: "NLB should configure the loadbalancer based on annotations",
91+
Name: "NLB should configure based on annotations",
8892
ResourceSuffix: "nlb",
8993
Annotations: map[string]string{
9094
annotationLBType: "nlb",
9195
},
9296
},
9397
{
94-
Name: "NLB should configure the loadbalancer with target-node-labels",
98+
Name: "NLB should configure with target-node-labels",
9599
ResourceSuffix: "sg-nd",
96100
Annotations: map[string]string{
97101
annotationLBType: "nlb",
@@ -132,15 +136,33 @@ var _ = Describe("[cloud-provider-aws-e2e] loadbalancer", func() {
132136
framework.ExpectNoError(getLBTargetCount(context.TODO(), lbDNS, clusterNodesCount), "AWS LB target count validation failed")
133137
},
134138
},
139+
{
140+
Name: "NLB should be created with security groups",
141+
ResourceSuffix: "nlb-sg",
142+
Annotations: map[string]string{
143+
annotationLBType: "nlb",
144+
},
145+
preCloudConfigUpdate: map[string]string{
146+
"NLBSecurityGroupMode": "Managed",
147+
},
148+
},
135149
}
136150

137151
serviceNameBase := "lbconfig-test"
138152
for _, tc := range cases {
139153
It(tc.Name, func() {
154+
// Test case requires updates in the cloud-config
155+
if len(tc.preCloudConfigUpdate) > 0 {
156+
cloudConfigHandler = NewTestClusterConfig(cs)
157+
framework.ExpectNoError(cloudConfigHandler.discoverClusterCloudConfig(), "failed to initialize cluster cloud config")
158+
defer cloudConfigHandler.restoreCloudConfig()
159+
cloudConfigHandler.setCloudConfig(tc.preCloudConfigUpdate)
160+
}
161+
162+
// Configure test
140163
loadBalancerCreateTimeout := e2eservice.GetServiceLoadBalancerCreationTimeout(cs)
141164
framework.Logf("Running tests against AWS with timeout %s", loadBalancerCreateTimeout)
142165

143-
// Create Configuration
144166
serviceName := serviceNameBase
145167
if len(tc.ResourceSuffix) > 0 {
146168
serviceName = serviceName + "-" + tc.ResourceSuffix
@@ -163,13 +185,13 @@ var _ = Describe("[cloud-provider-aws-e2e] loadbalancer", func() {
163185
framework.ExpectNoError(fmt.Errorf("failed to create LoadBalancer Service %q: %v", lbServiceConfig.Name, err))
164186
}
165187

166-
By("waiting for loadbalancer for service " + lbServiceConfig.Namespace + "/" + lbServiceConfig.Name)
167-
lbService, err := lbConfig.LBJig.WaitForLoadBalancer(loadBalancerCreateTimeout)
168-
framework.ExpectNoError(err)
169-
170188
// Run Workloads
171189
By("creating a pod to be part of the TCP service " + serviceName)
172-
_, err = lbConfig.LBJig.Run(lbConfig.buildReplicationController())
190+
_, err := lbConfig.LBJig.Run(lbConfig.buildReplicationController())
191+
framework.ExpectNoError(err)
192+
193+
By("waiting for loadbalancer for service " + lbServiceConfig.Namespace + "/" + lbServiceConfig.Name)
194+
lbService, err := lbConfig.LBJig.WaitForLoadBalancer(loadBalancerCreateTimeout)
173195
framework.ExpectNoError(err)
174196

175197
// Hook: PostRunValidation performs LB validations after it is created (before test).
@@ -400,3 +422,97 @@ func getLBTargetCount(ctx context.Context, lbDNSName string, expectedTargets int
400422
}
401423
return nil
402424
}
425+
426+
// testClusterConfig handle information for cloud-config configuration in the running cluster.
427+
type testClusterConfig struct {
428+
kubeClient clientset.Interface
429+
configMapName string
430+
configMapNamespace string
431+
configMapKey string
432+
originalConfig *v1.ConfigMap
433+
originalConfigValue string
434+
}
435+
436+
var supportedConfigLookup = []string{"openshift-config/cloud-provider-config/config"}
437+
438+
func NewTestClusterConfig(cs clientset.Interface) *testClusterConfig {
439+
tc := &testClusterConfig{
440+
kubeClient: cs,
441+
}
442+
return tc
443+
}
444+
445+
func (tc *testClusterConfig) discoverClusterCloudConfig() error {
446+
foundConfig := false
447+
for _, env := range supportedConfigLookup {
448+
envArr := strings.Split(env, "/")
449+
namespace := envArr[0]
450+
configMap := envArr[1]
451+
configKey := envArr[2]
452+
453+
// trying to find config
454+
cm, err := tc.kubeClient.CoreV1().ConfigMaps(namespace).Get(context.TODO(), configMap, metav1.GetOptions{})
455+
if err != nil {
456+
framework.Logf("unable to retrieve configuration from %v", envArr)
457+
continue
458+
}
459+
460+
configValue, ok := cm.Data[configKey]
461+
if !ok {
462+
framework.Logf("unable to find config key in the configuration %v", envArr)
463+
continue
464+
}
465+
tc.originalConfigValue = configValue
466+
467+
foundConfig = true
468+
if tc.originalConfig == nil {
469+
tc.originalConfig = cm
470+
}
471+
tc.configMapNamespace = string(namespace)
472+
tc.configMapName = string(configMap)
473+
tc.configMapKey = string(configKey)
474+
break
475+
}
476+
477+
if !foundConfig {
478+
return fmt.Errorf("unable to find the cloud-config")
479+
}
480+
return nil
481+
}
482+
483+
// updateConfigMap updates the cloud-config configMap
484+
func (tc *testClusterConfig) updateConfigMap(cfg *v1.ConfigMap) error {
485+
_, err := tc.kubeClient.CoreV1().ConfigMaps(tc.configMapNamespace).Update(context.TODO(), cfg, metav1.UpdateOptions{})
486+
if err != nil {
487+
return fmt.Errorf("unable to update the configuration: %v", err)
488+
}
489+
490+
// The configuration must be propagated to CCM. Should we need to watch CCM pods to restart or keep it simple and wait a few seconds?
491+
time.Sleep(5 * time.Second)
492+
// By("Waiting for cloud controller manager pod to roll out")
493+
// labelSelector := "app=cloud-controller-manager"
494+
// err = e2eservice.WaitForPodsWithLabelRunningReady(cs, tc.namespaceCCM, labelSelector, 1, framework.PodStartTimeout)
495+
// framework.ExpectNoError(err, "failed to wait for cloud controller manager pod rollout")
496+
497+
return nil
498+
}
499+
500+
// setCloudConfig updates the cloud-config to a new one.
501+
func (tc *testClusterConfig) setCloudConfig(cfgData map[string]string) error {
502+
newConfig := &v1.ConfigMap{}
503+
newConfig = tc.originalConfig.DeepCopy()
504+
// update configuration recursively
505+
for k, v := range cfgData {
506+
newConfig.Data[tc.configMapKey] += fmt.Sprintf("%s=%s\n", k, v)
507+
}
508+
return tc.updateConfigMap(newConfig)
509+
}
510+
511+
// restoreCloudConfig restores the cloudconfig to the original. It can be used as Defer.
512+
func (tc *testClusterConfig) restoreCloudConfig() {
513+
tc.originalConfig.Data = map[string]string{
514+
tc.configMapKey: tc.originalConfigValue,
515+
}
516+
framework.Logf("restoring cloud-config configuration: %v", tc.originalConfig)
517+
tc.updateConfigMap(tc.originalConfig)
518+
}

0 commit comments

Comments
 (0)