summaryrefslogtreecommitdiffstats
path: root/pytools
diff options
context:
space:
mode:
authorAndrew Jeffery <andrew@aj.id.au>2017-10-12 01:26:55 +1030
committerAndrew Jeffery <andrew@aj.id.au>2017-10-17 16:30:51 +1030
commitde4ed02da37a8b3319f0c4077d5be4a02f7b2e9c (patch)
treea9becbcbb732f5ef11508682aa9dffe0b861d00d /pytools
parentbba82bd39a614baa1a2bd5d27a9b2b591443945a (diff)
downloadtalos-skeleton-de4ed02da37a8b3319f0c4077d5be4a02f7b2e9c.tar.gz
talos-skeleton-de4ed02da37a8b3319f0c4077d5be4a02f7b2e9c.zip
pytools: obmcutil: Implement blocking behaviour
The technique to block is to attach a listener for systemd JobRemoved property change events, change the desired OpenBMC state management property to trigger the systemd transition, and then run the gobject dbus mainloop. We terminate the mainloop by invoking quit() in the callback on the captured mainloop object. Additionally, the result of the transition (success or failure) is judged in the callback. We can't obtain the result by returning it, and as we are using Python 2 we cannot meaningfully mutate captured variables to expose it. Instead, a variable is created on the callback function object after it is defined but before the function is invoked, which is mutated inside the function (which can reference its own object) when called. The result is retrieved after the mainloop has terminated and is propagated up the call chain to form the exit status. Change-Id: Ic19aa604631177abea7580de2357d8c6812ee874 Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Diffstat (limited to 'pytools')
-rw-r--r--pytools/obmcutil76
1 files changed, 63 insertions, 13 deletions
diff --git a/pytools/obmcutil b/pytools/obmcutil
index d0db8b5..aee294b 100644
--- a/pytools/obmcutil
+++ b/pytools/obmcutil
@@ -4,6 +4,9 @@ import sys
import dbus
import argparse
+from dbus.mainloop.glib import DBusGMainLoop
+import gobject
+
descriptors = {
'power': {
'bus_name': 'org.openbmc.control.Power',
@@ -15,28 +18,32 @@ descriptors = {
'object_name': '/xyz/openbmc_project/state/chassis0',
'interface_name': 'xyz.openbmc_project.State.Chassis',
'property': 'RequestedPowerTransition',
- 'value': 'xyz.openbmc_project.State.Chassis.Transition.On'
+ 'value': 'xyz.openbmc_project.State.Chassis.Transition.On',
+ 'monitor': 'obmc-chassis-poweron@0.target',
},
'chassisoff': {
'bus_name': 'xyz.openbmc_project.State.Chassis',
'object_name': '/xyz/openbmc_project/state/chassis0',
'interface_name': 'xyz.openbmc_project.State.Chassis',
'property': 'RequestedPowerTransition',
- 'value': 'xyz.openbmc_project.State.Chassis.Transition.Off'
+ 'value': 'xyz.openbmc_project.State.Chassis.Transition.Off',
+ 'monitor': 'obmc-chassis-hard-poweroff@0.target',
},
'poweron': {
'bus_name': 'xyz.openbmc_project.State.Host',
'object_name': '/xyz/openbmc_project/state/host0',
'interface_name': 'xyz.openbmc_project.State.Host',
'property': 'RequestedHostTransition',
- 'value': 'xyz.openbmc_project.State.Host.Transition.On'
+ 'value': 'xyz.openbmc_project.State.Host.Transition.On',
+ 'monitor': 'obmc-host-start@0.target',
},
'poweroff': {
'bus_name': 'xyz.openbmc_project.State.Host',
'object_name': '/xyz/openbmc_project/state/host0',
'interface_name': 'xyz.openbmc_project.State.Host',
'property': 'RequestedHostTransition',
- 'value': 'xyz.openbmc_project.State.Host.Transition.Off'
+ 'value': 'xyz.openbmc_project.State.Host.Transition.Off',
+ 'monitor': 'obmc-host-stop@0.target',
},
'bmcstate': {
'bus_name': 'xyz.openbmc_project.State.BMC',
@@ -65,45 +72,88 @@ descriptors = {
'state' : ['bmcstate', 'chassisstate', 'hoststate']
}
-def run_one_command(dbus_bus, descriptor):
+def run_set_property(dbus_bus, dbus_iface, descriptor, args):
+ mainloop = gobject.MainLoop()
+
+ iface = descriptor['interface_name']
+ prop = descriptor['property']
+
+ if 'monitor' not in descriptor:
+ dbus_iface.Set(iface, prop, descriptor['value'])
+ return True
+
+ def property_listener(job, path, unit, state):
+ if descriptor['monitor'] != unit:
+ return
+
+ property_listener.success = (state == 'done')
+ mainloop.quit()
+
+ property_listener.success = True
+
+ if args.wait:
+ sig_match = dbus_bus.add_signal_receiver(property_listener, "JobRemoved")
+
+ dbus_iface.Set(iface, prop, descriptor['value'])
+
+ if args.wait:
+ mainloop.run()
+ sig_match.remove()
+
+ return property_listener.success
+
+def run_one_command(dbus_bus, descriptor, args):
bus = descriptor['bus_name']
obj = descriptor['object_name']
iface = descriptor['interface_name']
dbus_obj = dbus_bus.get_object(bus, obj)
+ result = None
if (descriptor.has_key('property')):
- prop = descriptor['property']
dbus_iface = dbus.Interface(dbus_obj, "org.freedesktop.DBus.Properties")
if descriptor.has_key('value'):
- dbus_iface.Set(iface, prop, descriptor['value'])
+ result = run_set_property(dbus_bus, dbus_iface, descriptor, args)
else:
+ prop = descriptor['property']
dbus_prop = dbus_iface.Get(iface, prop)
print '{:<20}: {}'.format(prop, str(dbus_prop))
+ result = True
else:
dbus_iface = dbus.Interface(dbus_obj, "org.freedesktop.DBus.Properties")
props = dbus_iface.GetAll(iface)
for p in props:
print "{} = {}".format(p, str(props[p]))
+ result = True
-def run_all_commands(dbus_bus, recipe):
+ return result
+
+def run_all_commands(dbus_bus, recipe, args):
if isinstance(recipe, dict):
- run_one_command(dbus_bus, recipe)
- return
+ return run_one_command(dbus_bus, recipe, args)
assert isinstance(recipe, list)
for command in recipe:
- run_one_command(dbus_bus, descriptors[command])
+ descriptor = descriptors[command]
+ if not run_one_command(dbus_bus, descriptor, args):
+ print "Failed to execute command: {}".format(descriptor)
+ return False
+
+ return True
def main():
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
parser = argparse.ArgumentParser()
+ parser.add_argument('--wait', '-w', action='store_true',
+ help='Block until the state transition succeeds or fails')
parser.add_argument('recipe', choices=sorted(descriptors.keys()))
args = parser.parse_args()
dbus_bus = dbus.SystemBus()
try:
- run_all_commands(dbus_bus, descriptors[args.recipe], args)
+ return run_all_commands(dbus_bus, descriptors[args.recipe], args)
finally:
dbus_bus.close()
if __name__ == "__main__":
- main()
+ sys.exit(0 if main() else 1)
OpenPOWER on IntegriCloud