fix(inputs.redfish): Resolve iLO4 fan data (#14659)
This commit is contained in:
parent
ea35666b27
commit
d8dc29be85
|
|
@ -42,6 +42,11 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||||
## Available sets are: "chassis.location" and "chassis"
|
## Available sets are: "chassis.location" and "chassis"
|
||||||
# include_tag_sets = ["chassis.location"]
|
# include_tag_sets = ["chassis.location"]
|
||||||
|
|
||||||
|
## Workarounds
|
||||||
|
## Defines workarounds for certain hardware vendors. Choose from:
|
||||||
|
## * ilo4-thermal - Do not pass 0Data-Version header to Thermal endpoint
|
||||||
|
# workarounds = []
|
||||||
|
|
||||||
## Amount of time allowed to complete the HTTP request
|
## Amount of time allowed to complete the HTTP request
|
||||||
# timeout = "5s"
|
# timeout = "5s"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
|
"slices"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
"github.com/influxdata/telegraf"
|
||||||
|
|
@ -28,6 +30,7 @@ type Redfish struct {
|
||||||
ComputerSystemID string `toml:"computer_system_id"`
|
ComputerSystemID string `toml:"computer_system_id"`
|
||||||
IncludeMetrics []string `toml:"include_metrics"`
|
IncludeMetrics []string `toml:"include_metrics"`
|
||||||
IncludeTagSets []string `toml:"include_tag_sets"`
|
IncludeTagSets []string `toml:"include_tag_sets"`
|
||||||
|
Workarounds []string `toml:"workarounds"`
|
||||||
Timeout config.Duration `toml:"timeout"`
|
Timeout config.Duration `toml:"timeout"`
|
||||||
|
|
||||||
tagSet map[string]bool
|
tagSet map[string]bool
|
||||||
|
|
@ -111,6 +114,8 @@ type Thermal struct {
|
||||||
Fans []struct {
|
Fans []struct {
|
||||||
Name string
|
Name string
|
||||||
MemberID string
|
MemberID string
|
||||||
|
FanName string
|
||||||
|
CurrentReading *int64
|
||||||
Reading *int64
|
Reading *int64
|
||||||
ReadingUnits *string
|
ReadingUnits *string
|
||||||
UpperThresholdCritical *int64
|
UpperThresholdCritical *int64
|
||||||
|
|
@ -175,6 +180,13 @@ func (r *Redfish) Init() error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, workaround := range r.Workarounds {
|
||||||
|
switch workaround {
|
||||||
|
case "ilo4-thermal":
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown workaround requested: %s", workaround)
|
||||||
|
}
|
||||||
|
}
|
||||||
r.tagSet = make(map[string]bool, len(r.IncludeTagSets))
|
r.tagSet = make(map[string]bool, len(r.IncludeTagSets))
|
||||||
for _, setLabel := range r.IncludeTagSets {
|
for _, setLabel := range r.IncludeTagSets {
|
||||||
r.tagSet[setLabel] = true
|
r.tagSet[setLabel] = true
|
||||||
|
|
@ -212,6 +224,12 @@ func (r *Redfish) getData(address string, payload interface{}) error {
|
||||||
req.Header.Set("Accept", "application/json")
|
req.Header.Set("Accept", "application/json")
|
||||||
req.Header.Set("Content-Type", "application/json")
|
req.Header.Set("Content-Type", "application/json")
|
||||||
req.Header.Set("OData-Version", "4.0")
|
req.Header.Set("OData-Version", "4.0")
|
||||||
|
|
||||||
|
// workaround for iLO4 thermal data
|
||||||
|
if slices.Contains(r.Workarounds, "ilo4-thermal") && strings.Contains(address, "/Thermal") {
|
||||||
|
req.Header.Del("OData-Version")
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := r.client.Do(req)
|
resp, err := r.client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
|
@ -364,6 +382,9 @@ func (r *Redfish) gatherThermal(acc telegraf.Accumulator, address string, system
|
||||||
tags["member_id"] = j.MemberID
|
tags["member_id"] = j.MemberID
|
||||||
tags["address"] = address
|
tags["address"] = address
|
||||||
tags["name"] = j.Name
|
tags["name"] = j.Name
|
||||||
|
if j.FanName != "" {
|
||||||
|
tags["name"] = j.FanName
|
||||||
|
}
|
||||||
tags["source"] = system.Hostname
|
tags["source"] = system.Hostname
|
||||||
tags["state"] = j.Status.State
|
tags["state"] = j.Status.State
|
||||||
tags["health"] = j.Status.Health
|
tags["health"] = j.Status.Health
|
||||||
|
|
@ -383,6 +404,8 @@ func (r *Redfish) gatherThermal(acc telegraf.Accumulator, address string, system
|
||||||
fields["lower_threshold_critical"] = j.LowerThresholdCritical
|
fields["lower_threshold_critical"] = j.LowerThresholdCritical
|
||||||
fields["lower_threshold_fatal"] = j.LowerThresholdFatal
|
fields["lower_threshold_fatal"] = j.LowerThresholdFatal
|
||||||
fields["reading_rpm"] = j.Reading
|
fields["reading_rpm"] = j.Reading
|
||||||
|
} else if j.CurrentReading != nil {
|
||||||
|
fields["reading_percent"] = j.CurrentReading
|
||||||
} else {
|
} else {
|
||||||
fields["reading_percent"] = j.Reading
|
fields["reading_percent"] = j.Reading
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -616,6 +616,103 @@ func TestHPApis(t *testing.T) {
|
||||||
testutil.IgnoreTime())
|
testutil.IgnoreTime())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHPilo4Apis(t *testing.T) {
|
||||||
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if !checkAuth(r, "test", "test") {
|
||||||
|
http.Error(w, "Unauthorized.", 401)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
switch r.URL.Path {
|
||||||
|
case "/redfish/v1/Chassis/1/Thermal":
|
||||||
|
http.ServeFile(w, r, "testdata/hp_thermal_ilo4.json")
|
||||||
|
case "/redfish/v1/Chassis/1/Power":
|
||||||
|
http.ServeFile(w, r, "testdata/hp_power.json")
|
||||||
|
case "/redfish/v1/Systems/1":
|
||||||
|
http.ServeFile(w, r, "testdata/hp_systems.json")
|
||||||
|
case "/redfish/v1/Chassis/1/":
|
||||||
|
http.ServeFile(w, r, "testdata/hp_chassis.json")
|
||||||
|
default:
|
||||||
|
w.WriteHeader(http.StatusNotFound)
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
|
||||||
|
defer ts.Close()
|
||||||
|
|
||||||
|
u, err := url.Parse(ts.URL)
|
||||||
|
require.NoError(t, err)
|
||||||
|
address, _, err := net.SplitHostPort(u.Host)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
expectedMetricsHp := []telegraf.Metric{
|
||||||
|
testutil.MustMetric(
|
||||||
|
"redfish_thermal_temperatures",
|
||||||
|
map[string]string{
|
||||||
|
"name": "01-Inlet Ambient",
|
||||||
|
"member_id": "0",
|
||||||
|
"source": "tpa-hostname",
|
||||||
|
"address": address,
|
||||||
|
"health": "OK",
|
||||||
|
"state": "Enabled",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"reading_celsius": 19.0,
|
||||||
|
"upper_threshold_critical": 42.0,
|
||||||
|
"upper_threshold_fatal": 47.0,
|
||||||
|
},
|
||||||
|
time.Unix(0, 0),
|
||||||
|
),
|
||||||
|
testutil.MustMetric(
|
||||||
|
"redfish_thermal_temperatures",
|
||||||
|
map[string]string{
|
||||||
|
"name": "44-P/S 2 Zone",
|
||||||
|
"member_id": "42",
|
||||||
|
"source": "tpa-hostname",
|
||||||
|
"address": address,
|
||||||
|
"health": "OK",
|
||||||
|
"state": "Enabled",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"reading_celsius": 34.0,
|
||||||
|
"upper_threshold_critical": 75.0,
|
||||||
|
"upper_threshold_fatal": 80.0,
|
||||||
|
},
|
||||||
|
time.Unix(0, 0),
|
||||||
|
),
|
||||||
|
testutil.MustMetric(
|
||||||
|
"redfish_thermal_fans",
|
||||||
|
map[string]string{
|
||||||
|
"address": address,
|
||||||
|
"health": "OK",
|
||||||
|
"member_id": "",
|
||||||
|
"name": "Fan 1",
|
||||||
|
"source": "tpa-hostname",
|
||||||
|
"state": "Enabled",
|
||||||
|
},
|
||||||
|
map[string]interface{}{
|
||||||
|
"reading_percent": 17,
|
||||||
|
},
|
||||||
|
time.Unix(0, 0),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
hpPlugin := &Redfish{
|
||||||
|
Address: ts.URL,
|
||||||
|
Username: "test",
|
||||||
|
Password: "test",
|
||||||
|
ComputerSystemID: "1",
|
||||||
|
IncludeMetrics: []string{"thermal"},
|
||||||
|
}
|
||||||
|
require.NoError(t, hpPlugin.Init())
|
||||||
|
var hpAcc testutil.Accumulator
|
||||||
|
|
||||||
|
err = hpPlugin.Gather(&hpAcc)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, hpAcc.HasMeasurement("redfish_thermal_temperatures"))
|
||||||
|
testutil.RequireMetricsEqual(t, expectedMetricsHp, hpAcc.GetTelegrafMetrics(),
|
||||||
|
testutil.IgnoreTime())
|
||||||
|
}
|
||||||
|
|
||||||
func checkAuth(r *http.Request, username, password string) bool {
|
func checkAuth(r *http.Request, username, password string) bool {
|
||||||
user, pass, ok := r.BasicAuth()
|
user, pass, ok := r.BasicAuth()
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,11 @@
|
||||||
## Available sets are: "chassis.location" and "chassis"
|
## Available sets are: "chassis.location" and "chassis"
|
||||||
# include_tag_sets = ["chassis.location"]
|
# include_tag_sets = ["chassis.location"]
|
||||||
|
|
||||||
|
## Workarounds
|
||||||
|
## Defines workarounds for certain hardware vendors. Choose from:
|
||||||
|
## * ilo4-thermal - Do not pass 0Data-Version header to Thermal endpoint
|
||||||
|
# workarounds = []
|
||||||
|
|
||||||
## Amount of time allowed to complete the HTTP request
|
## Amount of time allowed to complete the HTTP request
|
||||||
# timeout = "5s"
|
# timeout = "5s"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,72 @@
|
||||||
|
{
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#Thermal.Thermal",
|
||||||
|
"@odata.etag": "W/\"14E8662D\"",
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/1/Thermal",
|
||||||
|
"@odata.type": "#Thermal.v1_1_0.Thermal",
|
||||||
|
"Id": "Thermal",
|
||||||
|
"Fans": [
|
||||||
|
{
|
||||||
|
"CurrentReading": 17,
|
||||||
|
"FanName": "Fan 1",
|
||||||
|
"Oem": {
|
||||||
|
"Hp": {
|
||||||
|
"@odata.type": "#HpServerFan.1.0.0.HpServerFan",
|
||||||
|
"Location": "System",
|
||||||
|
"Type": "HpServerFan.1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Status": {
|
||||||
|
"Health": "OK",
|
||||||
|
"State": "Enabled"
|
||||||
|
},
|
||||||
|
"Units": "Percent"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Name": "Thermal",
|
||||||
|
"Temperatures": [
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/1/Thermal#Temperatures/0",
|
||||||
|
"MemberId": "0",
|
||||||
|
"Name": "01-Inlet Ambient",
|
||||||
|
"Oem": {
|
||||||
|
"Hpe": {
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#HpeSeaOfSensors.HpeSeaOfSensors",
|
||||||
|
"@odata.type": "#HpeSeaOfSensors.v2_0_0.HpeSeaOfSensors",
|
||||||
|
"LocationXmm": 15,
|
||||||
|
"LocationYmm": 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PhysicalContext": "Intake",
|
||||||
|
"ReadingCelsius": 19,
|
||||||
|
"SensorNumber": 1,
|
||||||
|
"Status": {
|
||||||
|
"Health": "OK",
|
||||||
|
"State": "Enabled"
|
||||||
|
},
|
||||||
|
"UpperThresholdCritical": 42,
|
||||||
|
"UpperThresholdFatal": 47
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"@odata.id": "/redfish/v1/Chassis/1/Thermal#Temperatures/42",
|
||||||
|
"MemberId": "42",
|
||||||
|
"Name": "44-P/S 2 Zone",
|
||||||
|
"Oem": {
|
||||||
|
"Hpe": {
|
||||||
|
"@odata.context": "/redfish/v1/$metadata#HpeSeaOfSensors.HpeSeaOfSensors",
|
||||||
|
"@odata.type": "#HpeSeaOfSensors.v2_0_0.HpeSeaOfSensors",
|
||||||
|
"LocationXmm": 4,
|
||||||
|
"LocationYmm": 7
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"PhysicalContext": "PowerSupply",
|
||||||
|
"ReadingCelsius": 34,
|
||||||
|
"SensorNumber": 43,
|
||||||
|
"Status": {
|
||||||
|
"Health": "OK",
|
||||||
|
"State": "Enabled"
|
||||||
|
},
|
||||||
|
"UpperThresholdCritical": 75,
|
||||||
|
"UpperThresholdFatal": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue