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 }