Skip to content

Commit 5051360

Browse files
Merge pull request #7898 from dtantsur/OCPBUGS-25996
OCPBUGS-25996: baremetal: correct external_http_url for v6-only BMCs
2 parents ab848a8 + 99c4602 commit 5051360

File tree

3 files changed

+245
-6
lines changed

3 files changed

+245
-6
lines changed

pkg/asset/cluster/tfvars.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -771,7 +771,7 @@ func (t *TerraformVariables) Generate(parents asset.Parents) error {
771771
data, err = baremetaltfvars.TFVars(
772772
*installConfig.Config.ControlPlane.Replicas,
773773
installConfig.Config.Platform.BareMetal.LibvirtURI,
774-
installConfig.Config.Platform.BareMetal.APIVIPs[0],
774+
installConfig.Config.Platform.BareMetal.APIVIPs,
775775
imageCacheIP,
776776
string(*rhcosBootstrapImage),
777777
installConfig.Config.Platform.BareMetal.ExternalBridge,

pkg/tfvars/baremetal/baremetal.go

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
hardware "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1/profile"
1111
"github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
1212
"github.com/pkg/errors"
13+
utilsnet "k8s.io/utils/net"
1314
"sigs.k8s.io/yaml"
1415

1516
"github.com/openshift/installer/pkg/asset"
@@ -47,13 +48,31 @@ func init() {
4748
imageDownloader = cache.DownloadImageFile
4849
}
4950

51+
func externalURLs(apiVIPs []string) (externalURLv4 string, externalURLv6 string) {
52+
if len(apiVIPs) > 1 {
53+
// IPv6 BMCs may not be able to reach IPv4 servers, use the right callback URL for them.
54+
// Warning: when backporting to 4.12 or earlier, change the port to 80!
55+
externalURL := fmt.Sprintf("http://%s/", net.JoinHostPort(apiVIPs[1], "6180"))
56+
if utilsnet.IsIPv6String(apiVIPs[1]) {
57+
externalURLv6 = externalURL
58+
}
59+
if utilsnet.IsIPv4String(apiVIPs[1]) {
60+
externalURLv4 = externalURL
61+
}
62+
}
63+
64+
return
65+
}
66+
5067
// TFVars generates bare metal specific Terraform variables.
51-
func TFVars(numControlPlaneReplicas int64, libvirtURI, apiVIP, imageCacheIP, bootstrapOSImage, externalBridge, externalMAC, provisioningBridge, provisioningMAC string, platformHosts []*baremetal.Host, hostFiles []*asset.File, image, ironicUsername, ironicPassword, ignition string) ([]byte, error) {
68+
func TFVars(numControlPlaneReplicas int64, libvirtURI string, apiVIPs []string, imageCacheIP, bootstrapOSImage, externalBridge, externalMAC, provisioningBridge, provisioningMAC string, platformHosts []*baremetal.Host, hostFiles []*asset.File, image, ironicUsername, ironicPassword, ignition string) ([]byte, error) {
5269
bootstrapOSImage, err := imageDownloader(bootstrapOSImage, cache.InstallerApplicationName)
5370
if err != nil {
5471
return nil, errors.Wrap(err, "failed to use cached bootstrap libvirt image")
5572
}
5673

74+
externalURLv4, externalURLv6 := externalURLs(apiVIPs)
75+
5776
var masters, rootDevices, properties, driverInfos, instanceInfos []map[string]interface{}
5877
var deploySteps []string
5978

@@ -83,6 +102,11 @@ func TFVars(numControlPlaneReplicas int64, libvirtURI, apiVIP, imageCacheIP, boo
83102
if err != nil {
84103
return nil, err
85104
}
105+
bmcURL, err := bmc.GetParsedURL(host.BMC.Address)
106+
if err != nil {
107+
return nil, err
108+
}
109+
86110
credentials := bmc.Credentials{
87111
Username: host.BMC.Username,
88112
Password: host.BMC.Password,
@@ -91,6 +115,12 @@ func TFVars(numControlPlaneReplicas int64, libvirtURI, apiVIP, imageCacheIP, boo
91115
driverInfo["deploy_kernel"] = fmt.Sprintf("http://%s/images/ironic-python-agent.kernel", net.JoinHostPort(imageCacheIP, "6180"))
92116
driverInfo["deploy_ramdisk"] = fmt.Sprintf("http://%s/%s.initramfs", net.JoinHostPort(imageCacheIP, "8084"), host.Name)
93117
driverInfo["deploy_iso"] = fmt.Sprintf("http://%s/%s.iso", net.JoinHostPort(imageCacheIP, "8084"), host.Name)
118+
if externalURLv6 != "" && utilsnet.IsIPv6String(bmcURL.Hostname()) {
119+
driverInfo["external_http_url"] = externalURLv6
120+
}
121+
if externalURLv4 != "" && utilsnet.IsIPv4String(bmcURL.Hostname()) {
122+
driverInfo["external_http_url"] = externalURLv4
123+
}
94124

95125
var raidConfig, bmhFirmwareConfig, biosSettings []byte
96126
var bmcFirmwareConfig *bmc.FirmwareConfig
@@ -216,10 +246,11 @@ func TFVars(numControlPlaneReplicas int64, libvirtURI, apiVIP, imageCacheIP, boo
216246
})
217247
}
218248

249+
ironicIP := apiVIPs[0]
219250
cfg := &config{
220251
LibvirtURI: libvirtURI,
221-
IronicURI: fmt.Sprintf("http://%s/v1", net.JoinHostPort(apiVIP, "6385")),
222-
InspectorURI: fmt.Sprintf("http://%s/v1", net.JoinHostPort(apiVIP, "5050")),
252+
IronicURI: fmt.Sprintf("http://%s/v1", net.JoinHostPort(ironicIP, "6385")),
253+
InspectorURI: fmt.Sprintf("http://%s/v1", net.JoinHostPort(ironicIP, "5050")),
223254
BootstrapOSImage: bootstrapOSImage,
224255
IronicUsername: ironicUsername,
225256
IronicPassword: ironicPassword,

pkg/tfvars/baremetal/baremetal_test.go

Lines changed: 210 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func TestMastersSelectionByRole(t *testing.T) {
169169
data, err := TFVars(
170170
tc.numControlPlaneReplicas,
171171
tc.libvirtURI,
172-
tc.apiVIP,
172+
[]string{tc.apiVIP},
173173
tc.imageCacheIP,
174174
tc.bootstrapOSImage,
175175
tc.externalBridge,
@@ -298,7 +298,7 @@ func TestRAIDBIOSConfig(t *testing.T) {
298298
data, err := TFVars(
299299
tc.numControlPlaneReplicas,
300300
tc.libvirtURI,
301-
tc.apiVIP,
301+
[]string{tc.apiVIP},
302302
tc.imageCacheIP,
303303
tc.bootstrapOSImage,
304304
tc.externalBridge,
@@ -333,6 +333,203 @@ func TestRAIDBIOSConfig(t *testing.T) {
333333
}
334334
}
335335

336+
func TestDriverInfo(t *testing.T) {
337+
cases := []struct {
338+
scenario string
339+
340+
numControlPlaneReplicas int64
341+
apiVIPs []string
342+
platformHosts []*baremetal.Host
343+
hostFiles []*asset.File
344+
345+
expectedError string
346+
expectedDriverInfos []map[string]string
347+
}{
348+
{
349+
scenario: "v4-only",
350+
351+
numControlPlaneReplicas: 2,
352+
apiVIPs: []string{"192.0.2.42"},
353+
platformHosts: platformHosts(
354+
host("master-0", "master"),
355+
host("master-1", "master"),
356+
),
357+
hostFiles: hostFiles(
358+
files("master-0", nil),
359+
files("master-1", nil),
360+
),
361+
362+
expectedDriverInfos: []map[string]string{
363+
{
364+
"deploy_kernel": "http://192.0.2.42:6180/images/ironic-python-agent.kernel",
365+
"deploy_ramdisk": "http://192.0.2.42:8084/master-0.initramfs",
366+
"external_http_url": "",
367+
},
368+
{
369+
"deploy_kernel": "http://192.0.2.42:6180/images/ironic-python-agent.kernel",
370+
"deploy_ramdisk": "http://192.0.2.42:8084/master-1.initramfs",
371+
"external_http_url": "",
372+
},
373+
},
374+
},
375+
{
376+
scenario: "v6-only",
377+
378+
numControlPlaneReplicas: 2,
379+
apiVIPs: []string{"2001:db8::1"},
380+
platformHosts: platformHosts(
381+
hostv6("master-0", "master"),
382+
hostv6("master-1", "master"),
383+
),
384+
hostFiles: hostFiles(
385+
files("master-0", nil),
386+
files("master-1", nil),
387+
),
388+
389+
expectedDriverInfos: []map[string]string{
390+
{
391+
"deploy_kernel": "http://[2001:db8::1]:6180/images/ironic-python-agent.kernel",
392+
"deploy_ramdisk": "http://[2001:db8::1]:8084/master-0.initramfs",
393+
"external_http_url": "",
394+
},
395+
{
396+
"deploy_kernel": "http://[2001:db8::1]:6180/images/ironic-python-agent.kernel",
397+
"deploy_ramdisk": "http://[2001:db8::1]:8084/master-1.initramfs",
398+
"external_http_url": "",
399+
},
400+
},
401+
},
402+
{
403+
scenario: "v4-primary",
404+
405+
numControlPlaneReplicas: 3,
406+
apiVIPs: []string{"192.0.2.42", "2001:db8::1"},
407+
platformHosts: platformHosts(
408+
host("master-0", "master"),
409+
hostv6("master-1", "master"),
410+
// DNS names are not resolved, the right networking is assumed
411+
&baremetal.Host{
412+
Name: "master-2",
413+
Role: "master",
414+
HardwareProfile: "default",
415+
BMC: baremetal.BMC{
416+
Address: "redfish+http://example.com:8000/redfish/v1/Systems/e4427260-6250-4df9-9e8a-120f78a46aa6",
417+
},
418+
},
419+
),
420+
hostFiles: hostFiles(
421+
files("master-0", nil),
422+
files("master-1", nil),
423+
files("master-2", nil),
424+
),
425+
426+
expectedDriverInfos: []map[string]string{
427+
{
428+
"deploy_kernel": "http://192.0.2.42:6180/images/ironic-python-agent.kernel",
429+
"deploy_ramdisk": "http://192.0.2.42:8084/master-0.initramfs",
430+
"external_http_url": "",
431+
},
432+
{
433+
"deploy_kernel": "http://192.0.2.42:6180/images/ironic-python-agent.kernel",
434+
"deploy_ramdisk": "http://192.0.2.42:8084/master-1.initramfs",
435+
"external_http_url": "http://[2001:db8::1]:6180/",
436+
},
437+
{
438+
"deploy_kernel": "http://192.0.2.42:6180/images/ironic-python-agent.kernel",
439+
"deploy_ramdisk": "http://192.0.2.42:8084/master-2.initramfs",
440+
"external_http_url": "",
441+
},
442+
},
443+
},
444+
{
445+
scenario: "v6-primary",
446+
447+
numControlPlaneReplicas: 3,
448+
apiVIPs: []string{"2001:db8::1", "192.0.2.42"},
449+
platformHosts: platformHosts(
450+
host("master-0", "master"),
451+
hostv6("master-1", "master"),
452+
&baremetal.Host{
453+
Name: "master-2",
454+
Role: "master",
455+
HardwareProfile: "default",
456+
BMC: baremetal.BMC{
457+
Address: "redfish+http://example.com:8000/redfish/v1/Systems/e4427260-6250-4df9-9e8a-120f78a46aa6",
458+
},
459+
},
460+
),
461+
hostFiles: hostFiles(
462+
files("master-0", nil),
463+
files("master-1", nil),
464+
files("master-2", nil),
465+
),
466+
467+
expectedDriverInfos: []map[string]string{
468+
{
469+
"deploy_kernel": "http://[2001:db8::1]:6180/images/ironic-python-agent.kernel",
470+
"deploy_ramdisk": "http://[2001:db8::1]:8084/master-0.initramfs",
471+
"external_http_url": "http://192.0.2.42:6180/",
472+
},
473+
{
474+
"deploy_kernel": "http://[2001:db8::1]:6180/images/ironic-python-agent.kernel",
475+
"deploy_ramdisk": "http://[2001:db8::1]:8084/master-1.initramfs",
476+
"external_http_url": "",
477+
},
478+
{
479+
"deploy_kernel": "http://[2001:db8::1]:6180/images/ironic-python-agent.kernel",
480+
"deploy_ramdisk": "http://[2001:db8::1]:8084/master-2.initramfs",
481+
"external_http_url": "",
482+
},
483+
},
484+
},
485+
}
486+
487+
for _, tc := range cases {
488+
t.Run(tc.scenario, func(t *testing.T) {
489+
imageDownloader = func(baseURL, applicationName string) (string, error) {
490+
return "", nil
491+
}
492+
493+
data, err := TFVars(
494+
tc.numControlPlaneReplicas,
495+
"",
496+
tc.apiVIPs,
497+
tc.apiVIPs[0],
498+
"",
499+
"",
500+
"",
501+
"",
502+
"",
503+
tc.platformHosts,
504+
tc.hostFiles,
505+
"",
506+
"",
507+
"",
508+
"")
509+
510+
if tc.expectedError == "" {
511+
assert.NoError(t, err)
512+
} else {
513+
assert.Regexp(t, tc.expectedError, err)
514+
}
515+
516+
var cfg struct {
517+
// Simpler type since we know the values are strings currently
518+
DriverInfos []map[string]string `json:"driver_infos"`
519+
}
520+
err = json.Unmarshal(data, &cfg)
521+
assert.NoError(t, err)
522+
523+
assert.Equal(t, len(tc.expectedDriverInfos), len(cfg.DriverInfos))
524+
for i, driverInfo := range tc.expectedDriverInfos {
525+
for name, value := range driverInfo {
526+
assert.Equal(t, value, cfg.DriverInfos[i][name])
527+
}
528+
}
529+
})
530+
}
531+
}
532+
336533
func host(name, tag string) *baremetal.Host {
337534
return &baremetal.Host{
338535
Name: name,
@@ -344,6 +541,17 @@ func host(name, tag string) *baremetal.Host {
344541
}
345542
}
346543

544+
func hostv6(name, tag string) *baremetal.Host {
545+
return &baremetal.Host{
546+
Name: name,
547+
Role: tag,
548+
HardwareProfile: "default",
549+
BMC: baremetal.BMC{
550+
Address: "redfish+http://[2001:db8::1]:8000/redfish/v1/Systems/e4427260-6250-4df9-9e8a-120f78a46aa6",
551+
},
552+
}
553+
}
554+
347555
func iRMChost(name, tag string) *baremetal.Host {
348556
return &baremetal.Host{
349557
Name: name,

0 commit comments

Comments
 (0)