xref: /openbmc/skeleton/pychassisctl/chassis_control.py (revision 666be2aee1f4c2e123a6823e59c7d883709db89c)
1#!/usr/bin/env python
2
3import gobject
4import dbus
5import dbus.service
6import dbus.mainloop.glib
7from obmc.dbuslib.bindings import get_dbus, DbusProperties, DbusObjectManager
8
9DBUS_NAME = 'org.openbmc.control.Chassis'
10OBJ_NAME = '/org/openbmc/control/chassis0'
11CONTROL_INTF = 'org.openbmc.Control'
12
13MACHINE_ID = '/etc/machine-id'
14
15POWER_OFF = 0
16POWER_ON = 1
17
18BOOTED = 100
19
20
21class ChassisControlObject(DbusProperties, DbusObjectManager):
22    def getUuid(self):
23        uuid = ""
24        try:
25            with open(MACHINE_ID) as f:
26                data = f.readline().rstrip('\n')
27                if (len(data) == 32):
28                    uuid = data
29                else:
30                    print "ERROR:  UUID is not formatted correctly: " + data
31        except:
32            print "ERROR: Unable to open uuid file: " + MACHINE_ID
33
34        return uuid
35
36    def __init__(self, bus, name):
37        super(ChassisControlObject, self).__init__(
38            conn=bus,
39            object_path=name)
40        ## load utilized objects
41        self.dbus_objects = {
42            'power_control': {
43                'bus_name': 'org.openbmc.control.Power',
44                'object_name': '/org/openbmc/control/power0',
45                'interface_name': 'org.openbmc.control.Power'
46            },
47            'host_services': {
48                'bus_name': 'org.openbmc.HostServices',
49                'object_name': '/org/openbmc/HostServices',
50                'interface_name': 'org.openbmc.HostServices'
51            },
52            'settings': {
53                'bus_name': 'org.openbmc.settings.Host',
54                'object_name': '/org/openbmc/settings/host0',
55                'interface_name': 'org.freedesktop.DBus.Properties'
56            },
57            'systemd': {
58                'bus_name': 'org.freedesktop.systemd1',
59                'object_name': '/org/freedesktop/systemd1',
60                'interface_name': 'org.freedesktop.systemd1.Manager'
61            },
62        }
63
64        # uuid
65        self.Set(DBUS_NAME, "uuid", self.getUuid())
66        self.Set(DBUS_NAME, "reboot", 0)
67
68        bus.add_signal_receiver(self.power_button_signal_handler,
69                                dbus_interface="org.openbmc.Button",
70                                signal_name="Released",
71                                path="/org/openbmc/buttons/power0")
72        bus.add_signal_receiver(self.long_power_button_signal_handler,
73                                dbus_interface="org.openbmc.Button",
74                                signal_name="PressedLong",
75                                path="/org/openbmc/buttons/power0")
76        bus.add_signal_receiver(self.softreset_button_signal_handler,
77                                dbus_interface="org.openbmc.Button",
78                                signal_name="Released",
79                                path="/org/openbmc/buttons/reset0")
80
81        bus.add_signal_receiver(self.host_watchdog_signal_handler,
82                                dbus_interface="org.openbmc.Watchdog",
83                                signal_name="WatchdogError")
84
85        bus.add_signal_receiver(self.emergency_shutdown_signal_handler,
86                                dbus_interface="org.openbmc.SensorThresholds",
87                                signal_name="Emergency")
88
89        bus.add_signal_receiver(self.SystemStateHandler,
90                                signal_name="GotoSystemState")
91
92    def getInterface(self, name):
93        o = self.dbus_objects[name]
94        obj = bus.get_object(o['bus_name'], o['object_name'], introspect=False)
95        return dbus.Interface(obj, o['interface_name'])
96
97    @dbus.service.method(DBUS_NAME,
98                         in_signature='', out_signature='')
99    def powerOn(self):
100        print "Turn on power and boot"
101        self.Set(DBUS_NAME, "reboot", 0)
102        intf = self.getInterface('systemd')
103        f = getattr(intf, 'StartUnit')
104        f.call_async('obmc-host-start@0.target', 'replace')
105        return None
106
107    @dbus.service.method(DBUS_NAME,
108                         in_signature='', out_signature='')
109    def powerOff(self):
110        print "Turn off power"
111
112        intf = self.getInterface('systemd')
113        f = getattr(intf, 'StartUnit')
114        f.call_async('obmc-host-stop@0.target', 'replace')
115        return None
116
117    @dbus.service.method(DBUS_NAME,
118                         in_signature='', out_signature='')
119    def softPowerOff(self):
120        print "Soft off power"
121        intf = self.getInterface('host_services')
122        ## host services will call power off when ready
123        intf.SoftPowerOff()
124        return None
125
126    @dbus.service.method(DBUS_NAME,
127                         in_signature='', out_signature='')
128    def reboot(self):
129        print "Rebooting"
130        if self.getPowerState() == POWER_OFF:
131            self.powerOn()
132        else:
133            self.Set(DBUS_NAME, "reboot", 1)
134            self.powerOff()
135        return None
136
137    @dbus.service.method(DBUS_NAME,
138                         in_signature='', out_signature='')
139    def softReboot(self):
140        print "Soft Rebooting"
141        if self.getPowerState() == POWER_OFF:
142            self.powerOn()
143        else:
144            self.Set(DBUS_NAME, "reboot", 1)
145            self.softPowerOff()
146        return None
147
148    @dbus.service.method(DBUS_NAME,
149                         in_signature='', out_signature='')
150    def quiesce(self):
151        intf = self.getInterface('systemd')
152        f = getattr(intf, 'StartUnit')
153        f.call_async('obmc-host-quiesce@0.target', 'replace')
154        return None
155
156    @dbus.service.method(DBUS_NAME,
157                         in_signature='', out_signature='i')
158    def getPowerState(self):
159        intf = self.getInterface('power_control')
160        return intf.getPowerState()
161
162    ## Signal handler
163
164    def SystemStateHandler(self, state_name):
165        if state_name in ["HOST_POWERED_OFF", "HOST_POWERED_ON"]:
166            intf = self.getInterface('settings')
167            intf.Set("org.openbmc.settings.Host", "system_state", state_name)
168
169        if (state_name == "HOST_POWERED_OFF" and self.Get(DBUS_NAME,
170                                                          "reboot") == 1):
171            self.powerOn()
172
173    def power_button_signal_handler(self):
174        # toggle power, power-on / soft-power-off
175        state = self.getPowerState()
176        if state == POWER_OFF:
177            self.powerOn()
178        elif state == POWER_ON:
179            self.softPowerOff()
180
181    def long_power_button_signal_handler(self):
182        print "Long-press button, hard power off"
183        self.powerOff()
184
185    def softreset_button_signal_handler(self):
186        self.softReboot()
187
188    def host_watchdog_signal_handler(self):
189        print "Watchdog Error, Going to quiesce"
190        self.quiesce()
191
192    def emergency_shutdown_signal_handler(self, message):
193        print "Emergency Shutdown!"
194        # Log an event.
195        try:
196            # Exception happens or not, we need to power off.
197            obj = bus.get_object("org.openbmc.records.events",
198                                 "/org/openbmc/records/events",
199                                 introspect=False)
200            intf = dbus.Interface(obj, "org.openbmc.recordlog")
201            desc = message
202            sev = "critical error"
203            details = "Get emergency shutdown signal. Shutdown the host."
204            debug = dbus.ByteArray("")
205            intf.acceptBMCMessage(desc, sev, details, debug)
206        except Exception as e:
207            print "Emergency shutdown signal handler: log event error."
208            print e
209        self.powerOff()
210
211
212if __name__ == '__main__':
213    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
214
215    bus = get_dbus()
216    obj = ChassisControlObject(bus, OBJ_NAME)
217    mainloop = gobject.MainLoop()
218
219    obj.unmask_signals()
220    name = dbus.service.BusName(DBUS_NAME, bus)
221
222    print "Running ChassisControlService"
223    mainloop.run()
224
225# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
226