diff --git a/pkg/controllers/hub/trafficmanagerbackend/controller_integration_test.go b/pkg/controllers/hub/trafficmanagerbackend/controller_integration_test.go index 35df084c..657cf8bd 100644 --- a/pkg/controllers/hub/trafficmanagerbackend/controller_integration_test.go +++ b/pkg/controllers/hub/trafficmanagerbackend/controller_integration_test.go @@ -62,32 +62,35 @@ func trafficManagerProfileForTest(name string) *fleetnetv1alpha1.TrafficManagerP } } -func buildFalseCondition() []metav1.Condition { +func buildFalseCondition(generation int64) []metav1.Condition { return []metav1.Condition{ { - Status: metav1.ConditionFalse, - Type: string(fleetnetv1alpha1.TrafficManagerBackendConditionAccepted), - Reason: string(fleetnetv1alpha1.TrafficManagerBackendReasonInvalid), + Status: metav1.ConditionFalse, + Type: string(fleetnetv1alpha1.TrafficManagerBackendConditionAccepted), + Reason: string(fleetnetv1alpha1.TrafficManagerBackendReasonInvalid), + ObservedGeneration: generation, }, } } -func buildUnknownCondition() []metav1.Condition { +func buildUnknownCondition(generation int64) []metav1.Condition { return []metav1.Condition{ { - Status: metav1.ConditionUnknown, - Type: string(fleetnetv1alpha1.TrafficManagerBackendConditionAccepted), - Reason: string(fleetnetv1alpha1.TrafficManagerBackendReasonPending), + Status: metav1.ConditionUnknown, + Type: string(fleetnetv1alpha1.TrafficManagerBackendConditionAccepted), + Reason: string(fleetnetv1alpha1.TrafficManagerBackendReasonPending), + ObservedGeneration: generation, }, } } -func buildTrueCondition() []metav1.Condition { +func buildTrueCondition(generation int64) []metav1.Condition { return []metav1.Condition{ { - Status: metav1.ConditionTrue, - Type: string(fleetnetv1alpha1.TrafficManagerBackendConditionAccepted), - Reason: string(fleetnetv1alpha1.TrafficManagerBackendReasonAccepted), + Status: metav1.ConditionTrue, + Type: string(fleetnetv1alpha1.TrafficManagerBackendConditionAccepted), + Reason: string(fleetnetv1alpha1.TrafficManagerBackendReasonAccepted), + ObservedGeneration: generation, }, } } @@ -123,7 +126,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildFalseCondition(), + Conditions: buildFalseCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -167,7 +170,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildUnknownCondition(), + Conditions: buildUnknownCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -187,7 +190,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildFalseCondition(), + Conditions: buildFalseCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -245,7 +248,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildUnknownCondition(), + Conditions: buildUnknownCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -371,7 +374,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildFalseCondition(), + Conditions: buildFalseCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -398,7 +401,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildUnknownCondition(), + Conditions: buildUnknownCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -456,7 +459,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildFalseCondition(), + Conditions: buildFalseCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -586,7 +589,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildFalseCondition(), + Conditions: buildFalseCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -611,7 +614,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildUnknownCondition(), + Conditions: buildUnknownCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -637,7 +640,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildUnknownCondition(), + Conditions: buildUnknownCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackendConsistently(ctx, k8sClient, &want) @@ -701,7 +704,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildFalseCondition(), + Conditions: buildFalseCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -727,7 +730,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildUnknownCondition(), + Conditions: buildUnknownCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -757,7 +760,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildFalseCondition(), + Conditions: buildFalseCondition(backend.Generation), Endpoints: []fleetnetv1alpha1.TrafficManagerEndpointStatus{ { Name: fmt.Sprintf(AzureResourceEndpointNameFormat, backendName+"#", serviceName, memberClusterNames[0]), @@ -797,7 +800,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildTrueCondition(), + Conditions: buildTrueCondition(backend.Generation), Endpoints: []fleetnetv1alpha1.TrafficManagerEndpointStatus{ { Name: fmt.Sprintf(AzureResourceEndpointNameFormat, backendName+"#", serviceName, memberClusterNames[0]), @@ -845,7 +848,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildFalseCondition(), + Conditions: buildFalseCondition(backend.Generation), Endpoints: []fleetnetv1alpha1.TrafficManagerEndpointStatus{ { Name: fmt.Sprintf(AzureResourceEndpointNameFormat, backendName+"#", serviceName, memberClusterNames[0]), @@ -885,7 +888,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildUnknownCondition(), + Conditions: buildUnknownCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -919,7 +922,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildFalseCondition(), + Conditions: buildFalseCondition(backend.Generation), }, } validator.ValidateTrafficManagerBackend(ctx, k8sClient, &want) @@ -942,7 +945,7 @@ var _ = Describe("Test TrafficManagerBackend Controller", func() { }, Spec: backend.Spec, Status: fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: buildTrueCondition(), + Conditions: buildTrueCondition(backend.Generation), Endpoints: []fleetnetv1alpha1.TrafficManagerEndpointStatus{ { Name: fmt.Sprintf(AzureResourceEndpointNameFormat, backendName+"#", serviceName, memberClusterNames[0]), diff --git a/pkg/controllers/hub/trafficmanagerprofile/controller_integration_test.go b/pkg/controllers/hub/trafficmanagerprofile/controller_integration_test.go index ca4f5ddd..e31e90a4 100644 --- a/pkg/controllers/hub/trafficmanagerprofile/controller_integration_test.go +++ b/pkg/controllers/hub/trafficmanagerprofile/controller_integration_test.go @@ -63,9 +63,10 @@ var _ = Describe("Test TrafficManagerProfile Controller", func() { DNSName: ptr.To(fqdn), Conditions: []metav1.Condition{ { - Status: metav1.ConditionTrue, - Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), - Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonProgrammed), + Status: metav1.ConditionTrue, + Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), + Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonProgrammed), + ObservedGeneration: profile.Generation, }, }, }, @@ -91,9 +92,10 @@ var _ = Describe("Test TrafficManagerProfile Controller", func() { Status: fleetnetv1alpha1.TrafficManagerProfileStatus{ Conditions: []metav1.Condition{ { - Status: metav1.ConditionFalse, - Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), - Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonInvalid), + Status: metav1.ConditionFalse, + Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), + Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonInvalid), + ObservedGeneration: profile.Generation, }, }, }, @@ -148,9 +150,10 @@ var _ = Describe("Test TrafficManagerProfile Controller", func() { DNSName: ptr.To(fmt.Sprintf(fakeprovider.ProfileDNSNameFormat, name)), Conditions: []metav1.Condition{ { - Status: metav1.ConditionTrue, - Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), - Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonProgrammed), + Status: metav1.ConditionTrue, + Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), + Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonProgrammed), + ObservedGeneration: profile.Generation, }, }, }, @@ -188,9 +191,10 @@ var _ = Describe("Test TrafficManagerProfile Controller", func() { Status: fleetnetv1alpha1.TrafficManagerProfileStatus{ Conditions: []metav1.Condition{ { - Status: metav1.ConditionFalse, - Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), - Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonDNSNameNotAvailable), + Status: metav1.ConditionFalse, + Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), + Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonDNSNameNotAvailable), + ObservedGeneration: profile.Generation, }, }, }, @@ -228,9 +232,10 @@ var _ = Describe("Test TrafficManagerProfile Controller", func() { Status: fleetnetv1alpha1.TrafficManagerProfileStatus{ Conditions: []metav1.Condition{ { - Status: metav1.ConditionUnknown, - Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), - Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonPending), + Status: metav1.ConditionUnknown, + Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), + Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonPending), + ObservedGeneration: profile.Generation, }, }, }, @@ -268,9 +273,10 @@ var _ = Describe("Test TrafficManagerProfile Controller", func() { Status: fleetnetv1alpha1.TrafficManagerProfileStatus{ Conditions: []metav1.Condition{ { - Status: metav1.ConditionFalse, - Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), - Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonInvalid), + Status: metav1.ConditionFalse, + Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), + Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonInvalid), + ObservedGeneration: profile.Generation, }, }, }, @@ -308,9 +314,10 @@ var _ = Describe("Test TrafficManagerProfile Controller", func() { Status: fleetnetv1alpha1.TrafficManagerProfileStatus{ Conditions: []metav1.Condition{ { - Status: metav1.ConditionUnknown, - Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), - Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonPending), + Status: metav1.ConditionUnknown, + Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), + Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonPending), + ObservedGeneration: profile.Generation, }, }, }, diff --git a/test/common/trafficmanager/azureprovider/profile.go b/test/common/trafficmanager/azureprovider/profile.go index 1c425d25..cff69bbe 100644 --- a/test/common/trafficmanager/azureprovider/profile.go +++ b/test/common/trafficmanager/azureprovider/profile.go @@ -13,12 +13,19 @@ import ( "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/onsi/gomega" + + "go.goms.io/fleet-networking/pkg/common/azureerrors" ) var ( cmpProfileOptions = cmp.Options{ cmpopts.IgnoreFields(armtrafficmanager.Profile{}, "ID", "Name", "Type"), - cmpopts.IgnoreFields(armtrafficmanager.MonitorConfig{}, "ProfileMonitorStatus"), // cannot predict the monitor status + cmpopts.IgnoreFields(armtrafficmanager.MonitorConfig{}, "ProfileMonitorStatus"), // cannot predict the monitor status + cmpopts.IgnoreFields(armtrafficmanager.Endpoint{}, "ID"), // ignore the resource ID for now + cmpopts.IgnoreFields(armtrafficmanager.EndpointProperties{}, "TargetResourceID", "EndpointLocation", "EndpointMonitorStatus", "Priority"), // cannot predict the status + cmpopts.SortSlices(func(e1, e2 armtrafficmanager.Endpoint) bool { + return *e1.Name < *e2.Name + }), } ) @@ -35,3 +42,9 @@ func (v *Validator) ValidateProfile(ctx context.Context, name string, want armtr diff := cmp.Diff(want, res.Profile, cmpProfileOptions) gomega.Expect(diff).Should(gomega.BeEmpty(), "trafficManagerProfile mismatch (-want, +got) :\n%s", diff) } + +// IsProfileDeleted validates the traffic manager profile is deleted. +func (v *Validator) IsProfileDeleted(ctx context.Context, name string) { + _, err := v.ProfileClient.Get(ctx, v.ResourceGroup, name, nil) + gomega.Expect(azureerrors.IsNotFound(err)).Should(gomega.BeTrue(), "trafficManagerProfile %s still exists or hit error %v", name, err) +} diff --git a/test/common/trafficmanager/validator/backend.go b/test/common/trafficmanager/validator/backend.go index 03f98896..cdddfa70 100644 --- a/test/common/trafficmanager/validator/backend.go +++ b/test/common/trafficmanager/validator/backend.go @@ -32,9 +32,12 @@ var ( cmpConditionOptions, } - cmpTrafficManagerStatusByIgnoringEndpointName = cmp.Options{ + cmpTrafficManagerBackendStatusByIgnoringEndpointName = cmp.Options{ cmpConditionOptions, cmpopts.IgnoreFields(fleetnetv1alpha1.TrafficManagerEndpointStatus{}, "Name"), // ignore the generated endpoint name + cmpopts.SortSlices(func(s1, s2 fleetnetv1alpha1.TrafficManagerEndpointStatus) bool { + return s1.Cluster.Cluster < s2.Cluster.Cluster + }), } ) @@ -54,47 +57,50 @@ func IsTrafficManagerBackendFinalizerAdded(ctx context.Context, k8sClient client // ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName validates the trafficManagerBackend object if it is accepted // while ignoring the generated endpoint name. -func ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx context.Context, k8sClient client.Client, backendName types.NamespacedName, wantEndpoints []fleetnetv1alpha1.TrafficManagerEndpointStatus) fleetnetv1alpha1.TrafficManagerBackendStatus { - var wantStatus fleetnetv1alpha1.TrafficManagerBackendStatus - if len(wantEndpoints) == 0 { - wantStatus = fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionFalse, - Type: string(fleetnetv1alpha1.TrafficManagerBackendConditionAccepted), - Reason: string(fleetnetv1alpha1.TrafficManagerBackendReasonInvalid), - }, - }, - } - } else { - wantStatus = fleetnetv1alpha1.TrafficManagerBackendStatus{ - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetnetv1alpha1.TrafficManagerBackendConditionAccepted), - Reason: string(fleetnetv1alpha1.TrafficManagerBackendReasonAccepted), - }, - }, - Endpoints: wantEndpoints, - } - } - +func ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx context.Context, k8sClient client.Client, backendName types.NamespacedName, isAccepted bool, wantEndpoints []fleetnetv1alpha1.TrafficManagerEndpointStatus) fleetnetv1alpha1.TrafficManagerBackendStatus { + var gotStatus fleetnetv1alpha1.TrafficManagerBackendStatus gomega.Eventually(func() error { backend := &fleetnetv1alpha1.TrafficManagerBackend{} if err := k8sClient.Get(ctx, backendName, backend); err != nil { return err } - + var wantStatus fleetnetv1alpha1.TrafficManagerBackendStatus + if !isAccepted { + wantStatus = fleetnetv1alpha1.TrafficManagerBackendStatus{ + Conditions: []metav1.Condition{ + { + Status: metav1.ConditionFalse, + Type: string(fleetnetv1alpha1.TrafficManagerBackendConditionAccepted), + Reason: string(fleetnetv1alpha1.TrafficManagerBackendReasonInvalid), + ObservedGeneration: backend.Generation, + }, + }, + Endpoints: wantEndpoints, + } + } else { + wantStatus = fleetnetv1alpha1.TrafficManagerBackendStatus{ + Conditions: []metav1.Condition{ + { + Status: metav1.ConditionTrue, + Type: string(fleetnetv1alpha1.TrafficManagerBackendConditionAccepted), + Reason: string(fleetnetv1alpha1.TrafficManagerBackendReasonAccepted), + ObservedGeneration: backend.Generation, + }, + }, + Endpoints: wantEndpoints, + } + } + gotStatus = backend.Status if diff := cmp.Diff( - backend.Status, + gotStatus, wantStatus, - cmpTrafficManagerStatusByIgnoringEndpointName, + cmpTrafficManagerBackendStatusByIgnoringEndpointName, ); diff != "" { return fmt.Errorf("trafficManagerBackend status diff (-got, +want): %s", diff) } return nil }, timeout, interval).Should(gomega.Succeed(), "Get() trafficManagerBackend status mismatch") - return wantStatus + return gotStatus } // ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently validates the trafficManagerBackend status consistently @@ -109,7 +115,7 @@ func ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx if diff := cmp.Diff( backend.Status, want, - cmpTrafficManagerStatusByIgnoringEndpointName, + cmpTrafficManagerBackendStatusByIgnoringEndpointName, ); diff != "" { return fmt.Errorf("trafficManagerBackend status diff (-got, +want): %s", diff) } diff --git a/test/common/trafficmanager/validator/profile.go b/test/common/trafficmanager/validator/profile.go index b3f26bc0..80757b51 100644 --- a/test/common/trafficmanager/validator/profile.go +++ b/test/common/trafficmanager/validator/profile.go @@ -24,7 +24,7 @@ import ( ) const ( - timeout = time.Second * 10 + timeout = time.Second * 60 // need more time to create azure resources interval = time.Millisecond * 250 // duration used by consistently duration = time.Second * 30 @@ -39,7 +39,7 @@ var ( }), } cmpConditionOptions = cmp.Options{ - cmpopts.IgnoreFields(metav1.Condition{}, "Message", "LastTransitionTime", "ObservedGeneration"), + cmpopts.IgnoreFields(metav1.Condition{}, "Message", "LastTransitionTime"), } cmpTrafficManagerProfileOptions = cmp.Options{ commonCmpOptions, @@ -64,25 +64,24 @@ func ValidateTrafficManagerProfile(ctx context.Context, k8sClient client.Client, } // ValidateIfTrafficManagerProfileIsProgrammed validates the trafficManagerProfile is programmed and returns the DNSName. -func ValidateIfTrafficManagerProfileIsProgrammed(ctx context.Context, k8sClient client.Client, profileName types.NamespacedName) string { +func ValidateIfTrafficManagerProfileIsProgrammed(ctx context.Context, k8sClient client.Client, profileName types.NamespacedName) *fleetnetv1alpha1.TrafficManagerProfile { wantDNSName := fmt.Sprintf("%s-%s.trafficmanager.net", profileName.Namespace, profileName.Name) - wantStatus := fleetnetv1alpha1.TrafficManagerProfileStatus{ - DNSName: ptr.To(wantDNSName), - Conditions: []metav1.Condition{ - { - Status: metav1.ConditionTrue, - Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), - Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonProgrammed), - }, - }, - } - + var profile fleetnetv1alpha1.TrafficManagerProfile gomega.Eventually(func() error { - profile := &fleetnetv1alpha1.TrafficManagerProfile{} - if err := k8sClient.Get(ctx, profileName, profile); err != nil { + if err := k8sClient.Get(ctx, profileName, &profile); err != nil { return err } - + wantStatus := fleetnetv1alpha1.TrafficManagerProfileStatus{ + DNSName: ptr.To(wantDNSName), + Conditions: []metav1.Condition{ + { + Status: metav1.ConditionTrue, + Type: string(fleetnetv1alpha1.TrafficManagerProfileConditionProgrammed), + Reason: string(fleetnetv1alpha1.TrafficManagerProfileReasonProgrammed), + ObservedGeneration: profile.Generation, + }, + }, + } if diff := cmp.Diff( profile.Status, wantStatus, @@ -92,7 +91,7 @@ func ValidateIfTrafficManagerProfileIsProgrammed(ctx context.Context, k8sClient } return nil }, timeout, interval).Should(gomega.Succeed(), "Get() trafficManagerProfile status mismatch") - return wantDNSName + return &profile } // IsTrafficManagerProfileDeleted validates whether the profile is deleted or not. diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index ca03b84f..e1f3e3bb 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -31,11 +31,14 @@ import ( const ( azureSubscriptionEnv = "AZURE_SUBSCRIPTION_ID" azureTrafficManagerResourceGroupEnv = "AZURE_RESOURCE_GROUP" + + azureDNSFormat = "%s.%s.cloudapp.azure.com" ) var ( hubClusterName = "hub" memberClusterNames = []string{"member-1", "member-2"} + clusterLocation = "eastus2" testNamespace string diff --git a/test/e2e/framework/workload_manager.go b/test/e2e/framework/workload_manager.go index 6e12be87..2323dd4a 100644 --- a/test/e2e/framework/workload_manager.go +++ b/test/e2e/framework/workload_manager.go @@ -24,6 +24,7 @@ import ( "k8s.io/utils/ptr" fleetnetv1alpha1 "go.goms.io/fleet-networking/api/v1alpha1" + "go.goms.io/fleet-networking/pkg/common/objectmeta" "go.goms.io/fleet-networking/pkg/common/uniquename" ) @@ -201,6 +202,27 @@ func (wm *WorkloadManager) DeployWorkload(ctx context.Context) error { return nil } +// AddServiceDNSLabel adds a DNS label to the service in member cluster. +func (wm *WorkloadManager) AddServiceDNSLabel(ctx context.Context, cluster *Cluster) error { + var service corev1.Service + if err := cluster.kubeClient.Get(ctx, types.NamespacedName{Namespace: wm.namespace, Name: wm.service.Name}, &service); err != nil { + return fmt.Errorf("failed to get service %s in cluster %s: %w", wm.service.Name, cluster.Name(), err) + } + if service.Annotations == nil { + service.Annotations = make(map[string]string) + } + service.Annotations[objectmeta.ServiceAnnotationAzureDNSLabelName] = wm.BuildServiceDNSLabelName(cluster) + if err := cluster.kubeClient.Update(ctx, &service); err != nil { + return fmt.Errorf("failed to update service %s in cluster %s: %w", service.Name, cluster.Name(), err) + } + return nil +} + +// BuildServiceDNSLabelName builds the DNS label name for the service. +func (wm *WorkloadManager) BuildServiceDNSLabelName(cluster *Cluster) string { + return fmt.Sprintf("%s-%s-%s", wm.namespace, wm.service.Name, cluster.name) +} + // RemoveWorkload deletes workload(deployment and its service) from member clusters. func (wm *WorkloadManager) RemoveWorkload(ctx context.Context) error { for _, m := range wm.Fleet.MemberClusters() { diff --git a/test/e2e/traffic_manager_test.go b/test/e2e/traffic_manager_test.go index 16fd6167..9b3fe40c 100644 --- a/test/e2e/traffic_manager_test.go +++ b/test/e2e/traffic_manager_test.go @@ -29,7 +29,10 @@ var ( var _ = Describe("Test exporting service via Azure traffic manager", func() { var wm *framework.WorkloadManager var profile fleetnetv1alpha1.TrafficManagerProfile + var profileName types.NamespacedName var hubClient client.Client + var atmProfileName string + var atmProfile armtrafficmanager.Profile BeforeEach(func() { if !enabled { @@ -47,38 +50,13 @@ var _ = Describe("Test exporting service via Azure traffic manager", func() { Expect(hubClient.Create(ctx, &profile)).Should(Succeed(), "Failed to creat the trafficManagerProfile") By("Validating the trafficManagerProfile status") - wantDNSName := validator.ValidateIfTrafficManagerProfileIsProgrammed(ctx, hubClient, types.NamespacedName{Namespace: profile.Namespace, Name: profile.Name}) + profileName = types.NamespacedName{Namespace: profile.Namespace, Name: profile.Name} + profile = *validator.ValidateIfTrafficManagerProfileIsProgrammed(ctx, hubClient, profileName) By("Validating the Azure traffic manager profile") - atmName := fmt.Sprintf(trafficmanagerprofile.AzureResourceProfileNameFormat, profile.UID) - monitorConfig := profile.Spec.MonitorConfig - namespacedName := types.NamespacedName{Name: profile.Name, Namespace: profile.Namespace} - want := armtrafficmanager.Profile{ - Location: ptr.To("global"), - Tags: map[string]*string{ - objectmeta.AzureTrafficManagerProfileTagKey: ptr.To(namespacedName.String()), - }, - Properties: &armtrafficmanager.ProfileProperties{ - ProfileStatus: ptr.To(armtrafficmanager.ProfileStatusEnabled), - TrafficRoutingMethod: ptr.To(armtrafficmanager.TrafficRoutingMethodWeighted), - DNSConfig: &armtrafficmanager.DNSConfig{ - RelativeName: ptr.To(fmt.Sprintf(trafficmanagerprofile.DNSRelativeNameFormat, profile.Namespace, profile.Name)), - Fqdn: &wantDNSName, - TTL: ptr.To(trafficmanagerprofile.DefaultDNSTTL), - }, - MonitorConfig: &armtrafficmanager.MonitorConfig{ - IntervalInSeconds: monitorConfig.IntervalInSeconds, - Path: monitorConfig.Path, - Port: monitorConfig.Port, - Protocol: ptr.To(armtrafficmanager.MonitorProtocol(*monitorConfig.Protocol)), - TimeoutInSeconds: monitorConfig.TimeoutInSeconds, - ToleratedNumberOfFailures: monitorConfig.ToleratedNumberOfFailures, - }, - Endpoints: []*armtrafficmanager.Endpoint{}, - TrafficViewEnrollmentStatus: ptr.To(armtrafficmanager.TrafficViewEnrollmentStatusDisabled), - }, - } - atmValidator.ValidateProfile(ctx, atmName, want) + atmProfileName = fmt.Sprintf(trafficmanagerprofile.AzureResourceProfileNameFormat, profile.UID) + atmProfile = buildDesiredATMProfile(profile, nil) + atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) }) AfterEach(func() { @@ -93,7 +71,34 @@ var _ = Describe("Test exporting service via Azure traffic manager", func() { Expect(hubClient.Delete(ctx, &profile)).Should(Succeed(), "Failed to delete the trafficManagerProfile") By("Validating trafficManagerProfile is deleted") - validator.IsTrafficManagerProfileDeleted(ctx, hubClient, types.NamespacedName{Namespace: profile.Namespace, Name: profile.Name}) + validator.IsTrafficManagerProfileDeleted(ctx, hubClient, profileName) + + By("Validating Azure traffic manager profile") + atmValidator.IsProfileDeleted(ctx, atmProfileName) + }) + + Context("Test updating trafficManagerProfile", Ordered, func() { + BeforeAll(func() { + By("Updating Azure traffic manager profile") + atmProfile.Properties.DNSConfig.TTL = ptr.To(int64(30)) + atmProfile.Properties.TrafficViewEnrollmentStatus = ptr.To(armtrafficmanager.TrafficViewEnrollmentStatusEnabled) + _, err := atmValidator.ProfileClient.CreateOrUpdate(ctx, atmValidator.ResourceGroup, atmProfileName, atmProfile, nil) + Expect(err).Should(Succeed(), "Failed to update the Azure traffic manager profile") + + By("Updating the trafficManagerProfile spec") + profile.Spec.MonitorConfig.ToleratedNumberOfFailures = ptr.To(int64(5)) + Expect(hubClient.Update(ctx, &profile)).Should(Succeed(), "Failed to update the trafficManagerProfile") + }) + + It("Validating the trafficManagerProfile status", func() { + validator.ValidateIfTrafficManagerProfileIsProgrammed(ctx, hubClient, profileName) + + By("Validating the Azure traffic manager profile") + atmProfile = buildDesiredATMProfile(profile, nil) + // Controller does not set the trafficViewEnrollmentStatus. + atmProfile.Properties.TrafficViewEnrollmentStatus = ptr.To(armtrafficmanager.TrafficViewEnrollmentStatusEnabled) + atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) + }) }) Context("Test invalid trafficManagerBackend (invalid serviceImport)", Ordered, func() { @@ -113,8 +118,103 @@ var _ = Describe("Test exporting service via Azure traffic manager", func() { }) It("Validating the trafficManagerBackend status", func() { - status := validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, name, nil) + status := validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, name, false, nil) validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, name, status) + + By("Exporting service with no DNS label assigned") + Expect(wm.ExportService(ctx, wm.ServiceExport())).Should(Succeed()) + + By("Validating the trafficManagerBackend status") + status = validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, name, false, nil) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, name, status) + + By("Adding DNS label to the service on member-1") + Eventually(func() error { + return wm.AddServiceDNSLabel(ctx, memberClusters[0]) + }, framework.PollTimeout, framework.PollInterval).Should(Succeed(), "Failed to add DNS label to the service") + + By("Validating the trafficManagerBackend status") + wantEndpoints := []fleetnetv1alpha1.TrafficManagerEndpointStatus{ + { + Weight: ptr.To(int64(100)), + Target: ptr.To(fmt.Sprintf(azureDNSFormat, wm.BuildServiceDNSLabelName(memberClusters[0]), clusterLocation)), + Cluster: &fleetnetv1alpha1.ClusterStatus{Cluster: memberClusters[0].Name()}, + }, + } + status = validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, name, false, wantEndpoints) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, name, status) + + By("Validating the Azure traffic manager profile") + atmProfile = buildDesiredATMProfile(profile, status.Endpoints) + atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) + + By("Adding DNS label to the service on member-2") + Eventually(func() error { + return wm.AddServiceDNSLabel(ctx, memberClusters[1]) + }, framework.PollTimeout, framework.PollInterval).Should(Succeed(), "Failed to add DNS label to the service") + + By("Validating the trafficManagerBackend status") + wantEndpoints = []fleetnetv1alpha1.TrafficManagerEndpointStatus{ + { + Weight: ptr.To(int64(50)), + Target: ptr.To(fmt.Sprintf(azureDNSFormat, wm.BuildServiceDNSLabelName(memberClusters[0]), clusterLocation)), + Cluster: &fleetnetv1alpha1.ClusterStatus{Cluster: memberClusters[0].Name()}, + }, + { + Weight: ptr.To(int64(50)), + Target: ptr.To(fmt.Sprintf(azureDNSFormat, wm.BuildServiceDNSLabelName(memberClusters[1]), clusterLocation)), + Cluster: &fleetnetv1alpha1.ClusterStatus{Cluster: memberClusters[1].Name()}, + }, + } + status = validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, name, true, wantEndpoints) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, name, status) + + By("Validating the Azure traffic manager profile") + atmProfile = buildDesiredATMProfile(profile, status.Endpoints) + atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) }) }) }) + +func buildDesiredATMProfile(profile fleetnetv1alpha1.TrafficManagerProfile, endpoints []fleetnetv1alpha1.TrafficManagerEndpointStatus) armtrafficmanager.Profile { + monitorConfig := profile.Spec.MonitorConfig + namespacedName := types.NamespacedName{Name: profile.Name, Namespace: profile.Namespace} + res := armtrafficmanager.Profile{ + Location: ptr.To("global"), + Tags: map[string]*string{ + objectmeta.AzureTrafficManagerProfileTagKey: ptr.To(namespacedName.String()), + }, + Properties: &armtrafficmanager.ProfileProperties{ + ProfileStatus: ptr.To(armtrafficmanager.ProfileStatusEnabled), + TrafficRoutingMethod: ptr.To(armtrafficmanager.TrafficRoutingMethodWeighted), + DNSConfig: &armtrafficmanager.DNSConfig{ + RelativeName: ptr.To(fmt.Sprintf(trafficmanagerprofile.DNSRelativeNameFormat, profile.Namespace, profile.Name)), + Fqdn: profile.Status.DNSName, + TTL: ptr.To(trafficmanagerprofile.DefaultDNSTTL), + }, + MonitorConfig: &armtrafficmanager.MonitorConfig{ + IntervalInSeconds: monitorConfig.IntervalInSeconds, + Path: monitorConfig.Path, + Port: monitorConfig.Port, + Protocol: ptr.To(armtrafficmanager.MonitorProtocol(*monitorConfig.Protocol)), + TimeoutInSeconds: monitorConfig.TimeoutInSeconds, + ToleratedNumberOfFailures: monitorConfig.ToleratedNumberOfFailures, + }, + Endpoints: []*armtrafficmanager.Endpoint{}, + TrafficViewEnrollmentStatus: ptr.To(armtrafficmanager.TrafficViewEnrollmentStatusDisabled), + }, + } + for _, e := range endpoints { + res.Properties.Endpoints = append(res.Properties.Endpoints, &armtrafficmanager.Endpoint{ + Name: ptr.To(e.Name), + Type: ptr.To("Microsoft.Network/trafficManagerProfiles/azureEndpoints"), + Properties: &armtrafficmanager.EndpointProperties{ + Target: e.Target, + Weight: e.Weight, + EndpointStatus: ptr.To(armtrafficmanager.EndpointStatusEnabled), + AlwaysServe: ptr.To(armtrafficmanager.AlwaysServeDisabled), + }, + }) + } + return res +}