| Norman James | 42c1be8 | 2015-10-22 14:34:26 -0500 | [diff] [blame] | 1 | #!/usr/bin/python -u | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 2 |  | 
| Norman James | 471ab59 | 2015-08-30 22:29:40 -0500 | [diff] [blame] | 3 | import sys | 
| Adriana Kobylak | 08d3bdb | 2015-10-20 16:59:14 -0500 | [diff] [blame] | 4 | import uuid | 
| Norman James | 6f8d042 | 2015-09-14 18:48:00 -0500 | [diff] [blame] | 5 | import gobject | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 6 | import dbus | 
|  | 7 | import dbus.service | 
|  | 8 | import dbus.mainloop.glib | 
| Brad Bishop | 84e73b5 | 2016-05-12 15:57:52 -0400 | [diff] [blame] | 9 | from obmc.dbuslib.bindings import get_dbus, DbusProperties, DbusObjectManager | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 10 |  | 
| Norman James | 3f97c5d | 2015-08-26 17:44:14 -0500 | [diff] [blame] | 11 | DBUS_NAME = 'org.openbmc.control.Chassis' | 
| Norman James | 8fee6f2 | 2015-10-28 12:48:43 -0500 | [diff] [blame] | 12 | OBJ_NAME = '/org/openbmc/control/chassis0' | 
| Norman James | a3e47c4 | 2015-10-18 14:43:10 -0500 | [diff] [blame] | 13 | CONTROL_INTF = 'org.openbmc.Control' | 
| Norman James | 3f97c5d | 2015-08-26 17:44:14 -0500 | [diff] [blame] | 14 |  | 
| Norman James | ad8c3d3 | 2016-02-11 15:19:01 -0600 | [diff] [blame] | 15 | MACHINE_ID = '/etc/machine-id' | 
|  | 16 |  | 
| Norman James | 2a3d20b | 2015-08-20 07:09:33 -0500 | [diff] [blame] | 17 | POWER_OFF = 0 | 
|  | 18 | POWER_ON = 1 | 
|  | 19 |  | 
| Norman James | 9e6acf9 | 2015-09-08 07:00:04 -0500 | [diff] [blame] | 20 | BOOTED = 100 | 
|  | 21 |  | 
| Norman James | 90baede | 2015-09-02 20:32:49 -0500 | [diff] [blame] | 22 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 23 | class 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 | 
| Adriana Kobylak | 08d3bdb | 2015-10-20 16:59:14 -0500 | [diff] [blame] | 35 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 36 | return uuid | 
| Norman James | cfc2b44 | 2015-10-31 17:31:46 -0500 | [diff] [blame] | 37 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 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 | }, | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 55 | 'host_services': { | 
|  | 56 | 'bus_name': 'org.openbmc.HostServices', | 
|  | 57 | 'object_name': '/org/openbmc/HostServices', | 
|  | 58 | 'interface_name': 'org.openbmc.HostServices' | 
|  | 59 | }, | 
|  | 60 | 'settings': { | 
|  | 61 | 'bus_name': 'org.openbmc.settings.Host', | 
|  | 62 | 'object_name': '/org/openbmc/settings/host0', | 
|  | 63 | 'interface_name': 'org.freedesktop.DBus.Properties' | 
|  | 64 | }, | 
| Brad Bishop | abe0f68 | 2016-08-22 19:27:18 -0400 | [diff] [blame] | 65 | 'systemd': { | 
|  | 66 | 'bus_name': 'org.freedesktop.systemd1', | 
|  | 67 | 'object_name': '/org/freedesktop/systemd1', | 
|  | 68 | 'interface_name': 'org.freedesktop.systemd1.Manager' | 
| Andrew Geissler | 6b63e9a | 2016-06-30 10:45:01 -0500 | [diff] [blame] | 69 | }, | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 70 | } | 
| Norman James | 72567ba | 2016-01-13 16:57:48 -0600 | [diff] [blame] | 71 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 72 | # uuid | 
|  | 73 | self.Set(DBUS_NAME, "uuid", self.getUuid()) | 
|  | 74 | self.Set(DBUS_NAME, "reboot", 0) | 
| Norman James | 72567ba | 2016-01-13 16:57:48 -0600 | [diff] [blame] | 75 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 76 | bus.add_signal_receiver(self.power_button_signal_handler, | 
|  | 77 | dbus_interface="org.openbmc.Button", | 
|  | 78 | signal_name="Released", | 
|  | 79 | path="/org/openbmc/buttons/power0") | 
| Adriana Kobylak | eeb9b44 | 2016-08-15 11:12:53 -0500 | [diff] [blame] | 80 | bus.add_signal_receiver(self.long_power_button_signal_handler, | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 81 | dbus_interface="org.openbmc.Button", | 
|  | 82 | signal_name="PressedLong", | 
|  | 83 | path="/org/openbmc/buttons/power0") | 
|  | 84 | bus.add_signal_receiver(self.softreset_button_signal_handler, | 
|  | 85 | dbus_interface="org.openbmc.Button", | 
|  | 86 | signal_name="Released", | 
|  | 87 | path="/org/openbmc/buttons/reset0") | 
|  | 88 |  | 
|  | 89 | bus.add_signal_receiver(self.host_watchdog_signal_handler, | 
|  | 90 | dbus_interface="org.openbmc.Watchdog", | 
|  | 91 | signal_name="WatchdogError") | 
|  | 92 |  | 
|  | 93 | bus.add_signal_receiver(self.emergency_shutdown_signal_handler, | 
|  | 94 | dbus_interface="org.openbmc.SensorThresholds", | 
|  | 95 | signal_name="Emergency") | 
|  | 96 |  | 
|  | 97 | bus.add_signal_receiver(self.SystemStateHandler, | 
|  | 98 | signal_name="GotoSystemState") | 
| Norman James | 471ab59 | 2015-08-30 22:29:40 -0500 | [diff] [blame] | 99 |  | 
| Norman James | 9e6acf9 | 2015-09-08 07:00:04 -0500 | [diff] [blame] | 100 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 101 | def getInterface(self, name): | 
|  | 102 | o = self.dbus_objects[name] | 
|  | 103 | obj = bus.get_object(o['bus_name'], o['object_name'], introspect=False) | 
|  | 104 | return dbus.Interface(obj, o['interface_name']) | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 105 |  | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 106 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 107 | @dbus.service.method(DBUS_NAME, | 
|  | 108 | in_signature='', out_signature='') | 
|  | 109 | def setIdentify(self): | 
|  | 110 | print "Turn on identify" | 
|  | 111 | intf = self.getInterface('identify_led') | 
|  | 112 | intf.setOn() | 
|  | 113 | return None | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 114 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 115 | @dbus.service.method(DBUS_NAME, | 
|  | 116 | in_signature='', out_signature='') | 
|  | 117 | def clearIdentify(self): | 
|  | 118 | print "Turn on identify" | 
|  | 119 | intf = self.getInterface('identify_led') | 
|  | 120 | intf.setOff() | 
|  | 121 | return None | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 122 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 123 | @dbus.service.method(DBUS_NAME, | 
|  | 124 | in_signature='', out_signature='') | 
|  | 125 | def powerOn(self): | 
|  | 126 | print "Turn on power and boot" | 
|  | 127 | self.Set(DBUS_NAME, "reboot", 0) | 
| Brad Bishop | abe0f68 | 2016-08-22 19:27:18 -0400 | [diff] [blame] | 128 | intf = self.getInterface('systemd') | 
|  | 129 | f = getattr(intf, 'StartUnit') | 
|  | 130 | f.call_async('obmc-chassis-start@0.target', 'replace') | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 131 | return None | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 132 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 133 | @dbus.service.method(DBUS_NAME, | 
|  | 134 | in_signature='', out_signature='') | 
|  | 135 | def powerOff(self): | 
|  | 136 | print "Turn off power" | 
| Brad Bishop | abe0f68 | 2016-08-22 19:27:18 -0400 | [diff] [blame] | 137 |  | 
|  | 138 | intf = self.getInterface('systemd') | 
|  | 139 | f = getattr(intf, 'StartUnit') | 
|  | 140 | f.call_async('obmc-chassis-stop@0.target', 'replace') | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 141 | return None | 
| Norman James | 362a80f | 2015-09-14 14:04:39 -0500 | [diff] [blame] | 142 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 143 | @dbus.service.method(DBUS_NAME, | 
|  | 144 | in_signature='', out_signature='') | 
|  | 145 | def softPowerOff(self): | 
|  | 146 | print "Soft off power" | 
|  | 147 | intf = self.getInterface('host_services') | 
|  | 148 | ## host services will call power off when ready | 
|  | 149 | intf.SoftPowerOff() | 
|  | 150 | return None | 
| Norman James | 362a80f | 2015-09-14 14:04:39 -0500 | [diff] [blame] | 151 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 152 | @dbus.service.method(DBUS_NAME, | 
|  | 153 | in_signature='', out_signature='') | 
|  | 154 | def reboot(self): | 
|  | 155 | print "Rebooting" | 
|  | 156 | if self.getPowerState() == POWER_OFF: | 
|  | 157 | self.powerOn(); | 
|  | 158 | else: | 
|  | 159 | self.Set(DBUS_NAME, "reboot", 1) | 
|  | 160 | self.powerOff() | 
|  | 161 | return None | 
| Norman James | b4ef318 | 2015-12-03 17:54:35 -0600 | [diff] [blame] | 162 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 163 | @dbus.service.method(DBUS_NAME, | 
|  | 164 | in_signature='', out_signature='') | 
|  | 165 | def softReboot(self): | 
|  | 166 | print "Soft Rebooting" | 
|  | 167 | if self.getPowerState() == POWER_OFF: | 
|  | 168 | self.powerOn(); | 
|  | 169 | else: | 
|  | 170 | self.Set(DBUS_NAME, "reboot", 1) | 
|  | 171 | self.softPowerOff() | 
|  | 172 | return None | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 173 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 174 | @dbus.service.method(DBUS_NAME, | 
|  | 175 | in_signature='', out_signature='i') | 
|  | 176 | def getPowerState(self): | 
|  | 177 | intf = self.getInterface('power_control') | 
|  | 178 | return intf.getPowerState() | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 179 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 180 | ## Signal handler | 
| Norman James | 362a80f | 2015-09-14 14:04:39 -0500 | [diff] [blame] | 181 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 182 | def SystemStateHandler(self, state_name): | 
|  | 183 | if ( | 
|  | 184 | state_name == "HOST_POWERED_OFF" or state_name == "HOST_POWERED_ON"): | 
|  | 185 | intf = self.getInterface('settings') | 
|  | 186 | intf.Set("org.openbmc.settings.Host", "system_state", state_name) | 
| Norman James | f5edb9e | 2016-01-31 13:32:24 -0600 | [diff] [blame] | 187 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 188 | if (state_name == "HOST_POWERED_OFF" and self.Get(DBUS_NAME, | 
|  | 189 | "reboot") == 1): | 
|  | 190 | self.powerOn() | 
| Norman James | 362a80f | 2015-09-14 14:04:39 -0500 | [diff] [blame] | 191 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 192 | def power_button_signal_handler(self): | 
| Adriana Kobylak | eeb9b44 | 2016-08-15 11:12:53 -0500 | [diff] [blame] | 193 | # toggle power, power-on / soft-power-off | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 194 | state = self.getPowerState() | 
|  | 195 | if state == POWER_OFF: | 
|  | 196 | self.powerOn() | 
|  | 197 | elif state == POWER_ON: | 
| Adriana Kobylak | eeb9b44 | 2016-08-15 11:12:53 -0500 | [diff] [blame] | 198 | self.softPowerOff(); | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 199 |  | 
| Adriana Kobylak | eeb9b44 | 2016-08-15 11:12:53 -0500 | [diff] [blame] | 200 | def long_power_button_signal_handler(self): | 
|  | 201 | print "Long-press button, hard power off" | 
|  | 202 | self.powerOff(); | 
| Ken | c95eccd | 2015-12-19 07:02:34 +0800 | [diff] [blame] | 203 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 204 | def softreset_button_signal_handler(self): | 
|  | 205 | self.softReboot(); | 
| Norman James | 72567ba | 2016-01-13 16:57:48 -0600 | [diff] [blame] | 206 |  | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 207 | def host_watchdog_signal_handler(self): | 
|  | 208 | print "Watchdog Error, Hard Rebooting" | 
|  | 209 | self.Set(DBUS_NAME, "reboot", 1) | 
|  | 210 | self.powerOff() | 
|  | 211 |  | 
| Yi Li | 4eab1dc | 2016-07-02 22:29:45 +0800 | [diff] [blame] | 212 | def emergency_shutdown_signal_handler(self, message): | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 213 | print "Emergency Shutdown!" | 
| Yi Li | 4eab1dc | 2016-07-02 22:29:45 +0800 | [diff] [blame] | 214 | # Log an event. | 
|  | 215 | try: | 
|  | 216 | # Exception happens or not, we need to power off. | 
|  | 217 | obj = bus.get_object("org.openbmc.records.events", | 
|  | 218 | "/org/openbmc/records/events", | 
|  | 219 | introspect=False) | 
|  | 220 | intf = dbus.Interface(obj, "org.openbmc.recordlog") | 
|  | 221 | desc = message | 
|  | 222 | sev = "critical error" | 
|  | 223 | details = "Get emergency shutdown signal. Shutdown the host." | 
|  | 224 | debug = dbus.ByteArray("") | 
|  | 225 | intf.acceptBMCMessage(desc, sev, details, debug) | 
|  | 226 | except Exception as e: | 
|  | 227 | print "Emergency shutdown signal handler: log event error." | 
|  | 228 | print e | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 229 | self.powerOff() | 
|  | 230 |  | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 231 |  | 
|  | 232 | if __name__ == '__main__': | 
|  | 233 | dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) | 
|  | 234 |  | 
| Brad Bishop | 84e73b5 | 2016-05-12 15:57:52 -0400 | [diff] [blame] | 235 | bus = get_dbus() | 
| Norman James | 3f97c5d | 2015-08-26 17:44:14 -0500 | [diff] [blame] | 236 | obj = ChassisControlObject(bus, OBJ_NAME) | 
| Norman James | 6f8d042 | 2015-09-14 18:48:00 -0500 | [diff] [blame] | 237 | mainloop = gobject.MainLoop() | 
| Brad Bishop | f0f3efe | 2016-06-29 23:20:24 -0400 | [diff] [blame] | 238 |  | 
|  | 239 | obj.unmask_signals() | 
| Brad Bishop | 70852a3 | 2016-06-29 22:58:51 -0400 | [diff] [blame] | 240 | name = dbus.service.BusName(DBUS_NAME, bus) | 
| Andrew Geissler | b7f40b5 | 2016-06-29 15:49:26 -0500 | [diff] [blame] | 241 |  | 
| Norman James | e276510 | 2015-08-19 22:00:55 -0500 | [diff] [blame] | 242 | print "Running ChassisControlService" | 
|  | 243 | mainloop.run() | 
|  | 244 |  |