github.com/openshift/installer@v1.4.17/pkg/asset/installconfig/ibmcloud/validation_test.go (about) 1 package ibmcloud 2 3 import ( 4 "errors" 5 "fmt" 6 "testing" 7 8 "github.com/IBM/go-sdk-core/v5/core" 9 "github.com/IBM/networking-go-sdk/dnsrecordsv1" 10 "github.com/IBM/platform-services-go-sdk/resourcemanagerv2" 11 "github.com/IBM/vpc-go-sdk/vpcv1" 12 "github.com/golang/mock/gomock" 13 "github.com/stretchr/testify/assert" 14 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 15 "k8s.io/utils/ptr" 16 17 configv1 "github.com/openshift/api/config/v1" 18 "github.com/openshift/installer/pkg/asset/installconfig/ibmcloud/mock" 19 "github.com/openshift/installer/pkg/asset/installconfig/ibmcloud/responses" 20 "github.com/openshift/installer/pkg/ipnet" 21 "github.com/openshift/installer/pkg/types" 22 ibmcloudtypes "github.com/openshift/installer/pkg/types/ibmcloud" 23 ) 24 25 type editFunctions []func(ic *types.InstallConfig) 26 27 var ( 28 validRegion = "us-south" 29 validCIDR = "10.0.0.0/16" 30 validCISInstanceCRN = "crn:v1:bluemix:public:internet-svcs:global:a/valid-account-id:valid-instance-id::" 31 validClusterName = "valid-cluster-name" 32 validDNSZoneID = "valid-zone-id" 33 validBaseDomain = "valid.base.domain" 34 validPublicSubnetUSSouth1ID = "public-subnet-us-south-1-id" 35 validPublicSubnetUSSouth2ID = "public-subnet-us-south-2-id" 36 validPrivateSubnetUSSouth1ID = "private-subnet-us-south-1-id" 37 validPrivateSubnetUSSouth2ID = "private-subnet-us-south-2-id" 38 validSubnets = []string{ 39 validPublicSubnetUSSouth1ID, 40 validPublicSubnetUSSouth2ID, 41 validPrivateSubnetUSSouth1ID, 42 validPrivateSubnetUSSouth2ID, 43 } 44 validSubnet1Name = "valid-subnet-1" 45 validSubnet2Name = "valid-subnet-2" 46 validSubnet3Name = "valid-subnet-3" 47 validVPCID = "valid-id" 48 validVPC = "valid-vpc" 49 validRG = "valid-resource-group" 50 validZoneUSSouth1 = "us-south-1" 51 validZoneUSSouth2 = "us-south-2" 52 validZoneUSSouth3 = "us-south-3" 53 validZones = []string{ 54 validZoneUSSouth1, 55 validZoneUSSouth2, 56 validZoneUSSouth3, 57 } 58 validZoneSubnetNameMap = map[string]string{ 59 validZoneUSSouth1: validSubnet1Name, 60 validZoneUSSouth2: validSubnet2Name, 61 validZoneUSSouth3: validSubnet3Name, 62 } 63 64 wrongRG = "wrong-resource-group" 65 wrongSubnetName = "wrong-subnet" 66 wrongVPCID = "wrong-id" 67 wrongVPC = "wrong-vpc" 68 wrongZone = "wrong-zone" 69 anotherValidVPCID = "another-valid-id" 70 anotherValidVPC = "another-valid-vpc" 71 anotherValidRG = "another-valid-resource-group" 72 73 validResourceGroups = []resourcemanagerv2.ResourceGroup{ 74 { 75 Name: &validRG, 76 ID: &validRG, 77 }, 78 { 79 Name: &anotherValidRG, 80 ID: &anotherValidRG, 81 }, 82 } 83 validVPCs = []vpcv1.VPC{ 84 { 85 Name: &validVPC, 86 ID: &validVPCID, 87 ResourceGroup: &vpcv1.ResourceGroupReference{ 88 Name: &validRG, 89 ID: &validRG, 90 }, 91 }, 92 { 93 Name: &anotherValidVPC, 94 ID: &anotherValidVPCID, 95 ResourceGroup: &vpcv1.ResourceGroupReference{ 96 Name: &anotherValidRG, 97 ID: &anotherValidRG, 98 }, 99 }, 100 } 101 invalidVPC = []vpcv1.VPC{ 102 { 103 Name: &wrongVPC, 104 ID: &wrongVPCID, 105 ResourceGroup: &vpcv1.ResourceGroupReference{ 106 Name: &validRG, 107 ID: &validRG, 108 }, 109 }, 110 } 111 validVPCInvalidRG = []vpcv1.VPC{ 112 { 113 Name: &validVPC, 114 ID: &validVPCID, 115 ResourceGroup: &vpcv1.ResourceGroupReference{ 116 Name: &wrongRG, 117 ID: &wrongRG, 118 }, 119 }, 120 } 121 validSubnet1 = &vpcv1.Subnet{ 122 Name: &validSubnet1Name, 123 VPC: &vpcv1.VPCReference{ 124 Name: &validVPC, 125 ID: &validVPCID, 126 }, 127 ResourceGroup: &vpcv1.ResourceGroupReference{ 128 Name: &validRG, 129 ID: &validRG, 130 }, 131 Zone: &vpcv1.ZoneReference{ 132 Name: &validZoneUSSouth1, 133 }, 134 } 135 validSubnet2 = &vpcv1.Subnet{ 136 Name: &validSubnet2Name, 137 VPC: &vpcv1.VPCReference{ 138 Name: &validVPC, 139 ID: &validVPCID, 140 }, 141 ResourceGroup: &vpcv1.ResourceGroupReference{ 142 Name: &validRG, 143 ID: &validRG, 144 }, 145 Zone: &vpcv1.ZoneReference{ 146 Name: &validZoneUSSouth2, 147 }, 148 } 149 validSubnet3 = &vpcv1.Subnet{ 150 Name: &validSubnet3Name, 151 VPC: &vpcv1.VPCReference{ 152 Name: &validVPC, 153 ID: &validVPCID, 154 }, 155 ResourceGroup: &vpcv1.ResourceGroupReference{ 156 Name: &validRG, 157 ID: &validRG, 158 }, 159 Zone: &vpcv1.ZoneReference{ 160 Name: &validZoneUSSouth3, 161 }, 162 } 163 wrongSubnet = &vpcv1.Subnet{ 164 Name: &wrongSubnetName, 165 VPC: &vpcv1.VPCReference{ 166 Name: &validVPC, 167 ID: &validVPCID, 168 }, 169 ResourceGroup: &vpcv1.ResourceGroupReference{ 170 Name: &validRG, 171 ID: &validRG, 172 }, 173 Zone: &vpcv1.ZoneReference{ 174 Name: &wrongZone, 175 }, 176 } 177 178 validInstanceProfiles = []vpcv1.InstanceProfile{{Name: &[]string{"type-a"}[0]}, {Name: &[]string{"type-b"}[0]}} 179 180 invalidEncryptionKey = "invalid-encryption-key-crn" 181 validEncryptionKey = "valid-encryption-key-crn" 182 183 validEncryptionKeyResponse = &responses.EncryptionKeyResponse{ 184 CRN: validEncryptionKey, 185 State: 1, 186 Deleted: ptr.To(false), 187 } 188 189 disabledEncryptionKeyResponse = &responses.EncryptionKeyResponse{ 190 CRN: validEncryptionKey, 191 State: 0, 192 Deleted: ptr.To(false), 193 } 194 195 deletedEncryptionKeyResponse = &responses.EncryptionKeyResponse{ 196 CRN: validEncryptionKey, 197 State: 1, 198 Deleted: ptr.To(true), 199 } 200 201 existingDNSRecordsResponse = []dnsrecordsv1.DnsrecordDetails{ 202 { 203 ID: core.StringPtr("valid-dns-record-1"), 204 }, 205 { 206 ID: core.StringPtr("valid-dns-record-2"), 207 }, 208 } 209 noDNSRecordsResponse = []dnsrecordsv1.DnsrecordDetails{} 210 211 unittestURL = "e2e.unittest.local" 212 ) 213 214 func validInstallConfig() *types.InstallConfig { 215 return &types.InstallConfig{ 216 ObjectMeta: metav1.ObjectMeta{ 217 Name: validClusterName, 218 }, 219 BaseDomain: validBaseDomain, 220 Networking: &types.Networking{ 221 MachineNetwork: []types.MachineNetworkEntry{ 222 {CIDR: *ipnet.MustParseCIDR(validCIDR)}, 223 }, 224 }, 225 Publish: types.ExternalPublishingStrategy, 226 Platform: types.Platform{ 227 IBMCloud: validMinimalPlatform(), 228 }, 229 ControlPlane: &types.MachinePool{ 230 Platform: types.MachinePoolPlatform{ 231 IBMCloud: validMachinePool(), 232 }, 233 }, 234 Compute: []types.MachinePool{{ 235 Platform: types.MachinePoolPlatform{ 236 IBMCloud: validMachinePool(), 237 }, 238 }}, 239 } 240 } 241 242 func validMinimalPlatform() *ibmcloudtypes.Platform { 243 return &ibmcloudtypes.Platform{ 244 Region: validRegion, 245 } 246 } 247 248 func validMachinePool() *ibmcloudtypes.MachinePool { 249 return &ibmcloudtypes.MachinePool{} 250 } 251 252 func validResourceGroupName(ic *types.InstallConfig) { 253 ic.Platform.IBMCloud.ResourceGroupName = "valid-resource-group" 254 } 255 256 func validNetworkResourceGroupName(ic *types.InstallConfig) { 257 ic.Platform.IBMCloud.NetworkResourceGroupName = "valid-resource-group" 258 } 259 260 func validVPCName(ic *types.InstallConfig) { 261 ic.Platform.IBMCloud.VPCName = "valid-vpc" 262 } 263 264 func validControlPlaneSubnetsForZones(ic *types.InstallConfig, zones []string) { 265 // If no zones are passed, we select all valid zones 266 if zones == nil || len(zones) == 0 { 267 zones = validZones 268 } 269 for _, zone := range zones { 270 ic.Platform.IBMCloud.ControlPlaneSubnets = append(ic.Platform.IBMCloud.ControlPlaneSubnets, validZoneSubnetNameMap[zone]) 271 } 272 } 273 274 func validComputeSubnetsForZones(ic *types.InstallConfig, zones []string) { 275 // If no zones are passed, we select all valid zones 276 if zones == nil || len(zones) == 0 { 277 zones = validZones 278 } 279 for _, zone := range zones { 280 ic.Platform.IBMCloud.ComputeSubnets = append(ic.Platform.IBMCloud.ComputeSubnets, validZoneSubnetNameMap[zone]) 281 } 282 } 283 284 func controlPlaneInvalidBootVolume(ic *types.InstallConfig) { 285 ic.ControlPlane.Platform.IBMCloud = &ibmcloudtypes.MachinePool{ 286 BootVolume: &ibmcloudtypes.BootVolume{ 287 EncryptionKey: invalidEncryptionKey, 288 }, 289 } 290 } 291 292 func controlPlaneValidBootVolume(ic *types.InstallConfig) { 293 ic.ControlPlane.Platform.IBMCloud = &ibmcloudtypes.MachinePool{ 294 BootVolume: &ibmcloudtypes.BootVolume{ 295 EncryptionKey: validEncryptionKey, 296 }, 297 } 298 } 299 300 func controlPlaneInvalidInstanceType(ic *types.InstallConfig) { 301 ic.ControlPlane.Platform.IBMCloud = &ibmcloudtypes.MachinePool{ 302 InstanceType: "invalid-instance-type", 303 } 304 } 305 306 func controlPlaneValidInstanceType(ic *types.InstallConfig) { 307 ic.ControlPlane.Platform.IBMCloud = &ibmcloudtypes.MachinePool{ 308 InstanceType: "type-a", 309 } 310 } 311 312 func TestValidate(t *testing.T) { 313 cases := []struct { 314 name string 315 edits editFunctions 316 errorMsg string 317 }{ 318 { 319 name: "valid install config", 320 edits: editFunctions{}, 321 errorMsg: "", 322 }, 323 { 324 name: "VPC with no network ResourceGroup supplied", 325 edits: editFunctions{ 326 validVPCName, 327 }, 328 errorMsg: `platform.ibmcloud.networkResourceGroupName: Invalid value: "": networkResourceGroupName cannot be empty when providing a vpcName: valid-vpc`, 329 }, 330 { 331 name: "VPC not found", 332 edits: editFunctions{ 333 validNetworkResourceGroupName, 334 func(ic *types.InstallConfig) { 335 ic.Platform.IBMCloud.VPCName = "missing-vpc" 336 }, 337 }, 338 errorMsg: `vpcName: Not found: "missing-vpc"$`, 339 }, 340 { 341 name: "VPC not in network ResourceGroup", 342 edits: editFunctions{ 343 func(ic *types.InstallConfig) { 344 ic.Platform.IBMCloud.NetworkResourceGroupName = wrongRG 345 }, 346 validVPCName, 347 }, 348 errorMsg: `platform.ibmcloud.vpcName: Invalid value: "valid-vpc": vpc is not in provided Network ResourceGroup: wrong-resource-group`, 349 }, 350 { 351 name: "VPC with no control plane subnets", 352 edits: editFunctions{ 353 validNetworkResourceGroupName, 354 validVPCName, 355 }, 356 errorMsg: `\Qplatform.ibmcloud.controlPlaneSubnets: Invalid value: []string(nil): controlPlaneSubnets cannot be empty when providing a vpcName: valid-vpc\E`, 357 }, 358 { 359 name: "control plane subnet not found", 360 edits: editFunctions{ 361 validNetworkResourceGroupName, 362 validVPCName, 363 func(ic *types.InstallConfig) { 364 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{"missing-cp-subnet"} 365 }, 366 }, 367 errorMsg: `platform.ibmcloud.controlPlaneSubnets: Not found: "missing-cp-subnet"`, 368 }, 369 { 370 name: "control plane subnet IBM error", 371 edits: editFunctions{ 372 validNetworkResourceGroupName, 373 validVPCName, 374 func(ic *types.InstallConfig) { 375 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{"ibm-error-cp-subnet"} 376 }, 377 }, 378 errorMsg: `platform.ibmcloud.controlPlaneSubnets: Internal error: ibmcloud error`, 379 }, 380 { 381 name: "control plane subnet invalid VPC", 382 edits: editFunctions{ 383 validNetworkResourceGroupName, 384 func(ic *types.InstallConfig) { 385 ic.Platform.IBMCloud.VPCName = "wrong-vpc" 386 }, 387 func(ic *types.InstallConfig) { 388 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{"valid-subnet"} 389 }, 390 }, 391 errorMsg: `platform.ibmcloud.controlPlaneSubnets: Invalid value: "valid-subnet": controlPlaneSubnets contains subnet: valid-subnet, not found in expected vpcID: wrong-id`, 392 }, 393 { 394 name: "control plane subnet invalid ResourceGroup", 395 edits: editFunctions{ 396 func(ic *types.InstallConfig) { 397 ic.Platform.IBMCloud.NetworkResourceGroupName = wrongRG 398 }, 399 validVPCName, 400 func(ic *types.InstallConfig) { 401 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{"valid-subnet"} 402 }, 403 }, 404 errorMsg: `platform.ibmcloud.controlPlaneSubnets: Invalid value: "valid-subnet": controlPlaneSubnets contains subnet: valid-subnet, not found in expected networkResourceGroupName: wrong-resource-group`, 405 }, 406 { 407 name: "control plane subnet no zones", 408 edits: editFunctions{ 409 validNetworkResourceGroupName, 410 validVPCName, 411 func(ic *types.InstallConfig) { 412 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 413 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 414 }, 415 }, 416 }, 417 { 418 name: "control plane subnet no machinepoolplatform", 419 edits: editFunctions{ 420 validNetworkResourceGroupName, 421 validVPCName, 422 func(ic *types.InstallConfig) { 423 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 424 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 425 }, 426 func(ic *types.InstallConfig) { 427 ic.ControlPlane.Platform.IBMCloud = nil 428 }, 429 }, 430 }, 431 { 432 name: "control plane subnet invalid zones", 433 edits: editFunctions{ 434 validNetworkResourceGroupName, 435 validVPCName, 436 func(ic *types.InstallConfig) { 437 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name} 438 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 439 }, 440 func(ic *types.InstallConfig) { 441 ic.ControlPlane.Platform.IBMCloud.Zones = validZones 442 }, 443 }, 444 errorMsg: `\Qplatform.ibmcloud.controlPlaneSubnets: Invalid value: []string{"valid-subnet-1"}: number of zones (1) covered by controlPlaneSubnets does not match number of provided or default zones (3) for control plane in us-south\E`, 445 }, 446 { 447 name: "control plane subnet valid zones some", 448 edits: editFunctions{ 449 validNetworkResourceGroupName, 450 validVPCName, 451 func(ic *types.InstallConfig) { 452 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet2Name, validSubnet3Name} 453 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 454 }, 455 func(ic *types.InstallConfig) { 456 ic.ControlPlane.Platform.IBMCloud.Zones = []string{"us-south-2", "us-south-3"} 457 }, 458 }, 459 }, 460 { 461 name: "control plane subnet valid zones all", 462 edits: editFunctions{ 463 validNetworkResourceGroupName, 464 validVPCName, 465 func(ic *types.InstallConfig) { 466 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 467 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 468 }, 469 func(ic *types.InstallConfig) { 470 ic.ControlPlane.Platform.IBMCloud.Zones = validZones 471 }, 472 }, 473 }, 474 { 475 name: "VPC with no compute subnets", 476 edits: editFunctions{ 477 validNetworkResourceGroupName, 478 validVPCName, 479 }, 480 errorMsg: `\Qplatform.ibmcloud.computeSubnets: Invalid value: []string(nil): computeSubnets cannot be empty when providing a vpcName: valid-vpc\E`, 481 }, 482 { 483 name: "compute subnet not found", 484 edits: editFunctions{ 485 validNetworkResourceGroupName, 486 validVPCName, 487 func(ic *types.InstallConfig) { 488 ic.Platform.IBMCloud.ComputeSubnets = []string{"missing-compute-subnet"} 489 }, 490 }, 491 errorMsg: `platform.ibmcloud.computeSubnets: Not found: "missing-compute-subnet"`, 492 }, 493 { 494 name: "compute subnet IBM error", 495 edits: editFunctions{ 496 validNetworkResourceGroupName, 497 validVPCName, 498 func(ic *types.InstallConfig) { 499 ic.Platform.IBMCloud.ComputeSubnets = []string{"ibm-error-compute-subnet"} 500 }, 501 }, 502 errorMsg: `platform.ibmcloud.computeSubnets: Internal error: ibmcloud error`, 503 }, 504 { 505 name: "compute subnet invalid VPC", 506 edits: editFunctions{ 507 validNetworkResourceGroupName, 508 func(ic *types.InstallConfig) { 509 ic.Platform.IBMCloud.VPCName = "wrong-vpc" 510 }, 511 func(ic *types.InstallConfig) { 512 ic.Platform.IBMCloud.ComputeSubnets = []string{"valid-subnet"} 513 }, 514 }, 515 errorMsg: `platform.ibmcloud.computeSubnets: Invalid value: "valid-subnet": computeSubnets contains subnet: valid-subnet, not found in expected vpcID: wrong-id`, 516 }, 517 { 518 name: "compute subnet invalid ResourceGroup", 519 edits: editFunctions{ 520 func(ic *types.InstallConfig) { 521 ic.Platform.IBMCloud.NetworkResourceGroupName = wrongRG 522 }, 523 validVPCName, 524 func(ic *types.InstallConfig) { 525 ic.Platform.IBMCloud.ComputeSubnets = []string{"valid-subnet"} 526 }, 527 }, 528 errorMsg: `platform.ibmcloud.computeSubnets: Invalid value: "valid-subnet": computeSubnets contains subnet: valid-subnet, not found in expected networkResourceGroupName: wrong-resource-group`, 529 }, 530 { 531 name: "compute subnet no zones", 532 edits: editFunctions{ 533 validNetworkResourceGroupName, 534 validVPCName, 535 func(ic *types.InstallConfig) { 536 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 537 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 538 }, 539 }, 540 }, 541 { 542 name: "compute subnet no machinepoolplatform", 543 edits: editFunctions{ 544 validNetworkResourceGroupName, 545 validVPCName, 546 func(ic *types.InstallConfig) { 547 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 548 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 549 }, 550 func(ic *types.InstallConfig) { 551 ic.Compute[0].Platform.IBMCloud = nil 552 }, 553 }, 554 }, 555 { 556 name: "compute subnet invalid zones", 557 edits: editFunctions{ 558 validNetworkResourceGroupName, 559 validVPCName, 560 func(ic *types.InstallConfig) { 561 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 562 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet1Name} 563 }, 564 func(ic *types.InstallConfig) { 565 ic.Compute[0].Platform.IBMCloud.Zones = validZones 566 }, 567 }, 568 errorMsg: `\Qplatform.ibmcloud.computeSubnets: Invalid value: []string{"valid-subnet-1"}: number of zones (1) covered by computeSubnets does not match number of provided or default zones (3) for compute[0] in us-south\E`, 569 }, 570 { 571 name: "single compute subnet valid zones some", 572 edits: editFunctions{ 573 validNetworkResourceGroupName, 574 validVPCName, 575 func(ic *types.InstallConfig) { 576 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 577 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet2Name} 578 }, 579 func(ic *types.InstallConfig) { 580 ic.Compute[0].Platform.IBMCloud.Zones = []string{validZoneUSSouth2} 581 }, 582 }, 583 }, 584 { 585 name: "multiple compute subnet invalid zones some", 586 edits: editFunctions{ 587 validNetworkResourceGroupName, 588 validVPCName, 589 func(ic *types.InstallConfig) { 590 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 591 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet2Name, validSubnet3Name} 592 }, 593 func(ic *types.InstallConfig) { 594 secondCompute := types.MachinePool{ 595 Platform: types.MachinePoolPlatform{ 596 IBMCloud: validMachinePool(), 597 }, 598 } 599 ic.Compute = append(ic.Compute, secondCompute) 600 ic.Compute[0].Platform.IBMCloud.Zones = []string{validZoneUSSouth2, validZoneUSSouth3} 601 ic.Compute[1].Platform.IBMCloud.Zones = []string{validZoneUSSouth3} 602 }, 603 }, 604 errorMsg: `\Qplatform.ibmcloud.computeSubnets: Invalid value: []string{"valid-subnet-2", "valid-subnet-3"}: number of zones (2) covered by computeSubnets does not match number of provided or default zones (1) for compute[1] in us-south\E`, 605 }, 606 { 607 name: "multiple compute subnet valid zones some", 608 edits: editFunctions{ 609 validNetworkResourceGroupName, 610 validVPCName, 611 func(ic *types.InstallConfig) { 612 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 613 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet2Name, validSubnet3Name} 614 }, 615 func(ic *types.InstallConfig) { 616 secondCompute := types.MachinePool{ 617 Platform: types.MachinePoolPlatform{ 618 IBMCloud: validMachinePool(), 619 }, 620 } 621 ic.Compute = append(ic.Compute, secondCompute) 622 ic.Compute[0].Platform.IBMCloud.Zones = []string{validZoneUSSouth2, validZoneUSSouth3} 623 ic.Compute[1].Platform.IBMCloud.Zones = []string{validZoneUSSouth2, validZoneUSSouth3} 624 }, 625 }, 626 }, 627 { 628 name: "single compute subnet valid zones all", 629 edits: editFunctions{ 630 validNetworkResourceGroupName, 631 validVPCName, 632 func(ic *types.InstallConfig) { 633 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 634 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 635 }, 636 func(ic *types.InstallConfig) { 637 ic.Compute[0].Platform.IBMCloud.Zones = validZones 638 }, 639 }, 640 }, 641 { 642 name: "multiple compute subnet valid zones all", 643 edits: editFunctions{ 644 validNetworkResourceGroupName, 645 validVPCName, 646 func(ic *types.InstallConfig) { 647 ic.Platform.IBMCloud.ControlPlaneSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 648 ic.Platform.IBMCloud.ComputeSubnets = []string{validSubnet1Name, validSubnet2Name, validSubnet3Name} 649 }, 650 func(ic *types.InstallConfig) { 651 secondCompute := types.MachinePool{ 652 Platform: types.MachinePoolPlatform{ 653 IBMCloud: validMachinePool(), 654 }, 655 } 656 ic.Compute = append(ic.Compute, secondCompute) 657 ic.Compute[0].Platform.IBMCloud.Zones = validZones 658 ic.Compute[1].Platform.IBMCloud.Zones = validZones 659 }, 660 }, 661 }, 662 { 663 name: "invalid control plane machine pool type", 664 edits: editFunctions{ 665 controlPlaneInvalidInstanceType, 666 }, 667 errorMsg: `\QcontrolPlane.platform.ibmcloud.type: Not found: "invalid-instance-type"\E`, 668 }, 669 { 670 name: "valid control plane machine pool type", 671 edits: editFunctions{ 672 controlPlaneValidInstanceType, 673 }, 674 }, 675 { 676 name: "invalid control plane machine pool boot volume crn", 677 edits: editFunctions{ 678 controlPlaneInvalidBootVolume, 679 }, 680 errorMsg: `\QcontrolPlane.platform.ibmcloud.bootVolume.encryptionKey: Invalid value: "invalid-encryption-key-crn": key CRN does not match: valid-encryption-key-crn\E`, 681 }, 682 { 683 name: "invalid control plane machine pool boot volume disabled key", 684 edits: editFunctions{ 685 controlPlaneValidBootVolume, 686 }, 687 errorMsg: `\QcontrolPlane.platform.ibmcloud.bootVolume.encryptionKey: Invalid value: "valid-encryption-key-crn": key is disabled\E`, 688 }, 689 { 690 name: "invalid control plane machine pool boot volume deleted key", 691 edits: editFunctions{ 692 controlPlaneValidBootVolume, 693 }, 694 errorMsg: `\QcontrolPlane.platform.ibmcloud.bootVolume.encryptionKey: Invalid value: "valid-encryption-key-crn": key has been deleted\E`, 695 }, 696 { 697 name: "valid control plane machine pool boot volume crn", 698 edits: editFunctions{ 699 controlPlaneValidBootVolume, 700 }, 701 }, 702 } 703 704 mockCtrl := gomock.NewController(t) 705 defer mockCtrl.Finish() 706 707 ibmcloudClient := mock.NewMockAPI(mockCtrl) 708 709 // Mocks: valid install config and all other tests ('AnyTimes()') 710 ibmcloudClient.EXPECT().GetSubnet(gomock.Any(), validPublicSubnetUSSouth1ID).Return(&vpcv1.Subnet{Zone: &vpcv1.ZoneReference{Name: &validZoneUSSouth1}}, nil).AnyTimes() 711 ibmcloudClient.EXPECT().GetSubnet(gomock.Any(), validPublicSubnetUSSouth2ID).Return(&vpcv1.Subnet{Zone: &vpcv1.ZoneReference{Name: &validZoneUSSouth1}}, nil).AnyTimes() 712 ibmcloudClient.EXPECT().GetSubnet(gomock.Any(), validPrivateSubnetUSSouth1ID).Return(&vpcv1.Subnet{Zone: &vpcv1.ZoneReference{Name: &validZoneUSSouth1}}, nil).AnyTimes() 713 ibmcloudClient.EXPECT().GetSubnet(gomock.Any(), validPrivateSubnetUSSouth2ID).Return(&vpcv1.Subnet{Zone: &vpcv1.ZoneReference{Name: &validZoneUSSouth1}}, nil).AnyTimes() 714 ibmcloudClient.EXPECT().GetSubnet(gomock.Any(), "subnet-invalid-zone").Return(&vpcv1.Subnet{Zone: &vpcv1.ZoneReference{Name: &[]string{"invalid"}[0]}}, nil).AnyTimes() 715 ibmcloudClient.EXPECT().GetVSIProfiles(gomock.Any()).Return(validInstanceProfiles, nil).AnyTimes() 716 ibmcloudClient.EXPECT().GetVPCZonesForRegion(gomock.Any(), validRegion).Return([]string{"us-south-1", "us-south-2", "us-south-3"}, nil).AnyTimes() 717 718 // Mocks: VPC with no ResourceGroup supplied 719 // No mocks required 720 721 // Mocks: VPC not found 722 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 723 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 724 725 // Mocks: VPC not in ResourceGroup 726 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 727 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 728 729 // Mocks: VPC with no control plane subnets 730 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 731 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 732 733 // Mocks: control plane subnet not found 734 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 735 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 736 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), "missing-cp-subnet", validRegion).Return(nil, &VPCResourceNotFoundError{}) 737 738 // Mocks: control plane subnet IBM error 739 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 740 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 741 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), "ibm-error-cp-subnet", validRegion).Return(nil, errors.New("ibmcloud error")) 742 743 // Mocks: control plane subnet invalid VPC 744 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 745 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(invalidVPC, nil) 746 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), "valid-subnet", validRegion).Return(validSubnet1, nil) 747 748 // Mocks: control plane subnet invalid ResourceGroup 749 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 750 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCInvalidRG, nil) 751 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), "valid-subnet", validRegion).Return(validSubnet1, nil) 752 753 // Mocks: control plane subnet no zones 754 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 755 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 756 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil).Times(2) 757 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil).Times(2) 758 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil).Times(2) 759 760 // Mocks: control plane subnet no machinepoolplatform 761 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 762 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 763 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil).Times(2) 764 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil).Times(2) 765 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil).Times(2) 766 767 // Mocks: control plane subnet invalid zones 768 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 769 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 770 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil).Times(2) 771 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil) 772 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil) 773 774 // Mocks: control plane subnet valid zones some 775 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 776 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 777 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil) 778 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil).Times(2) 779 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil).Times(2) 780 781 // Mocks: control plane subnet valid zones all 782 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 783 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 784 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil).Times(2) 785 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil).Times(2) 786 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil).Times(2) 787 788 // Mocks: VPC with no compute subnets 789 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 790 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 791 792 // Mocks: compute subnet not found 793 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 794 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 795 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), "missing-compute-subnet", validRegion).Return(nil, &VPCResourceNotFoundError{}) 796 797 // Mocks: compute subnet IBM error 798 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 799 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 800 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), "ibm-error-compute-subnet", validRegion).Return(nil, errors.New("ibmcloud error")) 801 802 // Mocks: compute subnet invalid VPC 803 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 804 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(invalidVPC, nil) 805 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), "valid-subnet", validRegion).Return(validSubnet1, nil) 806 807 // Mocks: compute subnet invalid ResourceGroup 808 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 809 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCInvalidRG, nil) 810 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), "valid-subnet", validRegion).Return(validSubnet1, nil) 811 812 // Mocks: compute subnet no zones 813 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 814 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 815 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil).Times(2) 816 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil).Times(2) 817 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil).Times(2) 818 819 // Mocks: compute subnet no machinepoolplatform 820 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 821 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 822 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil).Times(2) 823 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil).Times(2) 824 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil).Times(2) 825 826 // Mocks: compute subnet invalid zones 827 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 828 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 829 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil).Times(2) 830 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil) 831 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil) 832 833 // Mocks: single compute subnet valid zones some 834 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 835 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 836 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil) 837 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil).Times(2) 838 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil) 839 840 // Mocks: multiple compute subnet invalid zones some 841 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 842 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 843 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil) 844 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil).Times(2) 845 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil).Times(2) 846 847 // Mocks: multiple compute subnet valid zones some 848 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 849 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 850 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil) 851 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil).Times(2) 852 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil).Times(2) 853 854 // Mocks: single compute subnet valid zones all 855 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 856 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 857 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil).Times(2) 858 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil).Times(2) 859 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil).Times(2) 860 861 // Mocks: multiple compute subnet valid zones all 862 ibmcloudClient.EXPECT().GetResourceGroups(gomock.Any()).Return(validResourceGroups, nil) 863 ibmcloudClient.EXPECT().GetVPCs(gomock.Any(), validRegion).Return(validVPCs, nil) 864 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet1Name, validRegion).Return(validSubnet1, nil).Times(2) 865 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet2Name, validRegion).Return(validSubnet2, nil).Times(2) 866 ibmcloudClient.EXPECT().GetSubnetByName(gomock.Any(), validSubnet3Name, validRegion).Return(validSubnet3, nil).Times(2) 867 868 // Mocks: invalid control plane machine pool type 869 // No additional mocks required 870 871 // Mocks: valid control plane machine pool type 872 // No additional mocks required 873 874 // Mocks: invalid control plane machine pool boot volume crn 875 ibmcloudClient.EXPECT().GetEncryptionKey(gomock.Any(), invalidEncryptionKey).Return(validEncryptionKeyResponse, nil) 876 877 // Mocks: invalid control plane machine pool boot volume disabled 878 ibmcloudClient.EXPECT().GetEncryptionKey(gomock.Any(), validEncryptionKey).Return(disabledEncryptionKeyResponse, nil) 879 880 // Mocks: invalid control plane machine pool boot volume deleted 881 ibmcloudClient.EXPECT().GetEncryptionKey(gomock.Any(), validEncryptionKey).Return(deletedEncryptionKeyResponse, nil) 882 883 // Mock: valid control plane machine pool boot volume crn 884 ibmcloudClient.EXPECT().GetEncryptionKey(gomock.Any(), validEncryptionKey).Return(validEncryptionKeyResponse, nil) 885 886 for _, tc := range cases { 887 t.Run(tc.name, func(t *testing.T) { 888 editedInstallConfig := validInstallConfig() 889 for _, edit := range tc.edits { 890 edit(editedInstallConfig) 891 } 892 893 aggregatedErrors := Validate(ibmcloudClient, editedInstallConfig) 894 if tc.errorMsg != "" { 895 assert.Regexp(t, tc.errorMsg, aggregatedErrors) 896 } else { 897 assert.NoError(t, aggregatedErrors) 898 } 899 }) 900 } 901 } 902 903 func TestValidatePreExistingPublicDNS(t *testing.T) { 904 cases := []struct { 905 name string 906 internal bool 907 edits editFunctions 908 errorMsg string 909 }{ 910 { 911 name: "no pre-existing External DNS records", 912 internal: false, 913 errorMsg: "", 914 }, 915 { 916 name: "pre-existing External DNS records", 917 internal: false, 918 errorMsg: `^record api\.valid-cluster-name\.valid\.base\.domain already exists in CIS zone \(valid-zone-id\) and might be in use by another cluster, please remove it to continue$`, 919 }, 920 { 921 name: "cannot get External zone ID", 922 internal: false, 923 errorMsg: `^baseDomain: Internal error$`, 924 }, 925 { 926 name: "cannot get External DNS records", 927 internal: false, 928 errorMsg: `^baseDomain: Internal error$`, 929 }, 930 { 931 name: "no validation of Internal PublishStrategy", 932 internal: true, 933 errorMsg: "", 934 }, 935 } 936 937 mockCtrl := gomock.NewController(t) 938 defer mockCtrl.Finish() 939 940 ibmcloudClient := mock.NewMockAPI(mockCtrl) 941 942 dnsRecordName := fmt.Sprintf("api.%s.%s", validClusterName, validBaseDomain) 943 944 metadata := NewMetadata(&types.InstallConfig{ 945 BaseDomain: validBaseDomain, 946 Platform: types.Platform{ 947 IBMCloud: &ibmcloudtypes.Platform{ 948 Region: "us-south", 949 }, 950 }, 951 }) 952 metadata.cisInstanceCRN = validCISInstanceCRN 953 954 // Mocks: no pre-existing External DNS records 955 ibmcloudClient.EXPECT().GetDNSZoneIDByName(gomock.Any(), validBaseDomain, types.ExternalPublishingStrategy).Return(validDNSZoneID, nil) 956 ibmcloudClient.EXPECT().GetDNSRecordsByName(gomock.Any(), validCISInstanceCRN, validDNSZoneID, dnsRecordName).Return(noDNSRecordsResponse, nil) 957 958 // Mocks: pre-existing External DNS records 959 ibmcloudClient.EXPECT().GetDNSZoneIDByName(gomock.Any(), validBaseDomain, types.ExternalPublishingStrategy).Return(validDNSZoneID, nil) 960 ibmcloudClient.EXPECT().GetDNSRecordsByName(gomock.Any(), validCISInstanceCRN, validDNSZoneID, dnsRecordName).Return(existingDNSRecordsResponse, nil) 961 962 // Mocks: cannot get External zone ID 963 ibmcloudClient.EXPECT().GetDNSZoneIDByName(gomock.Any(), validBaseDomain, types.ExternalPublishingStrategy).Return("", fmt.Errorf("")) 964 965 // Mocks: cannot get External DNS records 966 ibmcloudClient.EXPECT().GetDNSZoneIDByName(gomock.Any(), validBaseDomain, types.ExternalPublishingStrategy).Return(validDNSZoneID, nil) 967 ibmcloudClient.EXPECT().GetDNSRecordsByName(gomock.Any(), validCISInstanceCRN, validDNSZoneID, dnsRecordName).Return(nil, fmt.Errorf("")) 968 969 for _, tc := range cases { 970 t.Run(tc.name, func(t *testing.T) { 971 validInstallConfig := validInstallConfig() 972 if tc.internal { 973 validInstallConfig.Publish = types.InternalPublishingStrategy 974 } 975 aggregatedErrors := ValidatePreExistingPublicDNS(ibmcloudClient, validInstallConfig, metadata) 976 if tc.errorMsg != "" { 977 assert.Regexp(t, tc.errorMsg, aggregatedErrors) 978 } else { 979 assert.NoError(t, aggregatedErrors) 980 } 981 }) 982 } 983 } 984 985 func TestValidateServiceEndpoints(t *testing.T) { 986 cases := []struct { 987 name string 988 edits editFunctions 989 errorMsg string 990 }{ 991 { 992 name: "empty service endpoints", 993 }, 994 { 995 name: "single valid service endpoint", 996 edits: editFunctions{ 997 func(ic *types.InstallConfig) { 998 ic.Platform.IBMCloud.ServiceEndpoints = []configv1.IBMCloudServiceEndpoint{ 999 { 1000 Name: configv1.IBMCloudServiceIAM, 1001 URL: unittestURL, 1002 }, 1003 } 1004 }, 1005 }, 1006 }, 1007 { 1008 name: "single invalid override service endpoint", 1009 edits: editFunctions{ 1010 func(ic *types.InstallConfig) { 1011 ic.Platform.IBMCloud.ServiceEndpoints = []configv1.IBMCloudServiceEndpoint{ 1012 { 1013 Name: "invalid-service", 1014 URL: unittestURL, 1015 }, 1016 } 1017 }, 1018 }, 1019 errorMsg: `\Qplatform.ibmcloud.serviceEndpoints[0].name: Invalid value: "invalid-service": not a supported override service\E`, 1020 }, 1021 { 1022 name: "single invalid URI service endpoint", 1023 edits: editFunctions{ 1024 func(ic *types.InstallConfig) { 1025 ic.Platform.IBMCloud.ServiceEndpoints = []configv1.IBMCloudServiceEndpoint{ 1026 { 1027 Name: configv1.IBMCloudServiceIAM, 1028 URL: "/invalid/uri/format", 1029 }, 1030 } 1031 }, 1032 }, 1033 errorMsg: `\Qplatform.ibmcloud.serviceEndpoints[0].url: Invalid value: "/invalid/uri/format": Head "/invalid/uri/format": unsupported protocol scheme ""\E`, 1034 }, 1035 { 1036 name: "multiple valid service endpoint", 1037 edits: editFunctions{ 1038 func(ic *types.InstallConfig) { 1039 ic.Platform.IBMCloud.ServiceEndpoints = []configv1.IBMCloudServiceEndpoint{ 1040 { 1041 Name: configv1.IBMCloudServiceIAM, 1042 URL: unittestURL, 1043 }, 1044 { 1045 Name: configv1.IBMCloudServiceCOS, 1046 URL: unittestURL, 1047 }, 1048 } 1049 }, 1050 }, 1051 }, 1052 { 1053 name: "multiple invalid duplicate service endpoints", 1054 edits: editFunctions{ 1055 func(ic *types.InstallConfig) { 1056 ic.Platform.IBMCloud.ServiceEndpoints = []configv1.IBMCloudServiceEndpoint{ 1057 { 1058 Name: configv1.IBMCloudServiceIAM, 1059 URL: unittestURL, 1060 }, 1061 { 1062 Name: configv1.IBMCloudServiceIAM, 1063 URL: unittestURL, 1064 }, 1065 } 1066 }, 1067 }, 1068 errorMsg: `\Qplatform.ibmcloud.serviceEndpoints[1].name: Duplicate value: "IAM"\E`, 1069 }, 1070 { 1071 name: "multiple invalid service endpoints", 1072 edits: editFunctions{ 1073 func(ic *types.InstallConfig) { 1074 ic.Platform.IBMCloud.ServiceEndpoints = []configv1.IBMCloudServiceEndpoint{ 1075 { 1076 Name: "invalid-service", 1077 URL: unittestURL, 1078 }, 1079 { 1080 Name: configv1.IBMCloudServiceCOS, 1081 URL: "/invalid/uri/format", 1082 }, 1083 { 1084 Name: configv1.IBMCloudServiceCOS, 1085 URL: unittestURL, 1086 }, 1087 } 1088 }, 1089 }, 1090 errorMsg: `\Q[platform.ibmcloud.serviceEndpoints[0].name: Invalid value: "invalid-service": not a supported override service, platform.ibmcloud.serviceEndpoints[1].url: Invalid value: "/invalid/uri/format": Head "/invalid/uri/format": unsupported protocol scheme "", platform.ibmcloud.serviceEndpoints[2].name: Duplicate value: "COS"]\E`, 1091 }, 1092 { 1093 name: "multiple mixed validity service endpoints", 1094 edits: editFunctions{ 1095 func(ic *types.InstallConfig) { 1096 ic.Platform.IBMCloud.ServiceEndpoints = []configv1.IBMCloudServiceEndpoint{ 1097 { 1098 Name: configv1.IBMCloudServiceIAM, 1099 URL: unittestURL, 1100 }, 1101 { 1102 Name: configv1.IBMCloudServiceCOS, 1103 URL: unittestURL, 1104 }, 1105 { 1106 Name: configv1.IBMCloudServiceCOS, 1107 URL: "/invalid/uri/format", 1108 }, 1109 { 1110 Name: "invalid-service", 1111 URL: unittestURL, 1112 }, 1113 } 1114 }, 1115 }, 1116 errorMsg: `\Qplatform.ibmcloud.serviceEndpoints[2].name: Duplicate value: "COS", platform.ibmcloud.serviceEndpoints[3].name: Invalid value: "invalid-service": not a supported override service\E`, 1117 }, 1118 } 1119 1120 for _, tc := range cases { 1121 t.Run(tc.name, func(t *testing.T) { 1122 editedInstallConfig := validInstallConfig() 1123 for _, edit := range tc.edits { 1124 edit(editedInstallConfig) 1125 } 1126 aggregatedErrors := ValidateServiceEndpoints(editedInstallConfig) 1127 if tc.errorMsg != "" { 1128 assert.Regexp(t, tc.errorMsg, aggregatedErrors) 1129 } else { 1130 assert.NoError(t, aggregatedErrors) 1131 } 1132 }) 1133 } 1134 }