1#!/usr/bin/env python
2
3# TODO: openbmc/openbmc#2994 remove python 2 support
4try:  # python 2
5    import gobject
6except ImportError:  # python 3
7    from gi.repository import GObject as gobject
8import dbus
9import dbus.service
10import dbus.mainloop.glib
11from obmc.dbuslib.bindings import get_dbus, DbusProperties, DbusObjectManager
12
13DBUS_NAME = 'org.openbmc.control.Chassis'
14OBJ_NAME = '/org/openbmc/control/chassis0'
15CONTROL_INTF = 'org.openbmc.Control'
16
17MACHINE_ID = '/etc/machine-id'
18
19POWER_OFF = 0
20POWER_ON = 1
21
22BOOTED = 100
23
24
25class ChassisControlObject(DbusProperties, DbusObjectManager):
26    def getUuid(self):
27        uuid = ""
28        try:
29            with open(MACHINE_ID) as f:
30                data = f.readline().rstrip('\n')
31                if (len(data) == 32):
32                    uuid = data
33                else:
34                    print("ERROR:  UUID is not formatted correctly: " + data)
35        except Exception:
36            print("ERROR: Unable to open uuid file: " + MACHINE_ID)
37
38        return uuid
39
40    def __init__(self, bus, name):
41        super(ChassisControlObject, self).__init__(
42            conn=bus,
43            object_path=name)
44        # load utilized objects
45        self.dbus_objects = {
46            'power_control': {
47                'bus_name': 'org.openbmc.control.Power',
48                'object_name': '/org/openbmc/control/power0',
49                'interface_name': 'org.openbmc.control.Power'
50            },
51            'host_services': {
52                'bus_name': 'org.openbmc.HostServices',
53                'object_name': '/org/openbmc/HostServices',
54                'interface_name': 'org.openbmc.HostServices'
55            },
56            'systemd': {
57                'bus_name': 'org.freedesktop.systemd1',
58                'object_name': '/org/freedesktop/systemd1',
59                'interface_name': 'org.freedesktop.systemd1.Manager'
60            },
61        }
62
63        # uuid
64        self.Set(DBUS_NAME, "uuid", self.getUuid())
65        self.Set(DBUS_NAME, "reboot", 0)
66
67        bus.add_signal_receiver(self.power_button_signal_handler,
68                                dbus_interface="org.openbmc.Button",
69                                signal_name="Released",
70                                path="/org/openbmc/buttons/power0")
71        bus.add_signal_receiver(self.long_power_button_signal_handler,
72                                dbus_interface="org.openbmc.Button",
73                                signal_name="PressedLong",
74                                path="/org/openbmc/buttons/power0")
75        bus.add_signal_receiver(self.softreset_button_signal_handler,
76                                dbus_interface="org.openbmc.Button",
77                                signal_name="Released",
78                                path="/org/openbmc/buttons/reset0")
79
80        bus.add_signal_receiver(self.host_watchdog_signal_handler,
81                                dbus_interface="org.openbmc.Watchdog",
82                                signal_name="WatchdogError")
83
84
85    def getInterface(self, name):
86        o = self.dbus_objects[name]
87        obj = bus.get_object(o['bus_name'], o['object_name'], introspect=False)
88        return dbus.Interface(obj, o['interface_name'])
89
90    @dbus.service.method(DBUS_NAME,
91                         in_signature='', out_signature='')
92    def powerOn(self):
93        print("Turn on power and boot")
94        self.Set(DBUS_NAME, "reboot", 0)
95        intf = self.getInterface('systemd')
96        f = getattr(intf, 'StartUnit')
97        f.call_async('obmc-host-start@0.target', 'replace')
98        return None
99
100    @dbus.service.method(DBUS_NAME,
101                         in_signature='', out_signature='')
102    def powerOff(self):
103        print("Turn off power")
104        intf = self.getInterface('systemd')
105        f = getattr(intf, 'StartUnit')
106        f.call_async('obmc-chassis-hard-poweroff@0.target', 'replace')
107        return None
108
109    @dbus.service.method(DBUS_NAME,
110                         in_signature='', out_signature='')
111    def softPowerOff(self):
112        print("Soft off power")
113        intf = self.getInterface('systemd')
114        f = getattr(intf, 'StartUnit')
115        f.call_async('obmc-host-shutdown@0.target', 'replace')
116        return None
117
118    @dbus.service.method(DBUS_NAME,
119                         in_signature='', out_signature='')
120    def reboot(self):
121        print("Rebooting")
122        if self.getPowerState() == POWER_OFF:
123            self.powerOn()
124        else:
125            self.Set(DBUS_NAME, "reboot", 1)
126            self.powerOff()
127        return None
128
129    @dbus.service.method(DBUS_NAME,
130                         in_signature='', out_signature='')
131    def softReboot(self):
132        print("Soft Rebooting")
133        if self.getPowerState() == POWER_OFF:
134            self.powerOn()
135        else:
136            self.Set(DBUS_NAME, "reboot", 1)
137            self.softPowerOff()
138        return None
139
140    @dbus.service.method(DBUS_NAME,
141                         in_signature='', out_signature='')
142    def quiesce(self):
143        intf = self.getInterface('systemd')
144        f = getattr(intf, 'StartUnit')
145        f.call_async('obmc-host-quiesce@0.target', 'replace')
146        return None
147
148    @dbus.service.method(DBUS_NAME,
149                         in_signature='', out_signature='i')
150    def getPowerState(self):
151        intf = self.getInterface('power_control')
152        return intf.getPowerState()
153
154    # Signal handler
155
156    def power_button_signal_handler(self):
157        # toggle power, power-on / soft-power-off
158        state = self.getPowerState()
159        if state == POWER_OFF:
160            self.powerOn()
161        elif state == POWER_ON:
162            self.softPowerOff()
163
164    def long_power_button_signal_handler(self):
165        print("Long-press button, hard power off")
166        self.powerOff()
167
168    def softreset_button_signal_handler(self):
169        self.softReboot()
170
171    def host_watchdog_signal_handler(self):
172        print("Watchdog Error, Going to quiesce")
173        self.quiesce()
174
175
176if __name__ == '__main__':
177    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
178
179    bus = get_dbus()
180    obj = ChassisControlObject(bus, OBJ_NAME)
181    mainloop = gobject.MainLoop()
182
183    obj.unmask_signals()
184    name = dbus.service.BusName(DBUS_NAME, bus)
185
186    print("Running ChassisControlService")
187    mainloop.run()
188
189# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
190