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 }