Skip to content

Commit 0acac11

Browse files
committed
IPMIPowerPort: add status polling into exporter
1 parent 137db19 commit 0acac11

3 files changed

Lines changed: 76 additions & 3 deletions

File tree

doc/configuration.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,9 @@ Arguments:
331331
- host (str): hostname or ip the IPMI interface of the PC is reachable
332332
- username (str): username to use for IPMI login
333333
- password (str): password to use for IPMI login
334-
- timeout (int): timeout to use when polling the resource
334+
- timeout (int): time to wait for the command to finish
335+
- polling (int): interval to poll resource in exporter (disabled if 0)
336+
- args (str): extra args to prepend the command with
335337

336338
Used by:
337339
- `IPMIPowerDriver`_

labgrid/remote/exporter.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,6 +977,73 @@ def _get_params(self):
977977
exports["TasmotaPowerPort"] = TasmotaPowerPortExport
978978

979979

980+
@attr.s(eq=False)
981+
class IPMIPowerPortExport(ResourceExport):
982+
"""ResourceExport for IPMIPowerPort devices"""
983+
984+
def __attrs_post_init__(self):
985+
super().__attrs_post_init__()
986+
self.data["cls"] = self.cls
987+
from ..resource.power import IPMIPowerPort
988+
self.local = IPMIPowerPort(target=None, name=None, **self.local_params)
989+
990+
self.lastpoll = 0
991+
self.job = None
992+
self.local.avail = False
993+
self.status = None
994+
995+
def poll(self):
996+
now = time.monotonic()
997+
if self.job:
998+
self.lastpoll = now
999+
if self.job.poll() is None:
1000+
return super().poll()
1001+
if self.job.returncode != 0:
1002+
self.status = self._ipmi_parse()
1003+
self.local.avail = False
1004+
self.job = None
1005+
return super().poll()
1006+
1007+
self.status = self._ipmi_parse().upper()
1008+
self.local.avail = True
1009+
self.job = None
1010+
1011+
if now - self.lastpoll < self.local.polling:
1012+
return super().poll()
1013+
self.lastpoll = now
1014+
1015+
if self.local.polling > 0:
1016+
self.job = self._ipmi_power('--stat')
1017+
1018+
return super().poll()
1019+
1020+
def _ipmi_power(self, cmd):
1021+
runstr = f"ipmi-power -h {self.local.host} -u {self.local.username} "
1022+
runstr += f"--session-timeout={self.local.timeout*1000} "
1023+
runstr += f"-p {self.local.password} {cmd} {self.local.args}"
1024+
return subprocess.Popen(runstr.strip().split(' '), stdout=subprocess.PIPE,
1025+
stderr=subprocess.PIPE)
1026+
1027+
def _ipmi_parse(self):
1028+
out = self.job.stdout.read() + self.job.stderr.read()
1029+
try:
1030+
return out.decode('utf-8').split(':')[1][1:-1]
1031+
except:
1032+
return ""
1033+
1034+
def _get_params(self):
1035+
"""Helper function to return parameters"""
1036+
return {
1037+
**self.local_params,
1038+
"extra": {
1039+
"status": self.status,
1040+
}
1041+
}
1042+
1043+
1044+
exports["IPMIPowerPort"] = IPMIPowerPortExport
1045+
1046+
9801047
class ExporterSession(ApplicationSession):
9811048
def onConnect(self):
9821049
"""Set up internal datastructures on successful connection:

labgrid/resource/power.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,13 @@ class IPMIPowerPort(Resource):
5959
host (str): hostname or ip the IPMI interface of the PC is reachable
6060
username (str): username to use for IPMI login
6161
password (str): password to use for IPMI login
62-
timeout (int): timeout to use when polling the resource
62+
timeout (int): time to wait for command to finish
63+
polling (int): interval to poll resource in exporter (disabled if 0)
64+
args (str): extra args to prepend the command with
6365
"""
6466
host = attr.ib(validator=attr.validators.instance_of(str))
6567
username = attr.ib(validator=attr.validators.instance_of(str))
6668
password = attr.ib(validator=attr.validators.instance_of(str))
67-
timeout = attr.ib(default=30, validator=attr.validators.instance_of(int))
69+
timeout = attr.ib(default=5, validator=attr.validators.instance_of(int))
70+
polling = attr.ib(default=0, validator=attr.validators.instance_of(int))
71+
args = attr.ib(default="", validator=attr.validators.instance_of(str))

0 commit comments

Comments
 (0)