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

     1  //go:build e2e
     2  // +build e2e
     3  
     4  /*
     5  Copyright 2020 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  	"fmt"
    25  	"os"
    26  	"time"
    27  
    28  	. "github.com/onsi/ginkgo/v2"
    29  	. "github.com/onsi/gomega"
    30  	corev1 "k8s.io/api/core/v1"
    31  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    32  	"k8s.io/utils/ptr"
    33  	e2e_namespace "sigs.k8s.io/cluster-api-provider-azure/test/e2e/kubernetes/namespace"
    34  	clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
    35  	capi_e2e "sigs.k8s.io/cluster-api/test/e2e"
    36  	"sigs.k8s.io/cluster-api/test/framework"
    37  	"sigs.k8s.io/cluster-api/test/framework/clusterctl"
    38  	"sigs.k8s.io/cluster-api/util"
    39  )
    40  
    41  const (
    42  	IdentitySecretName = "cluster-identity-secret"
    43  )
    44  
    45  var _ = Describe("Running the Cluster API E2E tests", func() {
    46  	var (
    47  		ctx               = context.TODO()
    48  		identityNamespace *corev1.Namespace
    49  		specTimes         = map[string]time.Time{}
    50  		err               error
    51  	)
    52  	BeforeEach(func() {
    53  		Expect(e2eConfig.Variables).To(HaveKey(capi_e2e.CNIPath))
    54  		rgName := fmt.Sprintf("capz-e2e-%s", util.RandomString(6))
    55  		Expect(os.Setenv(AzureResourceGroup, rgName)).To(Succeed())
    56  		Expect(os.Setenv(AzureVNetName, fmt.Sprintf("%s-vnet", rgName))).To(Succeed())
    57  
    58  		Expect(e2eConfig.Variables).To(HaveKey(capi_e2e.KubernetesVersionUpgradeFrom))
    59  		Expect(os.Setenv("WINDOWS_WORKER_MACHINE_COUNT", "2")).To(Succeed())
    60  
    61  		clientset := bootstrapClusterProxy.GetClientSet()
    62  		Expect(clientset).NotTo(BeNil())
    63  		ns := fmt.Sprintf("capz-e2e-identity-%s", util.RandomString(6))
    64  
    65  		identityNamespace, err = e2e_namespace.Create(ctx, clientset, ns, map[string]string{})
    66  		Expect(err).NotTo(HaveOccurred())
    67  
    68  		spClientSecret := os.Getenv(AzureClientSecret)
    69  		secret := &corev1.Secret{
    70  			ObjectMeta: metav1.ObjectMeta{
    71  				Name:      IdentitySecretName,
    72  				Namespace: identityNamespace.Name,
    73  				Labels: map[string]string{
    74  					clusterctlv1.ClusterctlMoveHierarchyLabel: "true",
    75  				},
    76  			},
    77  			Type: corev1.SecretTypeOpaque,
    78  			Data: map[string][]byte{"clientSecret": []byte(spClientSecret)},
    79  		}
    80  		err = bootstrapClusterProxy.GetClient().Create(ctx, secret)
    81  		Expect(err).NotTo(HaveOccurred())
    82  
    83  		identityName := e2eConfig.GetVariable(ClusterIdentityName)
    84  		Expect(os.Setenv(ClusterIdentityName, identityName)).To(Succeed())
    85  		Expect(os.Setenv(ClusterIdentitySecretName, IdentitySecretName)).To(Succeed())
    86  		Expect(os.Setenv(ClusterIdentitySecretNamespace, identityNamespace.Name)).To(Succeed())
    87  
    88  		logCheckpoint(specTimes)
    89  	})
    90  
    91  	AfterEach(func() {
    92  		CheckTestBeforeCleanup()
    93  		redactLogs()
    94  
    95  		Expect(os.Unsetenv(AzureResourceGroup)).To(Succeed())
    96  		Expect(os.Unsetenv(AzureVNetName)).To(Succeed())
    97  		Expect(os.Unsetenv(ClusterIdentityName)).To(Succeed())
    98  		Expect(os.Unsetenv(ClusterIdentitySecretName)).To(Succeed())
    99  		Expect(os.Unsetenv(ClusterIdentitySecretNamespace)).To(Succeed())
   100  
   101  		logCheckpoint(specTimes)
   102  	})
   103  
   104  	Context("Running the quick-start spec", func() {
   105  		capi_e2e.QuickStartSpec(context.TODO(), func() capi_e2e.QuickStartSpecInput {
   106  			return capi_e2e.QuickStartSpecInput{
   107  				E2EConfig:             e2eConfig,
   108  				ClusterctlConfigPath:  clusterctlConfigPath,
   109  				BootstrapClusterProxy: bootstrapClusterProxy,
   110  				ArtifactFolder:        artifactFolder,
   111  				SkipCleanup:           skipCleanup,
   112  				ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   113  					WaitForControlPlaneInitialized: EnsureControlPlaneInitializedNoAddons,
   114  				},
   115  			}
   116  		})
   117  	})
   118  
   119  	Context("Running the MachineDeployment rollout spec", func() {
   120  		capi_e2e.MachineDeploymentRolloutSpec(context.TODO(), func() capi_e2e.MachineDeploymentRolloutSpecInput {
   121  			return capi_e2e.MachineDeploymentRolloutSpecInput{
   122  				E2EConfig:             e2eConfig,
   123  				ClusterctlConfigPath:  clusterctlConfigPath,
   124  				BootstrapClusterProxy: bootstrapClusterProxy,
   125  				ArtifactFolder:        artifactFolder,
   126  				SkipCleanup:           skipCleanup,
   127  				ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   128  					WaitForControlPlaneInitialized: EnsureControlPlaneInitializedNoAddons,
   129  				},
   130  			}
   131  		})
   132  	})
   133  
   134  	if os.Getenv("USE_LOCAL_KIND_REGISTRY") != "true" {
   135  		Context("Running the self-hosted spec", func() {
   136  			SelfHostedSpec(context.TODO(), func() SelfHostedSpecInput {
   137  				return SelfHostedSpecInput{
   138  					E2EConfig:             e2eConfig,
   139  					ClusterctlConfigPath:  clusterctlConfigPath,
   140  					BootstrapClusterProxy: bootstrapClusterProxy,
   141  					ArtifactFolder:        artifactFolder,
   142  					SkipCleanup:           skipCleanup,
   143  					ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   144  						WaitForControlPlaneInitialized: EnsureControlPlaneInitializedNoAddons,
   145  					},
   146  				}
   147  			})
   148  		})
   149  	}
   150  
   151  	// TODO: Add test using KCPRemediationSpec
   152  	Context("Should successfully remediate unhealthy worker machines with MachineHealthCheck", func() {
   153  		capi_e2e.MachineDeploymentRemediationSpec(context.TODO(), func() capi_e2e.MachineDeploymentRemediationSpecInput {
   154  			return capi_e2e.MachineDeploymentRemediationSpecInput{
   155  				E2EConfig:             e2eConfig,
   156  				ClusterctlConfigPath:  clusterctlConfigPath,
   157  				BootstrapClusterProxy: bootstrapClusterProxy,
   158  				ArtifactFolder:        artifactFolder,
   159  				SkipCleanup:           skipCleanup,
   160  				ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   161  					WaitForControlPlaneInitialized: EnsureControlPlaneInitializedNoAddons,
   162  				},
   163  			}
   164  		})
   165  	})
   166  
   167  	Context("Should successfully exercise machine pools", func() {
   168  		capi_e2e.MachinePoolSpec(context.TODO(), func() capi_e2e.MachinePoolInput {
   169  			return capi_e2e.MachinePoolInput{
   170  				E2EConfig:             e2eConfig,
   171  				ClusterctlConfigPath:  clusterctlConfigPath,
   172  				BootstrapClusterProxy: bootstrapClusterProxy,
   173  				ArtifactFolder:        artifactFolder,
   174  				SkipCleanup:           skipCleanup,
   175  				ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   176  					WaitForControlPlaneInitialized: EnsureControlPlaneInitializedNoAddons,
   177  				},
   178  			}
   179  		})
   180  	})
   181  
   182  	Context("Should successfully scale out and scale in a MachineDeployment", func() {
   183  		capi_e2e.MachineDeploymentScaleSpec(context.TODO(), func() capi_e2e.MachineDeploymentScaleSpecInput {
   184  			return capi_e2e.MachineDeploymentScaleSpecInput{
   185  				E2EConfig:             e2eConfig,
   186  				ClusterctlConfigPath:  clusterctlConfigPath,
   187  				BootstrapClusterProxy: bootstrapClusterProxy,
   188  				ArtifactFolder:        artifactFolder,
   189  				SkipCleanup:           skipCleanup,
   190  				ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   191  					WaitForControlPlaneInitialized: EnsureControlPlaneInitializedNoAddons,
   192  				},
   193  			}
   194  		})
   195  	})
   196  
   197  	Context("Should successfully set and use node drain timeout", func() {
   198  		capi_e2e.NodeDrainTimeoutSpec(context.TODO(), func() capi_e2e.NodeDrainTimeoutSpecInput {
   199  			return capi_e2e.NodeDrainTimeoutSpecInput{
   200  				E2EConfig:             e2eConfig,
   201  				ClusterctlConfigPath:  clusterctlConfigPath,
   202  				BootstrapClusterProxy: bootstrapClusterProxy,
   203  				ArtifactFolder:        artifactFolder,
   204  				SkipCleanup:           skipCleanup,
   205  				ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   206  					WaitForControlPlaneInitialized: EnsureControlPlaneInitializedNoAddons,
   207  				},
   208  			}
   209  		})
   210  	})
   211  
   212  	if os.Getenv("USE_LOCAL_KIND_REGISTRY") != "true" {
   213  		Context("API Version Upgrade", func() {
   214  			BeforeEach(func() {
   215  				// Unset resource group and vnet env variables, since the upgrade test creates 2 clusters,
   216  				// and will result in both the clusters using the same vnet and resource group.
   217  				Expect(os.Unsetenv(AzureResourceGroup)).To(Succeed())
   218  				Expect(os.Unsetenv(AzureVNetName)).To(Succeed())
   219  
   220  				// Unset windows specific variables
   221  				Expect(os.Unsetenv("WINDOWS_WORKER_MACHINE_COUNT")).To(Succeed())
   222  
   223  				Expect(os.Setenv("K8S_FEATURE_GATES", "WindowsHostProcessContainers=true")).To(Succeed())
   224  			})
   225  
   226  			Context("upgrade from an old version of v1beta1 to current, and scale workload clusters created in the old version", func() {
   227  				capi_e2e.ClusterctlUpgradeSpec(ctx, func() capi_e2e.ClusterctlUpgradeSpecInput {
   228  					return capi_e2e.ClusterctlUpgradeSpecInput{
   229  						E2EConfig:                 e2eConfig,
   230  						ClusterctlConfigPath:      clusterctlConfigPath,
   231  						BootstrapClusterProxy:     bootstrapClusterProxy,
   232  						ArtifactFolder:            artifactFolder,
   233  						SkipCleanup:               skipCleanup,
   234  						PreInit:                   getPreInitFunc(ctx),
   235  						InitWithProvidersContract: "v1beta1",
   236  						ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   237  							WaitForControlPlaneInitialized: EnsureControlPlaneInitialized,
   238  						},
   239  						InitWithKubernetesVersion:       e2eConfig.GetVariable(KubernetesVersionAPIUpgradeFrom),
   240  						InitWithBinary:                  fmt.Sprintf("https://github.com/kubernetes-sigs/cluster-api/releases/download/%s/clusterctl-{OS}-{ARCH}", e2eConfig.GetVariable(OldCAPIUpgradeVersion)),
   241  						InitWithCoreProvider:            "cluster-api:" + e2eConfig.GetVariable(OldCAPIUpgradeVersion),
   242  						InitWithBootstrapProviders:      []string{"kubeadm:" + e2eConfig.GetVariable(OldCAPIUpgradeVersion)},
   243  						InitWithControlPlaneProviders:   []string{"kubeadm:" + e2eConfig.GetVariable(OldCAPIUpgradeVersion)},
   244  						InitWithInfrastructureProviders: []string{"azure:" + e2eConfig.GetVariable(OldProviderUpgradeVersion)},
   245  						InitWithAddonProviders:          []string{"helm:" + e2eConfig.GetVariable(OldAddonProviderUpgradeVersion)},
   246  					}
   247  				})
   248  			})
   249  
   250  			Context("upgrade from the latest version of v1beta1 to current, and scale workload clusters created in the old version", func() {
   251  				capi_e2e.ClusterctlUpgradeSpec(ctx, func() capi_e2e.ClusterctlUpgradeSpecInput {
   252  					return capi_e2e.ClusterctlUpgradeSpecInput{
   253  						E2EConfig:                 e2eConfig,
   254  						ClusterctlConfigPath:      clusterctlConfigPath,
   255  						BootstrapClusterProxy:     bootstrapClusterProxy,
   256  						ArtifactFolder:            artifactFolder,
   257  						SkipCleanup:               skipCleanup,
   258  						PreInit:                   getPreInitFunc(ctx),
   259  						InitWithProvidersContract: "v1beta1",
   260  						ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   261  							WaitForControlPlaneInitialized: EnsureControlPlaneInitialized,
   262  						},
   263  						InitWithKubernetesVersion:       e2eConfig.GetVariable(KubernetesVersionAPIUpgradeFrom),
   264  						InitWithBinary:                  fmt.Sprintf("https://github.com/kubernetes-sigs/cluster-api/releases/download/%s/clusterctl-{OS}-{ARCH}", e2eConfig.GetVariable(LatestCAPIUpgradeVersion)),
   265  						InitWithCoreProvider:            "cluster-api:" + e2eConfig.GetVariable(LatestCAPIUpgradeVersion),
   266  						InitWithBootstrapProviders:      []string{"kubeadm:" + e2eConfig.GetVariable(LatestCAPIUpgradeVersion)},
   267  						InitWithControlPlaneProviders:   []string{"kubeadm:" + e2eConfig.GetVariable(LatestCAPIUpgradeVersion)},
   268  						InitWithInfrastructureProviders: []string{"azure:" + e2eConfig.GetVariable(LatestProviderUpgradeVersion)},
   269  						InitWithAddonProviders:          []string{"helm:" + e2eConfig.GetVariable(LatestAddonProviderUpgradeVersion)},
   270  					}
   271  				})
   272  			})
   273  		})
   274  	}
   275  
   276  	Context("Running the workload cluster upgrade spec [K8s-Upgrade]", func() {
   277  		capi_e2e.ClusterUpgradeConformanceSpec(ctx, func() capi_e2e.ClusterUpgradeConformanceSpecInput {
   278  			return capi_e2e.ClusterUpgradeConformanceSpecInput{
   279  				E2EConfig:             e2eConfig,
   280  				ClusterctlConfigPath:  clusterctlConfigPath,
   281  				BootstrapClusterProxy: bootstrapClusterProxy,
   282  				ArtifactFolder:        artifactFolder,
   283  				SkipCleanup:           skipCleanup,
   284  				SkipConformanceTests:  true,
   285  				ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   286  					WaitForControlPlaneInitialized: EnsureControlPlaneInitialized,
   287  				},
   288  			}
   289  		})
   290  	})
   291  
   292  	Context("Running KCP upgrade in a HA cluster [K8s-Upgrade]", func() {
   293  		capi_e2e.ClusterUpgradeConformanceSpec(context.TODO(), func() capi_e2e.ClusterUpgradeConformanceSpecInput {
   294  			return capi_e2e.ClusterUpgradeConformanceSpecInput{
   295  				E2EConfig:                e2eConfig,
   296  				ClusterctlConfigPath:     clusterctlConfigPath,
   297  				BootstrapClusterProxy:    bootstrapClusterProxy,
   298  				ArtifactFolder:           artifactFolder,
   299  				ControlPlaneMachineCount: ptr.To[int64](3),
   300  				WorkerMachineCount:       ptr.To[int64](0),
   301  				SkipCleanup:              skipCleanup,
   302  				SkipConformanceTests:     true,
   303  				ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   304  					WaitForControlPlaneInitialized: EnsureControlPlaneInitialized,
   305  				},
   306  			}
   307  		})
   308  	})
   309  
   310  	Context("Running KCP upgrade in a HA cluster using scale in rollout [K8s-Upgrade]", func() {
   311  		capi_e2e.ClusterUpgradeConformanceSpec(context.TODO(), func() capi_e2e.ClusterUpgradeConformanceSpecInput {
   312  			return capi_e2e.ClusterUpgradeConformanceSpecInput{
   313  				E2EConfig:                e2eConfig,
   314  				ClusterctlConfigPath:     clusterctlConfigPath,
   315  				BootstrapClusterProxy:    bootstrapClusterProxy,
   316  				ArtifactFolder:           artifactFolder,
   317  				ControlPlaneMachineCount: ptr.To[int64](3),
   318  				WorkerMachineCount:       ptr.To[int64](0),
   319  				SkipCleanup:              skipCleanup,
   320  				SkipConformanceTests:     true,
   321  				Flavor:                   ptr.To("kcp-scale-in"),
   322  				ControlPlaneWaiters: clusterctl.ControlPlaneWaiters{
   323  					WaitForControlPlaneInitialized: EnsureControlPlaneInitialized,
   324  				},
   325  			}
   326  		})
   327  	})
   328  })
   329  
   330  func getPreInitFunc(ctx context.Context) func(proxy framework.ClusterProxy) {
   331  	return func(clusterProxy framework.ClusterProxy) {
   332  		spClientSecret := os.Getenv(AzureClientSecret)
   333  		secret := &corev1.Secret{
   334  			ObjectMeta: metav1.ObjectMeta{
   335  				Name:      IdentitySecretName,
   336  				Namespace: "default",
   337  				Labels: map[string]string{
   338  					clusterctlv1.ClusterctlMoveHierarchyLabel: "true",
   339  				},
   340  			},
   341  			Type: corev1.SecretTypeOpaque,
   342  			Data: map[string][]byte{"clientSecret": []byte(spClientSecret)},
   343  		}
   344  		err := clusterProxy.GetClient().Create(ctx, secret)
   345  		Expect(err).NotTo(HaveOccurred())
   346  
   347  		identityName := e2eConfig.GetVariable(ClusterIdentityName)
   348  		Expect(os.Setenv(ClusterIdentityName, identityName)).To(Succeed())
   349  		Expect(os.Setenv(ClusterIdentitySecretName, IdentitySecretName)).To(Succeed())
   350  		Expect(os.Setenv(ClusterIdentitySecretNamespace, "default")).To(Succeed())
   351  	}
   352  }