Skip to content
4 changes: 4 additions & 0 deletions bmc/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import (
"github.com/hashicorp/go-multierror"
)

var (
ErrOpenConnection = errors.New("error opening connection")
)

// Opener interface for opening a connection to a BMC
type Opener interface {
Open(ctx context.Context) error
Expand Down
210 changes: 210 additions & 0 deletions bmc/sensors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
package bmc

import (
"context"
"errors"
"fmt"

"github.com/bmc-toolbox/bmclib/devices"
"github.com/hashicorp/go-multierror"
)

// PowerSensorsGetter retrieves power consumption values
type PowerSensorsGetter interface {
PowerSensors(ctx context.Context) ([]*devices.PowerSensor, error)
}

// TemperatureSensorGetter retrieves temperature values
type TemperatureSensorsGetter interface {
TemperatureSensors(ctx context.Context) ([]*devices.TemperatureSensor, error)
}

// FanSensorsGetter retrieves fan speed data
type FanSensorsGetter interface {
FanSensors(ctx context.Context) ([]*devices.FanSensor, error)
}

// ChassisHealthGetter retrieves chassis health data
type ChassisHealthGetter interface {
ChassisHealth(ctx context.Context) ([]*devices.ChassisHealth, error)
}

// PowerGetter interface implementation identifier and passthrough methods

// GetPowerSensors returns power draw data, trying all interface implementations passed in
func GetPowerSensors(ctx context.Context, p []PowerSensorsGetter) (power []*devices.PowerSensor, err error) {
Loop:
for _, elem := range p {
if elem == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
break Loop
default:
power, vErr := elem.PowerSensors(ctx)
if vErr != nil {
err = multierror.Append(err, vErr)
continue
}
return power, nil
}
}

return power, multierror.Append(err, errors.New("failed to get power sensor data"))
}

