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  }