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
99    def getInterface(self, name):
100        o = self.dbus_objects[name]
101        obj = bus.get_object(o['bus_name'], o['object_name'], introspect=False)
102        return dbus.Interface(obj, o['interface_name'])
103
104
105    @dbus.service.method(DBUS_NAME,
106                         in_signature='', out_signature='')
107    def setIdentify(self):
108        print "Turn on identify"
109        intf = self.getInterface('identify_led')
110        intf.setOn()
111        return None
112
113    @dbus.service.method(DBUS_NAME,
114                         in_signature='', out_signature='')
115    def clearIdentify(self):
116        print "Turn on identify"
117        intf = self.getInterface('identify_led')
118        intf.setOff()
119        return None
120
121    @dbus.service.method(DBUS_NAME,
122                         in_signature='', out_signature='')
123    def powerOn(self):
124        print "Turn on power and boot"
125        self.Set(DBUS_NAME, "reboot", 0)
126        intf = self.getInterface('systemd')
127        f = getattr(intf, 'StartUnit')
128        f.call_async('obmc-chassis-start@0.target', 'replace')
129        return None
130
131    @dbus.service.method(DBUS_NAME,
132                         in_signature='', out_signature='')
133    def powerOff(self):
134        print "Turn off power"
135
136        intf = self.getInterface('systemd')
137        f = getattr(intf, 'StartUnit')
138        f.call_async('obmc-chassis-stop@0.target', 'replace')
139        return None
140
141    @dbus.service.method(DBUS_NAME,
142                         in_signature='', out_signature='')
143    def softPowerOff(self):
144        print "Soft off power"
145        intf = self.getInterface('host_services')
146        ## host services will call power off when ready
147        intf.SoftPowerOff()
148        return None
149
150    @dbus.service.method(DBUS_NAME,
151                         in_signature='', out_signature='')
152    def reboot(self):
153        print "Rebooting"
154        if self.getPowerState() == POWER_OFF:
155            self.powerOn();
156        else:
157            self.Set(DBUS_NAME, "reboot", 1)
158            self.powerOff()
159        return None
160
161    @dbus.service.method(DBUS_NAME,
162                         in_signature='', out_signature='')
163    def softReboot(self):
164        print "Soft Rebooting"
165        if self.getPowerState() == POWER_OFF:
166            self.powerOn();
167        else:
168            self.Set(DBUS_NAME, "reboot", 1)
169            self.softPowerOff()
170        return None
171
172    @dbus.service.method(DBUS_NAME,
173                         in_signature='', out_signature='i')
174    def getPowerState(self):
175        intf = self.getInterface('power_control')
176        return intf.getPowerState()
177
178    ## Signal handler
179
180    def SystemStateHandler(self, state_name):
181        if (
182                state_name == "HOST_POWERED_OFF" or state_name == "HOST_POWERED_ON"):
183            intf = self.getInterface('settings')
184            intf.Set("org.openbmc.settings.Host", "system_state", state_name)
185
186        if (state_name == "HOST_POWERED_OFF" and self.Get(DBUS_NAME,
187                                                          "reboot") == 1):
188            self.powerOn()
189
190    def power_button_signal_handler(self):
191        # toggle power, power-on / soft-power-off
192        state = self.getPowerState()
193        if state == POWER_OFF:
194            self.powerOn()
195        elif state == POWER_ON:
196            self.softPowerOff();
197
198    def long_power_button_signal_handler(self):
199        print "Long-press button, hard power off"
200        self.powerOff();
201
202    def softreset_button_signal_handler(self):
203        self.softReboot();
204
205    def host_watchdog_signal_handler(self):
206        print "Watchdog Error, Hard Rebooting"
207        self.Set(DBUS_NAME, "reboot", 1)
208        self.powerOff()
209
210    def emergency_shutdown_signal_handler(self, message):
211        print "Emergency Shutdown!"
212        # Log an event.
213        try:
214            # Exception happens or not, we need to power off.
215            obj = bus.get_object("org.openbmc.records.events",
216                                 "/org/openbmc/records/events",
217                                 introspect=False)
218            intf = dbus.Interface(obj, "org.openbmc.recordlog")
219            desc = message
220            sev = "critical error"
221            details = "Get emergency shutdown signal. Shutdown the host."
222            debug = dbus.ByteArray("")
223            intf.acceptBMCMessage(desc, sev, details, debug)
224        except Exception as e:
225            print "Emergency shutdown signal handler: log event error."
226            print e
227        self.powerOff()
228
229
230if __name__ == '__main__':
231    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
232
233    bus = get_dbus()
234    obj = ChassisControlObject(bus, OBJ_NAME)
235    mainloop = gobject.MainLoop()
236
237    obj.unmask_signals()
238    name = dbus.service.BusName(DBUS_NAME, bus)
239
240    print "Running ChassisControlService"
241    mainloop.run()
242
243