// GetPowerSensorsFromInterfaces identfies implementations of the PowerSensorGetter interface and acts as a pass through method
func GetPowerSensorsFromInterfaces(ctx context.Context, generic []interface{}) (power []*devices.PowerSensor, err error) {
powerDrawGetter := make([]PowerSensorsGetter, 0)
for _, elem := range generic {
switch p := elem.(type) {
case PowerSensorsGetter:
powerDrawGetter = append(powerDrawGetter, p)
default:
e := fmt.Sprintf("not a PowerSensorGetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(powerDrawGetter) == 0 {
return power, multierror.Append(err, errors.New("no PowerSensorGetter implementations found"))
}

return GetPowerSensors(ctx, powerDrawGetter)
}

// TemperatureSensorsGetter interface identifier and passthrough methods

// GetTemperatureSensors returns temperature data, trying all interface implementations passed in
func GetTemperatureSensors(ctx context.Context, p []TemperatureSensorsGetter) (temps []*devices.TemperatureSensor, err error) {
Loop:
for _, elem := range p {
if elem == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
break Loop
default:
temps, vErr := elem.TemperatureSensors(ctx)
if vErr != nil {
err = multierror.Append(err, vErr)
continue
}
return temps, nil
}
}

return temps, multierror.Append(err, errors.New("failed to get temperature sensor data"))
}

// GetTemperatureSensorsFromInterfaces identfies implementations of the TemperatureGetter interface and acts as a pass through method
func GetTemperatureSensorsFromInterfaces(ctx context.Context, generic []interface{}) (temps []*devices.TemperatureSensor, err error) {
gets := make([]TemperatureSensorsGetter, 0)
for _, elem := range generic {
switch p := elem.(type) {
case TemperatureSensorsGetter:
gets = append(gets, p)
default:
e := fmt.Sprintf("not a TemperatureGetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(gets) == 0 {
return temps, multierror.Append(err, errors.New("no TemperatureGetter implementations found"))
}

return GetTemperatureSensors(ctx, gets)
}

// FanSensorsGetter interface identifier and passthrough methods

// GetFanSensors returns fan speed data, trying all interface implementations passed in
func GetFanSensors(ctx context.Context, p []FanSensorsGetter) (fanSensors []*devices.FanSensor, err error) {
Loop:
for _, elem := range p {
if elem == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
break Loop
default:
fanSensors, vErr := elem.FanSensors(ctx)
if vErr != nil {
err = multierror.Append(err, vErr)
continue
}
return fanSensors, nil
}
}

return fanSensors, multierror.Append(err, errors.New("failed to get fan sensor data"))
}

// GetFanSensorsFromInterfaces identfies implementations of the FanSpeedGetter interface and acts as a pass through method
func GetFanSensorsFromInterfaces(ctx context.Context, generic []interface{}) (fanSensors []*devices.FanSensor, err error) {
gets := make([]FanSensorsGetter, 0)
for _, elem := range generic {
switch p := elem.(type) {
case FanSensorsGetter:
gets = append(gets, p)
default:
e := fmt.Sprintf("not a FanSensorGetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(gets) == 0 {
return fanSensors, multierror.Append(err, errors.New("no FanSensorGetter implementations found"))
}

return GetFanSensors(ctx, gets)
}

// ChassisHealthGetter interface identifier and passthrough methods

// GetChassisHealth gets all chassis health data, trying all interface implementations passed in
func GetChassisHealth(ctx context.Context, p []ChassisHealthGetter) (health []*devices.ChassisHealth, err error) {
Loop:
for _, elem := range p {
if elem == nil {
continue
}
select {
case <-ctx.Done():
err = multierror.Append(err, ctx.Err())
break Loop
default:
health, vErr := elem.ChassisHealth(ctx)
if vErr != nil {
err = multierror.Append(err, vErr)
continue
}
return health, nil
}
}

return health, multierror.Append(err, errors.New("failed to get chassis health"))
}

// GetChassisHealthFromInterfaces identfies implementations of the ChassisHealthGetter interface and acts as a pass through method
func GetChassisHealthFromInterfaces(ctx context.Context, generic []interface{}) (health []*devices.ChassisHealth, err error) {
gets := make([]ChassisHealthGetter, 0)
for _, elem := range generic {
switch p := elem.(type) {
case ChassisHealthGetter:
gets = append(gets, p)
default:
e := fmt.Sprintf("not a ChassisHealthGetter implementation: %T", p)
err = multierror.Append(err, errors.New(e))
}
}
if len(gets) == 0 {
return health, multierror.Append(err, errors.New("no FanSensorGetter implementations found"))
}

return GetChassisHealth(ctx, gets)
}
21 changes: 21 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"sync"

"github.com/bmc-toolbox/bmclib/bmc"
"github.com/bmc-toolbox/bmclib/devices"
"github.com/bmc-toolbox/bmclib/providers/asrockrack"
"github.com/bmc-toolbox/bmclib/providers/dell/idrac9"
"github.com/bmc-toolbox/bmclib/providers/goipmi"
Expand Down Expand Up @@ -221,3 +222,23 @@ func (c *Client) GetBIOSVersion(ctx context.Context) (version string, err error)
func (c *Client) UpdateBIOSFirmware(ctx context.Context, fileReader io.Reader, fileSize int64) (err error) {
return bmc.UpdateBIOSFirmwareFromInterfaces(ctx, fileReader, fileSize, c.Registry.GetDriverInterfaces())
}

// GetPowerSensors pass through library function
func (c *Client) GetPowerSensors(ctx context.Context) (sensors []*devices.PowerSensor, err error) {
return bmc.GetPowerSensorsFromInterfaces(ctx, c.Registry.GetDriverInterfaces())
}

// GetTemperatureSensors pass through library function
func (c *Client) GetTemperatureSensors(ctx context.Context) (sensors []*devices.TemperatureSensor, err error) {
return bmc.GetTemperatureSensorsFromInterfaces(ctx, c.Registry.GetDriverInterfaces())
}

// GetFanSensors pass through library function
func (c *Client) GetFanSensors(ctx context.Context) (sensors []*devices.FanSensor, err error) {
return bmc.GetFanSensorsFromInterfaces(ctx, c.Registry.GetDriverInterfaces())
}

// GetChassisHealth pass through library function
func (c *Client) GetChassisHealth(ctx context.Context) (health []*devices.ChassisHealth, err error) {
return bmc.GetChassisHealthFromInterfaces(ctx, c.Registry.GetDriverInterfaces())
}
30 changes: 30 additions & 0 deletions devices/sensors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package devices

type PowerSensor struct {
ID string
Name string
InputWatts float32
OutputWatts float32
LastOutputWatts float32
}

type TemperatureSensor struct {
ID string
Name string
ReadingCelsius float32
PhysicalContext string
}

type FanSensor struct {
ID string
Name string
Reading float32
PhysicalContext string
}

type ChassisHealth struct {
ID string
Name string
State string
Health string
}
63 changes: 63 additions & 0 deletions examples/v1/sensors/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package main

import (
"context"
"fmt"
"log"
"time"

"github.com/bmc-toolbox/bmclib"
"github.com/bombsimon/logrusr"
"github.com/sirupsen/logrus"
)

func main() {
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
defer cancel()
host := ""
port := ""
user := ""
pass := ""

l := logrus.New()
l.Level = logrus.DebugLevel
logger := logrusr.NewLogger(l)

var err error

cl := bmclib.NewClient(host, port, user, pass, bmclib.WithLogger(logger))
cl.Registry.Drivers = cl.Registry.Using("redfish")
err = cl.Open(ctx)
if err != nil {
log.Fatal(err, "bmc login failed")
}

p, err := cl.GetPowerSensors(ctx)
if err != nil {
fmt.Println(err, "unable to retrieve power sensor data")
}

fmt.Printf("%+v\n", p)

t, err := cl.GetTemperatureSensors(ctx)
if err != nil {
fmt.Println(err, "unable to retrieve temperature sensor data")
}

fmt.Printf("%+v\n", t)

f, err := cl.GetFanSensors(ctx)
if err != nil {
fmt.Println(err, "unable to retrieve fan sensor data")
}

fmt.Printf("%+v\n", f)

c, err := cl.GetChassisHealth(ctx)
if err != nil {
fmt.Println(err, "unable to retrieve chassis health data")
}

fmt.Printf("%+v\n", c)

}
8 changes: 8 additions & 0 deletions providers/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,12 @@ const (
FeatureBmcFirmwareUpdate registrar.Feature = "bmcfirwareupdate"
// FeatureBiosFirmwareUpdate means an implementation that updates the BIOS firmware
FeatureBiosFirmwareUpdate registrar.Feature = "biosfirwareupdate"
// FeaturePowersensors indicates an implementation that returns Power sensor information
FeaturePowerSensors registrar.Feature = "powersensors"
// FeatureTemperatureSensors indicates an implementation that returns Temperature sensor information
FeatureTemperatureSensors registrar.Feature = "temperaturesensors"
// FeatureFanSensors indicates an implementation that returns Fan sensor information
FeatureFanSensors registrar.Feature = "fansensors"
// FeatureChassisHealth indicates an implementation that returns ChassisHealth information
FeatureChassisHealth registrar.Feature = "chassishealth"
)
Loading