sigs.k8s.io/cluster-api-provider-azure@v1.14.3/test/e2e/aks_tags.go (about)

     1  //go:build e2e
     2  // +build e2e
     3  
     4  /*
     5  Copyright 2022 The Kubernetes Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package e2e
    21  
    22  import (
    23  	"context"
    24  	"sync"
    25  
    26  	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
    27  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/containerservice/armcontainerservice/v4"
    28  	. "github.com/onsi/ginkgo/v2"
    29  	. "github.com/onsi/gomega"
    30  	"golang.org/x/exp/maps"
    31  	"k8s.io/apimachinery/pkg/types"
    32  	"k8s.io/utils/ptr"
    33  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    34  	"sigs.k8s.io/cluster-api-provider-azure/azure/converters"
    35  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    36  	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
    37  	"sigs.k8s.io/controller-runtime/pkg/client"
    38  )
    39  
    40  type AKSAdditionalTagsSpecInput struct {
    41  	Cluster       *clusterv1.Cluster
    42  	MachinePools  []*expv1.MachinePool
    43  	WaitForUpdate []interface{}
    44  }
    45  
    46  func AKSAdditionalTagsSpec(ctx context.Context, inputGetter func() AKSAdditionalTagsSpecInput) {
    47  	input := inputGetter()
    48  
    49  	cred, err := azidentity.NewDefaultAzureCredential(nil)
    50  	Expect(err).NotTo(HaveOccurred())
    51  
    52  	managedclustersClient, err := armcontainerservice.NewManagedClustersClient(getSubscriptionID(Default), cred, nil)
    53  	Expect(err).NotTo(HaveOccurred())
    54  
    55  	agentpoolsClient, err := armcontainerservice.NewAgentPoolsClient(getSubscriptionID(Default), cred, nil)
    56  	Expect(err).NotTo(HaveOccurred())
    57  
    58  	mgmtClient := bootstrapClusterProxy.GetClient()
    59  	Expect(mgmtClient).NotTo(BeNil())
    60  
    61  	infraControlPlane := &infrav1.AzureManagedControlPlane{}
    62  	err = mgmtClient.Get(ctx, client.ObjectKey{
    63  		Namespace: input.Cluster.Spec.ControlPlaneRef.Namespace,
    64  		Name:      input.Cluster.Spec.ControlPlaneRef.Name,
    65  	}, infraControlPlane)
    66  	Expect(err).NotTo(HaveOccurred())
    67  
    68  	var wg sync.WaitGroup
    69  
    70  	wg.Add(1)
    71  	go func() {
    72  		defer GinkgoRecover()
    73  		defer wg.Done()
    74  
    75  		nonAdditionalTagKeys := map[string]struct{}{}
    76  		resp, err := managedclustersClient.Get(ctx, infraControlPlane.Spec.ResourceGroupName, infraControlPlane.Name, nil)
    77  		Expect(err).NotTo(HaveOccurred())
    78  		for k := range resp.ManagedCluster.Tags {
    79  			if _, exists := infraControlPlane.Spec.AdditionalTags[k]; !exists {
    80  				nonAdditionalTagKeys[k] = struct{}{}
    81  			}
    82  		}
    83  
    84  		var expectedTags infrav1.Tags
    85  		checkTags := func(g Gomega) {
    86  			resp, err := managedclustersClient.Get(ctx, infraControlPlane.Spec.ResourceGroupName, infraControlPlane.Name, nil)
    87  			g.Expect(err).NotTo(HaveOccurred())
    88  			g.Expect(resp.Properties.ProvisioningState).To(Equal(ptr.To("Succeeded")))
    89  			actualTags := converters.MapToTags(resp.ManagedCluster.Tags)
    90  			// Ignore tags not originally specified in spec.additionalTags
    91  			for k := range nonAdditionalTagKeys {
    92  				delete(actualTags, k)
    93  			}
    94  			if len(actualTags) == 0 {
    95  				actualTags = nil
    96  			}
    97  			if expectedTags == nil {
    98  				g.Expect(actualTags).To(BeNil())
    99  			} else {
   100  				g.Expect(actualTags).To(Equal(expectedTags))
   101  			}
   102  		}
   103  
   104  		var initialTags infrav1.Tags
   105  		Eventually(func(g Gomega) {
   106  			g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(infraControlPlane), infraControlPlane)).To(Succeed())
   107  			initialTags = infraControlPlane.Spec.AdditionalTags
   108  		}, inputGetter().WaitForUpdate...).Should(Succeed())
   109  
   110  		By("Creating tags for control plane")
   111  		// Preserve "creationTimestamp" so the RG cleanup doesn't fire on this cluster during this test.
   112  		expectedTags = maps.Clone(initialTags)
   113  		expectedTags["test"] = "tag"
   114  		expectedTags["another"] = "value"
   115  		Eventually(func(g Gomega) {
   116  			g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(infraControlPlane), infraControlPlane)).To(Succeed())
   117  			infraControlPlane.Spec.AdditionalTags = expectedTags
   118  			g.Expect(mgmtClient.Update(ctx, infraControlPlane)).To(Succeed())
   119  		}, inputGetter().WaitForUpdate...).Should(Succeed())
   120  		Eventually(checkTags, input.WaitForUpdate...).Should(Succeed())
   121  
   122  		By("Updating tags for control plane")
   123  		expectedTags["test"] = "updated"
   124  		delete(expectedTags, "another")
   125  		expectedTags["new"] = "value"
   126  		Eventually(func(g Gomega) {
   127  			g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(infraControlPlane), infraControlPlane)).To(Succeed())
   128  			infraControlPlane.Spec.AdditionalTags = expectedTags
   129  			g.Expect(mgmtClient.Update(ctx, infraControlPlane)).To(Succeed())
   130  		}, inputGetter().WaitForUpdate...).Should(Succeed())
   131  		Eventually(checkTags, input.WaitForUpdate...).Should(Succeed())
   132  
   133  		By("Restoring initial tags for control plane")
   134  		expectedTags = initialTags
   135  		Eventually(func(g Gomega) {
   136  			g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(infraControlPlane), infraControlPlane)).To(Succeed())
   137  			infraControlPlane.Spec.AdditionalTags = expectedTags
   138  			g.Expect(mgmtClient.Update(ctx, infraControlPlane)).To(Succeed())
   139  		}, inputGetter().WaitForUpdate...).Should(Succeed())
   140  		Eventually(checkTags, input.WaitForUpdate...).Should(Succeed())
   141  	}()
   142  
   143  	for _, mp := range input.MachinePools {
   144  		wg.Add(1)
   145  		go func(mp *expv1.MachinePool) {
   146  			defer GinkgoRecover()
   147  			defer wg.Done()
   148  
   149  			ammp := &infrav1.AzureManagedMachinePool{}
   150  			Expect(mgmtClient.Get(ctx, types.NamespacedName{
   151  				Namespace: mp.Spec.Template.Spec.InfrastructureRef.Namespace,
   152  				Name:      mp.Spec.Template.Spec.InfrastructureRef.Name,
   153  			}, ammp)).To(Succeed())
   154  
   155  			nonAdditionalTagKeys := map[string]struct{}{}
   156  			resp, err := agentpoolsClient.Get(ctx, infraControlPlane.Spec.ResourceGroupName, infraControlPlane.Name, *ammp.Spec.Name, nil)
   157  			Expect(err).NotTo(HaveOccurred())
   158  			for k := range resp.AgentPool.Properties.Tags {
   159  				if _, exists := infraControlPlane.Spec.AdditionalTags[k]; !exists {
   160  					nonAdditionalTagKeys[k] = struct{}{}
   161  				}
   162  			}
   163  
   164  			var expectedTags infrav1.Tags
   165  			checkTags := func(g Gomega) {
   166  				resp, err := agentpoolsClient.Get(ctx, infraControlPlane.Spec.ResourceGroupName, infraControlPlane.Name, *ammp.Spec.Name, nil)
   167  				g.Expect(err).NotTo(HaveOccurred())
   168  				g.Expect(resp.Properties.ProvisioningState).To(Equal(ptr.To("Succeeded")))
   169  				actualTags := converters.MapToTags(resp.AgentPool.Properties.Tags)
   170  				// Ignore tags not originally specified in spec.additionalTags
   171  				for k := range nonAdditionalTagKeys {
   172  					delete(actualTags, k)
   173  				}
   174  				if len(actualTags) == 0 {
   175  					actualTags = nil
   176  				}
   177  				if expectedTags == nil {
   178  					g.Expect(actualTags).To(BeNil())
   179  				} else {
   180  					g.Expect(actualTags).To(Equal(expectedTags))
   181  				}
   182  			}
   183  
   184  			Byf("Deleting all tags for machine pool %s", mp.Name)
   185  			expectedTags = nil
   186  			var initialTags infrav1.Tags
   187  			Eventually(func(g Gomega) {
   188  				g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(ammp), ammp)).To(Succeed())
   189  				initialTags = ammp.Spec.AdditionalTags
   190  				ammp.Spec.AdditionalTags = expectedTags
   191  				g.Expect(mgmtClient.Update(ctx, ammp)).To(Succeed())
   192  			}, inputGetter().WaitForUpdate...).Should(Succeed())
   193  			Eventually(checkTags, input.WaitForUpdate...).Should(Succeed())
   194  
   195  			Byf("Creating tags for machine pool %s", mp.Name)
   196  			expectedTags = infrav1.Tags{
   197  				"test":    "tag",
   198  				"another": "value",
   199  			}
   200  			Eventually(func(g Gomega) {
   201  				g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(ammp), ammp)).To(Succeed())
   202  				ammp.Spec.AdditionalTags = expectedTags
   203  				g.Expect(mgmtClient.Update(ctx, ammp)).To(Succeed())
   204  			}, inputGetter().WaitForUpdate...).Should(Succeed())
   205  			Eventually(checkTags, input.WaitForUpdate...).Should(Succeed())
   206  
   207  			Byf("Updating tags for machine pool %s", mp.Name)
   208  			expectedTags["test"] = "updated"
   209  			delete(expectedTags, "another")
   210  			expectedTags["new"] = "value"
   211  			Eventually(func(g Gomega) {
   212  				g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(ammp), ammp)).To(Succeed())
   213  				ammp.Spec.AdditionalTags = expectedTags
   214  				g.Expect(mgmtClient.Update(ctx, ammp)).To(Succeed())
   215  			}, inputGetter().WaitForUpdate...).Should(Succeed())
   216  			Eventually(checkTags, input.WaitForUpdate...).Should(Succeed())
   217  
   218  			Byf("Restoring initial tags for machine pool %s", mp.Name)
   219  			expectedTags = initialTags
   220  			Eventually(func(g Gomega) {
   221  				g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(ammp), ammp)).To(Succeed())
   222  				ammp.Spec.AdditionalTags = expectedTags
   223  				g.Expect(mgmtClient.Update(ctx, ammp)).To(Succeed())
   224  			}, inputGetter().WaitForUpdate...).Should(Succeed())
   225  			Eventually(checkTags, input.WaitForUpdate...).Should(Succeed())
   226  		}(mp)
   227  	}
   228  
   229  	wg.Wait()
   230  }