Skip to content

Commit ad0f223

Browse files
committed
ote/ccm-aws: use common e2e clients
1 parent 6c7f9ee commit ad0f223

3 files changed

Lines changed: 54 additions & 108 deletions

File tree

cmd/cloud-controller-manager-aws-tests-ext/e2e/helper.go

Lines changed: 0 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,61 +5,13 @@ import (
55
"fmt"
66
"strings"
77

8-
"github.com/aws/aws-sdk-go-v2/aws"
9-
"github.com/aws/aws-sdk-go-v2/config"
108
ec2 "github.com/aws/aws-sdk-go-v2/service/ec2"
119
ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
12-
elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
13-
elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
1410
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
1511
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1612
"k8s.io/kubernetes/test/e2e/framework"
1713
)
1814

19-
// AWS helpers
20-
21-
// createAWSClientLoadBalancer creates an AWS ELBv2 client using default credentials configured in the environment.
22-
func createAWSClientLoadBalancer(ctx context.Context) (*elbv2.Client, error) {
23-
cfg, err := config.LoadDefaultConfig(ctx)
24-
if err != nil {
25-
return nil, fmt.Errorf("unable to load AWS config: %v", err)
26-
}
27-
return elbv2.NewFromConfig(cfg), nil
28-
}
29-
30-
// getAWSLoadBalancerFromDNSName finds a load balancer by DNS name using the AWS ELBv2 client.
31-
func getAWSLoadBalancerFromDNSName(ctx context.Context, elbClient *elbv2.Client, lbDNSName string) (*elbv2types.LoadBalancer, error) {
32-
var foundLB *elbv2types.LoadBalancer
33-
framework.Logf("describing load balancers with DNS %s", lbDNSName)
34-
35-
paginator := elbv2.NewDescribeLoadBalancersPaginator(elbClient, &elbv2.DescribeLoadBalancersInput{})
36-
for paginator.HasMorePages() {
37-
page, err := paginator.NextPage(ctx)
38-
if err != nil {
39-
return nil, fmt.Errorf("failed to describe load balancers: %v", err)
40-
}
41-
42-
framework.Logf("found %d load balancers in page", len(page.LoadBalancers))
43-
// Search for the load balancer with matching DNS name in this page
44-
for i := range page.LoadBalancers {
45-
if aws.ToString(page.LoadBalancers[i].DNSName) == lbDNSName {
46-
foundLB = &page.LoadBalancers[i]
47-
framework.Logf("found load balancer with DNS %s", aws.ToString(foundLB.DNSName))
48-
break
49-
}
50-
}
51-
if foundLB != nil {
52-
break
53-
}
54-
}
55-
56-
if foundLB == nil {
57-
return nil, fmt.Errorf("no load balancer found with DNS name: %s", lbDNSName)
58-
}
59-
60-
return foundLB, nil
61-
}
62-
6315
// isFeatureEnabled checks if an OpenShift feature gate is enabled by querying the
6416
// FeatureGate resource named "cluster" using the typed OpenShift config API.
6517
//
@@ -120,15 +72,6 @@ func isFeatureEnabled(ctx context.Context, featureName string) (bool, error) {
12072
return false, nil
12173
}
12274

