github.com/openshift/installer@v1.4.17/pkg/asset/installconfig/vsphere/validation_test.go (about) 1 package vsphere 2 3 import ( 4 "context" 5 "errors" 6 "net" 7 "sync" 8 "testing" 9 "time" 10 11 "github.com/golang/mock/gomock" 12 "github.com/sirupsen/logrus/hooks/test" 13 "github.com/stretchr/testify/assert" 14 "github.com/vmware/govmomi/session" 15 "github.com/vmware/govmomi/simulator" 16 "github.com/vmware/govmomi/vapi/rest" 17 vapitags "github.com/vmware/govmomi/vapi/tags" 18 "github.com/vmware/govmomi/vim25/mo" 19 vim25types "github.com/vmware/govmomi/vim25/types" 20 "k8s.io/apimachinery/pkg/util/validation/field" 21 22 "github.com/openshift/installer/pkg/asset/installconfig/vsphere/mock" 23 "github.com/openshift/installer/pkg/ipnet" 24 "github.com/openshift/installer/pkg/types" 25 "github.com/openshift/installer/pkg/types/vsphere" 26 ) 27 28 var ( 29 validCIDR = "10.0.0.0/16" 30 mu sync.Mutex 31 stopListening = false 32 ) 33 34 const ( 35 tagTestCreateRegionCategory = 0x01 36 tagTestCreateZoneCategory = 0x02 37 tagTestAttachRegionTags = 0x04 38 tagTestAttachZoneTags = 0x08 39 tagTestNothingCreatedOrAttached = 0x10 40 ) 41 42 const wildcardDNS = "nip.io" 43 44 func validIPIInstallConfig() *types.InstallConfig { 45 return &types.InstallConfig{ 46 Networking: &types.Networking{ 47 MachineNetwork: []types.MachineNetworkEntry{ 48 {CIDR: *ipnet.MustParseCIDR(validCIDR)}, 49 }, 50 }, 51 Publish: types.ExternalPublishingStrategy, 52 Platform: types.Platform{ 53 VSphere: &vsphere.Platform{ 54 APIVIPs: []string{"192.168.111.0"}, 55 IngressVIPs: []string{"192.168.111.1"}, 56 }, 57 }, 58 } 59 } 60 61 func validMultiVCenterPlatform() *vsphere.Platform { 62 return &vsphere.Platform{ 63 VCenters: []vsphere.VCenter{ 64 { 65 Server: "test-vcenter", 66 Port: 443, 67 Username: "test_username", 68 Password: "test_password", 69 Datacenters: []string{ 70 "DC0", 71 }, 72 }, 73 }, 74 FailureDomains: []vsphere.FailureDomain{ 75 { 76 Name: "test-east-1a", 77 Region: "test-region-east", 78 Zone: "test-zone-1a", 79 Topology: vsphere.Topology{ 80 Datacenter: "DC0", 81 ComputeCluster: "/DC0/host/DC0_C0", 82 ResourcePool: "/DC0/host/DC0_C0/Resources/test-resourcepool", 83 Folder: "/DC0/vm", 84 Networks: []string{ 85 "DC0_DVPG0", 86 }, 87 Datastore: "/DC0/datastore/LocalDS_0", 88 }}, 89 }, 90 } 91 } 92 93 func teardownTagAttachmentTest(ctx context.Context, tagMgr *vapitags.Manager) error { 94 tags, err := tagMgr.ListTags(ctx) 95 if err != nil { 96 return err 97 } 98 attachedMos, err := tagMgr.GetAttachedObjectsOnTags(ctx, tags) 99 if err != nil { 100 return err 101 } 102 103 for _, attachedMo := range attachedMos { 104 for _, mo := range attachedMo.ObjectIDs { 105 err := tagMgr.DetachTag(ctx, attachedMo.TagID, mo) 106 if err != nil { 107 return err 108 } 109 } 110 err := tagMgr.DeleteTag(ctx, attachedMo.Tag) 111 if err != nil { 112 return err 113 } 114 } 115 116 categories, err := tagMgr.GetCategories(ctx) 117 if err != nil { 118 return err 119 } 120 for _, category := range categories { 121 cat := category 122 err := tagMgr.DeleteCategory(ctx, &cat) 123 if err != nil { 124 return err 125 } 126 } 127 return nil 128 } 129 130 func setupTagAttachmentTest(ctx context.Context, restClient *rest.Client, finder Finder, attachmentMask int64) (*vapitags.Manager, error) { 131 tagMgr := vapitags.NewManager(restClient) 132 133 if attachmentMask&tagTestCreateRegionCategory != 0 { 134 categoryID, err := tagMgr.CreateCategory(ctx, &vapitags.Category{ 135 Name: "openshift-region", 136 Description: "region tag category", 137 }) 138 if err != nil { 139 return nil, err 140 } 141 142 if attachmentMask&tagTestAttachRegionTags != 0 { 143 tagID, err := tagMgr.CreateTag(ctx, &vapitags.Tag{ 144 Name: "us-east", 145 CategoryID: categoryID, 146 }) 147 if err != nil { 148 return nil, err 149 } 150 datacenters, err := finder.DatacenterList(ctx, "/...") 151 if err != nil { 152 return nil, err 153 } 154 for _, datacenter := range datacenters { 155 err = tagMgr.AttachTag(ctx, tagID, datacenter) 156 if err != nil { 157 return nil, err 158 } 159 } 160 } 161 } 162 if attachmentMask&tagTestCreateZoneCategory != 0 { 163 categoryID, err := tagMgr.CreateCategory(ctx, &vapitags.Category{ 164 Name: "openshift-zone", 165 Description: "zone tag category", 166 }) 167 if err != nil { 168 return nil, err 169 } 170 if attachmentMask&tagTestAttachZoneTags != 0 { 171 tagID, err := tagMgr.CreateTag(ctx, &vapitags.Tag{ 172 Name: "us-east-1a", 173 CategoryID: categoryID, 174 }) 175 if err != nil { 176 return nil, err 177 } 178 clusters, err := finder.ClusterComputeResourceList(ctx, "/...") 179 if err != nil { 180 return nil, err 181 } 182 for _, cluster := range clusters { 183 err = tagMgr.AttachTag(ctx, tagID, cluster) 184 if err != nil { 185 return nil, err 186 } 187 } 188 } 189 } 190 191 return tagMgr, nil 192 } 193 194 // simulatorHelper starts the govmomi simulator 195 // returning the simulator.Server so that we can defer closing later and 196 // shutdown the simulator to change versions. 197 func simulatorHelper(t *testing.T, setVersionToSupported bool) (*validationContext, *simulator.Server, *rest.Client, error) { 198 t.Helper() 199 200 server, err := mock.StartSimulator(setVersionToSupported) 201 if err != nil { 202 return nil, nil, nil, err 203 } 204 205 ctrl := gomock.NewController(t) 206 defer ctrl.Finish() 207 208 ctx, cancel := context.WithTimeout(context.TODO(), 5*time.Minute) 209 defer cancel() 210 211 finder, err := mock.GetFinder(server) 212 if err != nil { 213 return nil, nil, nil, err 214 } 215 216 client, _, err := mock.GetClient(server) 217 if err != nil { 218 return nil, nil, nil, err 219 } 220 221 restClient := rest.NewClient(client) 222 223 defer restClient.CloseIdleConnections() 224 err = restClient.Login(context.TODO(), simulator.DefaultLogin) 225 if err != nil { 226 return nil, nil, nil, err 227 } 228 229 vmFolder, err := finder.Folder(ctx, "/DC0/vm") 230 if err != nil { 231 return nil, nil, nil, err 232 } 233 234 myFolder, err := vmFolder.CreateFolder(ctx, "my-folder") 235 if err != nil { 236 return nil, nil, nil, err 237 } 238 var folder mo.Folder 239 240 err = myFolder.Properties(ctx, myFolder.Reference(), nil, &folder) 241 if err != nil { 242 return nil, nil, nil, err 243 } 244 245 resourcePools, err := finder.ResourcePoolList(ctx, "/DC0/host/DC0_C0") 246 if err != nil { 247 return nil, nil, nil, err 248 } 249 _, err = resourcePools[0].Create(ctx, "test-resourcepool", vim25types.DefaultResourceConfigSpec()) 250 if err != nil { 251 return nil, nil, nil, err 252 } 253 254 sessionMgr := session.NewManager(client) 255 userSession, err := sessionMgr.UserSession(ctx) 256 if err != nil { 257 return nil, nil, nil, err 258 } 259 username := userSession.UserName 260 validPermissionsAuthManagerClient, err := buildAuthManagerClient(ctx, t, ctrl, finder, username, nil, nil, nil) 261 if err != nil { 262 return nil, nil, nil, err 263 } 264 265 return &validationContext{ 266 AuthManager: validPermissionsAuthManagerClient, 267 Finder: finder, 268 Client: client, 269 }, server, restClient, nil 270 } 271 272 func TestValidateFailureDomains(t *testing.T) { 273 validationCtx, server, restClient, err := simulatorHelper(t, true) 274 if err != nil { 275 t.Error(err) 276 return 277 } 278 defer server.Close() 279 280 ctx, cancel := context.WithTimeout(context.TODO(), 60*time.Second) 281 defer cancel() 282 283 tests := []struct { 284 name string 285 installConfig *types.InstallConfig 286 validationMethod func(*validationContext, *vsphere.FailureDomain, bool) field.ErrorList 287 failureDomain *vsphere.FailureDomain 288 tagTestMask int64 289 checkTags bool 290 expectErr string 291 }{ 292 { 293 name: "multi-zone validation", 294 failureDomain: &validMultiVCenterPlatform().FailureDomains[0], 295 validationMethod: validateFailureDomain, 296 }, { 297 name: "multi-zone validation - invalid datacenter", 298 failureDomain: func() *vsphere.FailureDomain { 299 failureDomain := &validMultiVCenterPlatform().FailureDomains[0] 300 failureDomain.Topology.Datacenter = "invalid-dc" 301 return failureDomain 302 }(), 303 validationMethod: validateFailureDomain, 304 checkTags: false, 305 expectErr: `[platform.vsphere.failureDomains.topology.datacenter: Invalid value: "invalid-dc": datacenter 'invalid-dc' not found, platform.vsphere.failureDomains.topology.datastore: Invalid value: "invalid-dc": unable to find datacenter invalid-dc: datacenter 'invalid-dc' not found, platform.vsphere.failureDomains.topology: Invalid value: "invalid-dc": datacenter './invalid-dc' not found]`, 306 }, 307 { 308 name: "multi-zone validation - invalid cluster", 309 failureDomain: func() *vsphere.FailureDomain { 310 failureDomain := &validMultiVCenterPlatform().FailureDomains[0] 311 failureDomain.Topology.ComputeCluster = "/DC0/host/invalid-cluster" 312 return failureDomain 313 }(), 314 validationMethod: validateFailureDomain, 315 checkTags: false, 316 expectErr: `\[platform.vsphere.failureDomains.topology.computeCluster: Invalid value: "/DC0/host/invalid-cluster": cluster '/DC0/host/invalid-cluster' not found, platform.vsphere.failureDomains.topology: Invalid value: "DC0_DVPG0": could not find vSphere cluster at /DC0/host/invalid-cluster: cluster '/DC0/host/invalid-cluster' not found\]`, 317 }, 318 { 319 name: "multi-zone validation - missing cluster", 320 failureDomain: func() *vsphere.FailureDomain { 321 failureDomain := &validMultiVCenterPlatform().FailureDomains[0] 322 failureDomain.Topology.ComputeCluster = "" 323 return failureDomain 324 }(), 325 validationMethod: validateFailureDomain, 326 checkTags: false, 327 expectErr: `[platform.vsphere: Internal error: please specify a datacenter, platform.vsphere.failureDomains.topology.computeCluster: Required value: must specify the cluster]`, 328 }, 329 { 330 name: "multi-zone validation - missing datastore", 331 failureDomain: func() *vsphere.FailureDomain { 332 failureDomain := &validMultiVCenterPlatform().FailureDomains[0] 333 failureDomain.Topology.Datastore = "" 334 return failureDomain 335 }(), 336 validationMethod: validateFailureDomain, 337 checkTags: false, 338 expectErr: `^platform.vsphere.failureDomains.topology.datastore: Required value: must specify the datastore$`, 339 }, 340 { 341 name: "multi-zone validation - invalid resource pool", 342 failureDomain: func() *vsphere.FailureDomain { 343 failureDomain := &validMultiVCenterPlatform().FailureDomains[0] 344 failureDomain.Topology.ResourcePool = "/DC0/host/DC0_C0/Resources/invalid-resourcepool" 345 return failureDomain 346 }(), 347 validationMethod: validateFailureDomain, 348 checkTags: false, 349 expectErr: `^platform.vsphere.failureDomains.topology.resourcePool: Invalid value: "/DC0/host/DC0_C0/Resources/invalid-resourcepool": resource pool '/DC0/host/DC0_C0/Resources/invalid-resourcepool' not found$`, 350 }, 351 { 352 name: "multi-zone validation - invalid network", 353 failureDomain: func() *vsphere.FailureDomain { 354 failureDomain := &validMultiVCenterPlatform().FailureDomains[0] 355 failureDomain.Topology.Networks = []string{ 356 "invalid-network", 357 } 358 return failureDomain 359 }(), 360 validationMethod: validateFailureDomain, 361 checkTags: false, 362 expectErr: `^platform.vsphere.failureDomains.topology: Invalid value: "invalid-network": unable to find network provided$`, 363 }, { 364 name: "multi-zone validation - create missing folder", 365 failureDomain: func() *vsphere.FailureDomain { 366 failureDomain := &validMultiVCenterPlatform().FailureDomains[0] 367 failureDomain.Topology.Folder = "/DC0/vm/create-missing-folder" 368 return failureDomain 369 }(), 370 validationMethod: validateFailureDomain, 371 checkTags: false, 372 expectErr: ``, 373 }, { 374 name: "multi-zone tag categories present and tags attached", 375 validationMethod: validateFailureDomain, 376 failureDomain: &validMultiVCenterPlatform().FailureDomains[0], 377 checkTags: true, 378 tagTestMask: tagTestCreateZoneCategory | 379 tagTestCreateRegionCategory | 380 tagTestAttachRegionTags | 381 tagTestAttachZoneTags, 382 }, { 383 name: "multi-zone tag categories, missing zone tag attachment", 384 validationMethod: validateFailureDomain, 385 failureDomain: &validMultiVCenterPlatform().FailureDomains[0], 386 checkTags: true, 387 tagTestMask: tagTestCreateZoneCategory | 388 tagTestCreateRegionCategory | 389 tagTestAttachRegionTags, 390 expectErr: "platform.vsphere.failureDomains.topology.computeCluster: Internal error: tag associated with tag category openshift-zone not attached to this resource or ancestor", 391 }, { 392 name: "multi-zone tag categories, missing zone and region tag categories", 393 validationMethod: validateFailureDomain, 394 failureDomain: &validMultiVCenterPlatform().FailureDomains[0], 395 checkTags: true, 396 tagTestMask: tagTestNothingCreatedOrAttached, 397 expectErr: "platform.vsphere: Internal error: tag categories openshift-zone and openshift-region must be created", 398 }, 399 } 400 401 for _, test := range tests { 402 t.Run(test.name, func(t *testing.T) { 403 var err error 404 if test.validationMethod != nil { 405 var tagMgr *vapitags.Manager 406 407 if test.tagTestMask != 0 { 408 tagMgr, err = setupTagAttachmentTest(ctx, restClient, validationCtx.Finder, test.tagTestMask) 409 if err != nil { 410 assert.NoError(t, err) 411 } 412 validationCtx.zoneTagCategoryID = "" 413 validationCtx.regionTagCategoryID = "" 414 validationCtx.TagManager = tagMgr 415 } 416 417 err = test.validationMethod(validationCtx, test.failureDomain, test.checkTags).ToAggregate() 418 if test.tagTestMask != 0 { 419 err := teardownTagAttachmentTest(ctx, tagMgr) 420 if err != nil { 421 assert.NoError(t, err) 422 } 423 validationCtx.zoneTagCategoryID = "" 424 validationCtx.regionTagCategoryID = "" 425 validationCtx.TagManager = nil 426 } 427 } else { 428 err = errors.New("no test method defined") 429 } 430 if test.expectErr == "" { 431 assert.NoError(t, err) 432 } else { 433 assert.Regexp(t, test.expectErr, err) 434 } 435 }) 436 } 437 } 438 439 func Test_validateVCenterVersion(t *testing.T) { 440 tests := []struct { 441 name string 442 setVersionToSupported bool 443 fldPath *field.Path 444 expectErr string 445 }{ 446 { 447 name: "valid vcenter version", 448 setVersionToSupported: true, 449 fldPath: field.NewPath("platform").Child("vsphere").Child("vcenters"), 450 expectErr: ``, 451 }, 452 { 453 name: "unsupported vcenter version", 454 setVersionToSupported: false, 455 fldPath: field.NewPath("platform").Child("vsphere").Child("vcenters"), 456 expectErr: `platform.vsphere.vcenters: Required value: The vSphere storage driver requires a minimum of vSphere 7 Update 2. Current vCenter version: 6.5.0, build: 5973321`, 457 }, 458 } 459 460 for _, test := range tests { 461 t.Run(test.name, func(t *testing.T) { 462 validationCtx, server, _, err := simulatorHelper(t, test.setVersionToSupported) 463 464 if err != nil { 465 t.Error(err) 466 } 467 defer server.Close() 468 469 err = validateVCenterVersion(validationCtx, test.fldPath).ToAggregate() 470 471 if test.expectErr != "" { 472 assert.Regexp(t, test.expectErr, err) 473 } else if err != nil { 474 assert.NoError(t, err) 475 } 476 }) 477 } 478 } 479 480 func Test_validateESXiVersion(t *testing.T) { 481 vSphereFldPath := field.NewPath("platform").Child("vsphere") 482 computeClusterFldPath := vSphereFldPath.Child("failureDomains").Child("topology").Child("computeCluster") 483 platform := validMultiVCenterPlatform() 484 485 tests := []struct { 486 name string 487 setVersionToSupported bool 488 computeClusterPath string 489 expectErr string 490 }{ 491 { 492 name: "valid esxi version", 493 setVersionToSupported: true, 494 computeClusterPath: platform.FailureDomains[0].Topology.ComputeCluster, 495 expectErr: ``, 496 }, 497 { 498 name: "unsupported esxi version", 499 setVersionToSupported: false, 500 computeClusterPath: platform.FailureDomains[0].Topology.ComputeCluster, 501 expectErr: `[platform.vsphere.failureDomains.topology.computeCluster: Required value: The vSphere storage driver requires a minimum of vSphere 7 Update 2. The ESXi host: DC0_C0_H0 is version: 6.5.0 and build: 5969303, platform.vsphere.failureDomains.topology.computeCluster: Required value: The vSphere storage driver requires a minimum of vSphere 7 Update 2. The ESXi host: DC0_C0_H1 is version: 6.5.0 and build: 5969303, platform.vsphere.failureDomains.topology.computeCluster: Required value: The vSphere storage driver requires a minimum of vSphere 7 Update 2. The ESXi host: DC0_C0_H2 is version: 6.5.0 and build: 5969303]`, 502 }, 503 { 504 name: "computeCluster not found", 505 setVersionToSupported: true, 506 computeClusterPath: "/DC0/host/invalid-cluster", 507 expectErr: `platform.vsphere.failureDomains.topology.computeCluster: Invalid value: "/DC0/host/invalid-cluster": cluster '/DC0/host/invalid-cluster' not found`, 508 }, 509 } 510 511 for _, test := range tests { 512 t.Run(test.name, func(t *testing.T) { 513 validationCtx, server, _, err := simulatorHelper(t, test.setVersionToSupported) 514 515 if err != nil { 516 t.Error(err) 517 } 518 defer server.Close() 519 520 err = validateESXiVersion(validationCtx, test.computeClusterPath, vSphereFldPath, computeClusterFldPath).ToAggregate() 521 522 if test.expectErr != "" { 523 assert.Regexp(t, test.expectErr, err) 524 } else if err != nil { 525 t.Error(err) 526 } 527 }) 528 } 529 } 530 531 func Test_ensureDNS(t *testing.T) { 532 platformFieldPath := field.NewPath("platform") 533 534 resolver := &net.Resolver{ 535 PreferGo: true, 536 Dial: func(ctx context.Context, network, address string) (net.Conn, error) { 537 d := net.Dialer{ 538 Timeout: time.Millisecond * time.Duration(10000), 539 } 540 return d.DialContext(ctx, network, "1.1.1.1:53") 541 }, 542 } 543 544 tests := []struct { 545 name string 546 installConfig *types.InstallConfig 547 expectErr string 548 }{ 549 { 550 name: "valid dns", 551 installConfig: func() *types.InstallConfig { 552 installConfig := validIPIInstallConfig() 553 installConfig.ObjectMeta.Name = "0a000803" 554 installConfig.BaseDomain = wildcardDNS 555 556 return installConfig 557 }(), 558 expectErr: ``, 559 }, 560 } 561 for _, test := range tests { 562 t.Run(test.name, func(t *testing.T) { 563 err := ensureDNS(test.installConfig, platformFieldPath, resolver).ToAggregate() 564 if test.expectErr != "" { 565 assert.Regexp(t, test.expectErr, err) 566 } else if err != nil { 567 t.Error(err) 568 } 569 }) 570 } 571 } 572 573 // lbHelper creates a listening port of 6443 on loopback (127.0.0.1) 574 // If stopListening is true the loop is broken and the port closes. 575 func lbHelper(t *testing.T) { 576 t.Helper() 577 mu.Lock() 578 stopListening = false 579 mu.Unlock() 580 addr, err := net.ResolveTCPAddr("tcp4", "127.0.0.1:6443") 581 if err != nil { 582 t.Error(err) 583 } 584 585 listen, err := net.ListenTCP("tcp4", addr) 586 if err != nil { 587 t.Error(err) 588 } 589 for { 590 mu.Lock() 591 if stopListening { 592 err = listen.Close() 593 if err != nil { 594 t.Logf("closing tcp listener: %s", err.Error()) 595 } 596 break 597 } 598 mu.Unlock() 599 600 _, err = listen.Accept() 601 602 if err != nil { 603 t.Error(err) 604 } 605 } 606 mu.Unlock() 607 } 608 609 // Test_ensureLoadBalancer uses lbHelper to create an open 610 // on 127.0.0.1:6443. Also uses nip.io as the base domain 611 // and cluster name as 7f000001 which equals 127.0.0.1 612 // Examples for testing logrus output from here: 613 // https://maxchadwick.xyz/blog/testing-log-output-in-go-logrus 614 func Test_ensureLoadBalancer(t *testing.T) { 615 go lbHelper(t) 616 logger, hook := test.NewNullLogger() 617 localLogger = logger 618 619 tests := []struct { 620 name string 621 installConfig *types.InstallConfig 622 stopTCPListen bool 623 expectLevel string 624 expectWarn string 625 }{ 626 { 627 name: "valid lb", 628 installConfig: func() *types.InstallConfig { 629 installConfig := validIPIInstallConfig() 630 installConfig.ObjectMeta.Name = "7f000001" 631 installConfig.BaseDomain = wildcardDNS 632 installConfig.VSphere.APIVIPs = []string{} 633 installConfig.VSphere.IngressVIPs = []string{} 634 635 return installConfig 636 }(), 637 stopTCPListen: false, 638 expectLevel: ``, 639 expectWarn: ``, 640 }, 641 { 642 name: "warn lb", 643 installConfig: func() *types.InstallConfig { 644 installConfig := validIPIInstallConfig() 645 installConfig.ObjectMeta.Name = "7f000002" 646 installConfig.BaseDomain = wildcardDNS 647 installConfig.VSphere.APIVIPs = []string{} 648 installConfig.VSphere.IngressVIPs = []string{} 649 650 return installConfig 651 }(), 652 stopTCPListen: true, 653 expectLevel: `warning`, 654 expectWarn: `Installation may fail, load balancer not available: dial tcp 127.0.0.2:6443: connect: connection refused`, 655 }, 656 } 657 for _, test := range tests { 658 t.Run(test.name, func(t *testing.T) { 659 if test.stopTCPListen { 660 mu.Lock() 661 stopListening = true 662 mu.Unlock() 663 } 664 mu.Lock() 665 ensureLoadBalancer(test.installConfig) 666 mu.Unlock() 667 if test.expectWarn != "" { 668 // there should be only one entry 669 entries := hook.AllEntries() 670 assert.NotEmpty(t, entries) 671 for _, e := range entries { 672 assert.Equal(t, test.expectLevel, e.Level.String()) 673 assert.Regexp(t, test.expectWarn, e.Message) 674 } 675 } 676 hook.Reset() 677 }) 678 } 679 } 680 681 func Test_compareCurrentToTemplate(t *testing.T) { 682 logger, hook := test.NewNullLogger() 683 localLogger = logger 684 685 tests := []struct { 686 name string 687 rhcosReleaseVersion string 688 templateProductVersion string 689 expectErr string 690 expectWarn string 691 }{ 692 { 693 name: "same version", 694 rhcosReleaseVersion: "412.86.202303211731-0", 695 templateProductVersion: "412.86.202303211731-0", 696 expectErr: ``, 697 expectWarn: ``, 698 }, 699 { 700 name: "template newer than current rhcos", 701 rhcosReleaseVersion: "412.86.202303211731-0", 702 templateProductVersion: "414.92.202304252144-0", 703 expectErr: `rhcos version: 414.92.202304252144-0 is too many revisions ahead current version: 412.86.202303211731-0`, 704 expectWarn: ``, 705 }, 706 { 707 name: "rhcos one release newer than template", 708 rhcosReleaseVersion: "413.92.202304252144-0", 709 templateProductVersion: "412.86.202303211731-0", 710 expectErr: ``, 711 expectWarn: `rhcos version: 412.86.202303211731-0 is behind current version: 413.92.202304252144-0, installation may fail`, 712 }, 713 { 714 name: "rhcos two release newer than template", 715 rhcosReleaseVersion: "414.92.202304252144-0", 716 templateProductVersion: "412.86.202303211731-0", 717 expectErr: `rhcos version: 412.86.202303211731-0 is too many revisions behind current version: 414.92.202304252144-0`, 718 expectWarn: ``, 719 }, 720 } 721 for _, tc := range tests { 722 t.Run(tc.name, func(t *testing.T) { 723 err := compareCurrentToTemplate(tc.templateProductVersion, tc.rhcosReleaseVersion) 724 725 if tc.expectWarn != "" { 726 // there should be only one entry 727 entries := hook.AllEntries() 728 assert.NotEmpty(t, entries) 729 for _, e := range entries { 730 assert.Regexp(t, tc.expectWarn, e.Message) 731 } 732 } 733 734 if tc.expectErr != "" { 735 assert.Regexp(t, tc.expectErr, err) 736 } else if err != nil { 737 t.Error(err) 738 } 739 hook.Reset() 740 }) 741 } 742 }