sigs.k8s.io/cluster-api-provider-azure@v1.14.3/test/e2e/azure_vmextensions.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  
    25  	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
    26  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v5"
    27  	. "github.com/onsi/ginkgo/v2"
    28  	. "github.com/onsi/gomega"
    29  	corev1 "k8s.io/api/core/v1"
    30  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    31  	infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta1"
    32  	azureutil "sigs.k8s.io/cluster-api-provider-azure/util/azure"
    33  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    34  	"sigs.k8s.io/cluster-api/test/framework"
    35  	"sigs.k8s.io/controller-runtime/pkg/client"
    36  )
    37  
    38  // AzureVMExtensionsSpecInput is the input for AzureVMExtensionsSpec.
    39  type AzureVMExtensionsSpecInput struct {
    40  	BootstrapClusterProxy framework.ClusterProxy
    41  	Namespace             *corev1.Namespace
    42  	ClusterName           string
    43  }
    44  
    45  // AzureVMExtensionsSpec implements a test that verifies VM extensions are created and deleted.
    46  func AzureVMExtensionsSpec(ctx context.Context, inputGetter func() AzureVMExtensionsSpecInput) {
    47  	var (
    48  		specName = "azure-vmextensions"
    49  		input    AzureVMExtensionsSpecInput
    50  	)
    51  
    52  	Expect(ctx).NotTo(BeNil(), "ctx is required for %s spec", specName)
    53  
    54  	input = inputGetter()
    55  	Expect(input.BootstrapClusterProxy).NotTo(BeNil(), "Invalid argument. input.BootstrapClusterProxy can't be nil when calling %s spec", specName)
    56  	Expect(input.Namespace).NotTo(BeNil(), "Invalid argument. input.Namespace can't be nil when calling %s spec", specName)
    57  	Expect(input.ClusterName).NotTo(BeEmpty(), "Invalid argument. input.ClusterName can't be empty when calling %s spec", specName)
    58  
    59  	By("creating a Kubernetes client to the workload cluster")
    60  	workloadClusterProxy := input.BootstrapClusterProxy.GetWorkloadCluster(ctx, input.Namespace.Name, input.ClusterName)
    61  	Expect(workloadClusterProxy).NotTo(BeNil())
    62  	mgmtClient := bootstrapClusterProxy.GetClient()
    63  	Expect(mgmtClient).NotTo(BeNil())
    64  
    65  	By("Retrieving all machines from the machine template spec")
    66  	machineList := &infrav1.AzureMachineList{}
    67  	// list all of the requested objects within the cluster namespace with the cluster name label
    68  	Logf("Listing machines in namespace %s with label %s=%s", input.Namespace.Name, clusterv1.ClusterNameLabel, workloadClusterProxy.GetName())
    69  	err := mgmtClient.List(ctx, machineList, client.InNamespace(input.Namespace.Name), client.MatchingLabels{clusterv1.ClusterNameLabel: workloadClusterProxy.GetName()})
    70  	Expect(err).NotTo(HaveOccurred())
    71  
    72  	subscriptionID := getSubscriptionID(Default)
    73  
    74  	if len(machineList.Items) > 0 {
    75  		By("Creating a mapping of machine IDs to array of expected VM extensions")
    76  		expectedVMExtensionMap := make(map[string][]string)
    77  		for _, machine := range machineList.Items {
    78  			for _, extension := range machine.Spec.VMExtensions {
    79  				expectedVMExtensionMap[*machine.Spec.ProviderID] = append(expectedVMExtensionMap[*machine.Spec.ProviderID], extension.Name)
    80  			}
    81  		}
    82  
    83  		By("Creating a VM and VM extension client")
    84  		cred, err := azidentity.NewDefaultAzureCredential(nil)
    85  		Expect(err).NotTo(HaveOccurred())
    86  
    87  		// create a VM client
    88  		vmClient, err := armcompute.NewVirtualMachinesClient(subscriptionID, cred, nil)
    89  		Expect(err).NotTo(HaveOccurred())
    90  
    91  		// create a VM extension client
    92  		vmExtensionsClient, err := armcompute.NewVirtualMachineExtensionsClient(subscriptionID, cred, nil)
    93  		Expect(err).NotTo(HaveOccurred())
    94  
    95  		// get the resource group name
    96  		resource, err := azureutil.ParseResourceID(*machineList.Items[0].Spec.ProviderID)
    97  		Expect(err).NotTo(HaveOccurred())
    98  
    99  		var vms []*armcompute.VirtualMachine
   100  		pager := vmClient.NewListPager(resource.ResourceGroupName, nil)
   101  		for pager.More() {
   102  			nextResult, err := pager.NextPage(ctx)
   103  			Expect(err).NotTo(HaveOccurred())
   104  			vms = append(vms, nextResult.Value...)
   105  		}
   106  
   107  		By("Verifying specified VM extensions are created on Azure")
   108  		for _, machine := range vms {
   109  			vmExtensionListResult, err := vmExtensionsClient.List(ctx, resource.ResourceGroupName, *machine.Name, nil)
   110  			Expect(err).NotTo(HaveOccurred())
   111  			vmExtensionList := vmExtensionListResult.Value
   112  			var vmExtensionNames []string
   113  			for _, vmExtension := range vmExtensionList {
   114  				vmExtensionNames = append(vmExtensionNames, *vmExtension.Name)
   115  			}
   116  			osName := string(*machine.Properties.StorageProfile.OSDisk.OSType)
   117  			Expect(vmExtensionNames).To(ContainElements("CAPZ." + osName + ".Bootstrapping"))
   118  			Expect(vmExtensionNames).To(ContainElements(expectedVMExtensionMap[*machine.ID]))
   119  		}
   120  	}
   121  
   122  	By("Retrieving all machine pools from the machine template spec")
   123  	machinePoolList := &infrav1exp.AzureMachinePoolList{}
   124  	// list all of the requested objects within the cluster namespace with the cluster name label
   125  	Logf("Listing machine pools in namespace %s with label %s=%s", input.Namespace.Name, clusterv1.ClusterNameLabel, workloadClusterProxy.GetName())
   126  	err = mgmtClient.List(ctx, machinePoolList, client.InNamespace(input.Namespace.Name), client.MatchingLabels{clusterv1.ClusterNameLabel: workloadClusterProxy.GetName()})
   127  	Expect(err).NotTo(HaveOccurred())
   128  
   129  	if len(machinePoolList.Items) > 0 {
   130  		By("Creating a mapping of machine pool IDs to array of expected VMSS extensions")
   131  		expectedVMSSExtensionMap := make(map[string][]string)
   132  		for _, machinePool := range machinePoolList.Items {
   133  			for _, extension := range machinePool.Spec.Template.VMExtensions {
   134  				expectedVMSSExtensionMap[machinePool.Spec.ProviderID] = append(expectedVMSSExtensionMap[machinePool.Spec.ProviderID], extension.Name)
   135  			}
   136  		}
   137  
   138  		By("Creating a VMSS and VMSS extension client")
   139  		cred, err := azidentity.NewDefaultAzureCredential(nil)
   140  		Expect(err).NotTo(HaveOccurred())
   141  
   142  		// create a VMSS client
   143  		vmssClient, err := armcompute.NewVirtualMachineScaleSetsClient(subscriptionID, cred, nil)
   144  		Expect(err).NotTo(HaveOccurred())
   145  
   146  		// create a VMSS extension client
   147  		vmssExtensionsClient, err := armcompute.NewVirtualMachineScaleSetExtensionsClient(subscriptionID, cred, nil)
   148  		Expect(err).NotTo(HaveOccurred())
   149  
   150  		// get the resource group name
   151  		resource, err := azureutil.ParseResourceID(machinePoolList.Items[0].Spec.ProviderID)
   152  		Expect(err).NotTo(HaveOccurred())
   153  
   154  		var vmsses []*armcompute.VirtualMachineScaleSet
   155  		pager := vmssClient.NewListPager(resource.ResourceGroupName, nil)
   156  		for pager.More() {
   157  			nextResult, err := pager.NextPage(ctx)
   158  			Expect(err).NotTo(HaveOccurred())
   159  			vmsses = append(vmsses, nextResult.Value...)
   160  		}
   161  
   162  		By("Verifying VMSS extensions are created on Azure")
   163  		for _, machinePool := range vmsses {
   164  			var vmssExts []*armcompute.VirtualMachineScaleSetExtension
   165  			pager := vmssExtensionsClient.NewListPager(resource.ResourceGroupName, *machinePool.Name, nil)
   166  			for pager.More() {
   167  				nextResult, err := pager.NextPage(ctx)
   168  				Expect(err).NotTo(HaveOccurred())
   169  				vmssExts = append(vmssExts, nextResult.Value...)
   170  			}
   171  			var vmssExtensionNames []string
   172  			for _, vmssExtension := range vmssExts {
   173  				vmssExtensionNames = append(vmssExtensionNames, *vmssExtension.Name)
   174  			}
   175  			osName := string(*machinePool.Properties.VirtualMachineProfile.StorageProfile.OSDisk.OSType)
   176  			Expect(vmssExtensionNames).To(ContainElements("CAPZ." + osName + ".Bootstrapping"))
   177  			Expect(vmssExtensionNames).To(ContainElements(expectedVMSSExtensionMap[*machinePool.ID]))
   178  		}
   179  	}
   180  }