xref: /openbmc/skeleton/pychassisctl/chassis_control.py (revision eeb9b44e432ea0e976659fcae30b0bf9ba63a5b7)
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            'watchdog': {
56                'bus_name': 'org.openbmc.watchdog.Host',
57                'object_name': '/org/openbmc/watchdog/host0',
58                'interface_name': 'org.openbmc.Watchdog'
59            },
60            'host_services': {
61                'bus_name': 'org.openbmc.HostServices',
62                'object_name': '/org/openbmc/HostServices',
63                'interface_name': 'org.openbmc.HostServices'
64            },
65            'settings': {
66                'bus_name': 'org.openbmc.settings.Host',
67                'object_name': '/org/openbmc/settings/host0',
68                'interface_name': 'org.freedesktop.DBus.Properties'
69            },
70            'host_control': {
71                'bus_name': 'org.openbmc.control.Host',
72                'object_name': '/org/openbmc/control/host0',
73                'interface_name': 'org.openbmc.control.Host'
74            },
75        }
76
77        # uuid
78        self.Set(DBUS_NAME, "uuid", self.getUuid())
79        self.Set(DBUS_NAME, "reboot", 0)
80
81        bus.add_signal_receiver(self.power_button_signal_handler,
82                                dbus_interface="org.openbmc.Button",
83                                signal_name="Released",
84                                path="/org/openbmc/buttons/power0")
85        bus.add_signal_receiver(self.long_power_button_signal_handler,
86                                dbus_interface="org.openbmc.Button",
87                                signal_name="PressedLong",
88                                path="/org/openbmc/buttons/power0")
89        bus.add_signal_receiver(self.softreset_button_signal_handler,
90                                dbus_interface="org.openbmc.Button",
91                                signal_name="Released",
92                                path="/org/openbmc/buttons/reset0")
93
94        bus.add_signal_receiver(self.host_watchdog_signal_handler,
95                                dbus_interface="org.openbmc.Watchdog",
96                                signal_name="WatchdogError")
97
98        bus.add_signal_receiver(self.emergency_shutdown_signal_handler,
99                                dbus_interface="org.openbmc.SensorThresholds",
100                                signal_name="Emergency")
101
102        bus.add_signal_receiver(self.SystemStateHandler,
103                                signal_name="GotoSystemState")
104
105
106    def getInterface(self, name):
107        o = self.dbus_objects[name]
108        obj = bus.get_object(o['bus_name'], o['object_name'], introspect=False)
109        return dbus.Interface(obj, o['interface_name'])
110
111
112    @dbus.service.method(DBUS_NAME,
113                         in_signature='', out_signature='')
114    def setIdentify(self):
115        print "Turn on identify"
116        intf = self.getInterface('identify_led')
117        intf.setOn()
118        return None
119
120    @dbus.service.method(DBUS_NAME,
121                         in_signature='', out_signature='')
122    def clearIdentify(self):
123        print "Turn on identify"
124        intf = self.getInterface('identify_led')
125        intf.setOff()
126        return None
127
128    @dbus.service.method(DBUS_NAME,
129                         in_signature='', out_signature='')
130    def powerOn(self):
131        print "Turn on power and boot"
132        self.Set(DBUS_NAME, "reboot", 0)
133        if (self.getPowerState() == 0):
134            intf = self.getInterface('power_control')
135            intf.setPowerState(POWER_ON)
136
137            # Determine if debug_mode is set.  If it is then we don't
138            # want to start the watchdog since debug mode
139            intfcontrol = self.getInterface('host_control')
140            intfproperties = dbus.Interface(intfcontrol,
141                                            "org.freedesktop.DBus.Properties")
142            debug_mode = intfproperties.Get('org.openbmc.control.Host',
143                                            'debug_mode')
144            if(not debug_mode):
145                intfwatchdog = self.getInterface('watchdog')
146                # Start watchdog with 30s timeout per the OpenPower Host IPMI Spec
147                #Once the host starts booting, it'll reset and refresh the timer
148                intfwatchdog.set(30000)
149                intfwatchdog.start()
150            else:
151                print "Debug mode is on, no watchdog"
152        return None
153
154    @dbus.service.method(DBUS_NAME,
155                         in_signature='', out_signature='')
156    def powerOff(self):
157        print "Turn off power"
158        intfwatchdog = self.getInterface('watchdog')
159        intfwatchdog.stop()
160        intf = self.getInterface('power_control')
161        intf.setPowerState(POWER_OFF)
162        return None
163
164    @dbus.service.method(DBUS_NAME,
165                         in_signature='', out_signature='')
166    def softPowerOff(self):
167        print "Soft off power"
168        intf = self.getInterface('host_services')
169        ## host services will call power off when ready
170        intf.SoftPowerOff()
171        return None
172
173    @dbus.service.method(DBUS_NAME,
174                         in_signature='', out_signature='')
175    def reboot(self):
176        print "Rebooting"
177        if self.getPowerState() == POWER_OFF:
178            self.powerOn();
179        else:
180            self.Set(DBUS_NAME, "reboot", 1)
181            self.powerOff()
182        return None
183
184    @dbus.service.method(DBUS_NAME,
185                         in_signature='', out_signature='')
186    def softReboot(self):
187        print "Soft Rebooting"
188        if self.getPowerState() == POWER_OFF:
189            self.powerOn();
190        else:
191            self.Set(DBUS_NAME, "reboot", 1)
192            self.softPowerOff()
193        return None
194
195    @dbus.service.method(DBUS_NAME,
196                         in_signature='', out_signature='i')
197    def getPowerState(self):
198        intf = self.getInterface('power_control')
199        return intf.getPowerState()
200
201    ## Signal handler
202
203    def SystemStateHandler(self, state_name):
204        if (
205                state_name == "HOST_POWERED_OFF" or state_name == "HOST_POWERED_ON"):
206            intf = self.getInterface('settings')
207            intf.Set("org.openbmc.settings.Host", "system_state", state_name)
208
209        if (state_name == "HOST_POWERED_OFF" and self.Get(DBUS_NAME,
210                                                          "reboot") == 1):
211            self.powerOn()
212
213    def power_button_signal_handler(self):
214        # toggle power, power-on / soft-power-off
215        state = self.getPowerState()
216        if state == POWER_OFF:
217            self.powerOn()
218        elif state == POWER_ON:
219            self.softPowerOff();
220
221    def long_power_button_signal_handler(self):
222        print "Long-press button, hard power off"
223        self.powerOff();
224
225    def softreset_button_signal_handler(self):
226        self.softReboot();
227
228    def host_watchdog_signal_handler(self):
229        print "Watchdog Error, Hard Rebooting"
230        self.Set(DBUS_NAME, "reboot", 1)
231        self.powerOff()
232
233    def emergency_shutdown_signal_handler(self, message):
234        print "Emergency Shutdown!"
235        # Log an event.
236        try:
237            # Exception happens or not, we need to power off.
238            obj = bus.get_object("org.openbmc.records.events",
239                                 "/org/openbmc/records/events",
240                                 introspect=False)
241            intf = dbus.Interface(obj, "org.openbmc.recordlog")
242            desc = message
243            sev = "critical error"
244            details = "Get emergency shutdown signal. Shutdown the host."
245            debug = dbus.ByteArray("")
246            intf.acceptBMCMessage(desc, sev, details, debug)
247        except Exception as e:
248            print "Emergency shutdown signal handler: log event error."
249            print e
250        self.powerOff()
251
252
253if __name__ == '__main__':
254    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
255
256    bus = get_dbus()
257    obj = ChassisControlObject(bus, OBJ_NAME)
258    mainloop = gobject.MainLoop()
259
260    obj.unmask_signals()
261    name = dbus.service.BusName(DBUS_NAME, bus)
262
263    print "Running ChassisControlService"
264    mainloop.run()
265
266