github.com/openshift/installer@v1.4.17/pkg/asset/machines/baremetal/hosts_test.go (about) 1 package baremetal 2 3 import ( 4 "fmt" 5 "testing" 6 7 baremetalhost "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1" 8 "github.com/stretchr/testify/assert" 9 corev1 "k8s.io/api/core/v1" 10 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 11 "sigs.k8s.io/yaml" 12 13 machineapi "github.com/openshift/api/machine/v1beta1" 14 "github.com/openshift/installer/pkg/types" 15 baremetaltypes "github.com/openshift/installer/pkg/types/baremetal" 16 ) 17 18 func TestHosts(t *testing.T) { 19 20 nmstate := `interfaces: 21 - name: eth0 22 type: ethernet 23 routes: 24 config: 25 - destination: 198.51.100.0/24 26 metric: 150 27 next-hop-address: 192.0.2.1 28 next-hop-interface: eth1 29 table-id: 254 30 ` 31 32 testCases := []struct { 33 Scenario string 34 Machines []machineapi.Machine 35 Config *types.InstallConfig 36 ExpectedSecrets []corev1.Secret 37 ExpectedHosts []baremetalhost.BareMetalHost 38 ExpectedError string 39 ExpectedSetting *HostSettings 40 }{ 41 { 42 Scenario: "no-platform", 43 Config: &types.InstallConfig{ 44 Platform: types.Platform{ 45 BareMetal: nil, 46 }, 47 }, 48 49 ExpectedError: "no baremetal platform in configuration", 50 }, 51 { 52 Scenario: "no-hosts", 53 Config: config().build(), 54 55 ExpectedSetting: settings().build(), 56 }, 57 { 58 Scenario: "default", 59 Machines: machines(machine("machine-0")), 60 Config: configHosts(hostType("master-0").bmc("usr0", "pwd0").role("master")), 61 62 ExpectedSetting: settings(). 63 secrets(secret("master-0-bmc-secret").creds("usr0", "pwd0")). 64 hosts(host("master-0").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-0").customDeploy()).build(), 65 }, 66 { 67 Scenario: "default-norole", 68 Machines: machines(machine("machine-0")), 69 Config: configHosts(hostType("master-0").bmc("usr0", "pwd0")), 70 71 ExpectedSetting: settings(). 72 secrets(secret("master-0-bmc-secret").creds("usr0", "pwd0")). 73 hosts(host("master-0").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-0").customDeploy()).build(), 74 }, 75 { 76 Scenario: "network-config", 77 Machines: machines(machine("machine-0")), 78 Config: configHosts( 79 hostType("master-0"). 80 bmc("usr0", "pwd0"). 81 networkConfig(nmstate)), 82 83 ExpectedSetting: settings(). 84 secrets(secret("master-0-bmc-secret").creds("usr0", "pwd0")). 85 networkConfigSecrets(secret("master-0-network-config-secret").nmstate(nmstate)). 86 hosts( 87 host("master-0"). 88 label("installer.openshift.io/role", "control-plane"). 89 consumerRef("machine-0"). 90 userDataRef("user-data-secret"). 91 preprovisioningNetworkDataName("master-0-network-config-secret"). 92 customDeploy()).build(), 93 }, 94 { 95 Scenario: "3-hosts-3-machines-norole-all", 96 Machines: machines( 97 machine("machine-0"), 98 machine("machine-1"), 99 machine("machine-2")), 100 Config: configHosts( 101 hostType("master-0").bmc("usr0", "pwd0"), 102 hostType("master-1").bmc("usr1", "pwd1"), 103 hostType("master-2").bmc("usr2", "pwd2")), 104 105 ExpectedSetting: settings(). 106 secrets( 107 secret("master-0-bmc-secret").creds("usr0", "pwd0"), 108 secret("master-1-bmc-secret").creds("usr1", "pwd1"), 109 secret("master-2-bmc-secret").creds("usr2", "pwd2")). 110 hosts( 111 host("master-0").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-0").customDeploy(), 112 host("master-1").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-1").customDeploy(), 113 host("master-2").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-2").customDeploy()).build(), 114 }, 115 { 116 Scenario: "4-hosts-3-machines", 117 Machines: machines( 118 machine("machine-0"), 119 machine("machine-1"), 120 machine("machine-2")), 121 Config: configHosts( 122 hostType("master-0").bmc("usr0", "pwd0").role("master"), 123 hostType("master-1").bmc("usr1", "pwd1").role("master"), 124 hostType("master-2").bmc("usr2", "pwd2").role("master"), 125 hostType("worker-0").bmc("usr3", "pwd3").role("worker")), 126 127 ExpectedSetting: settings(). 128 secrets( 129 secret("master-0-bmc-secret").creds("usr0", "pwd0"), 130 secret("master-1-bmc-secret").creds("usr1", "pwd1"), 131 secret("master-2-bmc-secret").creds("usr2", "pwd2"), 132 secret("worker-0-bmc-secret").creds("usr3", "pwd3")). 133 hosts( 134 host("master-0").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-0").customDeploy(), 135 host("master-1").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-1").customDeploy(), 136 host("master-2").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-2").customDeploy(), 137 host("worker-0").annotation("baremetalhost.metal3.io/paused", ""), 138 ).build(), 139 }, 140 { 141 Scenario: "4-hosts-3-machines-norole", 142 Machines: machines( 143 machine("machine-0"), 144 machine("machine-1"), 145 machine("machine-2")), 146 Config: configHosts( 147 hostType("master-0").bmc("usr0", "pwd0"), 148 hostType("master-1").bmc("usr1", "pwd1"), 149 hostType("master-2").bmc("usr2", "pwd2"), 150 hostType("worker-0").bmc("wrk0", "pwd0")), 151 152 ExpectedSetting: settings(). 153 secrets( 154 secret("master-0-bmc-secret").creds("usr0", "pwd0"), 155 secret("master-1-bmc-secret").creds("usr1", "pwd1"), 156 secret("master-2-bmc-secret").creds("usr2", "pwd2"), 157 secret("worker-0-bmc-secret").creds("wrk0", "pwd0")). 158 hosts( 159 host("master-0").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-0").customDeploy(), 160 host("master-1").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-1").customDeploy(), 161 host("master-2").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-2").customDeploy(), 162 host("worker-0").annotation("baremetalhost.metal3.io/paused", ""), 163 ).build(), 164 }, 165 { 166 Scenario: "5-hosts-3-machines", 167 Machines: machines( 168 machine("machine-0"), 169 machine("machine-1"), 170 machine("machine-2")), 171 Config: configHosts( 172 hostType("master-0").bmc("usr0", "pwd0").role("master"), 173 hostType("master-1").bmc("usr1", "pwd1").role("master"), 174 hostType("master-2").bmc("usr2", "pwd2").role("master"), 175 hostType("worker-0").bmc("wrk0", "pwd0").role("worker"), 176 hostType("worker-1").bmc("wrk1", "pwd1").role("worker")), 177 178 ExpectedSetting: settings(). 179 secrets( 180 secret("master-0-bmc-secret").creds("usr0", "pwd0"), 181 secret("master-1-bmc-secret").creds("usr1", "pwd1"), 182 secret("master-2-bmc-secret").creds("usr2", "pwd2"), 183 secret("worker-0-bmc-secret").creds("wrk0", "pwd0"), 184 secret("worker-1-bmc-secret").creds("wrk1", "pwd1")). 185 hosts( 186 host("master-0").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-0").customDeploy(), 187 host("master-1").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-1").customDeploy(), 188 host("master-2").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-2").customDeploy(), 189 host("worker-0").annotation("baremetalhost.metal3.io/paused", ""), 190 host("worker-1").annotation("baremetalhost.metal3.io/paused", ""), 191 ).build(), 192 }, 193 { 194 Scenario: "5-hosts-3-machines-mixed", 195 Machines: machines( 196 machine("machine-0"), 197 machine("machine-1"), 198 machine("machine-2")), 199 Config: configHosts( 200 hostType("master-1").bmc("usr1", "pwd1").role("master"), 201 hostType("worker-0").bmc("wrk0", "pwd0").role("worker"), 202 hostType("worker-1").bmc("wrk1", "pwd1").role("worker"), 203 hostType("master-0").bmc("usr0", "pwd0"), 204 hostType("master-2").bmc("usr2", "pwd2")), 205 206 ExpectedSetting: settings(). 207 secrets( 208 secret("master-1-bmc-secret").creds("usr1", "pwd1"), 209 secret("worker-0-bmc-secret").creds("wrk0", "pwd0"), 210 secret("worker-1-bmc-secret").creds("wrk1", "pwd1"), 211 secret("master-0-bmc-secret").creds("usr0", "pwd0"), 212 secret("master-2-bmc-secret").creds("usr2", "pwd2")). 213 hosts( 214 host("master-1").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-0").customDeploy(), 215 host("worker-0").annotation("baremetalhost.metal3.io/paused", ""), 216 host("worker-1").annotation("baremetalhost.metal3.io/paused", ""), 217 host("master-0").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-1").customDeploy(), 218 host("master-2").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-2").customDeploy()).build(), 219 }, 220 { 221 Scenario: "4-hosts-3-machines-norole-master", 222 Machines: machines( 223 machine("machine-0"), 224 machine("machine-1"), 225 machine("machine-2")), 226 Config: configHosts( 227 hostType("worker-0").bmc("wrk0", "pwd0").role("worker"), 228 hostType("master-0").bmc("usr0", "pwd0"), 229 hostType("master-1").bmc("usr1", "pwd1"), 230 hostType("master-2").bmc("usr2", "pwd2")), 231 232 ExpectedSetting: settings(). 233 secrets( 234 secret("worker-0-bmc-secret").creds("wrk0", "pwd0"), 235 secret("master-0-bmc-secret").creds("usr0", "pwd0"), 236 secret("master-1-bmc-secret").creds("usr1", "pwd1"), 237 secret("master-2-bmc-secret").creds("usr2", "pwd2")). 238 hosts( 239 host("worker-0").annotation("baremetalhost.metal3.io/paused", ""), 240 host("master-0").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-0").customDeploy(), 241 host("master-1").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-1").customDeploy(), 242 host("master-2").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-2").customDeploy()).build(), 243 }, 244 { 245 Scenario: "4-hosts-3-machines-norole-worker", 246 Machines: machines( 247 machine("machine-0"), 248 machine("machine-1"), 249 machine("machine-2")), 250 Config: configHosts( 251 hostType("master-0").bmc("usr0", "pwd0").role("master"), 252 hostType("master-1").bmc("usr1", "pwd1").role("master"), 253 hostType("master-2").bmc("usr2", "pwd2").role("master"), 254 hostType("worker-0").bmc("wrk0", "pwd0")), 255 256 ExpectedSetting: settings(). 257 secrets( 258 secret("master-0-bmc-secret").creds("usr0", "pwd0"), 259 secret("master-1-bmc-secret").creds("usr1", "pwd1"), 260 secret("master-2-bmc-secret").creds("usr2", "pwd2"), 261 secret("worker-0-bmc-secret").creds("wrk0", "pwd0")). 262 hosts( 263 host("master-0").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-0").customDeploy(), 264 host("master-1").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-1").customDeploy(), 265 host("master-2").label("installer.openshift.io/role", "control-plane").userDataRef("user-data-secret").consumerRef("machine-2").customDeploy(), 266 host("worker-0").annotation("baremetalhost.metal3.io/paused", "")).build(), 267 }, 268 } 269 270 for _, tc := range testCases { 271 t.Run(tc.Scenario, func(t *testing.T) { 272 settings, err := Hosts(tc.Config, tc.Machines, "user-data-secret") 273 274 if tc.ExpectedError != "" { 275 assert.EqualError(t, err, tc.ExpectedError) 276 } 277 278 if tc.ExpectedSetting != nil { 279 for i, h := range tc.ExpectedSetting.Hosts { 280 assert.Equal(t, h, settings.Hosts[i], fmt.Sprintf("%s and %s are not equal", h.Name, settings.Hosts[i].Name)) 281 } 282 283 for i, s := range tc.ExpectedSetting.Secrets { 284 assert.Equal(t, s, settings.Secrets[i], s.Name, fmt.Sprintf("%s and %s are not equal", s.Name, settings.Secrets[i].Name)) 285 } 286 287 for i, s := range tc.ExpectedSetting.NetworkConfigSecrets { 288 assert.Equal(t, s, settings.NetworkConfigSecrets[i], s.Name, fmt.Sprintf("%s and %s are not equal", s.Name, settings.NetworkConfigSecrets[i].Name)) 289 } 290 } 291 }) 292 } 293 } 294 295 func configHosts(builders ...*hostTypeBuilder) *types.InstallConfig { 296 return config().hosts(builders...).build() 297 } 298 299 type installConfigBuilder struct { 300 types.InstallConfig 301 } 302 303 func (ib *installConfigBuilder) build() *types.InstallConfig { 304 return &ib.InstallConfig 305 } 306 307 func config() *installConfigBuilder { 308 return &installConfigBuilder{ 309 types.InstallConfig{ 310 Platform: types.Platform{ 311 BareMetal: &baremetaltypes.Platform{}, 312 }, 313 }, 314 } 315 } 316 317 func (ib *installConfigBuilder) hosts(builders ...*hostTypeBuilder) *installConfigBuilder { 318 ib.Platform.BareMetal.Hosts = []*baremetaltypes.Host{} 319 320 for _, hb := range builders { 321 ib.Platform.BareMetal.Hosts = append(ib.Platform.BareMetal.Hosts, hb.build()) 322 } 323 return ib 324 } 325 326 type hostTypeBuilder struct { 327 baremetaltypes.Host 328 } 329 330 func (htb *hostTypeBuilder) build() *baremetaltypes.Host { 331 return &htb.Host 332 } 333 334 func hostType(name string) *hostTypeBuilder { 335 return &hostTypeBuilder{ 336 Host: baremetaltypes.Host{ 337 Name: name, 338 BootMACAddress: "c0:ff:ee:ca:fe:00", 339 BootMode: baremetaltypes.UEFI, 340 RootDeviceHints: &baremetaltypes.RootDeviceHints{ 341 DeviceName: "userd_devicename", 342 }, 343 }, 344 } 345 } 346 347 func (htb *hostTypeBuilder) role(role string) *hostTypeBuilder { 348 htb.Role = role 349 return htb 350 } 351 352 func (htb *hostTypeBuilder) bmc(user, password string) *hostTypeBuilder { 353 htb.BMC = baremetaltypes.BMC{ 354 Username: user, 355 Password: password, 356 } 357 return htb 358 } 359 360 func (htb *hostTypeBuilder) networkConfig(config string) *hostTypeBuilder { 361 yaml.Unmarshal([]byte(config), &htb.NetworkConfig) 362 return htb 363 } 364 365 type machineBuilder struct { 366 machineapi.Machine 367 } 368 369 func (mb *machineBuilder) build() *machineapi.Machine { 370 return &mb.Machine 371 } 372 373 func machine(name string) *machineBuilder { 374 return &machineBuilder{ 375 machineapi.Machine{ 376 TypeMeta: metav1.TypeMeta{ 377 APIVersion: "v1", 378 Kind: "Machine", 379 }, 380 ObjectMeta: metav1.ObjectMeta{ 381 Name: name, 382 Namespace: "namespace", 383 }, 384 }, 385 } 386 } 387 388 func machines(builders ...*machineBuilder) []machineapi.Machine { 389 m := []machineapi.Machine{} 390 391 for _, mb := range builders { 392 m = append(m, *mb.build()) 393 } 394 return m 395 } 396 397 type hostBuilder struct { 398 baremetalhost.BareMetalHost 399 } 400 401 func host(name string) *hostBuilder { 402 return &hostBuilder{ 403 baremetalhost.BareMetalHost{ 404 405 TypeMeta: metav1.TypeMeta{ 406 APIVersion: "metal3.io/v1alpha1", 407 Kind: "BareMetalHost", 408 }, 409 ObjectMeta: metav1.ObjectMeta{ 410 Name: name, 411 Namespace: "openshift-machine-api", 412 }, 413 Spec: baremetalhost.BareMetalHostSpec{ 414 BMC: baremetalhost.BMCDetails{ 415 CredentialsName: name + "-bmc-secret", 416 }, 417 RootDeviceHints: &baremetalhost.RootDeviceHints{ 418 DeviceName: "userd_devicename", 419 }, 420 BootMode: "UEFI", 421 BootMACAddress: "c0:ff:ee:ca:fe:00", 422 Online: true, 423 }, 424 }, 425 } 426 } 427 428 func (hb *hostBuilder) build() *baremetalhost.BareMetalHost { 429 return &hb.BareMetalHost 430 } 431 432 func (hb *hostBuilder) externallyProvisioned() *hostBuilder { 433 hb.Spec.ExternallyProvisioned = true 434 return hb 435 } 436 437 func (hb *hostBuilder) customDeploy() *hostBuilder { 438 hb.Spec.CustomDeploy = &baremetalhost.CustomDeploy{ 439 Method: "install_coreos", 440 } 441 return hb 442 } 443 444 func (hb *hostBuilder) annotation(key, value string) *hostBuilder { 445 if hb.Annotations == nil { 446 hb.Annotations = map[string]string{} 447 } 448 449 hb.Annotations[key] = value 450 return hb 451 } 452 453 func (hb *hostBuilder) label(key, value string) *hostBuilder { 454 if hb.Labels == nil { 455 hb.Labels = map[string]string{} 456 } 457 458 hb.Labels[key] = value 459 return hb 460 } 461 462 func (hb *hostBuilder) consumerRef(name string) *hostBuilder { 463 hb.Spec.ConsumerRef = &corev1.ObjectReference{ 464 APIVersion: "v1", 465 Kind: "Machine", 466 Namespace: "namespace", 467 Name: name, 468 } 469 return hb 470 } 471 472 func (hb *hostBuilder) userDataRef(name string) *hostBuilder { 473 hb.Spec.UserData = &corev1.SecretReference{Name: name} 474 return hb 475 } 476 477 func (hb *hostBuilder) preprovisioningNetworkDataName(secretName string) *hostBuilder { 478 hb.Spec.PreprovisioningNetworkDataName = secretName 479 return hb 480 } 481 482 type secretBuilder struct { 483 corev1.Secret 484 } 485 486 func secret(name string) *secretBuilder { 487 return &secretBuilder{ 488 corev1.Secret{ 489 TypeMeta: metav1.TypeMeta{ 490 APIVersion: "v1", 491 Kind: "Secret", 492 }, 493 ObjectMeta: metav1.ObjectMeta{ 494 Name: name, 495 Namespace: "openshift-machine-api", 496 }, 497 }, 498 } 499 } 500 501 func (sb *secretBuilder) creds(user, password string) *secretBuilder { 502 sb.Data = map[string][]byte{ 503 "username": []byte(user), 504 "password": []byte(password), 505 } 506 return sb 507 } 508 509 func (sb *secretBuilder) nmstate(config string) *secretBuilder { 510 sb.Data = map[string][]byte{ 511 "nmstate": []byte(config), 512 } 513 return sb 514 } 515 516 func (sb *secretBuilder) build() *corev1.Secret { 517 return &sb.Secret 518 } 519 520 type hostSettingsBuilder struct { 521 HostSettings 522 } 523 524 func (hsb *hostSettingsBuilder) secrets(builders ...*secretBuilder) *hostSettingsBuilder { 525 hsb.Secrets = []corev1.Secret{} 526 for _, sb := range builders { 527 hsb.Secrets = append(hsb.Secrets, *sb.build()) 528 } 529 return hsb 530 } 531 532 func (hsb *hostSettingsBuilder) networkConfigSecrets(builders ...*secretBuilder) *hostSettingsBuilder { 533 hsb.Secrets = []corev1.Secret{} 534 for _, sb := range builders { 535 hsb.NetworkConfigSecrets = append(hsb.NetworkConfigSecrets, *sb.build()) 536 } 537 return hsb 538 } 539 540 func (hsb *hostSettingsBuilder) hosts(builders ...*hostBuilder) *hostSettingsBuilder { 541 hsb.Hosts = []baremetalhost.BareMetalHost{} 542 for _, hb := range builders { 543 hsb.Hosts = append(hsb.Hosts, *hb.build()) 544 } 545 return hsb 546 } 547 548 func (hsb *hostSettingsBuilder) build() *HostSettings { 549 return &hsb.HostSettings 550 } 551 552 func settings() *hostSettingsBuilder { 553 return &hostSettingsBuilder{ 554 HostSettings: HostSettings{}, 555 } 556 }