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