From 6c70770cc9f9eddfb61f9cfb2b458ca5e2251a4d Mon Sep 17 00:00:00 2001 From: Doug Hellmann Date: Mon, 3 Aug 2020 14:19:31 -0400 Subject: [PATCH] baremetal: copy the implementation of rootdevicehints from baremetal-operator Copy the struct and conversion function from the baremetal-operator repository to avoid depending on that code directly in the installer's API. Signed-off-by: Doug Hellmann --- pkg/tfvars/baremetal/baremetal.go | 3 +- pkg/types/baremetal/platform.go | 15 ++- pkg/types/baremetal/rootdevice.go | 98 ++++++++++++++++ pkg/types/baremetal/rootdevice_test.go | 155 +++++++++++++++++++++++++ 4 files changed, 261 insertions(+), 10 deletions(-) create mode 100644 pkg/types/baremetal/rootdevice.go create mode 100644 pkg/types/baremetal/rootdevice_test.go diff --git a/pkg/tfvars/baremetal/baremetal.go b/pkg/tfvars/baremetal/baremetal.go index c05c31328c8..ae44144e5e4 100644 --- a/pkg/tfvars/baremetal/baremetal.go +++ b/pkg/tfvars/baremetal/baremetal.go @@ -11,7 +11,6 @@ import ( "github.com/metal3-io/baremetal-operator/pkg/bmc" "github.com/metal3-io/baremetal-operator/pkg/hardware" - "github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/devicehints" "github.com/openshift/installer/pkg/tfvars/internal/cache" "github.com/openshift/installer/pkg/types/baremetal" "github.com/pkg/errors" @@ -98,7 +97,7 @@ func TFVars(libvirtURI, bootstrapProvisioningIP, bootstrapOSImage, externalBridg // host.RootDeviceHints overrides the root device hint in the profile if host.RootDeviceHints != nil { - rootDeviceStringMap := devicehints.MakeHintMap(host.RootDeviceHints) + rootDeviceStringMap := host.RootDeviceHints.MakeHintMap() for key, value := range rootDeviceStringMap { rootDevice[key] = value } diff --git a/pkg/types/baremetal/platform.go b/pkg/types/baremetal/platform.go index bde97a6d5fb..e826c389790 100644 --- a/pkg/types/baremetal/platform.go +++ b/pkg/types/baremetal/platform.go @@ -1,7 +1,6 @@ package baremetal import ( - "github.com/metal3-io/baremetal-operator/pkg/apis/metal3/v1alpha1" "github.com/openshift/installer/pkg/ipnet" ) @@ -26,13 +25,13 @@ const ( // Host stores all the configuration data for a baremetal host. type Host struct { - Name string `json:"name,omitempty" validate:"required,uniqueField"` - BMC BMC `json:"bmc"` - Role string `json:"role"` - BootMACAddress string `json:"bootMACAddress" validate:"required,uniqueField"` - HardwareProfile string `json:"hardwareProfile"` - RootDeviceHints *v1alpha1.RootDeviceHints `json:"rootDeviceHints,omitempty"` - BootMode BootMode `json:"bootMode,omitempty"` + Name string `json:"name,omitempty" validate:"required,uniqueField"` + BMC BMC `json:"bmc"` + Role string `json:"role"` + BootMACAddress string `json:"bootMACAddress" validate:"required,uniqueField"` + HardwareProfile string `json:"hardwareProfile"` + RootDeviceHints *RootDeviceHints `json:"rootDeviceHints,omitempty"` + BootMode BootMode `json:"bootMode,omitempty"` } // Platform stores all the global configuration that all machinesets use. diff --git a/pkg/types/baremetal/rootdevice.go b/pkg/types/baremetal/rootdevice.go new file mode 100644 index 00000000000..19b8621d8a3 --- /dev/null +++ b/pkg/types/baremetal/rootdevice.go @@ -0,0 +1,98 @@ +package baremetal + +// This package replicates the code from +// https://github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/devicehints + +import ( + "fmt" +) + +// RootDeviceHints holds the hints for specifying the storage location +// for the root filesystem for the image. +type RootDeviceHints struct { + // A Linux device name like "/dev/vda". The hint must match the + // actual value exactly. + DeviceName string `json:"deviceName,omitempty"` + + // A SCSI bus address like 0:0:0:0. The hint must match the actual + // value exactly. + HCTL string `json:"hctl,omitempty"` + + // A vendor-specific device identifier. The hint can be a + // substring of the actual value. + Model string `json:"model,omitempty"` + + // The name of the vendor or manufacturer of the device. The hint + // can be a substring of the actual value. + Vendor string `json:"vendor,omitempty"` + + // Device serial number. The hint must match the actual value + // exactly. + SerialNumber string `json:"serialNumber,omitempty"` + + // The minimum size of the device in Gigabytes. + // +kubebuilder:validation:Minimum=0 + MinSizeGigabytes int `json:"minSizeGigabytes,omitempty"` + + // Unique storage identifier. The hint must match the actual value + // exactly. + WWN string `json:"wwn,omitempty"` + + // Unique storage identifier with the vendor extension + // appended. The hint must match the actual value exactly. + WWNWithExtension string `json:"wwnWithExtension,omitempty"` + + // Unique vendor storage identifier. The hint must match the + // actual value exactly. + WWNVendorExtension string `json:"wwnVendorExtension,omitempty"` + + // True if the device should use spinning media, false otherwise. + Rotational *bool `json:"rotational,omitempty"` +} + +// MakeHintMap converts a RootDeviceHints instance into a string map +// suitable to pass to ironic. +func (source *RootDeviceHints) MakeHintMap() map[string]string { + hints := map[string]string{} + + if source == nil { + return hints + } + + if source.DeviceName != "" { + hints["name"] = fmt.Sprintf("s== %s", source.DeviceName) + } + if source.HCTL != "" { + hints["hctl"] = fmt.Sprintf("s== %s", source.HCTL) + } + if source.Model != "" { + hints["model"] = fmt.Sprintf(" %s", source.Model) + } + if source.Vendor != "" { + hints["vendor"] = fmt.Sprintf(" %s", source.Vendor) + } + if source.SerialNumber != "" { + hints["serial"] = fmt.Sprintf("s== %s", source.SerialNumber) + } + if source.MinSizeGigabytes != 0 { + hints["size"] = fmt.Sprintf(">= %d", source.MinSizeGigabytes) + } + if source.WWN != "" { + hints["wwn"] = fmt.Sprintf("s== %s", source.WWN) + } + if source.WWNWithExtension != "" { + hints["wwn_with_extension"] = fmt.Sprintf("s== %s", source.WWNWithExtension) + } + if source.WWNVendorExtension != "" { + hints["wwn_vendor_extension"] = fmt.Sprintf("s== %s", source.WWNVendorExtension) + } + switch { + case source.Rotational == nil: + case *source.Rotational == true: + hints["rotational"] = "true" + case *source.Rotational == false: + hints["rotational"] = "false" + } + + return hints +} diff --git a/pkg/types/baremetal/rootdevice_test.go b/pkg/types/baremetal/rootdevice_test.go new file mode 100644 index 00000000000..074ffaf38d5 --- /dev/null +++ b/pkg/types/baremetal/rootdevice_test.go @@ -0,0 +1,155 @@ +package baremetal + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestMakeHintMap(t *testing.T) { + addressableTrue := true + addressableFalse := false + + for _, tc := range []struct { + Scenario string + Hints RootDeviceHints + Expected map[string]string + }{ + { + Scenario: "device-name", + Hints: RootDeviceHints{ + DeviceName: "userd_devicename", + }, + Expected: map[string]string{ + "name": "s== userd_devicename", + }, + }, + { + Scenario: "hctl", + Hints: RootDeviceHints{ + HCTL: "1:2:3:4", + }, + Expected: map[string]string{ + "hctl": "s== 1:2:3:4", + }, + }, + { + Scenario: "model", + Hints: RootDeviceHints{ + Model: "userd_model", + }, + Expected: map[string]string{ + "model": " userd_model", + }, + }, + { + Scenario: "vendor", + Hints: RootDeviceHints{ + Vendor: "userd_vendor", + }, + Expected: map[string]string{ + "vendor": " userd_vendor", + }, + }, + { + Scenario: "serial-number", + Hints: RootDeviceHints{ + SerialNumber: "userd_serial", + }, + Expected: map[string]string{ + "serial": "s== userd_serial", + }, + }, + { + Scenario: "min-size", + Hints: RootDeviceHints{ + MinSizeGigabytes: 40, + }, + Expected: map[string]string{ + "size": ">= 40", + }, + }, + { + Scenario: "wwn", + Hints: RootDeviceHints{ + WWN: "userd_wwn", + }, + Expected: map[string]string{ + "wwn": "s== userd_wwn", + }, + }, + { + Scenario: "wwn-with-extension", + Hints: RootDeviceHints{ + WWNWithExtension: "userd_with_extension", + }, + Expected: map[string]string{ + "wwn_with_extension": "s== userd_with_extension", + }, + }, + { + Scenario: "wwn-extension", + Hints: RootDeviceHints{ + WWNVendorExtension: "userd_vendor_extension", + }, + Expected: map[string]string{ + "wwn_vendor_extension": "s== userd_vendor_extension", + }, + }, + { + Scenario: "rotational-true", + Hints: RootDeviceHints{ + Rotational: &addressableTrue, + }, + Expected: map[string]string{ + "rotational": "true", + }, + }, + { + Scenario: "rotational-false", + Hints: RootDeviceHints{ + Rotational: &addressableFalse, + }, + Expected: map[string]string{ + "rotational": "false", + }, + }, + { + Scenario: "everything-bagel", + Hints: RootDeviceHints{ + DeviceName: "userd_devicename", + HCTL: "1:2:3:4", + Model: "userd_model", + Vendor: "userd_vendor", + SerialNumber: "userd_serial", + MinSizeGigabytes: 40, + WWN: "userd_wwn", + WWNWithExtension: "userd_with_extension", + WWNVendorExtension: "userd_vendor_extension", + Rotational: &addressableTrue, + }, + Expected: map[string]string{ + "name": "s== userd_devicename", + "hctl": "s== 1:2:3:4", + "model": " userd_model", + "vendor": " userd_vendor", + "serial": "s== userd_serial", + "size": ">= 40", + "wwn": "s== userd_wwn", + "wwn_with_extension": "s== userd_with_extension", + "wwn_vendor_extension": "s== userd_vendor_extension", + "rotational": "true", + }, + }, + { + Scenario: "empty", + Hints: RootDeviceHints{}, + Expected: map[string]string{}, + }, + } { + t.Run(tc.Scenario, func(t *testing.T) { + actual := tc.Hints.MakeHintMap() + assert.Equal(t, tc.Expected, actual, "hint map does not match") + }) + } +}