sigs.k8s.io/cluster-api-provider-azure@v1.17.0/test/e2e/aks_patches.go (about) 1 //go:build e2e 2 // +build e2e 3 4 /* 5 Copyright 2024 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 asocontainerservicev1 "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231001" 29 asocontainerservicev1preview "github.com/Azure/azure-service-operator/v2/api/containerservice/v1api20231102preview" 30 . "github.com/onsi/ginkgo/v2" 31 . "github.com/onsi/gomega" 32 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 33 "k8s.io/apimachinery/pkg/types" 34 "k8s.io/utils/ptr" 35 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 36 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 37 expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" 38 "sigs.k8s.io/controller-runtime/pkg/client" 39 ) 40 41 type AKSPatchSpecInput struct { 42 Cluster *clusterv1.Cluster 43 MachinePools []*expv1.MachinePool 44 WaitForUpdate []interface{} 45 } 46 47 func AKSPatchSpec(ctx context.Context, inputGetter func() AKSPatchSpecInput) { 48 input := inputGetter() 49 50 cred, err := azidentity.NewDefaultAzureCredential(nil) 51 Expect(err).NotTo(HaveOccurred()) 52 53 mgmtClient := bootstrapClusterProxy.GetClient() 54 Expect(mgmtClient).NotTo(BeNil()) 55 56 infraControlPlane := &infrav1.AzureManagedControlPlane{} 57 err = mgmtClient.Get(ctx, client.ObjectKey{ 58 Namespace: input.Cluster.Spec.ControlPlaneRef.Namespace, 59 Name: input.Cluster.Spec.ControlPlaneRef.Name, 60 }, infraControlPlane) 61 Expect(err).NotTo(HaveOccurred()) 62 63 managedClustersClient, err := armcontainerservice.NewManagedClustersClient(getSubscriptionID(Default), cred, nil) 64 Expect(err).NotTo(HaveOccurred()) 65 66 var wg sync.WaitGroup 67 68 type CheckInput struct { 69 exist map[string]string 70 doNotExist []string 71 } 72 73 checkAnnotations := func(obj client.Object, c CheckInput) func(Gomega) { 74 return func(g Gomega) { 75 err := mgmtClient.Get(ctx, client.ObjectKeyFromObject(obj), obj) 76 g.Expect(err).NotTo(HaveOccurred()) 77 for k, v := range c.exist { 78 g.Expect(obj.GetAnnotations()).To(HaveKeyWithValue(k, v)) 79 } 80 for _, k := range c.doNotExist { 81 g.Expect(obj.GetAnnotations()).NotTo(HaveKey(k)) 82 } 83 } 84 } 85 86 wg.Add(1) 87 go func() { 88 defer GinkgoRecover() 89 defer wg.Done() 90 91 managedCluster := &asocontainerservicev1.ManagedCluster{ 92 ObjectMeta: metav1.ObjectMeta{ 93 Namespace: infraControlPlane.Namespace, 94 Name: infraControlPlane.Name, 95 }, 96 } 97 98 var initialPatches []string 99 By("Deleting patches for control plane") 100 Eventually(func(g Gomega) { 101 g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(infraControlPlane), infraControlPlane)).To(Succeed()) 102 initialPatches = infraControlPlane.Spec.ASOManagedClusterPatches 103 infraControlPlane.Spec.ASOManagedClusterPatches = nil 104 g.Expect(mgmtClient.Update(ctx, infraControlPlane)).To(Succeed()) 105 }, inputGetter().WaitForUpdate...).Should(Succeed()) 106 107 By("Creating patches for control plane") 108 Eventually(func(g Gomega) { 109 g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(infraControlPlane), infraControlPlane)).To(Succeed()) 110 infraControlPlane.Spec.ASOManagedClusterPatches = []string{ 111 `{"metadata": {"annotations": {"capzpatchtest": "value"}}}`, 112 } 113 g.Expect(mgmtClient.Update(ctx, infraControlPlane)).To(Succeed()) 114 }, inputGetter().WaitForUpdate...).Should(Succeed()) 115 Eventually(checkAnnotations(managedCluster, CheckInput{exist: map[string]string{"capzpatchtest": "value"}}), input.WaitForUpdate...).Should(Succeed()) 116 117 By("Updating patches for control plane") 118 Eventually(func(g Gomega) { 119 g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(infraControlPlane), infraControlPlane)).To(Succeed()) 120 infraControlPlane.Spec.ASOManagedClusterPatches = append(infraControlPlane.Spec.ASOManagedClusterPatches, `{"metadata": {"annotations": {"capzpatchtest": null}}}`) 121 g.Expect(mgmtClient.Update(ctx, infraControlPlane)).To(Succeed()) 122 }, inputGetter().WaitForUpdate...).Should(Succeed()) 123 Eventually(checkAnnotations(managedCluster, CheckInput{doNotExist: []string{"capzpatchtest"}}), input.WaitForUpdate...).Should(Succeed()) 124 125 By("Enabling preview features on the control plane") 126 var infraControlPlane = &infrav1.AzureManagedControlPlane{} 127 Eventually(func(g Gomega) { 128 err = mgmtClient.Get(ctx, client.ObjectKey{Namespace: input.Cluster.Spec.ControlPlaneRef.Namespace, Name: input.Cluster.Spec.ControlPlaneRef.Name}, infraControlPlane) 129 g.Expect(err).NotTo(HaveOccurred()) 130 infraControlPlane.Spec.EnablePreviewFeatures = ptr.To(true) 131 g.Expect(mgmtClient.Update(ctx, infraControlPlane)).To(Succeed()) 132 }, input.WaitForUpdate...).Should(Succeed()) 133 134 Eventually(func(g Gomega) { 135 resp, err := managedClustersClient.Get(ctx, infraControlPlane.Spec.ResourceGroupName, infraControlPlane.Name, nil) 136 g.Expect(err).NotTo(HaveOccurred()) 137 g.Expect(resp.Properties.ProvisioningState).To(Equal(ptr.To("Succeeded"))) 138 }, input.WaitForUpdate...).Should(Succeed()) 139 140 By("Patching a preview feature on the control plane") 141 Eventually(func(g Gomega) { 142 err = mgmtClient.Get(ctx, client.ObjectKey{Namespace: input.Cluster.Spec.ControlPlaneRef.Namespace, Name: input.Cluster.Spec.ControlPlaneRef.Name}, infraControlPlane) 143 g.Expect(err).NotTo(HaveOccurred()) 144 infraControlPlane.Spec.ASOManagedClusterPatches = append(infraControlPlane.Spec.ASOManagedClusterPatches, `{"spec": {"enableNamespaceResources": true}}`) 145 g.Expect(mgmtClient.Update(ctx, infraControlPlane)).To(Succeed()) 146 }, input.WaitForUpdate...).Should(Succeed()) 147 148 asoManagedCluster := &asocontainerservicev1preview.ManagedCluster{} 149 Eventually(func(g Gomega) { 150 err = mgmtClient.Get(ctx, client.ObjectKey{Namespace: input.Cluster.Spec.ControlPlaneRef.Namespace, Name: infraControlPlane.Name}, asoManagedCluster) 151 g.Expect(err).NotTo(HaveOccurred()) 152 g.Expect(asoManagedCluster.Spec.EnableNamespaceResources).To(HaveValue(BeTrue())) 153 }, input.WaitForUpdate...).Should(Succeed()) 154 155 By("Restoring initial patches for control plane") 156 Eventually(func(g Gomega) { 157 g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(infraControlPlane), infraControlPlane)).To(Succeed()) 158 infraControlPlane.Spec.ASOManagedClusterPatches = initialPatches 159 g.Expect(mgmtClient.Update(ctx, infraControlPlane)).To(Succeed()) 160 }, inputGetter().WaitForUpdate...).Should(Succeed()) 161 162 By("Disabling preview features on the control plane") 163 Eventually(func(g Gomega) { 164 err = mgmtClient.Get(ctx, client.ObjectKey{Namespace: input.Cluster.Spec.ControlPlaneRef.Namespace, Name: input.Cluster.Spec.ControlPlaneRef.Name}, infraControlPlane) 165 g.Expect(err).NotTo(HaveOccurred()) 166 infraControlPlane.Spec.EnablePreviewFeatures = ptr.To(false) 167 g.Expect(mgmtClient.Update(ctx, infraControlPlane)).To(Succeed()) 168 }, input.WaitForUpdate...).Should(Succeed()) 169 170 Eventually(func(g Gomega) { 171 resp, err := managedClustersClient.Get(ctx, infraControlPlane.Spec.ResourceGroupName, infraControlPlane.Name, nil) 172 g.Expect(err).NotTo(HaveOccurred()) 173 g.Expect(resp.Properties.ProvisioningState).To(Equal(ptr.To("Succeeded"))) 174 }, input.WaitForUpdate...).Should(Succeed()) 175 }() 176 177 for _, mp := range input.MachinePools { 178 wg.Add(1) 179 go func(mp *expv1.MachinePool) { 180 defer GinkgoRecover() 181 defer wg.Done() 182 183 ammp := &infrav1.AzureManagedMachinePool{} 184 Expect(mgmtClient.Get(ctx, types.NamespacedName{ 185 Namespace: mp.Spec.Template.Spec.InfrastructureRef.Namespace, 186 Name: mp.Spec.Template.Spec.InfrastructureRef.Name, 187 }, ammp)).To(Succeed()) 188 189 agentPool := &asocontainerservicev1.ManagedClustersAgentPool{ 190 ObjectMeta: metav1.ObjectMeta{ 191 Namespace: ammp.Namespace, 192 Name: ammp.Name, 193 }, 194 } 195 196 var initialPatches []string 197 Byf("Deleting all patches for machine pool %s", mp.Name) 198 Eventually(func(g Gomega) { 199 g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(ammp), ammp)).To(Succeed()) 200 initialPatches = ammp.Spec.ASOManagedClustersAgentPoolPatches 201 ammp.Spec.ASOManagedClustersAgentPoolPatches = nil 202 g.Expect(mgmtClient.Update(ctx, ammp)).To(Succeed()) 203 }, inputGetter().WaitForUpdate...).Should(Succeed()) 204 205 Byf("Creating patches for machine pool %s", mp.Name) 206 Eventually(func(g Gomega) { 207 g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(ammp), ammp)).To(Succeed()) 208 ammp.Spec.ASOManagedClustersAgentPoolPatches = []string{ 209 `{"metadata": {"annotations": {"capzpatchtest": "value"}}}`, 210 } 211 g.Expect(mgmtClient.Update(ctx, ammp)).To(Succeed()) 212 }, inputGetter().WaitForUpdate...).Should(Succeed()) 213 Eventually(checkAnnotations(agentPool, CheckInput{exist: map[string]string{"capzpatchtest": "value"}}), input.WaitForUpdate...).Should(Succeed()) 214 215 Byf("Updating patches for machine pool %s", mp.Name) 216 Eventually(func(g Gomega) { 217 g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(ammp), ammp)).To(Succeed()) 218 ammp.Spec.ASOManagedClustersAgentPoolPatches = append(ammp.Spec.ASOManagedClustersAgentPoolPatches, `{"metadata": {"annotations": {"capzpatchtest": null}}}`) 219 g.Expect(mgmtClient.Update(ctx, ammp)).To(Succeed()) 220 }, inputGetter().WaitForUpdate...).Should(Succeed()) 221 Eventually(checkAnnotations(agentPool, CheckInput{doNotExist: []string{"capzpatchtest"}}), input.WaitForUpdate...).Should(Succeed()) 222 223 Byf("Restoring initial patches for machine pool %s", mp.Name) 224 Eventually(func(g Gomega) { 225 g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(ammp), ammp)).To(Succeed()) 226 ammp.Spec.ASOManagedClustersAgentPoolPatches = initialPatches 227 g.Expect(mgmtClient.Update(ctx, ammp)).To(Succeed()) 228 }, inputGetter().WaitForUpdate...).Should(Succeed()) 229 }(mp) 230 } 231 232 wg.Wait() 233 }