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