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__(conn=bus, object_path=name)
42        # load utilized objects
43        self.dbus_objects = {
44            "power_control": {
45                "bus_name": "org.openbmc.control.Power",
46                "object_name": "/org/openbmc/control/power0",
47                "interface_name": "org.openbmc.control.Power",
48            },
49            "host_services": {
50                "bus_name": "org.openbmc.HostServices",
51                "object_name": "/org/openbmc/HostServices",
52                "interface_name": "org.openbmc.HostServices",
53            },
54            "systemd": {
55                "bus_name": "org.freedesktop.systemd1",
56                "object_name": "/org/freedesktop/systemd1",
57                "interface_name": "org.freedesktop.systemd1.Manager",
58            },
59        }
60
61        # uuid
62        self.Set(DBUS_NAME, "uuid", self.getUuid())
63        self.Set(DBUS_NAME, "reboot", 0)
64
65        bus.add_signal_receiver(
66            self.power_button_signal_handler,
67            dbus_interface="org.openbmc.Button",
68            signal_name="Released",
69            path="/org/openbmc/buttons/power0",
70        )
71        bus.add_signal_receiver(
72            self.long_power_button_signal_handler,
73            dbus_interface="org.openbmc.Button",
74            signal_name="PressedLong",
75            path="/org/openbmc/buttons/power0",
76        )
77        bus.add_signal_receiver(
78            self.softreset_button_signal_handler,
79            dbus_interface="org.openbmc.Button",
80            signal_name="Released",
81            path="/org/openbmc/buttons/reset0",
82        )
83
84        bus.add_signal_receiver(
85            self.host_watchdog_signal_handler,
86            dbus_interface="org.openbmc.Watchdog",
87            signal_name="WatchdogError",
88        )
89
90    def getInterface(self, name):
91        o = self.dbus_objects[name]
92        obj = bus.get_object(o["bus_name"], o["object_name"], introspect=False)
93        return dbus.Interface(obj, o["interface_name"])
94
95    @dbus.service.method(DBUS_NAME, in_signature="", out_signature="")
96    def powerOn(self):
97        print("Turn on power and boot")
98        self.Set(DBUS_NAME, "reboot", 0)
99        intf = self.getInterface("systemd")
100        f = getattr(intf, "StartUnit")
101        f.call_async("obmc-host-start@0.target", "replace")
102        return None
103
104    @dbus.service.method(DBUS_NAME, in_signature="", out_signature="")
105    def powerOff(self):
106        print("Turn off power")
107        intf = self.getInterface("systemd")
108        f = getattr(intf, "StartUnit")
109        f.call_async("obmc-chassis-hard-poweroff@0.target", "replace")
110        return None
111
112    @dbus.service.method(DBUS_NAME, in_signature="", out_signature="")
113    def softPowerOff(self):
114        print("Soft off power")
115        intf = self.getInterface("systemd")
116        f = getattr(intf, "StartUnit")
117        f.call_async("obmc-host-shutdown@0.target", "replace")
118        return None
119
120    @dbus.service.method(DBUS_NAME, in_signature="", out_signature="")
121    def reboot(self):
122        print("Rebooting")
123        if self.getPowerState() != POWER_OFF:
124            self.Set(DBUS_NAME, "reboot", 1)
125            self.powerOff()
126        return None
127
128    @dbus.service.method(DBUS_NAME, in_signature="", out_signature="")
129    def softReboot(self):
130        print("Soft Rebooting")
131        if self.getPowerState() != POWER_OFF:
132            self.Set(DBUS_NAME, "reboot", 1)
133            self.softPowerOff()
134        return None
135
136    @dbus.service.method(DBUS_NAME, in_signature="", out_signature="")
137    def quiesce(self):
138        intf = self.getInterface("systemd")
139        f = getattr(intf, "StartUnit")
140        f.call_async("obmc-host-quiesce@0.target", "replace")
141        return None
142
143    @dbus.service.method(DBUS_NAME, in_signature="", out_signature="i")
144    def getPowerState(self):
145        intf = self.getInterface("power_control")
146        return intf.getPowerState()
147
148    # Signal handler
149
150    def power_button_signal_handler(self):
151        # toggle power, power-on / soft-power-off
152        state = self.getPowerState()
153        if state == POWER_OFF:
154            self.powerOn()
155        elif state == POWER_ON:
156            self.softPowerOff()
157
158    def long_power_button_signal_handler(self):
159        print("Long-press button, hard power off")
160        self.powerOff()
161
162    def softreset_button_signal_handler(self):
163        self.softReboot()
164
165    def host_watchdog_signal_handler(self):
166        print("Watchdog Error, Going to quiesce")
167        self.quiesce()
168
169
170if __name__ == "__main__":
171    dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
172
173    bus = get_dbus()
174    obj = ChassisControlObject(bus, OBJ_NAME)
175    mainloop = gobject.MainLoop()
176
177    obj.unmask_signals()
178    name = dbus.service.BusName(DBUS_NAME, bus)
179
180    print("Running ChassisControlService")
181    mainloop.run()
182
183# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
184