Skip to content

Commit

Permalink
feat(inputs.redfish): Allow specifying with metrics to collect
Browse files Browse the repository at this point in the history
  • Loading branch information
powersj committed Oct 18, 2023
1 parent 7c8200f commit 49f640a
Show file tree
Hide file tree
Showing 4 changed files with 183 additions and 133 deletions.
4 changes: 4 additions & 0 deletions plugins/inputs/redfish/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
## System Id to collect data for in Redfish APIs.
computer_system_id="System.Embedded.1"

## Metrics to collect
## The metric collects to gather. Choose from "power" and "thermal".
# include_metrics = ["power", "thermal"]

## Tag sets allow you to include redfish OData link parent data
## For Example.
## Thermal data is an OData link with parent Chassis which has a link of Location.
Expand Down
301 changes: 168 additions & 133 deletions plugins/inputs/redfish/redfish.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type Redfish struct {
Username string `toml:"username"`
Password string `toml:"password"`
ComputerSystemID string `toml:"computer_system_id"`
IncludeMetrics []string `toml:"include_metrics"`
IncludeTagSets []string `toml:"include_tag_sets"`
Timeout config.Duration `toml:"timeout"`

Expand Down Expand Up @@ -163,6 +164,17 @@ func (r *Redfish) Init() error {
return fmt.Errorf("did not provide the computer system ID of the resource")
}

if len(r.IncludeMetrics) == 0 {
return fmt.Errorf("no metrics specified to collect")
}
for _, metric := range r.IncludeMetrics {
switch metric {
case "thermal", "power":
default:
return fmt.Errorf("unknown metric requested: %s", metric)
}
}

r.tagSet = make(map[string]bool, len(r.IncludeTagSets))
for _, setLabel := range r.IncludeTagSets {
r.tagSet[setLabel] = true
Expand Down Expand Up @@ -295,159 +307,181 @@ func (r *Redfish) Gather(acc telegraf.Accumulator) error {
return err
}

thermal, err := r.getThermal(chassis.Thermal.Ref)
if err != nil {
return err
}

for _, j := range thermal.Temperatures {
tags := map[string]string{}
tags["member_id"] = j.MemberID
tags["address"] = address
tags["name"] = j.Name
tags["source"] = system.Hostname
tags["state"] = j.Status.State
tags["health"] = j.Status.Health
if _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {
tags["datacenter"] = chassis.Location.PostalAddress.DataCenter
tags["room"] = chassis.Location.PostalAddress.Room
tags["rack"] = chassis.Location.Placement.Rack
tags["row"] = chassis.Location.Placement.Row
for _, metric := range r.IncludeMetrics {
var err error
switch metric {
case "thermal":
err = r.gatherThermal(acc, address, system, chassis)
case "power":
err = r.gatherPower(acc, address, system, chassis)
default:
return fmt.Errorf("unknown metric requested: %s", metric)
}
if _, ok := r.tagSet[tagSetChassis]; ok {
setChassisTags(chassis, tags)
if err != nil {
return err
}
}
}
return nil
}

fields := make(map[string]interface{})
fields["reading_celsius"] = j.ReadingCelsius
func (r *Redfish) gatherThermal(acc telegraf.Accumulator, address string, system *System, chassis *Chassis) error {
thermal, err := r.getThermal(chassis.Thermal.Ref)
if err != nil {
return err
}

for _, j := range thermal.Temperatures {
tags := map[string]string{}
tags["member_id"] = j.MemberID
tags["address"] = address
tags["name"] = j.Name
tags["source"] = system.Hostname
tags["state"] = j.Status.State
tags["health"] = j.Status.Health
if _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {
tags["datacenter"] = chassis.Location.PostalAddress.DataCenter
tags["room"] = chassis.Location.PostalAddress.Room
tags["rack"] = chassis.Location.Placement.Rack
tags["row"] = chassis.Location.Placement.Row
}
if _, ok := r.tagSet[tagSetChassis]; ok {
setChassisTags(chassis, tags)
}

fields := make(map[string]interface{})
fields["reading_celsius"] = j.ReadingCelsius
fields["upper_threshold_critical"] = j.UpperThresholdCritical
fields["upper_threshold_fatal"] = j.UpperThresholdFatal
fields["lower_threshold_critical"] = j.LowerThresholdCritical
fields["lower_threshold_fatal"] = j.LowerThresholdFatal
acc.AddFields("redfish_thermal_temperatures", fields, tags)
}

for _, j := range thermal.Fans {
tags := map[string]string{}
fields := make(map[string]interface{})
tags["member_id"] = j.MemberID
tags["address"] = address
tags["name"] = j.Name
tags["source"] = system.Hostname
tags["state"] = j.Status.State
tags["health"] = j.Status.Health
if _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {
tags["datacenter"] = chassis.Location.PostalAddress.DataCenter
tags["room"] = chassis.Location.PostalAddress.Room
tags["rack"] = chassis.Location.Placement.Rack
tags["row"] = chassis.Location.Placement.Row
}
if _, ok := r.tagSet[tagSetChassis]; ok {
setChassisTags(chassis, tags)
}

if j.ReadingUnits != nil && *j.ReadingUnits == "RPM" {
fields["upper_threshold_critical"] = j.UpperThresholdCritical
fields["upper_threshold_fatal"] = j.UpperThresholdFatal
fields["lower_threshold_critical"] = j.LowerThresholdCritical
fields["lower_threshold_fatal"] = j.LowerThresholdFatal
acc.AddFields("redfish_thermal_temperatures", fields, tags)
fields["reading_rpm"] = j.Reading
} else {
fields["reading_percent"] = j.Reading
}
acc.AddFields("redfish_thermal_fans", fields, tags)
}

for _, j := range thermal.Fans {
tags := map[string]string{}
fields := make(map[string]interface{})
tags["member_id"] = j.MemberID
tags["address"] = address
tags["name"] = j.Name
tags["source"] = system.Hostname
tags["state"] = j.Status.State
tags["health"] = j.Status.Health
if _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {
tags["datacenter"] = chassis.Location.PostalAddress.DataCenter
tags["room"] = chassis.Location.PostalAddress.Room
tags["rack"] = chassis.Location.Placement.Rack
tags["row"] = chassis.Location.Placement.Row
}
if _, ok := r.tagSet[tagSetChassis]; ok {
setChassisTags(chassis, tags)
}
return nil
}

if j.ReadingUnits != nil && *j.ReadingUnits == "RPM" {
fields["upper_threshold_critical"] = j.UpperThresholdCritical
fields["upper_threshold_fatal"] = j.UpperThresholdFatal
fields["lower_threshold_critical"] = j.LowerThresholdCritical
fields["lower_threshold_fatal"] = j.LowerThresholdFatal
fields["reading_rpm"] = j.Reading
} else {
fields["reading_percent"] = j.Reading
}
acc.AddFields("redfish_thermal_fans", fields, tags)
}
func (r *Redfish) gatherPower(acc telegraf.Accumulator, address string, system *System, chassis *Chassis) error {
power, err := r.getPower(chassis.Power.Ref)
if err != nil {
return err
}

power, err := r.getPower(chassis.Power.Ref)
if err != nil {
return err
for _, j := range power.PowerControl {
tags := map[string]string{
"member_id": j.MemberID,
"address": address,
"name": j.Name,
"source": system.Hostname,
}
if _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {
tags["datacenter"] = chassis.Location.PostalAddress.DataCenter
tags["room"] = chassis.Location.PostalAddress.Room
tags["rack"] = chassis.Location.Placement.Rack
tags["row"] = chassis.Location.Placement.Row
}
if _, ok := r.tagSet[tagSetChassis]; ok {
setChassisTags(chassis, tags)
}

for _, j := range power.PowerControl {
tags := map[string]string{
"member_id": j.MemberID,
"address": address,
"name": j.Name,
"source": system.Hostname,
}
if _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {
tags["datacenter"] = chassis.Location.PostalAddress.DataCenter
tags["room"] = chassis.Location.PostalAddress.Room
tags["rack"] = chassis.Location.Placement.Rack
tags["row"] = chassis.Location.Placement.Row
}
if _, ok := r.tagSet[tagSetChassis]; ok {
setChassisTags(chassis, tags)
}

fields := map[string]interface{}{
"power_allocated_watts": j.PowerAllocatedWatts,
"power_available_watts": j.PowerAvailableWatts,
"power_capacity_watts": j.PowerCapacityWatts,
"power_consumed_watts": j.PowerConsumedWatts,
"power_requested_watts": j.PowerRequestedWatts,
"average_consumed_watts": j.PowerMetrics.AverageConsumedWatts,
"interval_in_min": j.PowerMetrics.IntervalInMin,
"max_consumed_watts": j.PowerMetrics.MaxConsumedWatts,
"min_consumed_watts": j.PowerMetrics.MinConsumedWatts,
}

acc.AddFields("redfish_power_powercontrol", fields, tags)
fields := map[string]interface{}{
"power_allocated_watts": j.PowerAllocatedWatts,
"power_available_watts": j.PowerAvailableWatts,
"power_capacity_watts": j.PowerCapacityWatts,
"power_consumed_watts": j.PowerConsumedWatts,
"power_requested_watts": j.PowerRequestedWatts,
"average_consumed_watts": j.PowerMetrics.AverageConsumedWatts,
"interval_in_min": j.PowerMetrics.IntervalInMin,
"max_consumed_watts": j.PowerMetrics.MaxConsumedWatts,
"min_consumed_watts": j.PowerMetrics.MinConsumedWatts,
}

for _, j := range power.PowerSupplies {
tags := map[string]string{}
tags["member_id"] = j.MemberID
tags["address"] = address
tags["name"] = j.Name
tags["source"] = system.Hostname
tags["state"] = j.Status.State
tags["health"] = j.Status.Health
if _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {
tags["datacenter"] = chassis.Location.PostalAddress.DataCenter
tags["room"] = chassis.Location.PostalAddress.Room
tags["rack"] = chassis.Location.Placement.Rack
tags["row"] = chassis.Location.Placement.Row
}
if _, ok := r.tagSet[tagSetChassis]; ok {
setChassisTags(chassis, tags)
}
acc.AddFields("redfish_power_powercontrol", fields, tags)
}

fields := make(map[string]interface{})
fields["power_input_watts"] = j.PowerInputWatts
fields["power_output_watts"] = j.PowerOutputWatts
fields["line_input_voltage"] = j.LineInputVoltage
fields["last_power_output_watts"] = j.LastPowerOutputWatts
fields["power_capacity_watts"] = j.PowerCapacityWatts
acc.AddFields("redfish_power_powersupplies", fields, tags)
for _, j := range power.PowerSupplies {
tags := map[string]string{}
tags["member_id"] = j.MemberID
tags["address"] = address
tags["name"] = j.Name
tags["source"] = system.Hostname
tags["state"] = j.Status.State
tags["health"] = j.Status.Health
if _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {
tags["datacenter"] = chassis.Location.PostalAddress.DataCenter
tags["room"] = chassis.Location.PostalAddress.Room
tags["rack"] = chassis.Location.Placement.Rack
tags["row"] = chassis.Location.Placement.Row
}
if _, ok := r.tagSet[tagSetChassis]; ok {
setChassisTags(chassis, tags)
}

for _, j := range power.Voltages {
tags := map[string]string{}
tags["member_id"] = j.MemberID
tags["address"] = address
tags["name"] = j.Name
tags["source"] = system.Hostname
tags["state"] = j.Status.State
tags["health"] = j.Status.Health
if _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {
tags["datacenter"] = chassis.Location.PostalAddress.DataCenter
tags["room"] = chassis.Location.PostalAddress.Room
tags["rack"] = chassis.Location.Placement.Rack
tags["row"] = chassis.Location.Placement.Row
}
if _, ok := r.tagSet[tagSetChassis]; ok {
setChassisTags(chassis, tags)
}
fields := make(map[string]interface{})
fields["power_input_watts"] = j.PowerInputWatts
fields["power_output_watts"] = j.PowerOutputWatts
fields["line_input_voltage"] = j.LineInputVoltage
fields["last_power_output_watts"] = j.LastPowerOutputWatts
fields["power_capacity_watts"] = j.PowerCapacityWatts
acc.AddFields("redfish_power_powersupplies", fields, tags)
}

fields := make(map[string]interface{})
fields["reading_volts"] = j.ReadingVolts
fields["upper_threshold_critical"] = j.UpperThresholdCritical
fields["upper_threshold_fatal"] = j.UpperThresholdFatal
fields["lower_threshold_critical"] = j.LowerThresholdCritical
fields["lower_threshold_fatal"] = j.LowerThresholdFatal
acc.AddFields("redfish_power_voltages", fields, tags)
for _, j := range power.Voltages {
tags := map[string]string{}
tags["member_id"] = j.MemberID
tags["address"] = address
tags["name"] = j.Name
tags["source"] = system.Hostname
tags["state"] = j.Status.State
tags["health"] = j.Status.Health
if _, ok := r.tagSet[tagSetChassisLocation]; ok && chassis.Location != nil {
tags["datacenter"] = chassis.Location.PostalAddress.DataCenter
tags["room"] = chassis.Location.PostalAddress.Room
tags["rack"] = chassis.Location.Placement.Rack
tags["row"] = chassis.Location.Placement.Row
}
if _, ok := r.tagSet[tagSetChassis]; ok {
setChassisTags(chassis, tags)
}

fields := make(map[string]interface{})
fields["reading_volts"] = j.ReadingVolts
fields["upper_threshold_critical"] = j.UpperThresholdCritical
fields["upper_threshold_fatal"] = j.UpperThresholdFatal
fields["lower_threshold_critical"] = j.LowerThresholdCritical
fields["lower_threshold_fatal"] = j.LowerThresholdFatal
acc.AddFields("redfish_power_voltages", fields, tags)
}

return nil
Expand All @@ -458,6 +492,7 @@ func init() {
return &Redfish{
// default tag set of chassis.location required for backwards compatibility
IncludeTagSets: []string{tagSetChassisLocation},
IncludeMetrics: []string{"power", "thermal"},
}
})
}
Loading

0 comments on commit 49f640a

Please sign in to comment.