123-
// getAWSClientEC2 creates an AWS EC2 client using default credentials configured in the environment.
124-
func createAWSClientEC2(ctx context.Context) (*ec2.Client, error) {
125-
cfg, err := config.LoadDefaultConfig(ctx)
126-
if err != nil {
127-
return nil, fmt.Errorf("unable to load AWS config: %v", err)
128-
}
129-
return ec2.NewFromConfig(cfg), nil
130-
}
131-
13275
// getAWSSecurityGroup retrieves a security group by ID using the AWS EC2 client.
13376
func getAWSSecurityGroup(ctx context.Context, ec2Client *ec2.Client, sgID string) (*ec2types.SecurityGroup, error) {
13477
framework.Logf("describing security group %s", sgID)

cmd/cloud-controller-manager-aws-tests-ext/e2e/loadbalancer.go

Lines changed: 53 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import (
66
"strings"
77
"time"
88

9-
elbv2 "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2"
109
elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
1110
. "github.com/onsi/ginkgo/v2"
1211
. "github.com/onsi/gomega"
@@ -18,6 +17,8 @@ import (
1817
"k8s.io/kubernetes/test/e2e/framework"
1918
e2eservice "k8s.io/kubernetes/test/e2e/framework/service"
2019
admissionapi "k8s.io/pod-security-admission/api"
20+
21+
ccme2e "k8s.io/cloud-provider-aws/tests/e2e"
2122
)
2223

2324
const (
@@ -118,21 +119,21 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
118119
It("should create NLB service with security group attached", func(ctx context.Context) {
119120
isNLBFeatureEnabled(ctx)
120121

121-
By("creatomg required AWS clients")
122-
elbClient, err := createAWSClientLoadBalancer(ctx)
123-
framework.ExpectNoError(err, "failed to create AWS ELB client")
122+
By("creating E2E test helper")
123+
e2e, err := ccme2e.NewE2ETestHelper(ctx, cs)
124+
framework.ExpectNoError(err, "failed to create E2E test helper")
124125

125126
By("creating test service and deployment configuration")
126127
serviceName := "nlb-sg-crt"
127128
_, jig, err := createServiceNLB(ctx, cs, ns, serviceName, map[int32]int32{80: 8080})
128129
framework.ExpectNoError(err, "failed to create NLB service load balancer")
129130

130-
foundLB, lbDNS, err := getNLBMetaFromName(ctx, cs, ns, serviceName, elbClient)
131+
foundLB, lbDNS, err := getNLBMetaFromName(ctx, cs, ns, serviceName, e2e)
131132
framework.ExpectNoError(err, "failed to get NLB metadata")
132133
Expect(foundLB).NotTo(BeNil(), "found load balancer is nil")
133134

134-
DeferCleanup(func(cleanupCtx context.Context) {
135-
err := deleteServiceAndWaitForLoadBalancerDeletion(cleanupCtx, jig, lbDNS)
135+
DeferCleanup(func() {
136+
err := deleteServiceAndWaitForLoadBalancerDeletion(e2e, jig, lbDNS)
136137
framework.ExpectNoError(err, "failed to delete service and wait for load balancer deletion")
137138
})
138139

@@ -165,9 +166,9 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
165166
It("should have security groups attached to default ingress controller NLB", func(ctx context.Context) {
166167
isNLBFeatureEnabled(ctx)
167168

168-
By("creatomg required AWS clients")
169-
elbClient, err := createAWSClientLoadBalancer(ctx)
170-
framework.ExpectNoError(err, "failed to create AWS ELB client")
169+
By("creating E2E test helper")
170+
e2e, err := ccme2e.NewE2ETestHelper(ctx, cs)
171+
framework.ExpectNoError(err, "failed to create E2E test helper")
171172

172173
By("getting default ingress controller service")
173174
ingressNamespace := "openshift-ingress"
@@ -206,7 +207,7 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
206207

207208
var foundLB *elbv2types.LoadBalancer
208209
err = wait.PollUntilContextTimeout(ctx, 10*time.Second, 3*time.Minute, true, func(pollCtx context.Context) (bool, error) {
209-
lb, err := getAWSLoadBalancerFromDNSName(pollCtx, elbClient, lbDNS)
210+
lb, err := e2e.GetAWSHelper().GetLoadBalancerFromDNSNameWithRetry(lbDNS, 10*time.Minute)
210211
if err != nil {
211212
framework.Logf("Failed to find load balancer with DNS %s: %v", lbDNS, err)
212213
return false, nil
@@ -253,24 +254,21 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
253254
It("should update security group rules when service is updated", func(ctx context.Context) {
254255
isNLBFeatureEnabled(ctx)
255256

256-
By("creatomg required AWS clients")
257-
ec2Client, err := createAWSClientEC2(ctx)
258-
framework.ExpectNoError(err, "failed to create AWS EC2 client")
259-
260-
elbClient, err := createAWSClientLoadBalancer(ctx)
261-
framework.ExpectNoError(err, "failed to create AWS ELB client")
257+
By("creating E2E test helper")
258+
e2e, err := ccme2e.NewE2ETestHelper(ctx, cs)
259+
framework.ExpectNoError(err, "failed to create E2E test helper")
262260

263261
By("creating test service and deployment configuration")
264262
serviceName := "nlb-sg-upd"
265263
_, jig, err := createServiceNLB(ctx, cs, ns, serviceName, map[int32]int32{80: 8080})
266264
framework.ExpectNoError(err, "failed to create NLB service load balancer")
267265

268-
foundLB, lbDNS, err := getNLBMetaFromName(ctx, cs, ns, serviceName, elbClient)
266+
foundLB, lbDNS, err := getNLBMetaFromName(ctx, cs, ns, serviceName, e2e)
269267
framework.ExpectNoError(err, "failed to get NLB metadata")
270268
Expect(foundLB).NotTo(BeNil(), "found load balancer is nil")
271269

272-
DeferCleanup(func(cleanupCtx context.Context) {
273-
err := deleteServiceAndWaitForLoadBalancerDeletion(cleanupCtx, jig, lbDNS)
270+
DeferCleanup(func() {
271+
err := deleteServiceAndWaitForLoadBalancerDeletion(e2e, jig, lbDNS)
274272
framework.ExpectNoError(err, "failed to delete service and wait for load balancer deletion")
275273
})
276274

@@ -280,7 +278,7 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
280278
framework.Logf("Load balancer has %d security group(s) attached before update", len(foundLB.SecurityGroups))
281279

282280
By("getting security group rules")
283-
originalSGRules, err := getAWSSecurityGroupRules(ctx, ec2Client, foundLB.SecurityGroups)
281+
originalSGRules, err := getAWSSecurityGroupRules(ctx, e2e.GetAWSHelper().GetEC2Client(), foundLB.SecurityGroups)
284282
framework.ExpectNoError(err, "failed to get security group rules")
285283

286284
By("updating service: adding a new port")
@@ -297,7 +295,7 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
297295

298296
By("waiting for security group rules to include the new port 443")
299297
Eventually(ctx, func(ctx context.Context) ([]int32, error) {
300-
foundLB, err = getAWSLoadBalancerFromDNSName(ctx, elbClient, lbDNS)
298+
foundLB, err = e2e.GetAWSHelper().GetLoadBalancerFromDNSNameWithRetry(lbDNS, 10*time.Minute)
301299
if err != nil {
302300
framework.Logf("Error finding load balancer: %v", err)
303301
return nil, err
@@ -311,7 +309,7 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
311309
return nil, fmt.Errorf("load balancer has no security groups attached")
312310
}
313311

314-
currentSGRules, err := getAWSSecurityGroupRules(ctx, ec2Client, foundLB.SecurityGroups)
312+
currentSGRules, err := getAWSSecurityGroupRules(ctx, e2e.GetAWSHelper().GetEC2Client(), foundLB.SecurityGroups)
315313
if err != nil {
316314
framework.Logf("failed to get security group rules to calculate the diff: %v", err)
317315
return nil, err
@@ -364,20 +362,17 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
364362
It("should cleanup security groups when service is deleted", func(ctx context.Context) {
365363
isNLBFeatureEnabled(ctx)
366364

367-
By("creatomg required AWS clients")
368-
ec2Client, err := createAWSClientEC2(ctx)
369-
framework.ExpectNoError(err, "failed to create AWS EC2 client")
370-
371-
elbClient, err := createAWSClientLoadBalancer(ctx)
372-
framework.ExpectNoError(err, "failed to create AWS ELB client")
365+
By("creating E2E test helper")
366+
e2e, err := ccme2e.NewE2ETestHelper(ctx, cs)
367+
framework.ExpectNoError(err, "failed to create E2E test helper")
373368

374369
By("creating test service and deployment configuration")
375370
serviceName := "nlb-sg-cleanup-test"
376371

377372
_, jig, err := createServiceNLB(ctx, cs, ns, serviceName, map[int32]int32{80: 8080})
378373
framework.ExpectNoError(err, "failed to create NLB service load balancer")
379374

380-
foundLB, lbDNS, err := getNLBMetaFromName(ctx, cs, ns, serviceName, elbClient)
375+
foundLB, lbDNS, err := getNLBMetaFromName(ctx, cs, ns, serviceName, e2e)
381376
framework.ExpectNoError(err, "failed to get NLB metadata")
382377
Expect(foundLB).NotTo(BeNil(), "found load balancer is nil")
383378

@@ -393,20 +388,20 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
393388

394389
By("verifying security groups exist before deletion")
395390
for _, sgID := range securityGroupIDs {
396-
exists, err := securityGroupExists(ctx, ec2Client, sgID)
391+
exists, err := securityGroupExists(ctx, e2e.GetAWSHelper().GetEC2Client(), sgID)
397392
framework.ExpectNoError(err, "failed to check security group %s", sgID)
398393
Expect(exists).To(BeTrue(), "security group %s should exist before deletion", sgID)
399394
}
400395

401-
err = deleteServiceAndWaitForLoadBalancerDeletion(ctx, jig, lbDNS)
396+
err = deleteServiceAndWaitForLoadBalancerDeletion(e2e, jig, lbDNS)
402397
framework.ExpectNoError(err, "failed to delete service and wait for load balancer deletion")
403398

404399
By("verifying managed security groups are cleaned up")
405400
// Poll for security group cleanup with timeout (AWS cleanup can take time)
406401
err = wait.PollUntilContextTimeout(ctx, 10*time.Second, 3*time.Minute, true, func(ctx context.Context) (bool, error) {
407402
allDeleted := true
408403
for _, sgID := range securityGroupIDs {
409-
exists, err := securityGroupExists(ctx, ec2Client, sgID)
404+
exists, err := securityGroupExists(ctx, e2e.GetAWSHelper().GetEC2Client(), sgID)
410405
if err != nil {
411406
framework.Logf("Error checking security group %s: %v", sgID, err)
412407
return false, err
@@ -447,12 +442,9 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
447442
It("should have correct security group rules for service ports", func(ctx context.Context) {
448443
isNLBFeatureEnabled(ctx)
449444

450-
By("creatomg required AWS clients")
451-
ec2Client, err := createAWSClientEC2(ctx)
452-
framework.ExpectNoError(err, "failed to create AWS EC2 client")
453-
454-
elbClient, err := createAWSClientLoadBalancer(ctx)
455-
framework.ExpectNoError(err, "failed to create AWS ELB client")
445+
By("creating E2E test helper")
446+
e2e, err := ccme2e.NewE2ETestHelper(ctx, cs)
447+
framework.ExpectNoError(err, "failed to create E2E test helper")
456448

457449
By("creating test service and deployment configuration")
458450
serviceName := "nlb-sg-rules-test"
@@ -465,12 +457,12 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
465457
lbDNS := svc.Status.LoadBalancer.Ingress[0].Hostname
466458
framework.Logf("Load balancer DNS: %s", lbDNS)
467459

468-
foundLB, lbDNS, err := getNLBMetaFromName(ctx, cs, ns, serviceName, elbClient)
460+
foundLB, lbDNS, err := getNLBMetaFromName(ctx, cs, ns, serviceName, e2e)
469461
framework.ExpectNoError(err, "failed to get NLB metadata")
470462
Expect(foundLB).NotTo(BeNil(), "found load balancer is nil")
471463

472-
DeferCleanup(func(cleanupCtx context.Context) {
473-
err := deleteServiceAndWaitForLoadBalancerDeletion(cleanupCtx, jig, lbDNS)
464+
DeferCleanup(func() {
465+
err := deleteServiceAndWaitForLoadBalancerDeletion(e2e, jig, lbDNS)
474466
framework.ExpectNoError(err, "failed to delete service and wait for load balancer deletion")
475467
})
476468

@@ -480,7 +472,7 @@ var _ = Describe(fmt.Sprintf("%s NLB [OCPFeatureGate:%s]", e2eTestPrefixLoadBala
480472
framework.Logf("Load balancer has %d security group(s) attached", len(foundLB.SecurityGroups))
481473

482474
By("inspecting security group rules")
483-
currentSGRules, err := getAWSSecurityGroupRules(ctx, ec2Client, foundLB.SecurityGroups)
475+
currentSGRules, err := getAWSSecurityGroupRules(ctx, e2e.GetAWSHelper().GetEC2Client(), foundLB.SecurityGroups)
484476
framework.ExpectNoError(err, "failed to get security group rules to calculate the diff")
485477
Expect(len(currentSGRules)).To(BeNumerically(">", 0), "security group rules should not be empty")
486478

@@ -543,7 +535,7 @@ func createServiceNLB(ctx context.Context, cs clientset.Interface, ns *v1.Namesp
543535
}
544536

545537
// getNLBMetaFromName gets the NLB metadata (AWS API object) from the service/loadbalancer name.
546-
func getNLBMetaFromName(ctx context.Context, cs clientset.Interface, ns *v1.Namespace, serviceName string, elbc *elbv2.Client) (*elbv2types.LoadBalancer, string, error) {
538+
func getNLBMetaFromName(ctx context.Context, cs clientset.Interface, ns *v1.Namespace, serviceName string, e2e *ccme2e.E2ETestHelper) (*elbv2types.LoadBalancer, string, error) {
547539
By("getting service to extract load balancer DNS name")
548540
svc, err := cs.CoreV1().Services(ns.Name).Get(ctx, serviceName, metav1.GetOptions{})
549541
framework.ExpectNoError(err, "failed to get service %s", serviceName)
@@ -556,29 +548,39 @@ func getNLBMetaFromName(ctx context.Context, cs clientset.Interface, ns *v1.Name
556548
Expect(lbDNS).NotTo(BeEmpty(), "Ingress Hostname must not be empty")
557549
framework.Logf("Load balancer DNS: %s", lbDNS)
558550

559-
foundLB, err := getAWSLoadBalancerFromDNSName(ctx, elbc, lbDNS)
560-
framework.ExpectNoError(err, "failed to find load balancer with DNS name %s", lbDNS)
551+
// Use Eventually to handle AWS API eventual consistency - the Kubernetes service
552+
// may show the LB DNS before AWS API has fully propagated the resource.
553+
// Based on observed CI failures, this can take 30s-2min in high-load environments.
554+
var foundLB *elbv2types.LoadBalancer
555+
Eventually(ctx, func(ctx context.Context) error {
556+
lb, err := e2e.GetAWSHelper().GetLoadBalancerFromDNSNameWithRetry(lbDNS, 10*time.Minute)
557+
if err != nil {
558+
e2e.GatherServiceInfo(ns.Name, serviceName)
559+
return fmt.Errorf("failed to find load balancer with DNS name %s: %v", lbDNS, err)
560+
}
561+
foundLB = lb
562+
return nil
563+
}, 5*time.Minute, 5*time.Second).Should(Succeed(), "failed to find load balancer with DNS name %s", lbDNS)
561564
Expect(foundLB).NotTo(BeNil(), "found load balancer is nil")
562565

563566
return foundLB, lbDNS, nil
564567
}
565568

566569
// deleteServiceAndWaitForLoadBalancerDeletion deletes the service and waits for the load balancer to be deleted.
567-
func deleteServiceAndWaitForLoadBalancerDeletion(ctx context.Context, jig *e2eservice.TestJig, lbDNS string) error {
570+
func deleteServiceAndWaitForLoadBalancerDeletion(e2e *ccme2e.E2ETestHelper, jig *e2eservice.TestJig, lbDNS string) error {
568571
By("deleting the service")
572+
// using deletion context to avoid leaking resources
573+
ctx := context.TODO()
569574
err := jig.Client.CoreV1().Services(jig.Namespace).Delete(ctx, jig.Name, metav1.DeleteOptions{})
570575
framework.ExpectNoError(err, "failed to delete service")
571576

572577
By("waiting for load balancer to be destroyed")
573578
loadBalancerCreateTimeout := e2eservice.GetServiceLoadBalancerCreationTimeout(ctx, jig.Client)
574579

575580
// Get ELB client once before polling
576-
elbClient, err := createAWSClientLoadBalancer(ctx)
577-
framework.ExpectNoError(err, "failed to create AWS ELB client")
578-
579581
// Poll for load balancer deletion
580582
err = wait.PollUntilContextTimeout(ctx, 5*time.Second, loadBalancerCreateTimeout, true, func(ctx context.Context) (bool, error) {
581-
foundLB, err := getAWSLoadBalancerFromDNSName(ctx, elbClient, lbDNS)
583+
foundLB, err := e2e.GetAWSHelper().GetLoadBalancerFromDNSName(lbDNS)
582584
if err != nil {
583585
// Check if the error indicates the load balancer was not found (i.e., successfully deleted)
584586
if strings.Contains(err.Error(), "no load balancer found with DNS name") {

cmd/cloud-controller-manager-aws-tests-ext/main.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ func main() {
6161
if err != nil {
6262
panic(fmt.Errorf("failed to select specs: %w", err))
6363
}
64+
// TODO: Exclude specs when the environment variable is set.
6465

6566
// Skip set of tests when topology is SingleReplica.
6667
singleReplicaSkips := []string{

0 commit comments

Comments
 (0)