github.com/openshift/installer@v1.4.17/pkg/asset/agent/image/ignition_test.go (about) 1 package image 2 3 import ( 4 "context" 5 "encoding/base64" 6 "fmt" 7 "os" 8 "os/exec" 9 "path" 10 "strings" 11 "testing" 12 13 igntypes "github.com/coreos/ignition/v2/config/v3_2/types" 14 "github.com/stretchr/testify/assert" 15 "github.com/vincent-petithory/dataurl" 16 v1 "k8s.io/api/core/v1" 17 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 18 19 hiveext "github.com/openshift/assisted-service/api/hiveextension/v1beta1" 20 aiv1beta1 "github.com/openshift/assisted-service/api/v1beta1" 21 "github.com/openshift/assisted-service/models" 22 hivev1 "github.com/openshift/hive/apis/hive/v1" 23 "github.com/openshift/installer/pkg/asset" 24 "github.com/openshift/installer/pkg/asset/agent/agentconfig" 25 "github.com/openshift/installer/pkg/asset/agent/common" 26 "github.com/openshift/installer/pkg/asset/agent/gencrypto" 27 "github.com/openshift/installer/pkg/asset/agent/joiner" 28 "github.com/openshift/installer/pkg/asset/agent/manifests" 29 "github.com/openshift/installer/pkg/asset/agent/mirror" 30 "github.com/openshift/installer/pkg/asset/agent/workflow" 31 "github.com/openshift/installer/pkg/asset/password" 32 "github.com/openshift/installer/pkg/asset/tls" 33 "github.com/openshift/installer/pkg/types/agent" 34 ) 35 36 // Unable to test Generate because bootstrap.AddStorageFiles 37 // returns error in unit test: 38 // open data/agent/files: no such file or directory 39 // Unit test working directory is ./pkg/asset/agent/image 40 // While normal execution working directory is ./data 41 // func TestIgnition_Generate(t *testing.T) {} 42 43 func TestIgnition_getTemplateData(t *testing.T) { 44 clusterImageSet := &hivev1.ClusterImageSet{ 45 ObjectMeta: metav1.ObjectMeta{ 46 Name: "openshift-v4.10.0", 47 }, 48 Spec: hivev1.ClusterImageSetSpec{ 49 ReleaseImage: "quay.io:443/openshift-release-dev/ocp-release:4.10.0-rc.1-x86_64", 50 }, 51 } 52 pullSecret := "pull-secret" 53 agentClusterInstall := &hiveext.AgentClusterInstall{ 54 ObjectMeta: metav1.ObjectMeta{ 55 Name: "test-agent-cluster-install", 56 Namespace: "cluster0", 57 }, 58 Spec: hiveext.AgentClusterInstallSpec{ 59 APIVIP: "192.168.111.2", 60 SSHPublicKey: "ssh-rsa AAAAmyKey", 61 ProvisionRequirements: hiveext.ProvisionRequirements{ 62 ControlPlaneAgents: 3, 63 WorkerAgents: 5, 64 }, 65 }, 66 } 67 releaseImage := "quay.io:443/openshift-release-dev/ocp-release:4.10.0-rc.1-x86_64" 68 releaseImageMirror := "virthost.ostest.test.metalkube.org:5000/localimages/local-release-image" 69 infraEnvID := "random-infra-env-id" 70 haveMirrorConfig := true 71 publicContainerRegistries := "quay.io,registry.ci.openshift.org" 72 73 releaseImageList, err := releaseImageList(clusterImageSet.Spec.ReleaseImage, "x86_64", []string{"86_64"}) 74 assert.NoError(t, err) 75 76 arch := "x86_64" 77 ov := "4.12" 78 isoURL := "https://rhcos.mirror.openshift.com/art/storage/releases/rhcos-4.12/412.86.202208101039-0/x86_64/rhcos-412.86.202208101039-0-live.x86_64.iso" 79 ver := "412.86.202208101039-0" 80 osImage := &models.OsImage{ 81 CPUArchitecture: &arch, 82 OpenshiftVersion: &ov, 83 URL: &isoURL, 84 Version: &ver, 85 } 86 87 proxy := &aiv1beta1.Proxy{ 88 HTTPProxy: "http://1.1.1.1:80", 89 HTTPSProxy: "https://1.1.1.1:443", 90 NoProxy: "valid-proxy.com,172.30.0.0/16", 91 } 92 clusterName := "test-agent-cluster-install.test" 93 94 publicKey := "-----BEGIN EC PUBLIC KEY-----\nMHcCAQEEIOSCfDNmx0qe6dncV4tg==\n-----END EC PUBLIC KEY-----\n" 95 token := "someToken" 96 templateData := getTemplateData(clusterName, pullSecret, releaseImageList, releaseImage, releaseImageMirror, publicContainerRegistries, "minimal-iso", infraEnvID, publicKey, gencrypto.AuthType, token, "", "", haveMirrorConfig, agentClusterInstall.Spec.ProvisionRequirements.ControlPlaneAgents, agentClusterInstall.Spec.ProvisionRequirements.WorkerAgents, osImage, proxy) 97 assert.Equal(t, clusterName, templateData.ClusterName) 98 assert.Equal(t, "http", templateData.ServiceProtocol) 99 assert.Equal(t, pullSecret, templateData.PullSecret) 100 assert.Equal(t, agentClusterInstall.Spec.ProvisionRequirements.ControlPlaneAgents, templateData.ControlPlaneAgents) 101 assert.Equal(t, agentClusterInstall.Spec.ProvisionRequirements.WorkerAgents, templateData.WorkerAgents) 102 assert.Equal(t, releaseImageList, templateData.ReleaseImages) 103 assert.Equal(t, releaseImage, templateData.ReleaseImage) 104 assert.Equal(t, releaseImageMirror, templateData.ReleaseImageMirror) 105 assert.Equal(t, haveMirrorConfig, templateData.HaveMirrorConfig) 106 assert.Equal(t, publicContainerRegistries, templateData.PublicContainerRegistries) 107 assert.Equal(t, infraEnvID, templateData.InfraEnvID) 108 assert.Equal(t, osImage, templateData.OSImage) 109 assert.Equal(t, proxy, templateData.Proxy) 110 assert.Equal(t, publicKey, templateData.PublicKeyPEM) 111 assert.Equal(t, gencrypto.AuthType, templateData.AuthType) 112 assert.Equal(t, token, templateData.Token) 113 114 } 115 116 func TestIgnition_getRendezvousHostEnv(t *testing.T) { 117 nodeZeroIP := "2001:db8::dead:beef" 118 token := "someToken" 119 rendezvousHostEnv := getRendezvousHostEnv("http", nodeZeroIP, token, workflow.AgentWorkflowTypeInstall) 120 assert.Equal(t, 121 "NODE_ZERO_IP="+nodeZeroIP+"\nSERVICE_BASE_URL=http://["+nodeZeroIP+"]:8090/\nIMAGE_SERVICE_BASE_URL=http://["+nodeZeroIP+"]:8888/\nAGENT_AUTH_TOKEN="+token+"\nPULL_SECRET_TOKEN="+token+"\nWORKFLOW_TYPE=install\n", 122 rendezvousHostEnv) 123 } 124 125 func TestIgnition_addStaticNetworkConfig(t *testing.T) { 126 _, execErr := exec.LookPath("nmstatectl") 127 if execErr != nil { 128 t.Skip("No nmstatectl binary available") 129 } 130 131 cases := []struct { 132 Name string 133 staticNetworkConfig []*models.HostStaticNetworkConfig 134 expectedError string 135 expectedFileList []string 136 }{ 137 { 138 Name: "default", 139 staticNetworkConfig: []*models.HostStaticNetworkConfig{ 140 { 141 MacInterfaceMap: models.MacInterfaceMap{ 142 {LogicalNicName: "eth0", MacAddress: "52:54:01:aa:aa:a1"}, 143 }, 144 NetworkYaml: "interfaces:\n- ipv4:\n address:\n - ip: 192.168.122.21\n prefix-length: 24\n enabled: true\n mac-address: 52:54:01:aa:aa:a1\n name: eth0\n state: up\n type: ethernet\n", 145 }, 146 }, 147 expectedError: "", 148 expectedFileList: []string{ 149 "/etc/assisted/network/host0/eth0.nmconnection", 150 "/etc/assisted/network/host0/mac_interface.ini", 151 "/usr/local/bin/pre-network-manager-config.sh", 152 }, 153 }, 154 { 155 Name: "no-static-network-configs", 156 staticNetworkConfig: []*models.HostStaticNetworkConfig{}, 157 expectedError: "", 158 expectedFileList: nil, 159 }, 160 { 161 Name: "error-processing-config", 162 staticNetworkConfig: []*models.HostStaticNetworkConfig{ 163 { 164 MacInterfaceMap: models.MacInterfaceMap{ 165 {LogicalNicName: "eth0", MacAddress: "52:54:01:aa:aa:a1"}, 166 }, 167 NetworkYaml: "interfaces:\n- ipv4:\n address:\n - ip: bad-ip\n prefix-length: 24\n enabled: true\n mac-address: 52:54:01:aa:aa:a1\n name: eth0\n state: up\n type: ethernet\n", 168 }, 169 }, 170 expectedError: ".*invalid IP address syntax", 171 expectedFileList: nil, 172 }, 173 } 174 175 for _, tc := range cases { 176 t.Run(tc.Name, func(t *testing.T) { 177 config := igntypes.Config{} 178 err := addStaticNetworkConfig(&config, tc.staticNetworkConfig) 179 180 if tc.expectedError != "" { 181 assert.Regexp(t, tc.expectedError, err.Error()) 182 } else { 183 assert.NoError(t, err) 184 } 185 186 var fileList []string 187 for _, file := range config.Storage.Files { 188 fileList = append(fileList, file.Node.Path) 189 } 190 assert.Equal(t, tc.expectedFileList, fileList) 191 }) 192 } 193 } 194 195 func TestRetrieveRendezvousIP(t *testing.T) { 196 rawConfig := `interfaces: 197 - ipv4: 198 address: 199 - ip: "192.168.122.21"` 200 cases := []struct { 201 Name string 202 agentConfig *agent.Config 203 nmStateConfigs []*aiv1beta1.NMStateConfig 204 expectedRendezvousIP string 205 expectedError string 206 }{ 207 { 208 Name: "valid-agent-config-provided-with-RendezvousIP", 209 agentConfig: &agent.Config{ 210 RendezvousIP: "192.168.122.21", 211 Hosts: []agent.Host{ 212 { 213 Hostname: "control-0.example.org", 214 Role: "master", 215 }, 216 }, 217 }, 218 expectedRendezvousIP: "192.168.122.21", 219 }, 220 { 221 Name: "no-agent-config-provided-so-read-from-nmstateconfig", 222 nmStateConfigs: []*aiv1beta1.NMStateConfig{ 223 { 224 Spec: aiv1beta1.NMStateConfigSpec{ 225 NetConfig: aiv1beta1.NetConfig{ 226 Raw: []byte(rawConfig), 227 }, 228 }, 229 }, 230 }, 231 expectedRendezvousIP: "192.168.122.21", 232 }, 233 { 234 Name: "neither-agent-config-was-provided-with-RendezvousIP-nor-nmstateconfig-manifest", 235 agentConfig: &agent.Config{ 236 Hosts: []agent.Host{ 237 { 238 Hostname: "control-0.example.org", 239 Role: "master", 240 }, 241 }, 242 }, 243 expectedError: "missing rendezvousIP in agent-config, at least one host networkConfig, or at least one NMStateConfig manifest", 244 }, 245 { 246 Name: "non-canonical-ipv6-address", 247 agentConfig: &agent.Config{ 248 RendezvousIP: "fd2e:6f44:5dd8:c956:0000:0000:0000:0050", 249 Hosts: []agent.Host{ 250 { 251 Hostname: "control-0.example.org", 252 Role: "master", 253 }, 254 }, 255 }, 256 expectedRendezvousIP: "fd2e:6f44:5dd8:c956::50", 257 }, 258 { 259 Name: "invalid-ipv6-address", 260 agentConfig: &agent.Config{ 261 RendezvousIP: "fd2e:6f44:5dd8:c956::0000::0050", 262 Hosts: []agent.Host{ 263 { 264 Hostname: "control-0.example.org", 265 Role: "master", 266 }, 267 }, 268 }, 269 expectedError: "invalid rendezvous IP: fd2e:6f44:5dd8:c956::0000::0050", 270 }, 271 } 272 for _, tc := range cases { 273 t.Run(tc.Name, func(t *testing.T) { 274 var hosts []agent.Host 275 if tc.agentConfig != nil { 276 hosts = tc.agentConfig.Hosts 277 } 278 rendezvousIP, err := RetrieveRendezvousIP(tc.agentConfig, hosts, tc.nmStateConfigs) 279 if tc.expectedError != "" { 280 assert.Regexp(t, tc.expectedError, err.Error()) 281 } else { 282 assert.NoError(t, err) 283 assert.Equal(t, tc.expectedRendezvousIP, rendezvousIP) 284 } 285 }) 286 } 287 } 288 289 func TestAddHostConfig_Roles(t *testing.T) { 290 cases := []struct { 291 Name string 292 agentHosts *agentconfig.AgentHosts 293 expectedNumberOfHostConfigFiles int 294 }{ 295 { 296 Name: "one-host-role-defined", 297 agentHosts: &agentconfig.AgentHosts{ 298 Hosts: []agent.Host{ 299 { 300 Role: "master", 301 }, 302 }, 303 }, 304 expectedNumberOfHostConfigFiles: 1, 305 }, 306 { 307 Name: "multiple-host-roles-defined", 308 agentHosts: &agentconfig.AgentHosts{ 309 Hosts: []agent.Host{ 310 { 311 Role: "master", 312 }, 313 { 314 Role: "master", 315 }, 316 { 317 Role: "master", 318 }, 319 { 320 Role: "worker", 321 }, 322 { 323 Role: "worker", 324 }, 325 }, 326 }, 327 expectedNumberOfHostConfigFiles: 5, 328 }, 329 { 330 Name: "zero-host-roles-defined", 331 expectedNumberOfHostConfigFiles: 0, 332 }, 333 } 334 for _, tc := range cases { 335 t.Run(tc.Name, func(t *testing.T) { 336 config := &igntypes.Config{} 337 err := addHostConfig(config, tc.agentHosts) 338 assert.NoError(t, err) 339 assert.Equal(t, len(config.Storage.Files), tc.expectedNumberOfHostConfigFiles) 340 for _, file := range config.Storage.Files { 341 assert.Equal(t, true, strings.HasPrefix(file.Path, "/etc/assisted/hostconfig")) 342 assert.Equal(t, true, strings.HasSuffix(file.Path, "role")) 343 } 344 }) 345 } 346 } 347 348 func generatedFiles(otherFiles ...string) []string { 349 files := []string{ 350 "/etc/assisted/rendezvous-host.env", 351 "/etc/assisted/manifests/agent-config.yaml", 352 // TODO: ZTP manifest files should also be present. Bug? 353 // "/etc/assisted/manifests/cluster-deployment.yaml", 354 // "/etc/assisted/manifests/agent-cluster-install.yaml", 355 // "/etc/assisted/manifests/pull-secret.yaml", 356 // "/etc/assisted/manifests/cluster-image-set.yaml", 357 // "/etc/assisted/manifests/infraenv.yaml", 358 "/etc/assisted/network/host0/eth0.nmconnection", 359 "/etc/assisted/network/host0/mac_interface.ini", 360 "/usr/local/bin/pre-network-manager-config.sh", 361 "/opt/agent/tls/kubeadmin-password.hash"} 362 files = append(files, otherFiles...) 363 return append(files, commonFiles()...) 364 } 365 366 func commonFiles() []string { 367 return []string{ 368 "/etc/issue", 369 "/etc/multipath.conf", 370 "/etc/containers/containers.conf", 371 "/etc/NetworkManager/conf.d/clientid.conf", 372 "/root/.docker/config.json", 373 "/root/assisted.te", 374 "/usr/local/bin/agent-config-image-wait.sh", 375 "/usr/local/bin/agent-gather", 376 "/usr/local/bin/extract-agent.sh", 377 "/usr/local/bin/get-container-images.sh", 378 "/usr/local/bin/set-hostname.sh", 379 "/usr/local/bin/start-agent.sh", 380 "/usr/local/bin/start-cluster-installation.sh", 381 "/usr/local/bin/wait-for-assisted-service.sh", 382 "/usr/local/bin/set-node-zero.sh", 383 "/usr/local/share/assisted-service/assisted-db.env", 384 "/usr/local/share/assisted-service/assisted-service.env", 385 "/usr/local/share/start-cluster/start-cluster.env", 386 "/usr/local/share/assisted-service/images.env", 387 "/usr/local/bin/bootstrap-service-record.sh", 388 "/usr/local/bin/release-image.sh", 389 "/usr/local/bin/release-image-download.sh", 390 "/etc/assisted/agent-installer.env", 391 "/etc/motd.d/10-agent-installer", 392 "/etc/systemd/system.conf.d/10-default-env.conf", 393 "/usr/local/bin/install-status.sh", 394 "/usr/local/bin/issue_status.sh", 395 "/usr/local/bin/load-config-iso.sh", 396 "/etc/udev/rules.d/80-agent-config-image.rules", 397 "/usr/local/bin/add-node.sh", 398 "/usr/local/bin/agent-auth-token-status.sh", 399 "/usr/local/bin/common.sh", 400 } 401 } 402 403 func TestIgnition_Generate(t *testing.T) { 404 skipTestIfnmstatectlIsMissing(t) 405 406 // This patch currently allows testing the Ignition asset using the embedded resources. 407 // TODO: Replace it by mocking the filesystem in bootstrap.AddStorageFiles() 408 workingDirectory, err := os.Getwd() 409 assert.NoError(t, err) 410 err = os.Chdir(path.Join(workingDirectory, "../../../../data")) 411 assert.NoError(t, err) 412 413 secretDataBytes, err := base64.StdEncoding.DecodeString("c3VwZXItc2VjcmV0Cg==") 414 assert.NoError(t, err) 415 416 cases := []struct { 417 name string 418 overrideDeps []asset.Asset 419 expectedError string 420 expectedFiles []string 421 expectedFileContent map[string]string 422 serviceEnabledMap map[string]bool 423 }{ 424 { 425 name: "no-extra-manifests", 426 serviceEnabledMap: map[string]bool{ 427 "pre-network-manager-config.service": true, 428 "agent-check-config-image.service": false}, 429 expectedFiles: generatedFiles(), 430 }, 431 { 432 name: "default", 433 overrideDeps: []asset.Asset{ 434 &manifests.ExtraManifests{ 435 FileList: []*asset.File{ 436 { 437 Filename: "openshift/test-configmap.yaml", 438 Data: []byte(` 439 --- 440 apiVersion: v1 441 kind: ConfigMap 442 metadata: 443 name: agent-test-1 444 445 --- 446 apiVersion: v1 447 kind: ConfigMap 448 metadata: 449 name: agent-test-2`), 450 }, 451 }, 452 }, 453 }, 454 expectedFiles: generatedFiles("/etc/assisted/extra-manifests/test-configmap-0.yaml", "/etc/assisted/extra-manifests/test-configmap-1.yaml"), 455 expectedFileContent: map[string]string{ 456 "/etc/assisted/extra-manifests/test-configmap-0.yaml": `apiVersion: v1 457 kind: ConfigMap 458 metadata: 459 name: agent-test-1`, 460 "/etc/assisted/extra-manifests/test-configmap-1.yaml": `apiVersion: v1 461 kind: ConfigMap 462 metadata: 463 name: agent-test-2 464 `, 465 }, 466 serviceEnabledMap: map[string]bool{ 467 "pre-network-manager-config.service": true, 468 "agent-check-config-image.service": false}, 469 }, 470 { 471 name: "no nmstateconfigs defined, pre-network-manager-config.service should not be enabled", 472 overrideDeps: []asset.Asset{ 473 &manifests.AgentManifests{ 474 InfraEnv: &aiv1beta1.InfraEnv{ 475 Spec: aiv1beta1.InfraEnvSpec{ 476 SSHAuthorizedKey: "my-ssh-key", 477 }, 478 }, 479 ClusterImageSet: &hivev1.ClusterImageSet{ 480 Spec: hivev1.ClusterImageSetSpec{ 481 ReleaseImage: "registry.ci.openshift.org/origin/release:4.11", 482 }, 483 }, 484 ClusterDeployment: &hivev1.ClusterDeployment{ 485 Spec: hivev1.ClusterDeploymentSpec{ 486 ClusterName: "ostest", 487 BaseDomain: "ostest", 488 }, 489 }, 490 PullSecret: &v1.Secret{ 491 Data: map[string][]byte{ 492 ".dockerconfigjson": secretDataBytes, 493 }, 494 }, 495 AgentClusterInstall: &hiveext.AgentClusterInstall{ 496 Spec: hiveext.AgentClusterInstallSpec{ 497 APIVIP: "192.168.111.5", 498 ProvisionRequirements: hiveext.ProvisionRequirements{ 499 ControlPlaneAgents: 3, 500 WorkerAgents: 5, 501 }, 502 }, 503 }, 504 }, 505 }, 506 serviceEnabledMap: map[string]bool{ 507 "pre-network-manager-config.service": false}, 508 }, 509 } 510 for _, tc := range cases { 511 t.Run(tc.name, func(t *testing.T) { 512 deps := buildIgnitionAssetDefaultDependencies(t) 513 514 overrideDeps(deps, tc.overrideDeps) 515 516 parents := asset.Parents{} 517 parents.Add(deps...) 518 519 ignitionAsset := &Ignition{} 520 err := ignitionAsset.Generate(context.Background(), parents) 521 522 if tc.expectedError != "" { 523 assert.Equal(t, tc.expectedError, err.Error()) 524 } else { 525 assert.NoError(t, err) 526 527 assert.Len(t, ignitionAsset.Config.Storage.Directories, 1) 528 assert.Equal(t, "/etc/assisted/extra-manifests", ignitionAsset.Config.Storage.Directories[0].Node.Path) 529 530 assertExpectedFiles(t, ignitionAsset.Config, tc.expectedFiles, tc.expectedFileContent) 531 532 assertServiceEnabled(t, ignitionAsset.Config, tc.serviceEnabledMap) 533 } 534 }) 535 } 536 } 537 538 func skipTestIfnmstatectlIsMissing(t *testing.T) { 539 t.Helper() 540 // Generate calls addStaticNetworkConfig which calls nmstatectl 541 _, execErr := exec.LookPath("nmstatectl") 542 if execErr != nil { 543 t.Skip("No nmstatectl binary available") 544 } 545 } 546 547 func overrideDeps(deps []asset.Asset, overrides []asset.Asset) { 548 for _, od := range overrides { 549 for i, d := range deps { 550 if d.Name() == od.Name() { 551 deps[i] = od 552 break 553 } 554 } 555 } 556 } 557 558 func assertServiceEnabled(t *testing.T, config *igntypes.Config, serviceEnabledMap map[string]bool) { 559 t.Helper() 560 for serviceName, enabled := range serviceEnabledMap { 561 for _, unit := range config.Systemd.Units { 562 if unit.Name == serviceName { 563 if unit.Enabled == nil { 564 assert.Equal(t, enabled, false) 565 } else { 566 assert.Equal(t, enabled, *unit.Enabled) 567 } 568 } 569 } 570 } 571 } 572 573 func assertExpectedFiles(t *testing.T, config *igntypes.Config, expectedFiles []string, expectedFileContent map[string]string) { 574 t.Helper() 575 if len(expectedFiles) > 0 { 576 assert.Equal(t, len(expectedFiles), len(config.Storage.Files)) 577 578 for _, f := range expectedFiles { 579 found := false 580 for _, i := range config.Storage.Files { 581 if i.Node.Path == f { 582 if expectedData, ok := expectedFileContent[i.Node.Path]; ok { 583 actualData, err := dataurl.DecodeString(*i.FileEmbedded1.Contents.Source) 584 assert.NoError(t, err) 585 assert.Regexp(t, expectedData, string(actualData.Data)) 586 } 587 588 found = true 589 break 590 } 591 } 592 assert.True(t, found, fmt.Sprintf("Expected file %s not found", f)) 593 } 594 } 595 } 596 597 // This test util create the minimum valid set of dependencies for the 598 // Ignition asset 599 func buildIgnitionAssetDefaultDependencies(t *testing.T) []asset.Asset { 600 t.Helper() 601 secretDataBytes, err := base64.StdEncoding.DecodeString("c3VwZXItc2VjcmV0Cg==") 602 assert.NoError(t, err) 603 604 return []asset.Asset{ 605 &workflow.AgentWorkflow{Workflow: workflow.AgentWorkflowTypeInstall}, 606 &joiner.ClusterInfo{}, 607 &joiner.AddNodesConfig{}, 608 &manifests.AgentManifests{ 609 InfraEnv: &aiv1beta1.InfraEnv{ 610 Spec: aiv1beta1.InfraEnvSpec{ 611 SSHAuthorizedKey: "my-ssh-key", 612 }, 613 }, 614 ClusterDeployment: &hivev1.ClusterDeployment{ 615 Spec: hivev1.ClusterDeploymentSpec{ 616 ClusterName: "ostest", 617 BaseDomain: "ostest", 618 }, 619 }, 620 ClusterImageSet: &hivev1.ClusterImageSet{ 621 Spec: hivev1.ClusterImageSetSpec{ 622 ReleaseImage: "registry.ci.openshift.org/origin/release:4.11", 623 }, 624 }, 625 PullSecret: &v1.Secret{ 626 Data: map[string][]byte{ 627 ".dockerconfigjson": secretDataBytes, 628 }, 629 }, 630 AgentClusterInstall: &hiveext.AgentClusterInstall{ 631 Spec: hiveext.AgentClusterInstallSpec{ 632 APIVIP: "192.168.111.5", 633 ProvisionRequirements: hiveext.ProvisionRequirements{ 634 ControlPlaneAgents: 3, 635 WorkerAgents: 5, 636 }, 637 }, 638 }, 639 NMStateConfigs: []*aiv1beta1.NMStateConfig{ 640 { 641 Spec: aiv1beta1.NMStateConfigSpec{ 642 Interfaces: []*aiv1beta1.Interface{ 643 { 644 Name: "eth0", 645 MacAddress: "00:01:02:03:04:05", 646 }, 647 }, 648 }, 649 }, 650 }, 651 StaticNetworkConfigs: []*models.HostStaticNetworkConfig{ 652 { 653 MacInterfaceMap: models.MacInterfaceMap{ 654 {LogicalNicName: "eth0", MacAddress: "00:01:02:03:04:05"}, 655 }, 656 NetworkYaml: "interfaces:\n- ipv4:\n address:\n - ip: 192.168.122.21\n prefix-length: 24\n enabled: true\n mac-address: 00:01:02:03:04:05\n name: eth0\n state: up\n type: ethernet\n", 657 }, 658 }, 659 }, 660 &agentconfig.AgentConfig{ 661 Config: &agent.Config{ 662 RendezvousIP: "192.168.111.80", 663 }, 664 File: &asset.File{ 665 Filename: "/cluster-manifests/agent-config.yaml", 666 }, 667 }, 668 &agentconfig.AgentHosts{}, 669 &manifests.ExtraManifests{}, 670 &mirror.RegistriesConf{}, 671 &mirror.CaBundle{}, 672 &password.KubeadminPassword{}, 673 &tls.KubeAPIServerLBSignerCertKey{}, 674 &tls.KubeAPIServerLocalhostSignerCertKey{}, 675 &tls.KubeAPIServerServiceNetworkSignerCertKey{}, 676 &tls.AdminKubeConfigSignerCertKey{}, 677 &tls.AdminKubeConfigClientCertKey{}, 678 &gencrypto.AuthConfig{}, 679 &common.InfraEnvID{}, 680 } 681 } 682 683 func TestIgnition_getMirrorFromRelease(t *testing.T) { 684 685 cases := []struct { 686 name string 687 release string 688 registriesConf mirror.RegistriesConf 689 expectedMirror string 690 }{ 691 { 692 name: "no-mirror", 693 release: "registry.ci.openshift.org/ocp/release:latest", 694 registriesConf: mirror.RegistriesConf{}, 695 expectedMirror: "", 696 }, 697 { 698 name: "mirror-no-match", 699 release: "registry.ci.openshift.org/ocp/release:4.11.0-0.nightly-foo", 700 registriesConf: mirror.RegistriesConf{ 701 File: &asset.File{ 702 Filename: "registries.conf", 703 Data: []byte(""), 704 }, 705 MirrorConfig: []mirror.RegistriesConfig{ 706 { 707 Location: "some.registry.org/release", 708 Mirror: "some.mirror.org", 709 }, 710 }, 711 }, 712 expectedMirror: "", 713 }, 714 { 715 name: "mirror-match", 716 release: "registry.ci.openshift.org/ocp/release:4.11.0-0.nightly-foo", 717 registriesConf: mirror.RegistriesConf{ 718 File: &asset.File{ 719 Filename: "registries.conf", 720 Data: []byte(""), 721 }, 722 MirrorConfig: []mirror.RegistriesConfig{ 723 { 724 Location: "registry.ci.openshift.org/ocp/release", 725 Mirror: "virthost.ostest.test.metalkube.org:5000/localimages/local-release-image", 726 }, 727 }, 728 }, 729 expectedMirror: "virthost.ostest.test.metalkube.org:5000/localimages/local-release-image:4.11.0-0.nightly-foo", 730 }, 731 { 732 name: "mirror-match-with-checksum", 733 release: "quay.io/openshift-release-dev/ocp-release@sha256:300bce8246cf880e792e106607925de0a404484637627edf5f517375517d54a4", 734 registriesConf: mirror.RegistriesConf{ 735 File: &asset.File{ 736 Filename: "registries.conf", 737 Data: []byte(""), 738 }, 739 MirrorConfig: []mirror.RegistriesConfig{ 740 { 741 Location: "quay.io/openshift-release-dev/ocp-v4.0-art-dev", 742 Mirror: "localhost:5000/openshift4/openshift/release", 743 }, 744 { 745 Location: "quay.io/openshift-release-dev/ocp-release", 746 Mirror: "localhost:5000/openshift-release-dev/ocp-release", 747 }, 748 }, 749 }, 750 expectedMirror: "localhost:5000/openshift-release-dev/ocp-release@sha256:300bce8246cf880e792e106607925de0a404484637627edf5f517375517d54a4", 751 }, 752 } 753 for _, tc := range cases { 754 t.Run(tc.name, func(t *testing.T) { 755 756 mirror := mirror.GetMirrorFromRelease(tc.release, &tc.registriesConf) 757 758 assert.Equal(t, tc.expectedMirror, mirror) 759 }) 760 } 761 } 762 763 func TestIgnition_getPublicContainerRegistries(t *testing.T) { 764 765 cases := []struct { 766 name string 767 registriesConf mirror.RegistriesConf 768 expectedRegistries string 769 }{ 770 { 771 name: "no-mirror", 772 registriesConf: mirror.RegistriesConf{}, 773 expectedRegistries: "quay.io", 774 }, 775 { 776 name: "mirror-one-entry", 777 registriesConf: mirror.RegistriesConf{ 778 File: &asset.File{ 779 Filename: "registries.conf", 780 Data: []byte(""), 781 }, 782 MirrorConfig: []mirror.RegistriesConfig{ 783 { 784 Location: "some.registry.org/release", 785 Mirror: "some.mirror.org", 786 }, 787 }, 788 }, 789 expectedRegistries: "some.registry.org", 790 }, 791 { 792 name: "mirror-multiple-entries", 793 registriesConf: mirror.RegistriesConf{ 794 File: &asset.File{ 795 Filename: "registries.conf", 796 Data: []byte(""), 797 }, 798 MirrorConfig: []mirror.RegistriesConfig{ 799 { 800 Location: "quay.io/openshift-release-dev/ocp-v4.0-art-dev", 801 Mirror: "localhost:5000/openshift4/openshift/release", 802 }, 803 { 804 Location: "registry.ci.openshift.org/ocp/release", 805 Mirror: "localhost:5000/openshift-release-dev/ocp-release", 806 }, 807 }, 808 }, 809 expectedRegistries: "quay.io,registry.ci.openshift.org", 810 }, 811 { 812 name: "duplicate-entries", 813 registriesConf: mirror.RegistriesConf{ 814 File: &asset.File{ 815 Filename: "registries.conf", 816 Data: []byte(""), 817 }, 818 MirrorConfig: []mirror.RegistriesConfig{ 819 { 820 Location: "registry.ci.openshift.org/ocp-v4.0-art-dev", 821 Mirror: "localhost:5000/openshift4/openshift/release", 822 }, 823 { 824 Location: "registry.ci.openshift.org/ocp/release", 825 Mirror: "localhost:5000/openshift-release-dev/ocp-release", 826 }, 827 }, 828 }, 829 expectedRegistries: "registry.ci.openshift.org", 830 }, 831 } 832 for _, tc := range cases { 833 t.Run(tc.name, func(t *testing.T) { 834 835 publicContainerRegistries := getPublicContainerRegistries(&tc.registriesConf) 836 837 assert.Equal(t, tc.expectedRegistries, publicContainerRegistries) 838 }) 839 } 840 }