Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions internal/webhooks/metal3.io/v1alpha1/baremetalhost_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func (webhook *BareMetalHost) validateHost(host *metal3api.BareMetalHost) []erro
errs = append(errs, raidErrors...)
}

errs = append(errs, validateBMCAccess(host.Spec, bmcAccess)...)
errs = append(errs, validateBMCAccess(host, bmcAccess)...)

if err := validateBMHName(host.Name); err != nil {
errs = append(errs, err)
Expand Down Expand Up @@ -120,8 +120,9 @@ func (webhook *BareMetalHost) validateChanges(oldObj *metal3api.BareMetalHost, n
return errs
}

func validateBMCAccess(s metal3api.BareMetalHostSpec, bmcAccess bmc.AccessDetails) []error {
func validateBMCAccess(host *metal3api.BareMetalHost, bmcAccess bmc.AccessDetails) []error {
var errs []error
s := host.Spec

if bmcAccess == nil {
return errs
Expand All @@ -139,7 +140,14 @@ func validateBMCAccess(s metal3api.BareMetalHostSpec, bmcAccess bmc.AccessDetail
}
}

if bmcAccess.NeedsMAC() && s.BootMACAddress == "" {
// Check if bootMACAddress is required
requiresMAC := bmcAccess.NeedsMAC()
// Virtual media drivers (NeedsMAC() returns false) still require MAC when inspection is disabled
if !requiresMAC && host.InspectionDisabled() {
requiresMAC = true
}

if requiresMAC && s.BootMACAddress == "" {
errs = append(errs, fmt.Errorf("BMC driver %s requires a BootMACAddress value", bmcAccess.Type()))
}

Expand Down
102 changes: 70 additions & 32 deletions internal/webhooks/metal3.io/v1alpha1/baremetalhost_validation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import (
"testing"

metal3api "github.com/metal3-io/baremetal-operator/apis/metal3.io/v1alpha1"
// Import BMC drivers to register their factories.
_ "github.com/metal3-io/baremetal-operator/pkg/hardwareutils/bmc"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/utils/ptr"
Expand Down Expand Up @@ -270,6 +272,71 @@ func TestValidateCreate(t *testing.T) {
oldBMH: nil,
wantedErr: "",
},
{
name: "BootMACAddressNotRequiredForVirtualMedia",
newBMH: &metal3api.BareMetalHost{
TypeMeta: tm,
ObjectMeta: om,
Spec: metal3api.BareMetalHostSpec{
BMC: metal3api.BMCDetails{
Address: "idrac-virtualmedia+https://192.168.1.1/redfish/v1/Systems/System.Embedded.1",
CredentialsName: "test1",
},
}},
oldBMH: nil,
wantedErr: "",
},
{
name: "BootMACAddressRequiredForVirtualMediaWithInspectionDisabled",
newBMH: &metal3api.BareMetalHost{
TypeMeta: tm,
ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "test-namespace",
Annotations: map[string]string{
metal3api.InspectAnnotationPrefix: "disabled",
},
},
Spec: metal3api.BareMetalHostSpec{
BMC: metal3api.BMCDetails{
Address: "idrac-virtualmedia+https://192.168.1.1/redfish/v1/Systems/System.Embedded.1",
CredentialsName: "test1",
},
}},
oldBMH: nil,
wantedErr: "BMC driver idrac-virtualmedia+https requires a BootMACAddress value",
},
{
name: "BootMACAddressProvidedForVirtualMediaWithInspectionDisabled",
newBMH: &metal3api.BareMetalHost{
TypeMeta: tm,
ObjectMeta: om,
Spec: metal3api.BareMetalHostSpec{
BMC: metal3api.BMCDetails{
Address: "idrac-virtualmedia+https://192.168.1.1/redfish/v1/Systems/System.Embedded.1",
CredentialsName: "test1",
},
BootMACAddress: "00:00:00:00:00:00",
InspectionMode: metal3api.InspectionModeDisabled,
}},
oldBMH: nil,
wantedErr: "",
},
{
name: "BootMACAddressNotRequiredForVirtualMediaWithInspectionEnabled",
newBMH: &metal3api.BareMetalHost{
TypeMeta: tm,
ObjectMeta: om,
Spec: metal3api.BareMetalHostSpec{
BMC: metal3api.BMCDetails{
Address: "redfish-virtualmedia+https://192.168.1.1/redfish/v1/Systems/1",
CredentialsName: "test1",
},
InspectionMode: metal3api.InspectionModeAgent,
}},
oldBMH: nil,
wantedErr: "",
},
{
name: "BootMACAddressRequired",
newBMH: &metal3api.BareMetalHost{
Expand Down Expand Up @@ -458,7 +525,7 @@ func TestValidateCreate(t *testing.T) {
BMC: metal3api.BMCDetails{
Address: "ipmi://[fe80::fc33:62ff:fe33:8xff]:6223"}}},
oldBMH: nil,
wantedErr: "failed to parse BMC address information: parse \"ipmi://[fe80::fc33:62ff:fe33:8xff]:6223\": invalid host: ParseAddr(\"fe80::fc33:62ff:fe33:8xff\"): unexpected character, want colon (at \"xff\")",
wantedErr: "failed to parse BMC address information: BMC address hostname/IP : [fe80::fc33:62ff:fe33:8xff] is invalid",
},
{
name: "validRootDeviceHint",
Expand Down Expand Up @@ -1055,40 +1122,11 @@ func TestValidateUpdate(t *testing.T) {
{
name: "updateBootMAC",
newBMH: &metal3api.BareMetalHost{
TypeMeta: tm, ObjectMeta: om, Spec: metal3api.BareMetalHostSpec{BootMACAddress: "00:11:22:33:44:66"}},
TypeMeta: tm, ObjectMeta: om, Spec: metal3api.BareMetalHostSpec{BootMACAddress: "test-mac-changed"}},
oldBMH: &metal3api.BareMetalHost{
TypeMeta: tm, ObjectMeta: om, Spec: metal3api.BareMetalHostSpec{BootMACAddress: "00:11:22:33:44:55"}},
TypeMeta: tm, ObjectMeta: om, Spec: metal3api.BareMetalHostSpec{BootMACAddress: "test-mac"}},
wantedErr: "bootMACAddress can not be changed once it is set",
},
{
name: "updateBootMACCaseOnly",
newBMH: &metal3api.BareMetalHost{
TypeMeta: tm, ObjectMeta: om, Spec: metal3api.BareMetalHostSpec{BootMACAddress: "AA:BB:CC:DD:EE:FF"}},
oldBMH: &metal3api.BareMetalHost{
TypeMeta: tm, ObjectMeta: om, Spec: metal3api.BareMetalHostSpec{BootMACAddress: "aa:bb:cc:dd:ee:ff"}},
wantedErr: "",
},
{
name: "updateBootMACCaseMixed",
newBMH: &metal3api.BareMetalHost{
TypeMeta: tm, ObjectMeta: om, Spec: metal3api.BareMetalHostSpec{BootMACAddress: "aA:Bb:cC:Dd:Ee:Ff"}},
oldBMH: &metal3api.BareMetalHost{
TypeMeta: tm, ObjectMeta: om, Spec: metal3api.BareMetalHostSpec{BootMACAddress: "AA:BB:CC:DD:EE:FF"}},
wantedErr: "",
},
{
name: "updateBootMACInvalidNew",
newBMH: &metal3api.BareMetalHost{
TypeMeta: tm, ObjectMeta: om, Spec: metal3api.BareMetalHostSpec{
BMC: metal3api.BMCDetails{
Address: "redfish://127.0.0.1",
CredentialsName: "test1",
},
BootMACAddress: "invalid-mac"}},
oldBMH: &metal3api.BareMetalHost{
TypeMeta: tm, ObjectMeta: om, Spec: metal3api.BareMetalHostSpec{BootMACAddress: "00:11:22:33:44:55"}},
wantedErr: "address invalid-mac: invalid MAC address",
},
{
name: "updateExternallyProvisioned",
newBMH: &metal3api.BareMetalHost{
Expand Down
16 changes: 16 additions & 0 deletions internal/webhooks/metal3.io/v1alpha1/baremetalhost_webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@ func TestBareMetalHostCreate(t *testing.T) {
}, Spec: metal3api.BareMetalHostSpec{}},
wantedErr: "",
},
{
name: "invalid-no-bootMACAddress-no-preprovisioningNetworkData",
bmh: &metal3api.BareMetalHost{TypeMeta: metav1.TypeMeta{
Kind: "BareMetalHost",
APIVersion: "metal3.io/v1alpha1",
}, ObjectMeta: metav1.ObjectMeta{
Name: "test",
Namespace: "test-namespace",
}, Spec: metal3api.BareMetalHostSpec{
BMC: metal3api.BMCDetails{
Address: "libvirt://192.168.122.1:16509/",
},
BootMACAddress: "",
}},
wantedErr: "BMC driver libvirt requires a BootMACAddress value",
},
}

for _, tt := range tests {
Expand Down
18 changes: 9 additions & 9 deletions pkg/hardwareutils/bmc/access_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ func TestStaticDriverInfo(t *testing.T) {
{
Scenario: "redfish virtual media",
input: "redfish-virtualmedia://192.168.122.1",
needsMac: true,
needsMac: false,
driver: "redfish",
bios: "",
boot: "redfish-virtual-media",
Expand All @@ -351,7 +351,7 @@ func TestStaticDriverInfo(t *testing.T) {
{
Scenario: "redfish virtual media HTTP",
input: "redfish-virtualmedia+http://192.168.122.1",
needsMac: true,
needsMac: false,
driver: "redfish",
bios: "",
boot: "redfish-virtual-media",
Expand All @@ -363,7 +363,7 @@ func TestStaticDriverInfo(t *testing.T) {
{
Scenario: "redfish virtual media HTTPS",
input: "redfish-virtualmedia+https://192.168.122.1",
needsMac: true,
needsMac: false,
driver: "redfish",
bios: "",
boot: "redfish-virtual-media",
Expand Down Expand Up @@ -400,7 +400,7 @@ func TestStaticDriverInfo(t *testing.T) {
{
Scenario: "ilo5 virtual media",
input: "ilo5-virtualmedia://192.168.122.1",
needsMac: true,
needsMac: false,
driver: "redfish",
bios: "",
boot: "redfish-virtual-media",
Expand All @@ -410,7 +410,7 @@ func TestStaticDriverInfo(t *testing.T) {
{
Scenario: "ilo5 virtual media HTTP",
input: "ilo5-virtualmedia+http://192.168.122.1",
needsMac: true,
needsMac: false,
driver: "redfish",
bios: "",
boot: "redfish-virtual-media",
Expand All @@ -420,7 +420,7 @@ func TestStaticDriverInfo(t *testing.T) {
{
Scenario: "ilo5 virtual media HTTPS",
input: "ilo5-virtualmedia+https://192.168.122.1",
needsMac: true,
needsMac: false,
driver: "redfish",
bios: "",
boot: "redfish-virtual-media",
Expand All @@ -430,7 +430,7 @@ func TestStaticDriverInfo(t *testing.T) {
{
Scenario: "idrac virtual media",
input: "idrac-virtualmedia://192.168.122.1",
needsMac: true,
needsMac: false,
driver: "idrac",
bios: "idrac-redfish",
boot: "idrac-redfish-virtual-media",
Expand All @@ -443,7 +443,7 @@ func TestStaticDriverInfo(t *testing.T) {
{
Scenario: "idrac virtual media HTTP",
input: "idrac-virtualmedia+http://192.168.122.1",
needsMac: true,
needsMac: false,
driver: "idrac",
bios: "idrac-redfish",
boot: "idrac-redfish-virtual-media",
Expand All @@ -456,7 +456,7 @@ func TestStaticDriverInfo(t *testing.T) {
{
Scenario: "idrac virtual media HTTPS",
input: "idrac-virtualmedia+https://192.168.122.1",
needsMac: true,
needsMac: false,
driver: "idrac",
bios: "idrac-redfish",
boot: "idrac-redfish-virtual-media",
Expand Down
9 changes: 4 additions & 5 deletions pkg/hardwareutils/bmc/idrac_virtualmedia.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,11 @@ func (a *redfishiDracVirtualMediaAccessDetails) Type() string {
return a.bmcType
}

// NeedsMAC returns true when the host is going to need a separate
// port created rather than having it discovered.
// NeedsMAC returns false for virtual media drivers since they can boot
// from virtual media without requiring a pre-configured boot MAC address.
// The MAC address can be populated after hardware inspection completes.
func (a *redfishiDracVirtualMediaAccessDetails) NeedsMAC() bool {
// For the inspection to work, we need a MAC address
// https://github.com/metal3-io/baremetal-operator/pull/284#discussion_r317579040
return true
return false
}

func (a *redfishiDracVirtualMediaAccessDetails) DisableCertificateVerification() bool {
Expand Down
9 changes: 4 additions & 5 deletions pkg/hardwareutils/bmc/redfish_virtualmedia.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,11 @@ func (a *redfishVirtualMediaAccessDetails) Type() string {
return a.bmcType
}

// NeedsMAC returns true when the host is going to need a separate
// port created rather than having it discovered.
// NeedsMAC returns false for virtual media drivers since they can boot
// from virtual media without requiring a pre-configured boot MAC address.
// The MAC address can be populated after hardware inspection completes.
func (a *redfishVirtualMediaAccessDetails) NeedsMAC() bool {
// For the inspection to work, we need a MAC address
// https://github.com/metal3-io/baremetal-operator/pull/284#discussion_r317579040
return true
return false
}

func (a *redfishVirtualMediaAccessDetails) Driver() string {
Expand Down
Loading