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            'identify_led': {
48                'bus_name': 'org.openbmc.control.led',
49                'object_name': '/org/openbmc/control/led/identify',
50                'interface_name': 'org.openbmc.Led'
51            },
52            'host_services': {
53                'bus_name': 'org.openbmc.HostServices',
54                'object_name': '/org/openbmc/HostServices',
55                'interface_name': 'org.openbmc.HostServices'
56            },
57            'settings': {
58                'bus_name': 'org.openbmc.settings.Host',
59                'object_name': '/org/openbmc/settings/host0',
60                'interface_name': 'org.freedesktop.DBus.Properties'
61            },
62            'systemd': {
63                'bus_name': 'org.freedesktop.systemd1',
64                'object_name': '/org/freedesktop/systemd1',
65                'interface_name': 'org.freedesktop.systemd1.Manager'
66            },
67        }
68
69        # uuid
70        self.Set(DBUS_NAME, "uuid", self.getUuid())
71        self.Set(DBUS_NAME, "reboot", 0)
72
73        bus.add_signal_receiver(self.power_button_signal_handler,
74                                dbus_interface="org.openbmc.Button",
75                                signal_name="Released",
76                                path="/org/openbmc/buttons/power0")
77        bus.add_signal_receiver(self.long_power_button_signal_handler,
78                                dbus_interface="org.openbmc.Button",
79                                signal_name="PressedLong",
80                                path="/org/openbmc/buttons/power0")
81        bus.add_signal_receiver(self.softreset_button_signal_handler,
82                                dbus_interface="org.openbmc.Button",
83                                signal_name="Released",
84                                path="/org/openbmc/buttons/reset0")
85
86        bus.add_signal_receiver(self.host_watchdog_signal_handler,
87                                dbus_interface="org.openbmc.Watchdog",
88                                signal_name="WatchdogError")
89
90        bus.add_signal_receiver(self.emergency_shutdown_signal_handler,
91                                dbus_interface="org.openbmc.SensorThresholds",
92                                signal_name="Emergency")
93
94        bus.add_signal_receiver(self.SystemStateHandler,
95                                signal_name="GotoSystemState")
96
97    def getInterface(self, name):
98        o = self.dbus_objects[name]
99        obj = bus.get_object(o['bus_name'], o['object_name'], introspect=False)
100        return dbus.Interface(obj, o['interface_name'])
101
102    @dbus.service.method(DBUS_NAME,
103                         in_signature='', out_signature='')
104    def setIdentify(self):
105        print "Turn on identify"
106        intf = self.getInterface('identify_led')
107        intf.setOn()
108        return None
109
110    @dbus.service.method(DBUS_NAME,
111                         in_signature='', out_signature='')
112    def clearIdentify(self):
113        print "Turn on identify"
114        intf = self.getInterface('identify_led')
115        intf.setOff()
116        return None
117
118    @dbus.service.method(DBUS_NAME,
119                         in_signature='', out_signature='')
120    def powerOn(self):
121        print "Turn on power and boot"
122        self.Set(DBUS_NAME, "reboot", 0)
123        intf = self.getInterface('systemd')
124        f = getattr(intf, 'StartUnit')
125        f.call_async('obmc-chassis-start@0.target', 'replace')
126        return None
127
128    @dbus.service.method(DBUS_NAME,
129                         in_signature='', out_signature='')
130    def powerOff(self):
131        print "Turn off power"
132
133        intf = self.getInterface('systemd')
134        f = getattr(intf, 'StartUnit')
135        f.call_async('obmc-chassis-stop@0.target', 'replace')
136        return None
137
138    @dbus.service.method(DBUS_NAME,
139                         in_signature='', out_signature='')
140    def softPowerOff(self):
141        print "Soft off power"
142        intf = self.getInterface('host_services')
143        ## host services will call power off when ready
144        intf.SoftPowerOff()
145        return None
146
147    @dbus.service.method(DBUS_NAME,
148                         in_signature='', out_signature='')
149    def reboot(self):
150        print "Rebooting"
151        if self.getPowerState() == POWER_OFF:
152            self.powerOn()
153        else:
154            self.Set(DBUS_NAME, "reboot", 1)
155            self.powerOff()
156        return None
157
158    @dbus.service.method(DBUS_NAME,
159                         in_signature='', out_signature='')
160    def softReboot(self):
161        print "Soft Rebooting"
162        if self.getPowerState() == POWER_OFF:
163            self.powerOn()
164        else:
165            self.Set(DBUS_NAME, "reboot", 1)
166            self.softPowerOff()
167        return None
168
169    @dbus.service.method(DBUS_NAME,
170                         in_signature='', out_signature='i')
171    def getPowerState(self):
172        intf = self.getInterface('power_control')
173        return intf.getPowerState()
174
175    ## Signal handler
176
177    def SystemStateHandler(self, state_name):
178        if state_name in ["HOST_POWERED_OFF", "HOST_POWERED_ON"]:
179            intf = self.getInterface('settings')
180            intf.Set("org.openbmc.settings.Host", "system_state", state_name)
181
182        if (state_name == "HOST_POWERED_OFF" and self.Get(DBUS_NAME,
183                                                          "reboot") == 1):
184            self.powerOn()
185
186    def power_button_signal_handler(self):
187        # toggle power, power-on / soft-power-off
188        state = self.getPowerState()
189        if state == POWER_OFF:
190            self.powerOn()
191        elif state == POWER_ON:
192            self.softPowerOff()
193
194    def long_power_button_signal_handler(self):
195        print "Long-press button, hard power off"
196        self.powerOff()
197
198    def softreset_button_signal_handler(self):
199        self.softReboot()
200
201    def host_watchdog_signal_handler(self):
202        print "Watchdog Error, Hard Rebooting"
203        self.Set(DBUS_NAME, "reboot", 1)
204        self.powerOff()
205
206    def emergency_shutdown_signal_handler(self, message):
207        print "Emergency Shutdown!"
208        # Log an event.
209        try:
210            # Exception happens or not, we need to power off.
211            obj = bus.get_object("org.openbmc.records.events",
212                                 "/org/openbmc/records/events",
213                                 introspect=False)
214            intf = dbus.Interface(obj, "org.openbmc.recordlog")
215            desc = message
216            sev = "critical error"
217            details = "Get emergency shutdown signal. Shutdown the host."
218            debug = dbus.ByteArray("")
219            intf.acceptBMCMessage(desc, sev, details, debug)
220        except Exception as e:
221            print "Emergency shutdown signal handler: log event error."
222            print e
223        self.powerOff()
224
225
226if __name__ == '__main__':
227    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
228
229    bus = get_dbus()
230    obj = ChassisControlObject(bus, OBJ_NAME)
231    mainloop = gobject.MainLoop()
232
233    obj.unmask_signals()
234    name = dbus.service.BusName(DBUS_NAME, bus)
235
236    print "Running ChassisControlService"
237    mainloop.run()
238
239# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
240