Skip to content

Commit

Permalink
Merge pull request #87 from EgorLu/hardware-details-4.4
Browse files Browse the repository at this point in the history
[release-4.4] Bug 1840106: Backport get-hardware-details
  • Loading branch information
openshift-merge-robot committed Jul 30, 2020
2 parents 7638257 + cf402e5 commit e27e67f
Show file tree
Hide file tree
Showing 7 changed files with 473 additions and 404 deletions.
2 changes: 2 additions & 0 deletions Dockerfile
Expand Up @@ -2,7 +2,9 @@ FROM registry.svc.ci.openshift.org/openshift/release:golang-1.10 AS builder
WORKDIR /go/src/github.com/metal3-io/baremetal-operator
COPY . .
RUN make build
RUN make tools

FROM registry.svc.ci.openshift.org/openshift/origin-v4.0:base
COPY --from=builder /go/src/github.com/metal3-io/baremetal-operator/build/_output/bin/baremetal-operator /
COPY --from=builder /go/src/github.com/metal3-io/baremetal-operator/build/_output/bin/get-hardware-details /
RUN if ! rpm -q genisoimage; then yum install -y genisoimage && yum clean all && rm -rf /var/cache/yum/*; fi
5 changes: 5 additions & 0 deletions Makefile
Expand Up @@ -122,6 +122,11 @@ build:
@echo LDFLAGS=$(LDFLAGS)
go build -o build/_output/bin/baremetal-operator cmd/manager/main.go

.PHONY: tools
tools:
@echo LDFLAGS=$(LDFLAGS)
go build -o build/_output/bin/get-hardware-details cmd/get-hardware-details/main.go

.PHONY: deploy
deploy:
cd deploy && kustomize edit set namespace $(RUN_NAMESPACE) && cd ..
Expand Down
44 changes: 44 additions & 0 deletions cmd/get-hardware-details/main.go
@@ -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 pkg/provisioner/ironic/hardwaredetails/hardwaredetails.go
@@ -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,
}

}

0 comments on commit e27e67f

Please sign in to comment.