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