From 5c5411dba2622015ce341af101b18d1f74737c6e Mon Sep 17 00:00:00 2001 From: Stefan Majer Date: Wed, 2 Oct 2024 13:23:59 +0200 Subject: [PATCH] Allow Powersupply reporting (#578) --- .../datastore/machine_integration_test.go | 4 + cmd/metal-api/internal/metal/machine.go | 32 +++++--- .../internal/service/machine-service.go | 10 +++ cmd/metal-api/internal/service/v1/machine.go | 74 +++++++++++++------ spec/metal-api.json | 40 +++++++++- 5 files changed, 128 insertions(+), 32 deletions(-) diff --git a/cmd/metal-api/internal/datastore/machine_integration_test.go b/cmd/metal-api/internal/datastore/machine_integration_test.go index 643f0f843..b95dc5ffe 100644 --- a/cmd/metal-api/internal/datastore/machine_integration_test.go +++ b/cmd/metal-api/internal/datastore/machine_integration_test.go @@ -120,6 +120,9 @@ func (_ *machineTestable) defaultBody(m *metal.Machine) *metal.Machine { } } } + if m.IPMI.PowerSupplies == nil { + m.IPMI.PowerSupplies = metal.PowerSupplies{} + } return m } @@ -936,6 +939,7 @@ func TestRethinkStore_UpdateMachine(t *testing.T) { want: &metal.Machine{ Base: metal.Base{ID: "1"}, Hardware: metal.MachineHardware{Nics: metal.Nics{}, Disks: []metal.BlockDevice{}, MetalCPUs: []metal.MetalCPU{}, MetalGPUs: []metal.MetalGPU{}}, + IPMI: metal.IPMI{PowerSupplies: metal.PowerSupplies{}}, Tags: []string{"a=b"}, }, }, diff --git a/cmd/metal-api/internal/metal/machine.go b/cmd/metal-api/internal/metal/machine.go index 0f6eabfa3..3226d64b7 100644 --- a/cmd/metal-api/internal/metal/machine.go +++ b/cmd/metal-api/internal/metal/machine.go @@ -564,16 +564,17 @@ type Fru struct { // IPMI connection data type IPMI struct { // Address is host:port of the connection to the ipmi BMC, host can be either a ip address or a hostname - Address string `rethinkdb:"address" json:"address"` - MacAddress string `rethinkdb:"mac" json:"mac"` - User string `rethinkdb:"user" json:"user"` - Password string `rethinkdb:"password" json:"password"` - Interface string `rethinkdb:"interface" json:"interface"` - Fru Fru `rethinkdb:"fru" json:"fru"` - BMCVersion string `rethinkdb:"bmcversion" json:"bmcversion"` - PowerState string `rethinkdb:"powerstate" json:"powerstate"` - PowerMetric *PowerMetric `rethinkdb:"powermetric" json:"powermetric"` - LastUpdated time.Time `rethinkdb:"last_updated" json:"last_updated"` + Address string `rethinkdb:"address" json:"address"` + MacAddress string `rethinkdb:"mac" json:"mac"` + User string `rethinkdb:"user" json:"user"` + Password string `rethinkdb:"password" json:"password"` + Interface string `rethinkdb:"interface" json:"interface"` + Fru Fru `rethinkdb:"fru" json:"fru"` + BMCVersion string `rethinkdb:"bmcversion" json:"bmcversion"` + PowerState string `rethinkdb:"powerstate" json:"powerstate"` + PowerMetric *PowerMetric `rethinkdb:"powermetric" json:"powermetric"` + PowerSupplies PowerSupplies `rethinkdb:"powersupplies" json:"powersupplies"` + LastUpdated time.Time `rethinkdb:"last_updated" json:"last_updated"` } type PowerMetric struct { @@ -596,6 +597,17 @@ type PowerMetric struct { MinConsumedWatts float32 `rethinkdb:"minconsumedwatts" json:"minconsumedwatts"` } +type PowerSupplies []PowerSupply +type PowerSupply struct { + // Status shall contain any status or health properties + // of the resource. + Status PowerSupplyStatus `rethinkdb:"status" json:"status"` +} +type PowerSupplyStatus struct { + Health string `rethinkdb:"health" json:"health"` + State string `rethinkdb:"state" json:"state"` +} + // BIOS contains machine bios information type BIOS struct { Version string `rethinkdb:"version" json:"version"` diff --git a/cmd/metal-api/internal/service/machine-service.go b/cmd/metal-api/internal/service/machine-service.go index a95112188..24570e34f 100644 --- a/cmd/metal-api/internal/service/machine-service.go +++ b/cmd/metal-api/internal/service/machine-service.go @@ -926,6 +926,16 @@ func (r *machineResource) ipmiReport(request *restful.Request, response *restful MinConsumedWatts: report.PowerMetric.MinConsumedWatts, } } + var powerSupplies metal.PowerSupplies + for _, ps := range report.PowerSupplies { + powerSupplies = append(powerSupplies, metal.PowerSupply{ + Status: metal.PowerSupplyStatus{ + Health: ps.Status.Health, + State: ps.Status.State, + }, + }) + } + newMachine.IPMI.PowerSupplies = powerSupplies ledstate, err := metal.LEDStateFrom(report.IndicatorLEDState) if err == nil { diff --git a/cmd/metal-api/internal/service/v1/machine.go b/cmd/metal-api/internal/service/v1/machine.go index 13b924365..5ab288511 100644 --- a/cmd/metal-api/internal/service/v1/machine.go +++ b/cmd/metal-api/internal/service/v1/machine.go @@ -160,16 +160,17 @@ type MachineBIOS struct { } type MachineIPMI struct { - Address string `json:"address" modelDescription:"The IPMI connection data"` - MacAddress string `json:"mac"` - User string `json:"user"` - Password string `json:"password"` - Interface string `json:"interface"` - Fru MachineFru `json:"fru"` - BMCVersion string `json:"bmcversion"` - PowerState string `json:"powerstate"` - PowerMetric *PowerMetric `json:"powermetric"` - LastUpdated time.Time `json:"last_updated"` + Address string `json:"address" modelDescription:"The IPMI connection data"` + MacAddress string `json:"mac"` + User string `json:"user"` + Password string `json:"password"` + Interface string `json:"interface"` + Fru MachineFru `json:"fru"` + BMCVersion string `json:"bmcversion"` + PowerState string `json:"powerstate"` + PowerMetric *PowerMetric `json:"powermetric"` + PowerSupplies PowerSupplies `json:"powersupplies"` + LastUpdated time.Time `json:"last_updated"` } type PowerMetric struct { @@ -191,6 +192,16 @@ type PowerMetric struct { // IntervalInMin minutes. MinConsumedWatts float32 `json:"minconsumedwatts"` } +type PowerSupplies []PowerSupply +type PowerSupply struct { + // Status shall contain any status or health properties + // of the resource. + Status PowerSupplyStatus `json:"status"` +} +type PowerSupplyStatus struct { + Health string `json:"health"` + State string `json:"state"` +} type MachineFru struct { ChassisPartNumber *string `json:"chassis_part_number,omitempty" modelDescription:"The Field Replaceable Unit data" description:"the chassis part number" optional:"true"` @@ -270,6 +281,7 @@ type MachineIpmiReport struct { PowerState string IndicatorLEDState string PowerMetric *PowerMetric + PowerSupplies PowerSupplies } type MachineIpmiReports struct { @@ -362,6 +374,15 @@ func NewMetalIPMI(r *MachineIPMI) metal.IPMI { MinConsumedWatts: r.PowerMetric.MinConsumedWatts, } } + var powerSupplies metal.PowerSupplies + for _, ps := range r.PowerSupplies { + powerSupplies = append(powerSupplies, metal.PowerSupply{ + Status: metal.PowerSupplyStatus{ + Health: ps.Status.Health, + State: ps.Status.State, + }, + }) + } return metal.IPMI{ Address: r.Address, @@ -381,8 +402,9 @@ func NewMetalIPMI(r *MachineIPMI) metal.IPMI { ProductPartNumber: productPartNumber, ProductSerial: productSerial, }, - PowerState: r.PowerState, - PowerMetric: powerMetric, + PowerState: r.PowerState, + PowerMetric: powerMetric, + PowerSupplies: powerSupplies, } } @@ -398,20 +420,30 @@ func NewMachineIPMIResponse(m *metal.Machine, s *metal.Size, p *metal.Partition, MinConsumedWatts: m.IPMI.PowerMetric.MinConsumedWatts, } } + var powerSupplies PowerSupplies + for _, ps := range m.IPMI.PowerSupplies { + powerSupplies = append(powerSupplies, PowerSupply{ + Status: PowerSupplyStatus{ + Health: ps.Status.Health, + State: ps.Status.State, + }, + }) + } return &MachineIPMIResponse{ Common: machineResponse.Common, MachineBase: machineResponse.MachineBase, IPMI: MachineIPMI{ - Address: m.IPMI.Address, - MacAddress: m.IPMI.MacAddress, - User: m.IPMI.User, - Password: m.IPMI.Password, - Interface: m.IPMI.Interface, - BMCVersion: m.IPMI.BMCVersion, - PowerState: m.IPMI.PowerState, - PowerMetric: powerMetric, - LastUpdated: m.IPMI.LastUpdated, + Address: m.IPMI.Address, + MacAddress: m.IPMI.MacAddress, + User: m.IPMI.User, + Password: m.IPMI.Password, + Interface: m.IPMI.Interface, + BMCVersion: m.IPMI.BMCVersion, + PowerState: m.IPMI.PowerState, + PowerMetric: powerMetric, + PowerSupplies: powerSupplies, + LastUpdated: m.IPMI.LastUpdated, Fru: MachineFru{ ChassisPartNumber: &m.IPMI.Fru.ChassisPartNumber, ChassisPartSerial: &m.IPMI.Fru.ChassisPartSerial, diff --git a/spec/metal-api.json b/spec/metal-api.json index b929e738d..d73f9e059 100644 --- a/spec/metal-api.json +++ b/spec/metal-api.json @@ -2658,6 +2658,12 @@ "powerstate": { "type": "string" }, + "powersupplies": { + "items": { + "$ref": "#/definitions/v1.PowerSupply" + }, + "type": "array" + }, "user": { "type": "string" } @@ -2672,6 +2678,7 @@ "password", "powermetric", "powerstate", + "powersupplies", "user" ] }, @@ -2790,6 +2797,12 @@ }, "PowerState": { "type": "string" + }, + "PowerSupplies": { + "items": { + "$ref": "#/definitions/v1.PowerSupply" + }, + "type": "array" } }, "required": [ @@ -2799,7 +2812,8 @@ "FRU", "IndicatorLEDState", "PowerMetric", - "PowerState" + "PowerState", + "PowerSupplies" ] }, "v1.MachineIpmiReportResponse": { @@ -4241,6 +4255,30 @@ "minconsumedwatts" ] }, + "v1.PowerSupply": { + "properties": { + "status": { + "$ref": "#/definitions/v1.PowerSupplyStatus" + } + }, + "required": [ + "status" + ] + }, + "v1.PowerSupplyStatus": { + "properties": { + "health": { + "type": "string" + }, + "state": { + "type": "string" + } + }, + "required": [ + "health", + "state" + ] + }, "v1.Project": { "properties": { "description": {