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 }