blob: e2b422a3c6a023907d062891ce7f0586ea833195 [file] [log] [blame]
Norman Jamesb4914ad2015-10-26 07:14:29 -05001#!/usr/bin/python
2
3import sys
Norman Jamesb4914ad2015-10-26 07:14:29 -05004import dbus
Andrew Jeffery0b6883d2017-10-11 22:08:55 +10305import argparse
Norman Jamesb4914ad2015-10-26 07:14:29 -05006
Andrew Jefferyde4ed022017-10-12 01:26:55 +10307from dbus.mainloop.glib import DBusGMainLoop
8import gobject
Andrew Jefferyb43f7ed2017-10-12 01:33:59 +10309import os
10import signal
11import time
12from subprocess import Popen
Andrew Jefferyde4ed022017-10-12 01:26:55 +103013
Andrew Jefferyc6b5deb2017-10-11 22:18:27 +103014descriptors = {
Andrew Geisslercae038e2016-12-19 15:29:10 -060015 'power': {
16 'bus_name': 'org.openbmc.control.Power',
17 'object_name': '/org/openbmc/control/power0',
18 'interface_name': 'org.openbmc.control.Power'
19 },
Andrew Geissler2cbbb672017-05-17 10:52:49 -050020 'chassison': {
21 'bus_name': 'xyz.openbmc_project.State.Chassis',
22 'object_name': '/xyz/openbmc_project/state/chassis0',
23 'interface_name': 'xyz.openbmc_project.State.Chassis',
24 'property': 'RequestedPowerTransition',
Andrew Jefferyde4ed022017-10-12 01:26:55 +103025 'value': 'xyz.openbmc_project.State.Chassis.Transition.On',
26 'monitor': 'obmc-chassis-poweron@0.target',
Andrew Geissler2cbbb672017-05-17 10:52:49 -050027 },
28 'chassisoff': {
29 'bus_name': 'xyz.openbmc_project.State.Chassis',
30 'object_name': '/xyz/openbmc_project/state/chassis0',
31 'interface_name': 'xyz.openbmc_project.State.Chassis',
32 'property': 'RequestedPowerTransition',
Andrew Jefferyde4ed022017-10-12 01:26:55 +103033 'value': 'xyz.openbmc_project.State.Chassis.Transition.Off',
34 'monitor': 'obmc-chassis-hard-poweroff@0.target',
Andrew Geissler2cbbb672017-05-17 10:52:49 -050035 },
Andrew Geisslercae038e2016-12-19 15:29:10 -060036 'poweron': {
Andrew Geissler25b9a852016-12-19 16:14:09 -060037 'bus_name': 'xyz.openbmc_project.State.Host',
38 'object_name': '/xyz/openbmc_project/state/host0',
39 'interface_name': 'xyz.openbmc_project.State.Host',
40 'property': 'RequestedHostTransition',
Andrew Jefferyde4ed022017-10-12 01:26:55 +103041 'value': 'xyz.openbmc_project.State.Host.Transition.On',
42 'monitor': 'obmc-host-start@0.target',
Andrew Geisslercae038e2016-12-19 15:29:10 -060043 },
44 'poweroff': {
Andrew Geissler25b9a852016-12-19 16:14:09 -060045 'bus_name': 'xyz.openbmc_project.State.Host',
46 'object_name': '/xyz/openbmc_project/state/host0',
47 'interface_name': 'xyz.openbmc_project.State.Host',
48 'property': 'RequestedHostTransition',
Andrew Jefferyde4ed022017-10-12 01:26:55 +103049 'value': 'xyz.openbmc_project.State.Host.Transition.Off',
50 'monitor': 'obmc-host-stop@0.target',
Andrew Geisslercae038e2016-12-19 15:29:10 -060051 },
Andrew Geissler8f8cbce2017-02-20 16:10:26 -060052 'bmcstate': {
53 'bus_name': 'xyz.openbmc_project.State.BMC',
54 'object_name': '/xyz/openbmc_project/state/bmc0',
55 'interface_name': 'xyz.openbmc_project.State.BMC',
56 'property': 'CurrentBMCState',
57 },
58 'chassisstate': {
59 'bus_name': 'xyz.openbmc_project.State.Chassis',
60 'object_name': '/xyz/openbmc_project/state/chassis0',
61 'interface_name': 'xyz.openbmc_project.State.Chassis',
62 'property': 'CurrentPowerState',
63 },
64 'hoststate': {
65 'bus_name': 'xyz.openbmc_project.State.Host',
66 'object_name': '/xyz/openbmc_project/state/host0',
67 'interface_name': 'xyz.openbmc_project.State.Host',
68 'property': 'CurrentHostState',
Andrew Geisslercae038e2016-12-19 15:29:10 -060069 },
70 'bootprogress': {
George Keishing3be09952017-08-18 09:48:03 -050071 'bus_name': 'xyz.openbmc_project.State.Host',
72 'object_name': '/xyz/openbmc_project/state/host0',
73 'interface_name': 'xyz.openbmc_project.State.Boot.Progress',
74 'property': 'BootProgress',
Andrew Geisslercae038e2016-12-19 15:29:10 -060075 },
Andrew Jeffery0b6883d2017-10-11 22:08:55 +103076 'state' : ['bmcstate', 'chassisstate', 'hoststate']
Norman Jamesb4914ad2015-10-26 07:14:29 -050077}
78
Andrew Jefferyde4ed022017-10-12 01:26:55 +103079def run_set_property(dbus_bus, dbus_iface, descriptor, args):
80 mainloop = gobject.MainLoop()
81
82 iface = descriptor['interface_name']
83 prop = descriptor['property']
84
85 if 'monitor' not in descriptor:
86 dbus_iface.Set(iface, prop, descriptor['value'])
87 return True
88
89 def property_listener(job, path, unit, state):
90 if descriptor['monitor'] != unit:
91 return
92
93 property_listener.success = (state == 'done')
94 mainloop.quit()
95
96 property_listener.success = True
97
Andrew Jefferyb43f7ed2017-10-12 01:33:59 +103098 if args.wait and args.verbose:
99 pid = Popen(["/bin/journalctl", "-f", "--no-pager"]).pid
100
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030101 if args.wait:
102 sig_match = dbus_bus.add_signal_receiver(property_listener, "JobRemoved")
103
104 dbus_iface.Set(iface, prop, descriptor['value'])
105
106 if args.wait:
107 mainloop.run()
108 sig_match.remove()
109
Andrew Jefferyb43f7ed2017-10-12 01:33:59 +1030110 if args.wait and args.verbose:
111 # wait some time for the journal output
112 time.sleep(args.wait_tune)
113 os.kill(pid, signal.SIGTERM)
114
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030115 return property_listener.success
116
Andrew Jefferycf6a7842017-10-12 14:47:43 +1030117def get_dbus_obj(dbus_bus, bus, obj, args):
118 if not args.wait:
119 return dbus_bus.get_object(bus, obj)
120
121 mainloop = gobject.MainLoop()
122
123 def property_listener(job, path, unit, state):
124 if 'obmc-standby.target' == unit:
125 mainloop.quit()
126
127 sig_match = dbus_bus.add_signal_receiver(property_listener, "JobRemoved")
128 try:
129 return dbus_bus.get_object(bus, obj)
130 except dbus.exceptions.DBusException as e:
131 if args.verbose:
132 pid = Popen(["/bin/journalctl", "-f", "--no-pager"]).pid
133
134 mainloop.run()
135
136 if args.verbose:
137 os.kill(pid, signal.SIGTERM)
138 finally:
139 sig_match.remove()
140
141 return dbus_bus.get_object(bus, obj)
142
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030143def run_one_command(dbus_bus, descriptor, args):
Andrew Jefferyc6b5deb2017-10-11 22:18:27 +1030144 bus = descriptor['bus_name']
145 obj = descriptor['object_name']
146 iface = descriptor['interface_name']
Andrew Jefferycf6a7842017-10-12 14:47:43 +1030147 dbus_obj = get_dbus_obj(dbus_bus, bus, obj, args)
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030148 result = None
Andrew Jefferye4dcaef2017-10-11 18:08:01 +1030149
Andrew Jeffery08e149b2017-10-12 01:37:07 +1030150 if 'property' in descriptor:
Andrew Jefferye4dcaef2017-10-11 18:08:01 +1030151 dbus_iface = dbus.Interface(dbus_obj, "org.freedesktop.DBus.Properties")
Andrew Jeffery08e149b2017-10-12 01:37:07 +1030152 if 'value' in descriptor:
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030153 result = run_set_property(dbus_bus, dbus_iface, descriptor, args)
Andrew Jefferye4dcaef2017-10-11 18:08:01 +1030154 else:
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030155 prop = descriptor['property']
Andrew Jefferye4dcaef2017-10-11 18:08:01 +1030156 dbus_prop = dbus_iface.Get(iface, prop)
157 print '{:<20}: {}'.format(prop, str(dbus_prop))
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030158 result = True
Andrew Jefferye4dcaef2017-10-11 18:08:01 +1030159 else:
160 dbus_iface = dbus.Interface(dbus_obj, "org.freedesktop.DBus.Properties")
161 props = dbus_iface.GetAll(iface)
162 for p in props:
Andrew Jefferybba82bd2017-10-11 22:20:30 +1030163 print "{} = {}".format(p, str(props[p]))
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030164 result = True
Andrew Jefferye4dcaef2017-10-11 18:08:01 +1030165
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030166 return result
167
168def run_all_commands(dbus_bus, recipe, args):
Andrew Jefferyc6b5deb2017-10-11 22:18:27 +1030169 if isinstance(recipe, dict):
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030170 return run_one_command(dbus_bus, recipe, args)
Andrew Jeffery7b376e72017-10-11 18:12:05 +1030171
Andrew Jefferyc6b5deb2017-10-11 22:18:27 +1030172 assert isinstance(recipe, list)
173 for command in recipe:
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030174 descriptor = descriptors[command]
175 if not run_one_command(dbus_bus, descriptor, args):
176 print "Failed to execute command: {}".format(descriptor)
177 return False
178
179 return True
Andrew Jeffery7b376e72017-10-11 18:12:05 +1030180
Andrew Jeffery44e6d9c2017-10-11 16:57:31 +1030181def main():
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030182 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
183
Andrew Jeffery0b6883d2017-10-11 22:08:55 +1030184 parser = argparse.ArgumentParser()
Andrew Jefferyb43f7ed2017-10-12 01:33:59 +1030185 parser.add_argument('--verbose', '-v', action='store_true',
186 help="Verbose output")
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030187 parser.add_argument('--wait', '-w', action='store_true',
188 help='Block until the state transition succeeds or fails')
Andrew Jefferyb43f7ed2017-10-12 01:33:59 +1030189 parser.add_argument('--wait-tune', '-t', nargs='?', default=8, type=float,
190 # help='Seconds to wait for journal output to complete after receiving DBus signal',
191 help=argparse.SUPPRESS)
Andrew Jefferyc6b5deb2017-10-11 22:18:27 +1030192 parser.add_argument('recipe', choices=sorted(descriptors.keys()))
Andrew Jeffery0b6883d2017-10-11 22:08:55 +1030193 args = parser.parse_args()
Andrew Geissler8f8cbce2017-02-20 16:10:26 -0600194
Andrew Jefferybdb74352017-10-11 17:29:48 +1030195 dbus_bus = dbus.SystemBus()
Andrew Jefferycf6a7842017-10-12 14:47:43 +1030196
197 # The only way to get a sensible backtrace with python 2 without stupid
198 # hoops is to let the uncaught exception handler do the work for you.
199 # Catching and binding an exception appears to overwrite the stack trace at
200 # the point of bind.
201 #
202 # So, if we're in verbose mode, don't try to catch the DBus exception. That
203 # way we can understand where it originated.
204 if args.verbose:
205 return run_all_commands(dbus_bus, descriptors[args.recipe], args)
206
207 # Otherwise, we don't care about the traceback. Just catch it and print the
208 # error message.
Andrew Jeffery0b6883d2017-10-11 22:08:55 +1030209 try:
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030210 return run_all_commands(dbus_bus, descriptors[args.recipe], args)
Andrew Jefferycf6a7842017-10-12 14:47:43 +1030211 except dbus.exceptions.DBusException as e:
212 print >> sys.stderr, "DBus error occurred: {}".format(e.get_dbus_message())
Andrew Jeffery0b6883d2017-10-11 22:08:55 +1030213 finally:
214 dbus_bus.close()
Andrew Jeffery44e6d9c2017-10-11 16:57:31 +1030215
216if __name__ == "__main__":
Andrew Jefferyde4ed022017-10-12 01:26:55 +1030217 sys.exit(0 if main() else 1)