Skip to content

Commit

Permalink
Add a plugin to get information from ipmitool
Browse files Browse the repository at this point in the history
- get_all_sensors: run `ipmitool sdr list`
    - returns a JSON string with all sensors
- get_sensor: run `ipmitool sdr get <sensor>`
    - returns details about sensors passed as parameter
- get_ipmi_ip: returns the IP of the IPMI server as a string

Signed-off-by: Guillaume <[email protected]>
  • Loading branch information
gthvn1 committed Sep 5, 2024
1 parent 155fa07 commit 48b3e6f
Show file tree
Hide file tree
Showing 2 changed files with 117 additions and 0 deletions.
45 changes: 45 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,51 @@ $ xe host-call-plugin host-uuid=<uuid> plugin=hyperthreading.py fn=get_hyperthre
true
```

## Ipmitool

A xapi plugin that uses `ipmitool` to get information about sensors and the ipmi server.

### get sensor data

Returns a JSON containing all sensor data repository entries and readings.
```
$ xe host-call-plugin host-uuid=<uuid> plugin=ipmitool.py fn=get_all_sensors
[
{"name": "Fan1A", "value": "10920 RPM", "event": "ok"},
{"name": "Fan2A", "value": "10800 RPM", "event": "ok"},
{"name": "Inlet Temp", "value": "23 degrees C", "event": "ok"},
{"name": "Exhaust Temp", "value": "28 degrees C", "event": "ok"},
{"name": "Temp", "value": "38 degrees C", "event": "ok"}
{"name": "PFault Fail Safe", "value": "Not Readable", "event": "ns"}
]
```

### get sensor details

Returns a JSON containing detailed information about sensor passed as paramaters. The name of the sensor can be found
by running the `get_all_sensors` before.
```
$ xe host-call-plugin host-uuid=<uuid> plugin=ipmitool.py fn=get_sensor args:sensors="Fan7B,Inlet Temp"
[
{
"name": "Fan7B",
"info": [{"name": "Sensor ID", "value": "Fan7B (0x3d)"}, {"name": "Entity ID", "value": "7.1 (System Board)"}, {"name": "Sensor Type (Threshold)", "value": "Fan (0x04)"}, {"name": "Sensor Reading", "value": "10320 (+/- 120) RPM"}, {"name": "Status", "value": "ok"}, {"name": "Nominal Reading", "value": "6720.000"}, {"name": "Normal Minimum", "value": "16680.000"}, {"name": "Normal Maximum", "value": "23640.000"}, {"name": "Lower critical", "value": "720.000"}, {"name": "Lower non-critical", "value": "840.000"}, {"name": "Positive Hysteresis", "value": "120.000"}, {"name": "Negative Hysteresis", "value": "120.000"}, {"name": "Minimum sensor range", "value": "Unspecified"}, {"name": "Maximum sensor range", "value": "Unspecified"}, {"name": "Event Message Control", "value": "Per-threshold"}, {"name": "Readable Thresholds", "value": "lcr lnc"}, {"name": "Settable Thresholds", "value": ""}, {"name": "Threshold Read Mask", "value": "lcr lnc"}, {"name": "Assertion Events", "value": ""}, {"name": "Assertions Enabled", "value": "lnc- lcr-"}, {"name": "Deassertions Enabled", "value": "lnc- lcr-"}]
},
{
"name": "PFault Fail Safe",
"info": [{"name": "Sensor ID", "value": "PFault Fail Safe (0x66)"}, {"name": "Entity ID", "value": "7.1 (System Board)"}, {"name": "Sensor Type (Discrete)", "value": "Voltage (0x02)"}, {"name": "Sensor Reading", "value": "No Reading"}, {"name": "Event Message Control", "value": "Per-threshold"}, {"name": "OEM", "value": "0"}]
}
]
```

### get the IP address of the IPMI server

Returns a string with the IP of the IPMI server or an empty string if it is not found.
```
$ xe host-call-plugin host-uuid=<uuid> plugin=ipmitool.py fn=get_ipmi_ip
1.2.3.4
```

## Tests

To run the plugins' unit tests you'll need to install `pytest`, `pyfakefs` and `mock`.
Expand Down
72 changes: 72 additions & 0 deletions SOURCES/etc/xapi.d/plugins/ipmitool.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import json
import sys
import XenAPIPlugin

sys.path.append('.')
from xcpngutils import configure_logging, run_command, error_wrapped

@error_wrapped
def sensor_data(session, args):
sensor_data = []
output = run_command(["ipmitool", "sdr", "list"])

for line in output['stdout'].splitlines():
sensor_fields = line.split('|')
sensor_data.append({
'name': sensor_fields[0].strip(),
'value': sensor_fields[1].strip(),
'event': sensor_fields[2].strip(),
})

return json.dumps(sensor_data)

@error_wrapped
def sensor_info(session, args):
sensors_info = []
sensors = args.get('sensors')

if not sensors:
return '{}'

for sensor in sensors.split(','):
sensor = sensor.strip()
info = []
output = run_command(["ipmitool", "sdr", "get", sensor])
for line in output['stdout'].splitlines():
if ":" not in line:
continue
name, value = line.split(":", 1)
info.append({
"name": name.strip(),
"value": value.strip(),
})

sensors_info.append({
"name": sensor,
"info": info,
})

return json.dumps(sensors_info)

@error_wrapped
def ipmi_ip(session, args):
ip_addr = ""
output = run_command(["ipmitool", "lan", "print"])

for line in output['stdout'].splitlines():
if "IP Address" in line and "Source" not in line:
ip_addr = line.split(":")[1].strip()
break

return ip_addr

_LOGGER = configure_logging('ipmitool-xapi-plugin')
if __name__ == "__main__":
XenAPIPlugin.dispatch({
'get_all_sensors': sensor_data,
'get_sensor': sensor_info,
'get_ipmi_ip': ipmi_ip,
})

0 comments on commit 48b3e6f

Please sign in to comment.