forked from metal3-io/baremetal-operator
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #87 from EgorLu/hardware-details-4.4
[release-4.4] Bug 1840106: Backport get-hardware-details
- Loading branch information
Showing
7 changed files
with
473 additions
and
404 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
// get-hardware-details is a tool that can be used to convert raw Ironic introspection data into the HardwareDetails | ||
// type used by Metal3. | ||
package main | ||
|
||
import ( | ||
"encoding/json" | ||
"fmt" | ||
"os" | ||
|
||
"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/noauth" | ||
"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection" | ||
"github.com/metal3-io/baremetal-operator/pkg/provisioner/ironic/hardwaredetails" | ||
) | ||
|
||
func main() { | ||
if len(os.Args) != 3 { | ||
fmt.Println("Usage: get-hardware-details <inspector URI> <node UUID>") | ||
return | ||
} | ||
|
||
inspector, err := noauth.NewBareMetalIntrospectionNoAuth( | ||
noauth.EndpointOpts{ | ||
IronicInspectorEndpoint: os.Args[1], | ||
}) | ||
if err != nil { | ||
fmt.Printf("could not get inspector client: %s", err) | ||
os.Exit(1) | ||
} | ||
|
||
introData := introspection.GetIntrospectionData(inspector, os.Args[2]) | ||
data, err := introData.Extract() | ||
if err != nil { | ||
fmt.Printf("could not get introspection data: %s", err) | ||
os.Exit(1) | ||
} | ||
|
||
json, err := json.MarshalIndent(hardwaredetails.GetHardwareDetails(data), "", "\t") | ||
if err != nil { | ||
fmt.Printf("could not convert introspection data: %s", err) | ||
os.Exit(1) | ||
} | ||
|
||
fmt.Println(string(json)) | ||
} |
143 changes: 143 additions & 0 deletions
143
pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package hardwaredetails | ||
|
||
import ( | ||
"fmt" | ||
"sort" | ||
"strings" | ||
|
||
"github.com/gophercloud/gophercloud/openstack/baremetalintrospection/v1/introspection" | ||
metal3v1alpha1 "github.com/metal3-io/baremetal-operator/pkg/apis/metal3/v1alpha1" | ||
) | ||
|
||
// GetHardwareDetails converts Ironic introspection data into BareMetalHost HardwareDetails. | ||
func GetHardwareDetails(data *introspection.Data) *metal3v1alpha1.HardwareDetails { | ||
details := new(metal3v1alpha1.HardwareDetails) | ||
details.Firmware = getFirmwareDetails(data.Extra.Firmware) | ||
details.SystemVendor = getSystemVendorDetails(data.Inventory.SystemVendor) | ||
details.RAMMebibytes = data.MemoryMB | ||
details.NIC = getNICDetails(data.Inventory.Interfaces, data.AllInterfaces, data.Extra.Network) | ||
details.Storage = getStorageDetails(data.Inventory.Disks) | ||
details.CPU = getCPUDetails(&data.Inventory.CPU) | ||
details.Hostname = data.Inventory.Hostname | ||
return details | ||
} | ||
|
||
func getVLANs(intf introspection.BaseInterfaceType) (vlans []metal3v1alpha1.VLAN, vlanid metal3v1alpha1.VLANID) { | ||
if intf.LLDPProcessed == nil { | ||
return | ||
} | ||
if spvs, ok := intf.LLDPProcessed["switch_port_vlans"]; ok { | ||
if data, ok := spvs.([]map[string]interface{}); ok { | ||
vlans = make([]metal3v1alpha1.VLAN, len(data)) | ||
for i, vlan := range data { | ||
vid, _ := vlan["id"].(int) | ||
name, _ := vlan["name"].(string) | ||
vlans[i] = metal3v1alpha1.VLAN{ | ||
ID: metal3v1alpha1.VLANID(vid), | ||
Name: name, | ||
} | ||
} | ||
} | ||
} | ||
if vid, ok := intf.LLDPProcessed["switch_port_untagged_vlan_id"].(int); ok { | ||
vlanid = metal3v1alpha1.VLANID(vid) | ||
} | ||
return | ||
} | ||
|
||
func getNICSpeedGbps(intfExtradata introspection.ExtraHardwareData) (speedGbps int) { | ||
if speed, ok := intfExtradata["speed"].(string); ok { | ||
if strings.HasSuffix(speed, "Gbps") { | ||
fmt.Sscanf(speed, "%d", &speedGbps) | ||
} | ||
} | ||
return | ||
} | ||
|
||
func getNICDetails(ifdata []introspection.InterfaceType, | ||
basedata map[string]introspection.BaseInterfaceType, | ||
extradata introspection.ExtraHardwareDataSection) []metal3v1alpha1.NIC { | ||
nics := make([]metal3v1alpha1.NIC, len(ifdata)) | ||
for i, intf := range ifdata { | ||
baseIntf := basedata[intf.Name] | ||
vlans, vlanid := getVLANs(baseIntf) | ||
ip := intf.IPV4Address | ||
if ip == "" { | ||
ip = intf.IPV6Address | ||
} | ||
nics[i] = metal3v1alpha1.NIC{ | ||
Name: intf.Name, | ||
Model: strings.TrimLeft(fmt.Sprintf("%s %s", | ||
intf.Vendor, intf.Product), " "), | ||
MAC: intf.MACAddress, | ||
IP: ip, | ||
VLANs: vlans, | ||
VLANID: vlanid, | ||
SpeedGbps: getNICSpeedGbps(extradata[intf.Name]), | ||
PXE: baseIntf.PXE, | ||
} | ||
} | ||
return nics | ||
} | ||
|
||
func getStorageDetails(diskdata []introspection.RootDiskType) []metal3v1alpha1.Storage { | ||
storage := make([]metal3v1alpha1.Storage, len(diskdata)) | ||
for i, disk := range diskdata { | ||
storage[i] = metal3v1alpha1.Storage{ | ||
Name: disk.Name, | ||
Rotational: disk.Rotational, | ||
SizeBytes: metal3v1alpha1.Capacity(disk.Size), | ||
Vendor: disk.Vendor, | ||
Model: disk.Model, | ||
SerialNumber: disk.Serial, | ||
WWN: disk.Wwn, | ||
WWNVendorExtension: disk.WwnVendorExtension, | ||
WWNWithExtension: disk.WwnWithExtension, | ||
HCTL: disk.Hctl, | ||
} | ||
} | ||
return storage | ||
} | ||
|
||
func getSystemVendorDetails(vendor introspection.SystemVendorType) metal3v1alpha1.HardwareSystemVendor { | ||
return metal3v1alpha1.HardwareSystemVendor{ | ||
Manufacturer: vendor.Manufacturer, | ||
ProductName: vendor.ProductName, | ||
SerialNumber: vendor.SerialNumber, | ||
} | ||
} | ||
|
||
func getCPUDetails(cpudata *introspection.CPUType) metal3v1alpha1.CPU { | ||
var freq float64 | ||
fmt.Sscanf(cpudata.Frequency, "%f", &freq) | ||
sort.Strings(cpudata.Flags) | ||
cpu := metal3v1alpha1.CPU{ | ||
Arch: cpudata.Architecture, | ||
Model: cpudata.ModelName, | ||
ClockMegahertz: metal3v1alpha1.ClockSpeed(freq) * metal3v1alpha1.MegaHertz, | ||
Count: cpudata.Count, | ||
Flags: cpudata.Flags, | ||
} | ||
|
||
return cpu | ||
} | ||
|
||
func getFirmwareDetails(firmwaredata introspection.ExtraHardwareDataSection) metal3v1alpha1.Firmware { | ||
|
||
// handle bios optionally | ||
var bios metal3v1alpha1.BIOS | ||
|
||
if biosdata, ok := firmwaredata["bios"]; ok { | ||
// we do not know if all fields will be supplied | ||
// as this is not a structured response | ||
// so we must handle each field conditionally | ||
bios.Vendor, _ = biosdata["vendor"].(string) | ||
bios.Version, _ = biosdata["version"].(string) | ||
bios.Date, _ = biosdata["date"].(string) | ||
} | ||
|
||
return metal3v1alpha1.Firmware{ | ||
BIOS: bios, | ||
} | ||
|
||
} |
Oops, something went wrong.