github.com/verrazzano/verrazzano@v1.7.1/tests/e2e/clusterapi/oke-capi-driver/oke_cluster_driver_test.go (about)

     1  // Copyright (c) 2023, Oracle and/or its affiliates.
     2  // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
     3  
     4  package okecapidriver
     5  
     6  import (
     7  	"fmt"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/verrazzano/verrazzano/pkg/k8sutil"
    12  	"github.com/verrazzano/verrazzano/tests/e2e/backup/helpers"
    13  	"github.com/verrazzano/verrazzano/tests/e2e/pkg"
    14  	"github.com/verrazzano/verrazzano/tests/e2e/pkg/test/framework"
    15  
    16  	. "github.com/onsi/ginkgo/v2"
    17  	. "github.com/onsi/gomega"
    18  )
    19  
    20  const (
    21  	shortWaitTimeout       = 10 * time.Minute
    22  	shortPollingInterval   = 10 * time.Second
    23  	waitTimeout            = 45 * time.Minute
    24  	pollingInterval        = 30 * time.Second
    25  	skipOKEUpgradeMessage  = "Skipping test since the kubernetes version is same for install and update operations for OKE cluster upgrade"
    26  	skipRunAllTestsMessage = "Skipping test since the runAllTests flag was set to false"
    27  )
    28  
    29  var (
    30  	t = framework.NewTestFramework("okecapi-driver")
    31  
    32  	clusterNameNodePool       string
    33  	clusterNameNodePoolUpdate string
    34  	clusterNameOKEUpgrade     string
    35  	clusterNameInvalid        string
    36  )
    37  
    38  // Part of SynchronizedBeforeSuite, run by only one process
    39  func synchronizedBeforeSuiteProcess1Func() []byte {
    40  	kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
    41  	Expect(err).ShouldNot(HaveOccurred())
    42  	if !pkg.IsRancherEnabled(kubeconfigPath) || !pkg.IsClusterAPIEnabled(kubeconfigPath) {
    43  		AbortSuite("skipping OKE CAPI cluster driver test suite since either of rancher and capi components are not enabled")
    44  	}
    45  
    46  	httpClient, err = pkg.GetVerrazzanoHTTPClient(kubeconfigPath)
    47  	if err != nil {
    48  		AbortSuite(fmt.Sprintf("failed getting http client: %v", err))
    49  	}
    50  
    51  	rancherURL, err = helpers.GetRancherURL(t.Logs)
    52  	if err != nil {
    53  		AbortSuite(fmt.Sprintf("failed getting rancherURL: %v", err))
    54  	}
    55  
    56  	verifyRequiredEnvironmentVariables()
    57  
    58  	cloudCredentialName := fmt.Sprintf("strudel-cred-%s", okeCapiClusterNameSuffix)
    59  	// Create the cloud credential to be used for all tests
    60  	var credentialID string
    61  	Eventually(func() error {
    62  		var err error
    63  		credentialID, err = createCloudCredential(cloudCredentialName, t.Logs)
    64  		return err
    65  	}, shortWaitTimeout, shortPollingInterval).Should(BeNil())
    66  
    67  	Eventually(func() error {
    68  		return validateCloudCredential(credentialID, t.Logs)
    69  	}, shortWaitTimeout, shortPollingInterval).Should(BeNil())
    70  
    71  	// Return byte encoded cloud credential ID to be shared across all processes
    72  	return []byte(credentialID)
    73  }
    74  
    75  // Part of SynchronizedBeforeSuite, run by all processes
    76  func synchronizedBeforeSuiteAllProcessesFunc(credentialIDBytes []byte) {
    77  	// Define global variables for all processes
    78  	cloudCredentialID = string(credentialIDBytes)
    79  
    80  	kubeconfigPath, err := k8sutil.GetKubeConfigLocation()
    81  	Expect(err).ShouldNot(HaveOccurred())
    82  
    83  	httpClient, err = pkg.GetVerrazzanoHTTPClient(kubeconfigPath)
    84  	if err != nil {
    85  		AbortSuite(fmt.Sprintf("failed getting http client: %v", err))
    86  	}
    87  
    88  	rancherURL, err = helpers.GetRancherURL(t.Logs)
    89  	if err != nil {
    90  		AbortSuite(fmt.Sprintf("failed getting rancherURL: %v", err))
    91  	}
    92  
    93  	// Calling this method again so that all processes have the variables initialized
    94  	verifyRequiredEnvironmentVariables()
    95  
    96  	err = ensureOKEDriverVarsInitialized(t.Logs)
    97  	Expect(err).ShouldNot(HaveOccurred())
    98  
    99  	t.Logs.Infof("Min k8s version: %s", okeMetadataItemToInstall.KubernetesVersion.Original())
   100  	t.Logs.Infof("Max k8s version: %s", okeMetadataItemToUpgrade.KubernetesVersion.Original())
   101  
   102  	clusterNameNodePool = fmt.Sprintf("strudel-pool-%s", okeCapiClusterNameSuffix)
   103  	clusterNameNodePoolUpdate = fmt.Sprintf("strudel-pool-update-%s", okeCapiClusterNameSuffix)
   104  	clusterNameInvalid = fmt.Sprintf("strudel-invalid-k8s-%s", okeCapiClusterNameSuffix)
   105  	clusterNameOKEUpgrade = fmt.Sprintf("strudel-oke-upgrade-%s", okeCapiClusterNameSuffix)
   106  }
   107  
   108  var _ = t.SynchronizedBeforeSuite(synchronizedBeforeSuiteProcess1Func, synchronizedBeforeSuiteAllProcessesFunc)
   109  
   110  // Part of SynchronizedAfterSuite, run by only one process
   111  func synchronizedAfterSuiteProcess1Func() {
   112  	// Delete the clusters concurrently
   113  	clusterNames := []string{clusterNameNodePool}
   114  	if runAllTests {
   115  		clusterNames = append(clusterNames, clusterNameNodePoolUpdate, clusterNameInvalid, clusterNameOKEUpgrade)
   116  	}
   117  	var wg sync.WaitGroup
   118  	for _, clusterName := range clusterNames {
   119  		if clusterName != "" {
   120  			wg.Add(1)
   121  			go func(name string) {
   122  				defer wg.Done()
   123  				// Delete the OKE cluster
   124  				Eventually(func() error {
   125  					return deleteCluster(name, t.Logs)
   126  				}, shortWaitTimeout, shortPollingInterval).Should(BeNil())
   127  
   128  				// Verify the cluster is deleted
   129  				Eventually(func() (bool, error) { return isClusterDeleted(name, t.Logs) }, waitTimeout, pollingInterval).Should(
   130  					BeTrue(), fmt.Sprintf("cluster %s is not deleted", name))
   131  			}(clusterName)
   132  		}
   133  	}
   134  	wg.Wait()
   135  
   136  	// Delete the credential
   137  	deleteCredential(cloudCredentialID, t.Logs)
   138  
   139  	// Verify the credential is deleted
   140  	Eventually(func() (bool, error) { return isCredentialDeleted(cloudCredentialID, t.Logs) }, waitTimeout, pollingInterval).Should(
   141  		BeTrue(), fmt.Sprintf("cloud credential %s is not deleted", cloudCredentialID))
   142  }
   143  
   144  var _ = t.SynchronizedAfterSuite(func() {}, synchronizedAfterSuiteProcess1Func)
   145  
   146  var _ = t.Describe("OKE CAPI Cluster Driver", Label("f:rancher-capi:okecapi-cluster-driver"), func() {
   147  	// Cluster 1. Create with a node pool.
   148  	t.Context("OKE cluster creation with a node pool", Ordered, func() {
   149  		var poolName string
   150  		var poolReplicas int
   151  		var expectedNodeCount int
   152  
   153  		// clusterConfig specifies the parameters passed into the cluster creation
   154  		var clusterConfig RancherOKECluster
   155  
   156  		t.BeforeAll(func() {
   157  			poolName = fmt.Sprintf("pool-%s", okeCapiClusterNameSuffix)
   158  			poolReplicas = 1
   159  			expectedNodeCount = poolReplicas
   160  		})
   161  
   162  		// Create the cluster and verify it comes up
   163  		t.It("create OKE CAPI cluster", func() {
   164  			Eventually(func() error {
   165  				volumeSize, ocpus, memory := 150, 2, 32
   166  				version := kubernetesVersion
   167  				mutateFn := getMutateFnNodePoolsAndResourceUsage(poolName, version, poolReplicas, volumeSize, ocpus, memory)
   168  				return createClusterAndFillConfig(clusterNameNodePool, &clusterConfig, t.Logs, mutateFn)
   169  			}, shortWaitTimeout, shortPollingInterval).Should(BeNil())
   170  		})
   171  		t.It("check OKE cluster is active", func() {
   172  			Eventually(func() (bool, error) { return isClusterActive(clusterNameNodePool, t.Logs) }, waitTimeout, pollingInterval).Should(
   173  				BeTrue(), fmt.Sprintf("cluster %s is not active", clusterNameNodePool))
   174  			Eventually(func() error {
   175  				return verifyCluster(clusterNameNodePool, expectedNodeCount, activeClusterState, transitioningFlagNo, t.Logs)
   176  			}, shortWaitTimeout, shortPollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameNodePool))
   177  		})
   178  	})
   179  
   180  	// Cluster 2. Create with a node pool, then perform an update.
   181  	t.Context("OKE cluster creation with a node pool update", Ordered, func() {
   182  		var poolName string
   183  		var poolReplicas int
   184  		var expectedNodeCount int
   185  
   186  		// clusterConfig specifies the parameters passed into the cluster creation
   187  		// and is updated as update requests are made
   188  		var clusterConfig RancherOKECluster
   189  
   190  		t.BeforeAll(func() {
   191  			if !runAllTests {
   192  				Skip(skipRunAllTestsMessage)
   193  			}
   194  			poolName = fmt.Sprintf("pool-%s", okeCapiClusterNameSuffix)
   195  			poolReplicas = 1
   196  			expectedNodeCount = poolReplicas
   197  		})
   198  
   199  		// Create the cluster and verify it comes up
   200  		t.It("create OKE CAPI cluster", func() {
   201  			Eventually(func() error {
   202  				volumeSize, ocpus, memory := 150, 2, 32
   203  				version := kubernetesVersion
   204  				mutateFn := getMutateFnNodePoolsAndResourceUsage(poolName, version, poolReplicas, volumeSize, ocpus, memory)
   205  				return createClusterAndFillConfig(clusterNameNodePoolUpdate, &clusterConfig, t.Logs, mutateFn)
   206  			}, shortWaitTimeout, shortPollingInterval).Should(BeNil())
   207  		})
   208  		t.It("check OKE cluster is active", func() {
   209  			Eventually(func() (bool, error) { return isClusterActive(clusterNameNodePoolUpdate, t.Logs) }, waitTimeout, pollingInterval).Should(
   210  				BeTrue(), fmt.Sprintf("cluster %s is not active", clusterNameNodePoolUpdate))
   211  			Eventually(func() error {
   212  				return verifyCluster(clusterNameNodePoolUpdate, expectedNodeCount, activeClusterState, transitioningFlagNo, t.Logs)
   213  			}, shortWaitTimeout, shortPollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameNodePoolUpdate))
   214  		})
   215  
   216  		// Update - increase node usage
   217  		t.It("update OKE cluster to increase node usage", func() {
   218  			poolReplicas++
   219  			expectedNodeCount++
   220  
   221  			Eventually(func() error {
   222  				volumeSize, ocpus, memory := 150, 2, 32
   223  				version := kubernetesVersion
   224  				mutateFn := getMutateFnNodePoolsAndResourceUsage(poolName, version, poolReplicas, volumeSize, ocpus, memory)
   225  				return updateConfigAndCluster(&clusterConfig, mutateFn, t.Logs)
   226  			}, shortWaitTimeout, shortPollingInterval).Should(BeNil())
   227  		})
   228  		t.It("check the OKE cluster updated", func() {
   229  			Eventually(func() (bool, error) { return isClusterActive(clusterNameNodePoolUpdate, t.Logs) }, waitTimeout, pollingInterval).Should(
   230  				BeTrue(), fmt.Sprintf("cluster %s is not active", clusterNameNodePoolUpdate))
   231  			Eventually(func() error {
   232  				return verifyCluster(clusterNameNodePoolUpdate, expectedNodeCount, activeClusterState, transitioningFlagNo, t.Logs)
   233  			}, waitTimeout, pollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameNodePoolUpdate))
   234  		})
   235  	})
   236  
   237  	// Cluster 3. Pass in invalid parameters when creating a cluster.
   238  	t.Context("OKE cluster creation with invalid kubernetes version", Ordered, func() {
   239  		var clusterConfig RancherOKECluster
   240  
   241  		t.BeforeAll(func() {
   242  			if !runAllTests {
   243  				Skip(skipRunAllTestsMessage)
   244  			}
   245  		})
   246  
   247  		t.It("create OKE cluster", func() {
   248  			// Create the cluster
   249  			Eventually(func() error {
   250  				mutateFn := func(config *RancherOKECluster) {
   251  					// setting an invalid kubernetes version
   252  					config.OKECAPIEngineConfig.KubernetesVersion = "v1.22.7"
   253  				}
   254  				return createClusterAndFillConfig(clusterNameInvalid, &clusterConfig, t.Logs, mutateFn)
   255  			}, shortWaitTimeout, shortPollingInterval).Should(BeNil())
   256  		})
   257  
   258  		t.It("check OKE cluster is not active", func() {
   259  			// Verify the cluster is not active
   260  			waitTimeoutNegative := 20 * time.Minute
   261  			Eventually(func() (bool, error) { return isClusterActive(clusterNameInvalid, t.Logs) }, waitTimeoutNegative, pollingInterval).Should(
   262  				BeFalse(), fmt.Sprintf("cluster %s is active", clusterNameInvalid))
   263  
   264  			// Verify that the cluster is configured correctly
   265  			Eventually(func() error {
   266  				return verifyCluster(clusterNameInvalid, 0, provisioningClusterState, transitioningFlagError, t.Logs)
   267  			}, shortWaitTimeout, shortPollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameInvalid))
   268  		})
   269  	})
   270  
   271  	// Cluster 4. Create with a single node with the minimum OKE supported Kubernetes version and related info.
   272  	// Later, update the cluster with the maximum OKE supported Kubernetes version and related info.
   273  	t.Context("OKE cluster creation with single node with OKE cluster upgrade", Ordered, func() {
   274  		var poolName string
   275  		var poolReplicas, volumeSize, ocpus, memory int
   276  		var expectedNodeCount int
   277  		var clusterConfig RancherOKECluster
   278  
   279  		t.BeforeAll(func() {
   280  			if !runAllTests {
   281  				Skip(skipRunAllTestsMessage)
   282  			}
   283  			if !okeMetadataItemToInstall.KubernetesVersion.LessThan(okeMetadataItemToUpgrade.KubernetesVersion) {
   284  				Skip(skipOKEUpgradeMessage)
   285  			}
   286  			poolName = fmt.Sprintf("pool-%s", okeCapiClusterNameSuffix)
   287  			poolReplicas = 1
   288  			expectedNodeCount = poolReplicas
   289  			volumeSize, ocpus, memory = 150, 2, 32
   290  		})
   291  
   292  		// Create the cluster
   293  		t.It("create OKE cluster with the minimum OKE supported Kubernetes version and related info", func() {
   294  
   295  			mutateFn := func(config *RancherOKECluster) {
   296  				config.OKECAPIEngineConfig.KubernetesVersion = okeMetadataItemToInstall.KubernetesVersion.Original()
   297  				config.OKECAPIEngineConfig.NodePools = []string{
   298  					getNodePoolSpec(poolName, okeMetadataItemToInstall.KubernetesVersion.Original(), nodeShape,
   299  						expectedNodeCount, memory, ocpus, volumeSize),
   300  				}
   301  			}
   302  			Eventually(func() error {
   303  				return createClusterAndFillConfig(clusterNameOKEUpgrade, &clusterConfig, t.Logs, mutateFn)
   304  			}, shortWaitTimeout, shortPollingInterval).Should(BeNil())
   305  		})
   306  
   307  		t.It("check OKE cluster is active with the minimum OKE supported Kubernetes version and related info", func() {
   308  			// Verify the cluster is active
   309  			Eventually(func() (bool, error) { return isClusterActive(clusterNameOKEUpgrade, t.Logs) }, waitTimeout, pollingInterval).Should(
   310  				BeTrue(), fmt.Sprintf("cluster %s is not active", clusterNameOKEUpgrade))
   311  			// Verify that the cluster is configured correctly
   312  			Eventually(func() error {
   313  				return verifyCluster(clusterNameOKEUpgrade, expectedNodeCount, activeClusterState, transitioningFlagNo, t.Logs)
   314  			}, shortWaitTimeout, shortPollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameOKEUpgrade))
   315  		})
   316  
   317  		// Update the cluster
   318  		t.It("update OKE cluster with the maximum OKE supported Kubernetes version and related info", func() {
   319  			Eventually(func() error {
   320  				mutateFn := func(config *RancherOKECluster) {
   321  					config.OKECAPIEngineConfig.KubernetesVersion = okeMetadataItemToUpgrade.KubernetesVersion.Original()
   322  					config.OKECAPIEngineConfig.NodePools = []string{
   323  						getNodePoolSpec(poolName, okeMetadataItemToUpgrade.KubernetesVersion.Original(), nodeShape,
   324  							expectedNodeCount, memory, ocpus, volumeSize),
   325  					}
   326  				}
   327  				return updateConfigAndCluster(&clusterConfig, mutateFn, t.Logs)
   328  			}, shortWaitTimeout, shortPollingInterval).Should(BeNil())
   329  		})
   330  
   331  		t.It("check the OKE cluster updated with the maximum OKE supported Kubernetes version and related info", func() {
   332  			Eventually(func() (bool, error) { return isClusterActive(clusterNameOKEUpgrade, t.Logs) }, waitTimeout, pollingInterval).Should(
   333  				BeTrue(), fmt.Sprintf("cluster %s is not active", clusterNameOKEUpgrade))
   334  			Eventually(func() error {
   335  				return verifyCluster(clusterNameOKEUpgrade, expectedNodeCount, activeClusterState, transitioningFlagNo, t.Logs)
   336  			}, waitTimeout, pollingInterval).Should(BeNil(), fmt.Sprintf("could not verify cluster %s", clusterNameOKEUpgrade))
   337  		})
   338  	})
   339  })