sigs.k8s.io/cluster-api-provider-azure@v1.14.3/test/e2e/aks.go (about) 1 //go:build e2e 2 // +build e2e 3 4 /* 5 Copyright 2021 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/onsi/ginkgo/v2" 26 . "github.com/onsi/gomega" 27 "k8s.io/apimachinery/pkg/types" 28 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 29 clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" 30 expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1" 31 "sigs.k8s.io/cluster-api/test/framework" 32 "sigs.k8s.io/cluster-api/test/framework/clusterctl" 33 "sigs.k8s.io/controller-runtime/pkg/client" 34 ) 35 36 // DiscoverAndWaitForAKSControlPlaneInput contains the fields the required for checking the status of azure managed control plane. 37 type DiscoverAndWaitForAKSControlPlaneInput struct { 38 Lister framework.Lister 39 Getter framework.Getter 40 Cluster *clusterv1.Cluster 41 } 42 43 // WaitForAKSControlPlaneInitialized waits for the Azure managed control plane to be initialized. 44 // This will be invoked by cluster api e2e framework. 45 func WaitForAKSControlPlaneInitialized(ctx context.Context, input clusterctl.ApplyCustomClusterTemplateAndWaitInput, result *clusterctl.ApplyCustomClusterTemplateAndWaitResult) { 46 client := input.ClusterProxy.GetClient() 47 cluster := framework.GetClusterByName(ctx, framework.GetClusterByNameInput{ 48 Getter: client, 49 Name: input.ClusterName, 50 Namespace: input.Namespace, 51 }) 52 53 DiscoverAndWaitForAKSControlPlaneInitialized(ctx, DiscoverAndWaitForAKSControlPlaneInput{ 54 Lister: client, 55 Getter: client, 56 Cluster: result.Cluster, 57 }, input.WaitForControlPlaneIntervals...) 58 if cluster.Spec.ClusterNetwork != nil && cluster.Spec.ClusterNetwork.Services != nil { 59 InstallCNIManifest(ctx, input, cluster.Spec.ClusterNetwork.Services.CIDRBlocks, true) 60 } 61 } 62 63 // WaitForAKSControlPlaneReady waits for the azure managed control plane to be ready. 64 // This will be invoked by cluster api e2e framework. 65 func WaitForAKSControlPlaneReady(ctx context.Context, input clusterctl.ApplyCustomClusterTemplateAndWaitInput, result *clusterctl.ApplyCustomClusterTemplateAndWaitResult) { 66 client := input.ClusterProxy.GetClient() 67 DiscoverAndWaitForAKSControlPlaneReady(ctx, DiscoverAndWaitForAKSControlPlaneInput{ 68 Lister: client, 69 Getter: client, 70 Cluster: result.Cluster, 71 }, input.WaitForControlPlaneIntervals...) 72 } 73 74 // DiscoverAndWaitForAKSControlPlaneInitialized gets the Azure managed control plane associated with the cluster 75 // and waits for at least one machine in the "system" node pool to exist. 76 func DiscoverAndWaitForAKSControlPlaneInitialized(ctx context.Context, input DiscoverAndWaitForAKSControlPlaneInput, intervals ...interface{}) { 77 Expect(ctx).NotTo(BeNil(), "ctx is required for DiscoverAndWaitForAKSControlPlaneInitialized") 78 Expect(input.Lister).NotTo(BeNil(), "Invalid argument. input.Lister can't be nil when calling DiscoverAndWaitForAKSControlPlaneInitialized") 79 Expect(input.Cluster).NotTo(BeNil(), "Invalid argument. input.Cluster can't be nil when calling DiscoverAndWaitForAKSControlPlaneInitialized") 80 81 controlPlane := GetAzureManagedControlPlaneByCluster(ctx, GetAzureManagedControlPlaneByClusterInput{ 82 Lister: input.Lister, 83 ClusterName: input.Cluster.Name, 84 Namespace: input.Cluster.Namespace, 85 }) 86 Expect(controlPlane).NotTo(BeNil()) 87 88 Logf("Waiting for the first AKS machine in the %s/%s 'system' node pool to exist", controlPlane.Namespace, controlPlane.Name) 89 WaitForAtLeastOneSystemNodePoolMachineToExist(ctx, WaitForControlPlaneAndMachinesReadyInput{ 90 Lister: input.Lister, 91 Getter: input.Getter, 92 ControlPlane: controlPlane, 93 ClusterName: input.Cluster.Name, 94 Namespace: input.Cluster.Namespace, 95 }, intervals...) 96 } 97 98 // DiscoverAndWaitForAKSControlPlaneReady gets the Azure managed control plane associated with the cluster 99 // and waits for all the machines in the 'system' node pool to exist. 100 func DiscoverAndWaitForAKSControlPlaneReady(ctx context.Context, input DiscoverAndWaitForAKSControlPlaneInput, intervals ...interface{}) { 101 Expect(ctx).NotTo(BeNil(), "ctx is required for DiscoverAndWaitForAKSControlPlaneReady") 102 Expect(input.Lister).NotTo(BeNil(), "Invalid argument. input.Lister can't be nil when calling DiscoverAndWaitForAKSControlPlaneReady") 103 Expect(input.Cluster).NotTo(BeNil(), "Invalid argument. input.Cluster can't be nil when calling DiscoverAndWaitForAKSControlPlaneReady") 104 105 controlPlane := GetAzureManagedControlPlaneByCluster(ctx, GetAzureManagedControlPlaneByClusterInput{ 106 Lister: input.Lister, 107 ClusterName: input.Cluster.Name, 108 Namespace: input.Cluster.Namespace, 109 }) 110 Expect(controlPlane).NotTo(BeNil()) 111 112 Logf("Waiting for all AKS machines in the %s/%s 'system' node pool to exist", controlPlane.Namespace, controlPlane.Name) 113 WaitForAllControlPlaneAndMachinesToExist(ctx, WaitForControlPlaneAndMachinesReadyInput{ 114 Lister: input.Lister, 115 Getter: input.Getter, 116 ControlPlane: controlPlane, 117 ClusterName: input.Cluster.Name, 118 Namespace: input.Cluster.Namespace, 119 }, intervals...) 120 } 121 122 // GetAzureManagedControlPlaneByClusterInput contains the fields the required for fetching the azure managed control plane. 123 type GetAzureManagedControlPlaneByClusterInput struct { 124 Lister framework.Lister 125 ClusterName string 126 Namespace string 127 } 128 129 // GetAzureManagedControlPlaneByCluster returns the AzureManagedControlPlane object for a cluster. 130 // Important! this method relies on labels that are created by the CAPI controllers during the first reconciliation, so 131 // it is necessary to ensure this is already happened before calling it. 132 func GetAzureManagedControlPlaneByCluster(ctx context.Context, input GetAzureManagedControlPlaneByClusterInput) *infrav1.AzureManagedControlPlane { 133 controlPlaneList := &infrav1.AzureManagedControlPlaneList{} 134 Expect(input.Lister.List(ctx, controlPlaneList, byClusterOptions(input.ClusterName, input.Namespace)...)).To(Succeed(), "Failed to list AzureManagedControlPlane object for Cluster %s/%s", input.Namespace, input.ClusterName) 135 Expect(len(controlPlaneList.Items)).NotTo(BeNumerically(">", 1), "Cluster %s/%s should not have more than 1 AzureManagedControlPlane object", input.Namespace, input.ClusterName) 136 if len(controlPlaneList.Items) == 1 { 137 return &controlPlaneList.Items[0] 138 } 139 return nil 140 } 141 142 // WaitForControlPlaneAndMachinesReadyInput contains the fields required for checking the status of azure managed control plane machines. 143 type WaitForControlPlaneAndMachinesReadyInput struct { 144 Lister framework.Lister 145 Getter framework.Getter 146 ControlPlane *infrav1.AzureManagedControlPlane 147 ClusterName string 148 Namespace string 149 } 150 151 // WaitForAtLeastOneSystemNodePoolMachineToExist waits for at least one machine in the "system" node pool to exist. 152 func WaitForAtLeastOneSystemNodePoolMachineToExist(ctx context.Context, input WaitForControlPlaneAndMachinesReadyInput, intervals ...interface{}) { 153 By("Waiting for at least one node to exist in the 'system' node pool") 154 WaitForAKSSystemNodePoolMachinesToExist(ctx, input, atLeastOne, intervals...) 155 } 156 157 // WaitForAllControlPlaneAndMachinesToExist waits for all machines in the "system" node pool to exist. 158 func WaitForAllControlPlaneAndMachinesToExist(ctx context.Context, input WaitForControlPlaneAndMachinesReadyInput, intervals ...interface{}) { 159 By("Waiting for all nodes to exist in the 'system' node pool") 160 WaitForAKSSystemNodePoolMachinesToExist(ctx, input, all, intervals...) 161 } 162 163 // controlPlaneReplicas represents the count of control plane machines. 164 type controlPlaneReplicas string 165 166 const ( 167 atLeastOne controlPlaneReplicas = "atLeastOne" 168 all controlPlaneReplicas = "all" 169 ) 170 171 // value returns the integer equivalent of controlPlaneReplicas 172 func (r controlPlaneReplicas) value(mp *expv1.MachinePool) int { 173 switch r { 174 case atLeastOne: 175 return 1 176 case all: 177 return int(*mp.Spec.Replicas) 178 } 179 return 0 180 } 181 182 // WaitForAKSSystemNodePoolMachinesToExist waits for a certain number of machines in the "system" node pool to exist. 183 func WaitForAKSSystemNodePoolMachinesToExist(ctx context.Context, input WaitForControlPlaneAndMachinesReadyInput, minReplicas controlPlaneReplicas, intervals ...interface{}) { 184 Eventually(func() bool { 185 opt1 := client.InNamespace(input.Namespace) 186 opt2 := client.MatchingLabels(map[string]string{ 187 infrav1.LabelAgentPoolMode: string(infrav1.NodePoolModeSystem), 188 clusterv1.ClusterNameLabel: input.ClusterName, 189 }) 190 191 ammpList := &infrav1.AzureManagedMachinePoolList{} 192 193 if err := input.Lister.List(ctx, ammpList, opt1, opt2); err != nil { 194 LogWarningf("Failed to get machinePool: %+v", err) 195 return false 196 } 197 198 for _, pool := range ammpList.Items { 199 // Fetch the owning MachinePool. 200 for _, ref := range pool.OwnerReferences { 201 if ref.Kind != "MachinePool" { 202 continue 203 } 204 205 ownerMachinePool := &expv1.MachinePool{} 206 if err := input.Getter.Get(ctx, types.NamespacedName{Namespace: input.Namespace, Name: ref.Name}, 207 ownerMachinePool); err != nil { 208 LogWarningf("Failed to get machinePool: %+v", err) 209 return false 210 } 211 if len(ownerMachinePool.Status.NodeRefs) >= minReplicas.value(ownerMachinePool) { 212 return true 213 } 214 } 215 } 216 217 return false 218 }, intervals...).Should(BeTrue(), "System machine pools not detected") 219 }