github.com/vmware/go-vcloud-director/v2@v2.24.0/govcd/cse_test.go (about)

     1  //go:build functional || openapi || cse || ALL
     2  
     3  /*
     4   * Copyright 2024 VMware, Inc.  All rights reserved.  Licensed under the Apache v2 License.
     5   */
     6  
     7  package govcd
     8  
     9  import (
    10  	"fmt"
    11  	semver "github.com/hashicorp/go-version"
    12  	"github.com/vmware/go-vcloud-director/v2/types/v56"
    13  	. "gopkg.in/check.v1"
    14  	"net/url"
    15  	"os"
    16  	"reflect"
    17  	"strings"
    18  	"time"
    19  )
    20  
    21  func requireCseConfig(check *C, testConfig TestConfig) {
    22  	skippedPrefix := fmt.Sprintf("skipped %s because:", check.TestName())
    23  	if cse := os.Getenv("TEST_VCD_CSE"); cse == "" {
    24  		check.Skip(fmt.Sprintf("%s the environment variable TEST_VCD_CSE is not set", skippedPrefix))
    25  	}
    26  	cseConfigValues := reflect.ValueOf(testConfig.Cse)
    27  	cseConfigType := cseConfigValues.Type()
    28  	for i := 0; i < cseConfigValues.NumField(); i++ {
    29  		if cseConfigValues.Field(i).String() == "" {
    30  			check.Skip(fmt.Sprintf("%s the config value '%s' inside 'cse' block of govcd_test_config.yaml is not set", skippedPrefix, cseConfigType.Field(i).Name))
    31  		}
    32  	}
    33  }
    34  
    35  // Test_Cse tests all possible combinations of the CSE CRUD operations.
    36  func (vcd *TestVCD) Test_Cse(check *C) {
    37  	requireCseConfig(check, vcd.config)
    38  
    39  	// Prerequisites: We need to read several items before creating the cluster.
    40  	org, err := vcd.client.GetOrgByName(vcd.config.Cse.TenantOrg)
    41  	check.Assert(err, IsNil)
    42  
    43  	catalog, err := org.GetCatalogByName(vcd.config.Cse.OvaCatalog, false)
    44  	check.Assert(err, IsNil)
    45  
    46  	ova, err := catalog.GetVAppTemplateByName(vcd.config.Cse.OvaName)
    47  	check.Assert(err, IsNil)
    48  
    49  	tkgBundle, err := getTkgVersionBundleFromVAppTemplate(ova.VAppTemplate)
    50  	check.Assert(err, IsNil)
    51  
    52  	vdc, err := org.GetVDCByName(vcd.config.Cse.TenantVdc, false)
    53  	check.Assert(err, IsNil)
    54  
    55  	net, err := vdc.GetOrgVdcNetworkByName(vcd.config.Cse.RoutedNetwork, false)
    56  	check.Assert(err, IsNil)
    57  
    58  	sp, err := vdc.FindStorageProfileReference(vcd.config.Cse.StorageProfile)
    59  	check.Assert(err, IsNil)
    60  
    61  	policies, err := vcd.client.GetAllVdcComputePoliciesV2(url.Values{
    62  		"filter": []string{"name==TKG small"},
    63  	})
    64  	check.Assert(err, IsNil)
    65  	check.Assert(len(policies), Equals, 1)
    66  
    67  	token, err := vcd.client.CreateToken(vcd.config.Provider.SysOrg, check.TestName())
    68  	check.Assert(err, IsNil)
    69  	defer func() {
    70  		err = token.Delete()
    71  		check.Assert(err, IsNil)
    72  	}()
    73  	AddToCleanupListOpenApi(token.Token.Name, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointTokens+token.Token.ID)
    74  
    75  	apiToken, err := token.GetInitialApiToken()
    76  	check.Assert(err, IsNil)
    77  
    78  	cseVersion, err := semver.NewVersion(vcd.config.Cse.Version)
    79  	check.Assert(err, IsNil)
    80  	check.Assert(cseVersion, NotNil)
    81  
    82  	sshPublicKey := "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCrCI+QkLjgQVqR7c7dJfawJqCslVomo5I25JdolqlteX7RCUq0yncWyS+8MTYWCS03sm1jOroLOeuji8CDKCDCcKwQerJiOFoJS+VOK5xCjJ2u8RBGlIpXNcmIh2VriRJrV7TCKrFMSKLNF4/n83q4gWI/YPf6/dRhpPB72HYrdI4omvRlU4GG09jMmgiz+5Yb8wJEXYMsJni+MwPzFKe6TbMcqjBusDyeFGAhgyN7QJGpdNhAn1sqvqZrW2QjaE8P+4t8RzBo8B2ucyQazd6+lbYmOHq9366LjG160snzXrFzlARc4hhpjMzu9Bcm6i3ZZI70qhIbmi5IonbbVh8t"
    83  	// Create the cluster
    84  	clusterSettings := CseClusterSettings{
    85  		Name:                    "test-cse",
    86  		OrganizationId:          org.Org.ID,
    87  		VdcId:                   vdc.Vdc.ID,
    88  		NetworkId:               net.OrgVDCNetwork.ID,
    89  		KubernetesTemplateOvaId: ova.VAppTemplate.ID,
    90  		CseVersion:              *cseVersion,
    91  		ControlPlane: CseControlPlaneSettings{
    92  			MachineCount:     1,
    93  			DiskSizeGi:       20,
    94  			SizingPolicyId:   policies[0].VdcComputePolicyV2.ID,
    95  			StorageProfileId: sp.ID,
    96  			Ip:               "",
    97  		},
    98  		WorkerPools: []CseWorkerPoolSettings{{
    99  			Name:             "worker-pool-1",
   100  			MachineCount:     1,
   101  			DiskSizeGi:       20,
   102  			SizingPolicyId:   policies[0].VdcComputePolicyV2.ID,
   103  			StorageProfileId: sp.ID,
   104  		}},
   105  		DefaultStorageClass: &CseDefaultStorageClassSettings{
   106  			StorageProfileId: sp.ID,
   107  			Name:             "storage-class-1",
   108  			ReclaimPolicy:    "delete",
   109  			Filesystem:       "ext4",
   110  		},
   111  		Owner:              vcd.config.Provider.User,
   112  		ApiToken:           apiToken.RefreshToken,
   113  		NodeHealthCheck:    true,
   114  		PodCidr:            "100.96.0.0/11",
   115  		ServiceCidr:        "100.64.0.0/13",
   116  		SshPublicKey:       sshPublicKey,
   117  		AutoRepairOnErrors: true,
   118  	}
   119  	cluster, err := org.CseCreateKubernetesCluster(clusterSettings, 150*time.Minute)
   120  
   121  	// We assure that the cluster gets always deleted, even if the creation failed.
   122  	// Deletion process only needs the cluster ID
   123  	defer func() {
   124  		check.Assert(cluster, NotNil)
   125  		check.Assert(cluster.client, NotNil)
   126  		check.Assert(cluster.ID, Not(Equals), "")
   127  		err = cluster.Delete(0)
   128  		check.Assert(err, IsNil)
   129  	}()
   130  
   131  	check.Assert(err, IsNil)
   132  	assertCseClusterCreation(check, cluster, clusterSettings, tkgBundle)
   133  
   134  	kubeconfig, err := cluster.GetKubeconfig(false)
   135  	check.Assert(err, IsNil)
   136  	check.Assert(true, Equals, strings.Contains(kubeconfig, cluster.Name))
   137  	check.Assert(true, Equals, strings.Contains(kubeconfig, "client-certificate-data"))
   138  	check.Assert(true, Equals, strings.Contains(kubeconfig, "certificate-authority-data"))
   139  	check.Assert(true, Equals, strings.Contains(kubeconfig, "client-key-data"))
   140  
   141  	err = cluster.Refresh()
   142  	check.Assert(err, IsNil)
   143  
   144  	clusterGet, err := vcd.client.CseGetKubernetesClusterById(cluster.ID)
   145  	check.Assert(err, IsNil)
   146  	assertCseClusterEquals(check, clusterGet, cluster)
   147  	check.Assert(clusterGet.Etag, Not(Equals), "")
   148  
   149  	allClusters, err := org.CseGetKubernetesClustersByName(clusterGet.CseVersion, clusterGet.Name)
   150  	check.Assert(err, IsNil)
   151  	check.Assert(len(allClusters), Equals, 1)
   152  	assertCseClusterEquals(check, allClusters[0], clusterGet)
   153  	check.Assert(allClusters[0].Etag, Equals, "") // Can't recover ETag by name
   154  
   155  	// Update worker pool from 1 node to 2
   156  	err = cluster.UpdateWorkerPools(map[string]CseWorkerPoolUpdateInput{clusterSettings.WorkerPools[0].Name: {MachineCount: 2}}, true)
   157  	check.Assert(err, IsNil)
   158  	foundWorkerPool := false
   159  	for _, nodePool := range cluster.WorkerPools {
   160  		if nodePool.Name == clusterSettings.WorkerPools[0].Name {
   161  			foundWorkerPool = true
   162  			check.Assert(nodePool.MachineCount, Equals, 2)
   163  		}
   164  	}
   165  	check.Assert(foundWorkerPool, Equals, true)
   166  
   167  	// Add a new worker pool
   168  	err = cluster.AddWorkerPools([]CseWorkerPoolSettings{{
   169  		Name:         "new-pool",
   170  		MachineCount: 1,
   171  		DiskSizeGi:   20,
   172  	}}, true)
   173  	check.Assert(err, IsNil)
   174  	foundWorkerPool = false
   175  	for _, nodePool := range cluster.WorkerPools {
   176  		if nodePool.Name == "new-pool" {
   177  			foundWorkerPool = true
   178  			check.Assert(nodePool.MachineCount, Equals, 1)
   179  			check.Assert(nodePool.DiskSizeGi, Equals, 20)
   180  			check.Assert(nodePool.SizingPolicyId, Equals, "")
   181  			check.Assert(nodePool.StorageProfileId, Equals, "")
   182  		}
   183  	}
   184  	check.Assert(foundWorkerPool, Equals, true)
   185  
   186  	// Update control plane from 1 node to 3 (needs to be an odd number)
   187  	err = cluster.UpdateControlPlane(CseControlPlaneUpdateInput{MachineCount: 3}, true)
   188  	check.Assert(err, IsNil)
   189  	check.Assert(cluster.ControlPlane.MachineCount, Equals, 3)
   190  
   191  	// Turn off the node health check
   192  	err = cluster.SetNodeHealthCheck(false, true)
   193  	check.Assert(err, IsNil)
   194  	check.Assert(cluster.NodeHealthCheck, Equals, false)
   195  
   196  	// Update the auto repair flag
   197  	check.Assert(err, IsNil)
   198  	err = cluster.SetAutoRepairOnErrors(false, true)
   199  	check.Assert(err, IsNil) // It won't fail in CSE >4.1.0 as the flag is already false, so we update nothing.
   200  	check.Assert(cluster.AutoRepairOnErrors, Equals, false)
   201  
   202  	// Upgrade the cluster if possible
   203  	upgradeOvas, err := cluster.GetSupportedUpgrades(true)
   204  	check.Assert(err, IsNil)
   205  	if len(upgradeOvas) > 0 {
   206  		err = cluster.UpgradeCluster(upgradeOvas[0].ID, true)
   207  		check.Assert(err, IsNil)
   208  		check.Assert(cluster.KubernetesVersion, Not(Equals), clusterGet.KubernetesVersion)
   209  		check.Assert(cluster.TkgVersion, Not(Equals), clusterGet.TkgVersion)
   210  		check.Assert(cluster.KubernetesTemplateOvaId, Not(Equals), clusterGet.KubernetesTemplateOvaId)
   211  		upgradeOvas, err = cluster.GetSupportedUpgrades(true)
   212  		check.Assert(err, IsNil)
   213  		check.Assert(len(upgradeOvas), Equals, 0)
   214  	} else {
   215  		fmt.Println("WARNING: CseKubernetesCluster.UpgradeCluster method not tested. It was skipped as there's no OVA to upgrade the cluster")
   216  	}
   217  
   218  	// Helps to delete the cluster faster, also tests generic update method
   219  	err = cluster.Update(CseClusterUpdateInput{
   220  		ControlPlane: &CseControlPlaneUpdateInput{MachineCount: 1},
   221  		WorkerPools: &map[string]CseWorkerPoolUpdateInput{
   222  			clusterSettings.WorkerPools[0].Name: {
   223  				MachineCount: 1,
   224  			},
   225  			"new-pool": {
   226  				MachineCount: 0,
   227  			},
   228  		},
   229  	}, true)
   230  	check.Assert(err, IsNil)
   231  	check.Assert(cluster.ControlPlane.MachineCount, Equals, 1)
   232  	for _, pool := range cluster.WorkerPools {
   233  		if pool.Name == "new-pool" {
   234  			check.Assert(pool.MachineCount, Equals, 0)
   235  		} else {
   236  			check.Assert(pool.MachineCount, Equals, 1)
   237  		}
   238  	}
   239  }
   240  
   241  // Test_Cse_Failure tests cluster creation errors and their consequences
   242  func (vcd *TestVCD) Test_Cse_Failure(check *C) {
   243  	requireCseConfig(check, vcd.config)
   244  
   245  	// Prerequisites: We need to read several items before creating the cluster.
   246  	org, err := vcd.client.GetOrgByName(vcd.config.Cse.TenantOrg)
   247  	check.Assert(err, IsNil)
   248  
   249  	catalog, err := org.GetCatalogByName(vcd.config.Cse.OvaCatalog, false)
   250  	check.Assert(err, IsNil)
   251  
   252  	ova, err := catalog.GetVAppTemplateByName(vcd.config.Cse.OvaName)
   253  	check.Assert(err, IsNil)
   254  
   255  	vdc, err := org.GetVDCByName(vcd.config.Cse.TenantVdc, false)
   256  	check.Assert(err, IsNil)
   257  
   258  	net, err := vdc.GetOrgVdcNetworkByName(vcd.config.Cse.RoutedNetwork, false)
   259  	check.Assert(err, IsNil)
   260  
   261  	sp, err := vdc.FindStorageProfileReference(vcd.config.Cse.StorageProfile)
   262  	check.Assert(err, IsNil)
   263  
   264  	policies, err := vcd.client.GetAllVdcComputePoliciesV2(url.Values{
   265  		"filter": []string{"name==TKG small"},
   266  	})
   267  	check.Assert(err, IsNil)
   268  	check.Assert(len(policies), Equals, 1)
   269  
   270  	token, err := vcd.client.CreateToken(vcd.config.Provider.SysOrg, check.TestName())
   271  	check.Assert(err, IsNil)
   272  	defer func() {
   273  		err = token.Delete()
   274  		check.Assert(err, IsNil)
   275  	}()
   276  	AddToCleanupListOpenApi(token.Token.Name, check.TestName(), types.OpenApiPathVersion1_0_0+types.OpenApiEndpointTokens+token.Token.ID)
   277  
   278  	apiToken, err := token.GetInitialApiToken()
   279  	check.Assert(err, IsNil)
   280  
   281  	cseVersion, err := semver.NewVersion(vcd.config.Cse.Version)
   282  	check.Assert(err, IsNil)
   283  	check.Assert(cseVersion, NotNil)
   284  
   285  	componentsVersions, err := getCseComponentsVersions(*cseVersion)
   286  	check.Assert(err, IsNil)
   287  	check.Assert(componentsVersions, NotNil)
   288  
   289  	// Create the cluster
   290  	clusterSettings := CseClusterSettings{
   291  		Name:                    "test-cse-fail",
   292  		OrganizationId:          org.Org.ID,
   293  		VdcId:                   vdc.Vdc.ID,
   294  		NetworkId:               net.OrgVDCNetwork.ID,
   295  		KubernetesTemplateOvaId: ova.VAppTemplate.ID,
   296  		CseVersion:              *cseVersion,
   297  		ControlPlane: CseControlPlaneSettings{
   298  			MachineCount:     1,
   299  			DiskSizeGi:       20,
   300  			SizingPolicyId:   policies[0].VdcComputePolicyV2.ID,
   301  			StorageProfileId: sp.ID,
   302  			Ip:               "",
   303  		},
   304  		WorkerPools: []CseWorkerPoolSettings{{
   305  			Name:             "worker-pool-1",
   306  			MachineCount:     1,
   307  			DiskSizeGi:       20,
   308  			SizingPolicyId:   policies[0].VdcComputePolicyV2.ID,
   309  			StorageProfileId: sp.ID,
   310  		}},
   311  		Owner:              vcd.config.Provider.User,
   312  		ApiToken:           apiToken.RefreshToken,
   313  		NodeHealthCheck:    true,
   314  		PodCidr:            "1.1.1.1/24", // This should make the cluster fail
   315  		ServiceCidr:        "1.1.1.1/24", // This should make the cluster fail
   316  		AutoRepairOnErrors: false,        // Must be false to avoid never-ending loops
   317  	}
   318  	cluster, err := org.CseCreateKubernetesCluster(clusterSettings, 150*time.Minute)
   319  
   320  	// We assure that the cluster gets always deleted.
   321  	// Deletion process only needs the cluster ID
   322  	defer func() {
   323  		check.Assert(cluster, NotNil)
   324  		check.Assert(cluster.client, NotNil)
   325  		check.Assert(cluster.ID, Not(Equals), "")
   326  		err = cluster.Delete(0)
   327  		check.Assert(err, IsNil)
   328  	}()
   329  
   330  	check.Assert(err, NotNil)
   331  	check.Assert(cluster.client, NotNil)
   332  	check.Assert(cluster.ID, Not(Equals), "")
   333  
   334  	clusterGet, err := vcd.client.CseGetKubernetesClusterById(cluster.ID)
   335  	check.Assert(err, IsNil)
   336  	// We don't get an error when we retrieve a failed cluster, but some fields are missing
   337  	check.Assert(clusterGet.ID, Equals, cluster.ID)
   338  	check.Assert(clusterGet.Etag, Not(Equals), "")
   339  	check.Assert(clusterGet.State, Equals, "error")
   340  	check.Assert(len(clusterGet.Events), Not(Equals), 0)
   341  
   342  	err = cluster.Refresh()
   343  	check.Assert(err, IsNil)
   344  	assertCseClusterEquals(check, cluster, clusterGet)
   345  
   346  	allClusters, err := org.CseGetKubernetesClustersByName(clusterGet.CseVersion, clusterGet.Name)
   347  	check.Assert(err, IsNil)
   348  	check.Assert(len(allClusters), Equals, 1)
   349  	assertCseClusterEquals(check, allClusters[0], clusterGet)
   350  	check.Assert(allClusters[0].Etag, Equals, "") // Can't recover ETag by name
   351  
   352  	_, err = cluster.GetKubeconfig(false)
   353  	check.Assert(err, NotNil)
   354  
   355  	// All updates should fail
   356  	err = cluster.UpdateWorkerPools(map[string]CseWorkerPoolUpdateInput{clusterSettings.WorkerPools[0].Name: {MachineCount: 1}}, true)
   357  	check.Assert(err, NotNil)
   358  	err = cluster.AddWorkerPools([]CseWorkerPoolSettings{{
   359  		Name:         "i-dont-care-i-will-fail",
   360  		MachineCount: 1,
   361  		DiskSizeGi:   20,
   362  	}}, true)
   363  	check.Assert(err, NotNil)
   364  	err = cluster.UpdateControlPlane(CseControlPlaneUpdateInput{MachineCount: 1}, true)
   365  	check.Assert(err, NotNil)
   366  	err = cluster.SetNodeHealthCheck(false, true)
   367  	check.Assert(err, NotNil)
   368  	err = cluster.SetAutoRepairOnErrors(false, true)
   369  	check.Assert(err, NotNil)
   370  
   371  	upgradeOvas, err := cluster.GetSupportedUpgrades(true)
   372  	check.Assert(err, IsNil)
   373  	check.Assert(len(upgradeOvas), Equals, 0)
   374  
   375  	err = cluster.UpgradeCluster(clusterSettings.KubernetesTemplateOvaId, true)
   376  	check.Assert(err, NotNil)
   377  }
   378  
   379  func assertCseClusterCreation(check *C, createdCluster *CseKubernetesCluster, settings CseClusterSettings, expectedKubernetesData tkgVersionBundle) {
   380  	check.Assert(createdCluster, NotNil)
   381  	check.Assert(createdCluster.CseVersion.Original(), Equals, settings.CseVersion.Original())
   382  	check.Assert(createdCluster.Name, Equals, settings.Name)
   383  	check.Assert(createdCluster.OrganizationId, Equals, settings.OrganizationId)
   384  	check.Assert(createdCluster.VdcId, Equals, settings.VdcId)
   385  	check.Assert(createdCluster.NetworkId, Equals, settings.NetworkId)
   386  	check.Assert(createdCluster.KubernetesTemplateOvaId, Equals, settings.KubernetesTemplateOvaId)
   387  	check.Assert(createdCluster.ControlPlane.MachineCount, Equals, settings.ControlPlane.MachineCount)
   388  	check.Assert(createdCluster.ControlPlane.SizingPolicyId, Equals, settings.ControlPlane.SizingPolicyId)
   389  	check.Assert(createdCluster.ControlPlane.PlacementPolicyId, Equals, settings.ControlPlane.PlacementPolicyId)
   390  	check.Assert(createdCluster.ControlPlane.StorageProfileId, Equals, settings.ControlPlane.StorageProfileId)
   391  	check.Assert(createdCluster.ControlPlane.DiskSizeGi, Equals, settings.ControlPlane.DiskSizeGi)
   392  	if settings.ControlPlane.Ip != "" {
   393  		check.Assert(createdCluster.ControlPlane.Ip, Equals, settings.ControlPlane.Ip)
   394  	} else {
   395  		check.Assert(createdCluster.ControlPlane.Ip, Not(Equals), "")
   396  	}
   397  	check.Assert(createdCluster.WorkerPools, DeepEquals, settings.WorkerPools)
   398  	if settings.DefaultStorageClass != nil {
   399  		check.Assert(createdCluster.DefaultStorageClass, NotNil)
   400  		check.Assert(*createdCluster.DefaultStorageClass, DeepEquals, *settings.DefaultStorageClass)
   401  	}
   402  	if settings.Owner != "" {
   403  		check.Assert(createdCluster.Owner, Equals, settings.Owner)
   404  	} else {
   405  		check.Assert(createdCluster.Owner, Not(Equals), "")
   406  	}
   407  	check.Assert(createdCluster.ApiToken, Not(Equals), settings.ApiToken)
   408  	check.Assert(createdCluster.ApiToken, Equals, "******") // This one can't be recovered
   409  	check.Assert(createdCluster.NodeHealthCheck, Equals, settings.NodeHealthCheck)
   410  	check.Assert(createdCluster.PodCidr, Equals, settings.PodCidr)
   411  	check.Assert(createdCluster.ServiceCidr, Equals, settings.ServiceCidr)
   412  	check.Assert(createdCluster.SshPublicKey, Equals, settings.SshPublicKey)
   413  	check.Assert(createdCluster.VirtualIpSubnet, Equals, settings.VirtualIpSubnet)
   414  	check.Assert(createdCluster.SshPublicKey, Equals, settings.SshPublicKey)
   415  
   416  	v411, err := semver.NewVersion("4.1.1")
   417  	check.Assert(err, IsNil)
   418  	if settings.CseVersion.GreaterThanOrEqual(v411) {
   419  		// Since CSE 4.1.1, the flag is automatically switched off when the cluster is created
   420  		check.Assert(createdCluster.AutoRepairOnErrors, Equals, false)
   421  	} else {
   422  		check.Assert(createdCluster.AutoRepairOnErrors, Equals, settings.AutoRepairOnErrors)
   423  	}
   424  	check.Assert(createdCluster.VirtualIpSubnet, Equals, settings.VirtualIpSubnet)
   425  	check.Assert(true, Equals, strings.Contains(createdCluster.ID, "urn:vcloud:entity:vmware:capvcdCluster:"))
   426  	check.Assert(createdCluster.Etag, Not(Equals), "")
   427  	check.Assert(createdCluster.KubernetesVersion.Original(), Equals, expectedKubernetesData.KubernetesVersion)
   428  	check.Assert(createdCluster.TkgVersion.Original(), Equals, expectedKubernetesData.TkgVersion)
   429  	check.Assert(createdCluster.CapvcdVersion.Original(), Not(Equals), "")
   430  	check.Assert(createdCluster.CpiVersion.Original(), Not(Equals), "")
   431  	check.Assert(createdCluster.CsiVersion.Original(), Not(Equals), "")
   432  	check.Assert(len(createdCluster.ClusterResourceSetBindings), Not(Equals), 0)
   433  	check.Assert(createdCluster.State, Equals, "provisioned")
   434  	check.Assert(len(createdCluster.Events), Not(Equals), 0)
   435  }
   436  
   437  func assertCseClusterEquals(check *C, obtainedCluster, expectedCluster *CseKubernetesCluster) {
   438  	check.Assert(expectedCluster, NotNil)
   439  	check.Assert(obtainedCluster, NotNil)
   440  	check.Assert(obtainedCluster.CseVersion.Original(), Equals, expectedCluster.CseVersion.Original())
   441  	check.Assert(obtainedCluster.Name, Equals, expectedCluster.Name)
   442  	check.Assert(obtainedCluster.OrganizationId, Equals, expectedCluster.OrganizationId)
   443  	check.Assert(obtainedCluster.VdcId, Equals, expectedCluster.VdcId)
   444  	check.Assert(obtainedCluster.NetworkId, Equals, expectedCluster.NetworkId)
   445  	check.Assert(obtainedCluster.KubernetesTemplateOvaId, Equals, expectedCluster.KubernetesTemplateOvaId)
   446  	check.Assert(obtainedCluster.ControlPlane, DeepEquals, expectedCluster.ControlPlane)
   447  	check.Assert(obtainedCluster.WorkerPools, DeepEquals, expectedCluster.WorkerPools)
   448  	if expectedCluster.DefaultStorageClass != nil {
   449  		check.Assert(obtainedCluster.DefaultStorageClass, NotNil)
   450  		check.Assert(*obtainedCluster.DefaultStorageClass, DeepEquals, *expectedCluster.DefaultStorageClass)
   451  	}
   452  	check.Assert(obtainedCluster.Owner, Equals, expectedCluster.Owner)
   453  	check.Assert(obtainedCluster.ApiToken, Equals, "******") // This one can't be recovered
   454  	check.Assert(obtainedCluster.NodeHealthCheck, Equals, expectedCluster.NodeHealthCheck)
   455  	check.Assert(obtainedCluster.PodCidr, Equals, expectedCluster.PodCidr)
   456  	check.Assert(obtainedCluster.ServiceCidr, Equals, expectedCluster.ServiceCidr)
   457  	check.Assert(obtainedCluster.SshPublicKey, Equals, expectedCluster.SshPublicKey)
   458  	check.Assert(obtainedCluster.VirtualIpSubnet, Equals, expectedCluster.VirtualIpSubnet)
   459  	check.Assert(obtainedCluster.AutoRepairOnErrors, Equals, expectedCluster.AutoRepairOnErrors)
   460  	check.Assert(obtainedCluster.VirtualIpSubnet, Equals, expectedCluster.VirtualIpSubnet)
   461  	check.Assert(obtainedCluster.ID, Equals, expectedCluster.ID)
   462  	check.Assert(obtainedCluster.KubernetesVersion.Original(), Equals, expectedCluster.KubernetesVersion.Original())
   463  	check.Assert(obtainedCluster.TkgVersion.Original(), Equals, expectedCluster.TkgVersion.Original())
   464  	check.Assert(obtainedCluster.CapvcdVersion.Original(), Equals, expectedCluster.CapvcdVersion.Original())
   465  	check.Assert(obtainedCluster.CpiVersion.Original(), Equals, expectedCluster.CpiVersion.Original())
   466  	check.Assert(obtainedCluster.CsiVersion.Original(), Equals, expectedCluster.CsiVersion.Original())
   467  	check.Assert(obtainedCluster.ClusterResourceSetBindings, DeepEquals, expectedCluster.ClusterResourceSetBindings)
   468  	check.Assert(obtainedCluster.State, Equals, expectedCluster.State)
   469  	check.Assert(len(obtainedCluster.Events) >= len(expectedCluster.Events), Equals, true)
   470  }