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  }