From e3bb66512c5e5266a11368114c29a020d6bb0e22 Mon Sep 17 00:00:00 2001 From: Zhiying Lin Date: Mon, 30 Dec 2024 14:46:16 +0800 Subject: [PATCH] test: add atm e2e tests --- Makefile | 2 +- .../trafficmanager/azureprovider/profile.go | 12 +- .../trafficmanager/validator/backend.go | 4 +- test/e2e/e2e_test.go | 13 +- test/e2e/framework/workload_manager.go | 23 ++ test/e2e/traffic_manager_test.go | 361 +++++++++++++++++- 6 files changed, 400 insertions(+), 15 deletions(-) diff --git a/Makefile b/Makefile index 0f5edf67..aef35b6f 100644 --- a/Makefile +++ b/Makefile @@ -114,7 +114,7 @@ e2e-setup: .PHONY: e2e-tests e2e-tests: - go test -timeout 30m -tags=e2e -v ./test/e2e -args -ginkgo.v + go test -timeout 45m -tags=e2e -v ./test/e2e -args -ginkgo.v .PHONY: e2e-cleanup e2e-cleanup: diff --git a/test/common/trafficmanager/azureprovider/profile.go b/test/common/trafficmanager/azureprovider/profile.go index cff69bbe..be9ffe08 100644 --- a/test/common/trafficmanager/azureprovider/profile.go +++ b/test/common/trafficmanager/azureprovider/profile.go @@ -23,7 +23,7 @@ var ( 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 { + cmpopts.SortSlices(func(e1, e2 *armtrafficmanager.Endpoint) bool { return *e1.Name < *e2.Name }), } @@ -31,16 +31,18 @@ var ( // Validator contains the way of accessing the Azure Traffic Manager resources. type Validator struct { - ProfileClient *armtrafficmanager.ProfilesClient - ResourceGroup string + ProfileClient *armtrafficmanager.ProfilesClient + EndpointClient *armtrafficmanager.EndpointsClient + ResourceGroup string } -// ValidateProfile validates the traffic manager profile. -func (v *Validator) ValidateProfile(ctx context.Context, name string, want armtrafficmanager.Profile) { +// ValidateProfile validates the traffic manager profile and returns the actual Azure traffic manager profile. +func (v *Validator) ValidateProfile(ctx context.Context, name string, want armtrafficmanager.Profile) *armtrafficmanager.Profile { res, err := v.ProfileClient.Get(ctx, v.ResourceGroup, name, nil) gomega.Expect(err).Should(gomega.Succeed(), "Failed to get the traffic manager profile") diff := cmp.Diff(want, res.Profile, cmpProfileOptions) gomega.Expect(diff).Should(gomega.BeEmpty(), "trafficManagerProfile mismatch (-want, +got) :\n%s", diff) + return &res.Profile } // IsProfileDeleted validates the traffic manager profile is deleted. diff --git a/test/common/trafficmanager/validator/backend.go b/test/common/trafficmanager/validator/backend.go index cdddfa70..47b1b177 100644 --- a/test/common/trafficmanager/validator/backend.go +++ b/test/common/trafficmanager/validator/backend.go @@ -96,7 +96,7 @@ func ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx context. wantStatus, cmpTrafficManagerBackendStatusByIgnoringEndpointName, ); diff != "" { - return fmt.Errorf("trafficManagerBackend status diff (-got, +want): %s", diff) + return fmt.Errorf("trafficManagerBackend status diff (-got, +want): \n%s\n got %+v", diff, gotStatus) } return nil }, timeout, interval).Should(gomega.Succeed(), "Get() trafficManagerBackend status mismatch") @@ -117,7 +117,7 @@ func ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx want, cmpTrafficManagerBackendStatusByIgnoringEndpointName, ); diff != "" { - return fmt.Errorf("trafficManagerBackend status diff (-got, +want): %s", diff) + return fmt.Errorf("trafficManagerBackend status diff (-got, +want): \n%s\n got %+v", diff, backend.Status) } return nil }, duration, interval).Should(gomega.Succeed(), "Get() trafficManagerBackend status mismatch") diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index e1f3e3bb..2c9525e2 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -20,6 +20,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" utilruntime "k8s.io/apimachinery/pkg/util/runtime" clientgoscheme "k8s.io/client-go/kubernetes/scheme" + "sigs.k8s.io/cloud-provider-azure/pkg/azclient/publicipaddressclient" fleetv1beta1 "go.goms.io/fleet/apis/cluster/v1beta1" @@ -50,6 +51,7 @@ var ( ctx = context.Background() atmValidator *azureprovider.Validator + pipClient publicipaddressclient.Interface ) func init() { @@ -95,12 +97,15 @@ func initAzureClients() { cred, err := azidentity.NewDefaultAzureCredential(nil) Expect(err).Should(Succeed(), "Failed to obtain default Azure credential") - clientFactory, err := armtrafficmanager.NewClientFactory(subscriptionID, cred, nil) - Expect(err).Should(Succeed(), "Failed to create client") + atmClientFactory, err := armtrafficmanager.NewClientFactory(subscriptionID, cred, nil) + Expect(err).Should(Succeed(), "Failed to create Azure traffic manager clients") atmValidator = &azureprovider.Validator{ - ProfileClient: clientFactory.NewProfilesClient(), - ResourceGroup: atmResourceGroup, + ProfileClient: atmClientFactory.NewProfilesClient(), + EndpointClient: atmClientFactory.NewEndpointsClient(), + ResourceGroup: atmResourceGroup, } + pipClient, err = publicipaddressclient.New(subscriptionID, cred, nil) + Expect(err).Should(Succeed(), "Failed to create Azure public ip address client") } func createTestNamespace(ctx context.Context) { diff --git a/test/e2e/framework/workload_manager.go b/test/e2e/framework/workload_manager.go index 9340a0ab..96211ac0 100644 --- a/test/e2e/framework/workload_manager.go +++ b/test/e2e/framework/workload_manager.go @@ -223,6 +223,29 @@ func (wm *WorkloadManager) BuildServiceDNSLabelName(cluster *Cluster) string { return fmt.Sprintf("%s-%s-%s", wm.namespace, wm.service.Name, cluster.Name()) } +// UpdateServiceType updates the service type in the member cluster. +func (wm *WorkloadManager) UpdateServiceType(ctx context.Context, cluster *Cluster, serviceType corev1.ServiceType, isInternalLoadBalancer bool) 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) + } + service.Spec.Type = serviceType + if serviceType == corev1.ServiceTypeLoadBalancer { + if isInternalLoadBalancer { + if service.Annotations == nil { + service.Annotations = make(map[string]string) + } + service.Annotations[objectmeta.ServiceAnnotationAzureLoadBalancerInternal] = "true" + } else { + delete(service.Annotations, objectmeta.ServiceAnnotationAzureLoadBalancerInternal) + } + } + 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 +} + // 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 9b3fe40c..137cdc37 100644 --- a/test/e2e/traffic_manager_test.go +++ b/test/e2e/traffic_manager_test.go @@ -8,15 +8,19 @@ import ( "fmt" "os" + "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4" "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/trafficmanager/armtrafficmanager" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/types" "k8s.io/utils/ptr" "sigs.k8s.io/controller-runtime/pkg/client" fleetnetv1alpha1 "go.goms.io/fleet-networking/api/v1alpha1" "go.goms.io/fleet-networking/pkg/common/objectmeta" + "go.goms.io/fleet-networking/pkg/common/uniquename" "go.goms.io/fleet-networking/pkg/controllers/hub/trafficmanagerprofile" "go.goms.io/fleet-networking/test/common/trafficmanager/validator" "go.goms.io/fleet-networking/test/e2e/framework" @@ -26,7 +30,7 @@ var ( enabled = os.Getenv("ENABLE_TRAFFIC_MANAGER") == "true" ) -var _ = Describe("Test exporting service via Azure traffic manager", func() { +var _ = Describe("Test exporting service via Azure traffic manager", Ordered, func() { var wm *framework.WorkloadManager var profile fleetnetv1alpha1.TrafficManagerProfile var profileName types.NamespacedName @@ -68,7 +72,8 @@ var _ = Describe("Test exporting service via Azure traffic manager", func() { Expect(wm.RemoveWorkload(ctx)).Should(Succeed()) By("Deleting trafficManagerProfile") - Expect(hubClient.Delete(ctx, &profile)).Should(Succeed(), "Failed to delete the trafficManagerProfile") + err := hubClient.Delete(ctx, &profile) + Expect(err).Should(SatisfyAny(Succeed(), WithTransform(errors.IsNotFound, BeTrue())), "Failed to delete the trafficManagerProfile") By("Validating trafficManagerProfile is deleted") validator.IsTrafficManagerProfileDeleted(ctx, hubClient, profileName) @@ -115,6 +120,11 @@ var _ = Describe("Test exporting service via Azure traffic manager", func() { By("Deleting trafficManagerBackend") Expect(hubClient.Delete(ctx, &backend)).Should(Succeed(), "Failed to delete the trafficManagerBackend") validator.IsTrafficManagerBackendDeleted(ctx, hubClient, name) + + By("Validating the Azure traffic manager profile") + atmProfileName = fmt.Sprintf(trafficmanagerprofile.AzureResourceProfileNameFormat, profile.UID) + atmProfile = buildDesiredATMProfile(profile, nil) + atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) }) It("Validating the trafficManagerBackend status", func() { @@ -122,7 +132,7 @@ var _ = Describe("Test exporting service via Azure traffic manager", func() { validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, name, status) By("Exporting service with no DNS label assigned") - Expect(wm.ExportService(ctx, wm.ServiceExport())).Should(Succeed()) + Expect(wm.ExportService(ctx, wm.ServiceExport())).Should(Succeed(), "Failed to export the service") By("Validating the trafficManagerBackend status") status = validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, name, false, nil) @@ -174,6 +184,351 @@ var _ = Describe("Test exporting service via Azure traffic manager", func() { atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) }) }) + + Context("Test invalid trafficManagerBackend (invalid profile)", Ordered, func() { + var backend fleetnetv1alpha1.TrafficManagerBackend + var backendName types.NamespacedName + BeforeEach(func() { + // create valid serviceImport + By("Adding DNS label to the service on member-1 & member-2") + for _, cluster := range memberClusters { + Eventually(func() error { + return wm.AddServiceDNSLabel(ctx, cluster) + }, framework.PollTimeout, framework.PollInterval).Should(Succeed(), "Failed to add DNS label to the service") + } + + By("Exporting service with DNS label assigned") + Expect(wm.ExportService(ctx, wm.ServiceExport())).Should(Succeed(), "Failed to export the service") + }) + + AfterEach(func() { + // make sure each test will create the trafficManagerBackend + By("Deleting trafficManagerBackend") + Expect(hubClient.Delete(ctx, &backend)).Should(Succeed(), "Failed to delete the trafficManagerBackend") + validator.IsTrafficManagerBackendDeleted(ctx, hubClient, backendName) + }) + + It("Creating trafficManagerBackend with invalid profile", func() { + By("Creating trafficManagerBackend") + backend = wm.TrafficManagerBackend() + // update the profile to invalid one + backend.Spec.Profile = fleetnetv1alpha1.TrafficManagerProfileRef{ + Name: "invalid-profile", + } + backendName = types.NamespacedName{Namespace: backend.Namespace, Name: backend.Name} + Expect(hubClient.Create(ctx, &backend)).Should(Succeed(), "Failed to create the trafficManagerBackend") + + status := validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, backendName, false, nil) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, backendName, status) + }) + + It("Deleting trafficManagerProfile during runtime", func() { + By("Creating trafficManagerBackend") + backend = wm.TrafficManagerBackend() + backendName = types.NamespacedName{Namespace: backend.Namespace, Name: backend.Name} + Expect(hubClient.Create(ctx, &backend)).Should(Succeed(), "Failed to create the trafficManagerBackend") + + 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, backendName, true, wantEndpoints) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, backendName, status) + + By("Deleting trafficManagerProfile") + Expect(hubClient.Delete(ctx, &profile)).Should(Succeed(), "Failed to delete the trafficManagerProfile") + + By("Validating trafficManagerProfile is deleted") + validator.IsTrafficManagerProfileDeleted(ctx, hubClient, profileName) + + By("Validating the trafficManagerBackend status") + status = validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, backendName, false, nil) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, backendName, status) + }) + + It("Deleting Azure traffic manager profile before creating trafficManagerBackend", func() { + By("Deleting Azure traffic manager profile directly") + _, err := atmValidator.ProfileClient.Delete(ctx, atmValidator.ResourceGroup, atmProfileName, nil) + Expect(err).Should(Succeed(), "Failed to delete the Azure traffic manager profile") + + By("Creating trafficManagerBackend") + backend = wm.TrafficManagerBackend() + backendName = types.NamespacedName{Namespace: backend.Namespace, Name: backend.Name} + Expect(hubClient.Create(ctx, &backend)).Should(Succeed(), "Failed to create the trafficManagerBackend") + + By("Validating the trafficManagerBackend status") + status := validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, backendName, false, nil) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, backendName, status) + }) + }) + + Context("Test valid trafficManagerBackend", Ordered, func() { + var backend fleetnetv1alpha1.TrafficManagerBackend + var backendName types.NamespacedName + + var extraTrafficManagerEndpoint *armtrafficmanager.Endpoint + BeforeEach(func() { + // create valid serviceImport + By("Adding DNS label to the service on member-1 & member-2") + for _, cluster := range memberClusters { + Eventually(func() error { + return wm.AddServiceDNSLabel(ctx, cluster) + }, framework.PollTimeout, framework.PollInterval).Should(Succeed(), "Failed to add DNS label to the service") + } + + By("Exporting service with DNS label assigned") + Expect(wm.ExportService(ctx, wm.ServiceExport())).Should(Succeed(), "Failed to export the service") + + By("Creating trafficManagerBackend") + backend = wm.TrafficManagerBackend() + backendName = types.NamespacedName{Namespace: backend.Namespace, Name: backend.Name} + Expect(hubClient.Create(ctx, &backend)).Should(Succeed(), "Failed to create the trafficManagerBackend") + + 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, backendName, true, wantEndpoints) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, backendName, status) + + By("Validating the Azure traffic manager profile") + atmProfile = buildDesiredATMProfile(profile, status.Endpoints) + atmProfile = *atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) + + // reset extra endpoint + extraTrafficManagerEndpoint = nil + }) + + AfterEach(func() { + By("Deleting trafficManagerBackend") + Expect(hubClient.Delete(ctx, &backend)).Should(Succeed(), "Failed to delete the trafficManagerBackend") + validator.IsTrafficManagerBackendDeleted(ctx, hubClient, backendName) + + By("Validating the Azure traffic manager profile") + atmProfileName = fmt.Sprintf(trafficmanagerprofile.AzureResourceProfileNameFormat, profile.UID) + atmProfile = buildDesiredATMProfile(profile, nil) + if extraTrafficManagerEndpoint != nil { + atmProfile.Properties.Endpoints = append(atmProfile.Properties.Endpoints, extraTrafficManagerEndpoint) + } + atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) + }) + + It("Creating extra Azure traffic manager endpoint directly and then updating trafficManagerBackend", func() { + By("Creating a public IP address") + publicIPAddressName := fmt.Sprintf("e2e-test-public-ip-%s", uniquename.RandomLowerCaseAlphabeticString(5)) + publicIPReq := armnetwork.PublicIPAddress{ + Name: ptr.To(publicIPAddressName), + Location: ptr.To(clusterLocation), + Properties: &armnetwork.PublicIPAddressPropertiesFormat{ + PublicIPAllocationMethod: ptr.To(armnetwork.IPAllocationMethodStatic), + DNSSettings: &armnetwork.PublicIPAddressDNSSettings{ + DomainNameLabel: ptr.To(publicIPAddressName), + }, + }, + SKU: &armnetwork.PublicIPAddressSKU{ + Name: ptr.To(armnetwork.PublicIPAddressSKUNameStandard), + }, + } + publicIPResp, err := pipClient.CreateOrUpdate(ctx, atmValidator.ResourceGroup, publicIPAddressName, publicIPReq) + Expect(err).Should(Succeed(), "Failed to create public IP address") + + By("Creating new Azure traffic manager endpoint directly") + atmEndpointReq := armtrafficmanager.Endpoint{ + Name: ptr.To("extra-endpoint"), + Type: ptr.To("Microsoft.Network/trafficManagerProfiles/azureEndpoints"), + Properties: &armtrafficmanager.EndpointProperties{ + TargetResourceID: publicIPResp.ID, + EndpointStatus: ptr.To(armtrafficmanager.EndpointStatusEnabled), + Weight: ptr.To(int64(10)), + }, + } + atmEndpointResp, err := atmValidator.EndpointClient.CreateOrUpdate(ctx, atmValidator.ResourceGroup, atmProfileName, armtrafficmanager.EndpointTypeAzureEndpoints, *atmEndpointReq.Name, atmEndpointReq, nil) + Expect(err).Should(Succeed(), "Failed to create the extra traffic manager endpoint") + extraTrafficManagerEndpoint = &atmEndpointResp.Endpoint + + By("Updating the trafficManagerBackend spec") + Eventually(func() error { + if err := hubClient.Get(ctx, backendName, &backend); err != nil { + return err + } + backend.Spec.Weight = ptr.To(int64(10)) + return hubClient.Update(ctx, &backend) + }, framework.PollTimeout, framework.PollInterval).Should(Succeed(), "Failed to update the trafficManagerBackend") + + By("Validating the trafficManagerBackend status") + wantEndpoints := []fleetnetv1alpha1.TrafficManagerEndpointStatus{ + { + Weight: ptr.To(int64(5)), + Target: ptr.To(fmt.Sprintf(azureDNSFormat, wm.BuildServiceDNSLabelName(memberClusters[0]), clusterLocation)), + Cluster: &fleetnetv1alpha1.ClusterStatus{Cluster: memberClusters[0].Name()}, + }, + { + Weight: ptr.To(int64(5)), + Target: ptr.To(fmt.Sprintf(azureDNSFormat, wm.BuildServiceDNSLabelName(memberClusters[1]), clusterLocation)), + Cluster: &fleetnetv1alpha1.ClusterStatus{Cluster: memberClusters[1].Name()}, + }, + } + status := validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, backendName, true, wantEndpoints) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, backendName, status) + + By("Validating the Azure traffic manager profile") + atmProfile = buildDesiredATMProfile(profile, status.Endpoints) + atmProfile.Properties.Endpoints = append(atmProfile.Properties.Endpoints, extraTrafficManagerEndpoint) + atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) + + // The endpoint should be deleted when deleting the profile. + By("Deleting the public ip address") + Expect(pipClient.Delete(ctx, atmValidator.ResourceGroup, publicIPAddressName)).Should(Succeed(), "Failed to delete public IP address") + }) + + It("Updating the Azure traffic manager endpoint directly and then updating trafficManagerBackend", func() { + By("Updating the Azure traffic manager endpoint") + headers := []*armtrafficmanager.EndpointPropertiesCustomHeadersItem{ + {Name: ptr.To("header1"), Value: ptr.To("value1")}, + } + atmProfile.Properties.Endpoints[0].Properties.Weight = ptr.To(int64(10)) // set the weight to 10 explicitly + // the controller should reset All the changes. + for i := range atmProfile.Properties.Endpoints { + atmProfile.Properties.Endpoints[i].Properties.EndpointStatus = ptr.To(armtrafficmanager.EndpointStatusDisabled) + atmProfile.Properties.Endpoints[i].Properties.CustomHeaders = headers + } + _, 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 trafficManagerBackend spec") + Eventually(func() error { + if err := hubClient.Get(ctx, backendName, &backend); err != nil { + return err + } + backend.Spec.Weight = ptr.To(int64(10)) + return hubClient.Update(ctx, &backend) + }, framework.PollTimeout, framework.PollInterval).Should(Succeed(), "Failed to update the trafficManagerBackend") + + By("Validating the trafficManagerBackend status") + wantEndpoints := []fleetnetv1alpha1.TrafficManagerEndpointStatus{ + { + Weight: ptr.To(int64(5)), + Target: ptr.To(fmt.Sprintf(azureDNSFormat, wm.BuildServiceDNSLabelName(memberClusters[0]), clusterLocation)), + Cluster: &fleetnetv1alpha1.ClusterStatus{Cluster: memberClusters[0].Name()}, + }, + { + Weight: ptr.To(int64(5)), + Target: ptr.To(fmt.Sprintf(azureDNSFormat, wm.BuildServiceDNSLabelName(memberClusters[1]), clusterLocation)), + Cluster: &fleetnetv1alpha1.ClusterStatus{Cluster: memberClusters[1].Name()}, + }, + } + status := validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, backendName, true, wantEndpoints) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, backendName, status) + + By("Validating the Azure traffic manager profile") + atmProfile = buildDesiredATMProfile(profile, status.Endpoints) + // The controller should reset all the endpoint changes. + atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) + }) + + It("Deleting the Azure traffic manager endpoint directly and then updating trafficManagerBackend", func() { + By("Deleting one of the Azure traffic manager endpoint") + atmProfile.Properties.Endpoints = atmProfile.Properties.Endpoints[1:] + _, 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 trafficManagerBackend spec") + Eventually(func() error { + if err := hubClient.Get(ctx, backendName, &backend); err != nil { + return err + } + backend.Spec.Weight = ptr.To(int64(10)) + return hubClient.Update(ctx, &backend) + }, framework.PollTimeout, framework.PollInterval).Should(Succeed(), "Failed to update the trafficManagerBackend") + + By("Validating the trafficManagerBackend status") + wantEndpoints := []fleetnetv1alpha1.TrafficManagerEndpointStatus{ + { + Weight: ptr.To(int64(5)), + Target: ptr.To(fmt.Sprintf(azureDNSFormat, wm.BuildServiceDNSLabelName(memberClusters[0]), clusterLocation)), + Cluster: &fleetnetv1alpha1.ClusterStatus{Cluster: memberClusters[0].Name()}, + }, + { + Weight: ptr.To(int64(5)), + Target: ptr.To(fmt.Sprintf(azureDNSFormat, wm.BuildServiceDNSLabelName(memberClusters[1]), clusterLocation)), + Cluster: &fleetnetv1alpha1.ClusterStatus{Cluster: memberClusters[1].Name()}, + }, + } + status := validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, backendName, true, wantEndpoints) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, backendName, status) + + By("Validating the Azure traffic manager profile") + atmProfile = buildDesiredATMProfile(profile, status.Endpoints) + // The controller should reset all the endpoint changes. + atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) + }) + + It("Updating the service type", func() { + By("Updating the service type to clusterIP type in member-1") + Eventually(func() error { + return wm.UpdateServiceType(ctx, memberClusters[0], corev1.ServiceTypeClusterIP, false) + }, framework.PollTimeout, framework.PollInterval).Should(Succeed(), "Failed to update the service type to clusterIP type") + + By("Validating the trafficManagerBackend status") + wantEndpoints := []fleetnetv1alpha1.TrafficManagerEndpointStatus{ + { + Weight: ptr.To(int64(100)), + Target: ptr.To(fmt.Sprintf(azureDNSFormat, wm.BuildServiceDNSLabelName(memberClusters[1]), clusterLocation)), + Cluster: &fleetnetv1alpha1.ClusterStatus{Cluster: memberClusters[1].Name()}, + }, + } + status := validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, backendName, false, wantEndpoints) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, backendName, status) + + By("Validating the Azure traffic manager profile") + atmProfile = buildDesiredATMProfile(profile, status.Endpoints) + atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) + + By("Updating the service type to internal load balancer type in member-2") + Eventually(func() error { + return wm.UpdateServiceType(ctx, memberClusters[1], corev1.ServiceTypeLoadBalancer, true) + }, framework.PollTimeout, framework.PollInterval).Should(Succeed(), "Failed to update the service type to internal load balancer type") + + By("Validating the trafficManagerBackend status") + status = validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, backendName, false, nil) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, backendName, status) + + By("Validating the Azure traffic manager profile") + atmProfile = buildDesiredATMProfile(profile, status.Endpoints) + atmValidator.ValidateProfile(ctx, atmProfileName, atmProfile) + }) + + It("Deleting serviceExports during runtime", func() { + By("Deleting serviceExports") + Expect(wm.UnexportService(ctx, wm.ServiceExport())).Should(Succeed(), "Failed to unexport the service") + + By("Validating the trafficManagerBackend status") + status := validator.ValidateTrafficManagerBackendIfAcceptedAndIgnoringEndpointName(ctx, hubClient, backendName, false, nil) + validator.ValidateTrafficManagerBackendStatusAndIgnoringEndpointNameConsistently(ctx, hubClient, backendName, 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 {