sigs.k8s.io/cluster-api-provider-azure@v1.14.3/test/e2e/aks_byo_node.go (about)

     1  //go:build e2e
     2  // +build e2e
     3  
     4  /*
     5  Copyright 2023 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  	"os"
    25  
    26  	. "github.com/onsi/ginkgo/v2"
    27  	. "github.com/onsi/gomega"
    28  	corev1 "k8s.io/api/core/v1"
    29  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    30  	"k8s.io/utils/ptr"
    31  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    32  	infrav1exp "sigs.k8s.io/cluster-api-provider-azure/exp/api/v1beta1"
    33  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    34  	bootstrapv1 "sigs.k8s.io/cluster-api/bootstrap/kubeadm/api/v1beta1"
    35  	expv1 "sigs.k8s.io/cluster-api/exp/api/v1beta1"
    36  	"sigs.k8s.io/cluster-api/util/conditions"
    37  	"sigs.k8s.io/controller-runtime/pkg/client"
    38  )
    39  
    40  type AKSBYONodeSpecInput struct {
    41  	Cluster             *clusterv1.Cluster
    42  	KubernetesVersion   string
    43  	WaitIntervals       []interface{}
    44  	ExpectedWorkerNodes int32
    45  }
    46  
    47  func AKSBYONodeSpec(ctx context.Context, inputGetter func() AKSBYONodeSpecInput) {
    48  	input := inputGetter()
    49  
    50  	mgmtClient := bootstrapClusterProxy.GetClient()
    51  	Expect(mgmtClient).NotTo(BeNil())
    52  
    53  	infraControlPlane := &infrav1.AzureManagedControlPlane{}
    54  	err := mgmtClient.Get(ctx, client.ObjectKey{Namespace: input.Cluster.Spec.ControlPlaneRef.Namespace, Name: input.Cluster.Spec.ControlPlaneRef.Name}, infraControlPlane)
    55  	Expect(err).NotTo(HaveOccurred())
    56  
    57  	By("Creating a self-managed machine pool with 2 nodes")
    58  	infraMachinePool := &infrav1exp.AzureMachinePool{
    59  		ObjectMeta: metav1.ObjectMeta{
    60  			Name:      "byo-pool",
    61  			Namespace: input.Cluster.Namespace,
    62  		},
    63  		Spec: infrav1exp.AzureMachinePoolSpec{
    64  			Location: infraControlPlane.Spec.Location,
    65  			Template: infrav1exp.AzureMachinePoolMachineTemplate{
    66  				VMSize: os.Getenv("AZURE_NODE_MACHINE_TYPE"),
    67  			},
    68  		},
    69  	}
    70  	err = mgmtClient.Create(ctx, infraMachinePool)
    71  	Expect(err).NotTo(HaveOccurred())
    72  
    73  	kubeadmConfig := &bootstrapv1.KubeadmConfig{
    74  		ObjectMeta: metav1.ObjectMeta{
    75  			Namespace: infraMachinePool.Namespace,
    76  			Name:      infraMachinePool.Name,
    77  		},
    78  		Spec: bootstrapv1.KubeadmConfigSpec{
    79  			Files: []bootstrapv1.File{
    80  				{
    81  					ContentFrom: &bootstrapv1.FileSource{
    82  						Secret: bootstrapv1.SecretFileSource{
    83  							Name: infraMachinePool.Name + "-azure-json",
    84  							Key:  "worker-node-azure.json",
    85  						},
    86  					},
    87  					Path:        "/etc/kubernetes/azure.json",
    88  					Permissions: "0644",
    89  					Owner:       "root:root",
    90  				},
    91  				{
    92  					ContentFrom: &bootstrapv1.FileSource{
    93  						Secret: bootstrapv1.SecretFileSource{
    94  							Name: input.Cluster.Name + "-kubeconfig",
    95  							Key:  "value",
    96  						},
    97  					},
    98  					Path:        "/etc/kubernetes/admin.conf",
    99  					Permissions: "0644",
   100  					Owner:       "root:root",
   101  				},
   102  			},
   103  			JoinConfiguration: &bootstrapv1.JoinConfiguration{
   104  				Discovery: bootstrapv1.Discovery{
   105  					File: &bootstrapv1.FileDiscovery{
   106  						KubeConfigPath: "/etc/kubernetes/admin.conf",
   107  					},
   108  				},
   109  				NodeRegistration: bootstrapv1.NodeRegistrationOptions{
   110  					Name: "{{ ds.meta_data[\"local_hostname\"] }}",
   111  					KubeletExtraArgs: map[string]string{
   112  						"cloud-provider": "external",
   113  					},
   114  				},
   115  			},
   116  			PreKubeadmCommands: []string{"kubeadm init phase upload-config all"},
   117  		},
   118  	}
   119  	err = mgmtClient.Create(ctx, kubeadmConfig)
   120  	Expect(err).NotTo(HaveOccurred())
   121  
   122  	machinePool := &expv1.MachinePool{
   123  		ObjectMeta: metav1.ObjectMeta{
   124  			Namespace: infraMachinePool.Namespace,
   125  			Name:      infraMachinePool.Name,
   126  		},
   127  		Spec: expv1.MachinePoolSpec{
   128  			ClusterName: input.Cluster.Name,
   129  			Replicas:    ptr.To[int32](2),
   130  			Template: clusterv1.MachineTemplateSpec{
   131  				Spec: clusterv1.MachineSpec{
   132  					Bootstrap: clusterv1.Bootstrap{
   133  						ConfigRef: &corev1.ObjectReference{
   134  							APIVersion: bootstrapv1.GroupVersion.String(),
   135  							Kind:       "KubeadmConfig",
   136  							Name:       kubeadmConfig.Name,
   137  						},
   138  					},
   139  					ClusterName: input.Cluster.Name,
   140  					InfrastructureRef: corev1.ObjectReference{
   141  						APIVersion: infrav1.GroupVersion.String(),
   142  						Kind:       "AzureMachinePool",
   143  						Name:       infraMachinePool.Name,
   144  					},
   145  					Version: ptr.To(input.KubernetesVersion),
   146  				},
   147  			},
   148  		},
   149  	}
   150  	err = mgmtClient.Create(ctx, machinePool)
   151  	Expect(err).NotTo(HaveOccurred())
   152  
   153  	By("creating a Kubernetes client to the workload cluster")
   154  	workloadClusterProxy := bootstrapClusterProxy.GetWorkloadCluster(ctx, input.Cluster.Spec.ControlPlaneRef.Namespace, input.Cluster.Spec.ControlPlaneRef.Name)
   155  	Expect(workloadClusterProxy).NotTo(BeNil())
   156  	clientset := workloadClusterProxy.GetClientSet()
   157  	Expect(clientset).NotTo(BeNil())
   158  
   159  	By("Verifying the bootstrap succeeded")
   160  	Eventually(func(g Gomega) {
   161  		pool := &infrav1exp.AzureMachinePool{}
   162  		err := mgmtClient.Get(ctx, client.ObjectKeyFromObject(infraMachinePool), pool)
   163  		g.Expect(err).NotTo(HaveOccurred())
   164  		g.Expect(conditions.IsTrue(pool, infrav1.BootstrapSucceededCondition)).To(BeTrue())
   165  	}, input.WaitIntervals...).Should(Succeed())
   166  
   167  	By("Adding the expected AKS labels to the nodes")
   168  	// TODO: move this to the MachinePool object once MachinePools support label propagation
   169  	Eventually(func(g Gomega) {
   170  		nodeList, err := clientset.CoreV1().Nodes().List(ctx, metav1.ListOptions{})
   171  		g.Expect(err).NotTo(HaveOccurred())
   172  		g.Expect(int32(len(nodeList.Items))).To(Equal(input.ExpectedWorkerNodes + 2))
   173  		for i, node := range nodeList.Items {
   174  			if _, ok := node.Labels["kubernetes.azure.com/cluster"]; !ok {
   175  				node.Labels["kubernetes.azure.com/cluster"] = infraControlPlane.Spec.NodeResourceGroupName
   176  				_, err := clientset.CoreV1().Nodes().Update(ctx, &nodeList.Items[i], metav1.UpdateOptions{})
   177  				g.Expect(err).NotTo(HaveOccurred())
   178  			}
   179  		}
   180  	}, input.WaitIntervals...).Should(Succeed())
   181  
   182  	By("Verifying the MachinePool becomes ready")
   183  	Eventually(func(g Gomega) {
   184  		pool := &expv1.MachinePool{}
   185  		err := mgmtClient.Get(ctx, client.ObjectKeyFromObject(machinePool), pool)
   186  		g.Expect(err).NotTo(HaveOccurred())
   187  		g.Expect(conditions.IsTrue(pool, clusterv1.ReadyCondition)).To(BeTrue())
   188  	}, input.WaitIntervals...).Should(Succeed())
   189  }