blob: 7925b87ed82836c5aa8f68d3129664aa8bd6d54c [file] [log] [blame]
Andrew Geissler36529022016-11-29 15:23:54 -06001#include <iostream>
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -06002#include <map>
3#include <string>
Andrew Geissleref3c1842016-12-01 12:33:09 -06004#include <systemd/sd-bus.h>
Michael Tritz206a8332017-02-06 16:01:23 -06005#include <sdbusplus/server.hpp>
Andrew Geissler1e3bf942016-12-13 15:32:22 -06006#include <log.hpp>
Andrew Geissler36529022016-11-29 15:23:54 -06007#include "host_state_manager.hpp"
8
9namespace phosphor
10{
11namespace state
12{
13namespace manager
14{
15
Andrew Geissler3e3b84b2016-12-02 15:46:17 -060016// When you see server:: you know we're referencing our base class
17namespace server = sdbusplus::xyz::openbmc_project::State::server;
18
Andrew Geissler1e3bf942016-12-13 15:32:22 -060019using namespace phosphor::logging;
20
Andrew Geissler4da7e002017-01-24 15:21:40 -060021constexpr auto HOST_STATE_POWEROFF_TGT = "obmc-chassis-stop@0.target";
22constexpr auto HOST_STATE_POWERON_TGT = "obmc-chassis-start@0.target";
Michael Tritz206a8332017-02-06 16:01:23 -060023constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-quiesce-host@0.target";
Andrew Geissler4da7e002017-01-24 15:21:40 -060024
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060025/* Map a transition to it's systemd target */
26const std::map<server::Host::Transition,std::string> SYSTEMD_TARGET_TABLE =
27{
Andrew Geissler4da7e002017-01-24 15:21:40 -060028 {server::Host::Transition::Off, HOST_STATE_POWEROFF_TGT},
29 {server::Host::Transition::On, HOST_STATE_POWERON_TGT}
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060030};
31
32constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
33constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
34constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
35
36constexpr auto SYSTEM_SERVICE = "org.openbmc.managers.System";
37constexpr auto SYSTEM_OBJ_PATH = "/org/openbmc/managers/System";
38constexpr auto SYSTEM_INTERFACE = SYSTEM_SERVICE;
39
Michael Tritz206a8332017-02-06 16:01:23 -060040constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
41constexpr auto MAPPER_PATH = "/xyz/openbmc_project/ObjectMapper";
42constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
43
Andrew Geissleref621162016-12-08 12:56:21 -060044/* Map a system state to the HostState */
Andrew Geissleref621162016-12-08 12:56:21 -060045const std::map<std::string, server::Host::HostState> SYS_HOST_STATE_TABLE = {
46 {"HOST_BOOTING", server::Host::HostState::Running},
47 {"HOST_POWERED_OFF", server::Host::HostState::Off}
48};
49
Andrew Geissler4da7e002017-01-24 15:21:40 -060050void Host::subscribeToSystemdSignals()
51{
52 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
53 SYSTEMD_OBJ_PATH,
54 SYSTEMD_INTERFACE,
55 "Subscribe");
56 this->bus.call_noreply(method);
57
58 return;
59}
60
Andrew Geissleref3c1842016-12-01 12:33:09 -060061// TODO - Will be rewritten once sdbusplus client bindings are in place
62// and persistent storage design is in place
63void Host::determineInitialState()
64{
65 std::string sysState;
66
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060067 auto method = this->bus.new_method_call(SYSTEM_SERVICE,
68 SYSTEM_OBJ_PATH,
69 SYSTEM_INTERFACE,
Andrew Geissleref3c1842016-12-01 12:33:09 -060070 "getSystemState");
71
72 auto reply = this->bus.call(method);
73
74 reply.read(sysState);
75
76 if(sysState == "HOST_BOOTED")
77 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060078 log<level::INFO>("Initial Host State will be Running",
79 entry("CURRENT_HOST_STATE=%s",
80 convertForMessage(HostState::Running).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060081 server::Host::currentHostState(HostState::Running);
82 server::Host::requestedHostTransition(Transition::On);
Andrew Geissleref3c1842016-12-01 12:33:09 -060083 }
84 else
85 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060086 log<level::INFO>("Initial Host State will be Off",
87 entry("CURRENT_HOST_STATE=%s",
88 convertForMessage(HostState::Off).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060089 server::Host::currentHostState(HostState::Off);
90 server::Host::requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -060091 }
92
93 // Set transition initially to Off
94 // TODO - Eventually need to restore this from persistent storage
Andrew Geissler3e3b84b2016-12-02 15:46:17 -060095 server::Host::requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -060096
97 return;
98}
99
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600100void Host::executeTransition(Transition tranReq)
101{
102 auto sysdUnit = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
103
104 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
105 SYSTEMD_OBJ_PATH,
106 SYSTEMD_INTERFACE,
107 "StartUnit");
108
109 method.append(sysdUnit);
110 method.append("replace");
111
Andrew Geissler4da7e002017-01-24 15:21:40 -0600112 this->bus.call_noreply(method);
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600113
114 return;
115}
116
Michael Tritz206a8332017-02-06 16:01:23 -0600117bool Host::isAutoReboot()
118{
119 sdbusplus::message::variant<std::string> autoRebootParam;
120 std::string strParam;
121
122 std::string HOST_PATH("/org/openbmc/settings/host0");
123 std::string HOST_INTERFACE("org.openbmc.settings.Host");
124
125 auto mapper = this->bus.new_method_call(MAPPER_BUSNAME,
126 MAPPER_PATH,
127 MAPPER_INTERFACE,
128 "GetObject");
129
130 mapper.append(HOST_PATH, std::vector<std::string>({HOST_INTERFACE}));
131 auto mapperResponseMsg = this->bus.call(mapper);
132
133 if (mapperResponseMsg.is_method_error())
134 {
135 log<level::ERR>("Error in mapper call");
136 return false;
137 }
138
139 std::map<std::string, std::vector<std::string>> mapperResponse;
140 mapperResponseMsg.read(mapperResponse);
141 if (mapperResponse.empty())
142 {
143 log<level::ERR>("Error reading mapper response");
144 return false;
145 }
146
147 const auto& host = mapperResponse.begin()->first;
148
149 auto method = this->bus.new_method_call(host.c_str(),
150 HOST_PATH.c_str(),
151 "org.freedesktop.DBus.Properties",
152 "Get");
153
154 method.append(HOST_INTERFACE.c_str(), "auto_reboot");
155 auto reply = this->bus.call(method);
156
157 if (reply.is_method_error())
158 {
159 log<level::ERR>("Error in auto_reboot Get");
160 return false;
161 }
162
163 reply.read(autoRebootParam);
164 strParam =
165 sdbusplus::message::variant_ns::get<std::string>(autoRebootParam);
166
167 if (strParam.empty())
168 {
169 log<level::ERR>("Error reading auto_reboot response");
170 return false;
171 }
172
173 if (strParam == "yes")
174 {
175 return true;
176 }
177
178 return false;
179}
180
Andrew Geissler4da7e002017-01-24 15:21:40 -0600181int Host::sysStateChangeSignal(sd_bus_message *msg, void *userData,
182 sd_bus_error *retError)
Andrew Geissleref621162016-12-08 12:56:21 -0600183{
Andrew Geissler4da7e002017-01-24 15:21:40 -0600184 return static_cast<Host*>(userData)->sysStateChange(msg, retError);
185}
Andrew Geissleref621162016-12-08 12:56:21 -0600186
Andrew Geissler4da7e002017-01-24 15:21:40 -0600187int Host::sysStateChange(sd_bus_message* msg,
188 sd_bus_error* retError)
189{
190 uint32_t newStateID {};
191 sdbusplus::message::object_path newStateObjPath;
192 std::string newStateUnit{};
193 std::string newStateResult{};
194
195 auto sdPlusMsg = sdbusplus::message::message(msg);
196 //Read the msg and populate each variable
197 sdPlusMsg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
198
199 if((newStateUnit == HOST_STATE_POWEROFF_TGT) &&
200 (newStateResult == "done"))
Andrew Geissleref621162016-12-08 12:56:21 -0600201 {
Andrew Geissler4da7e002017-01-24 15:21:40 -0600202 log<level::INFO>("Recieved signal that host is off");
203 this->currentHostState(server::Host::HostState::Off);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600204
205 // Check if we need to start a new transition (i.e. a Reboot)
Andrew Geissler4da7e002017-01-24 15:21:40 -0600206 if(this->server::Host::requestedHostTransition() ==
207 Transition::Reboot)
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600208 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600209 log<level::DEBUG>("Reached intermediate state, going to next");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600210 this->executeTransition(server::Host::Transition::On);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600211 }
Andrew Geissleref621162016-12-08 12:56:21 -0600212 }
Andrew Geissler4da7e002017-01-24 15:21:40 -0600213 else if((newStateUnit == HOST_STATE_POWERON_TGT) &&
214 (newStateResult == "done"))
215 {
216 log<level::INFO>("Recieved signal that host is running");
217 this->currentHostState(server::Host::HostState::Running);
218 }
Michael Tritz206a8332017-02-06 16:01:23 -0600219 else if((newStateUnit == HOST_STATE_QUIESCE_TGT) &&
220 (newStateResult == "done"))
221 {
222 if (Host::isAutoReboot())
223 {
224 log<level::INFO>("Auto reboot enabled. Beginning reboot...");
225 Host::requestedHostTransition(server::Host::Transition::Reboot);
226 }
227 else
228 {
229 log<level::INFO>("Auto reboot disabled. Maintaining quiesce.");
230 }
231
232 }
Andrew Geissleref621162016-12-08 12:56:21 -0600233
234 return 0;
235}
236
Andrew Geissleref3c1842016-12-01 12:33:09 -0600237Host::Transition Host::requestedHostTransition(Transition value)
238{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600239 log<level::INFO>(
240 "Host State transaction request",
241 entry("REQUESTED_HOST_TRANSITION=%s",
242 convertForMessage(value).c_str()));
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600243
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600244 Transition tranReq = value;
245 if(value == server::Host::Transition::Reboot)
246 {
247 // On reboot requests we just need to do a off if we're on and
248 // vice versa. The handleSysStateChange() code above handles the
249 // second part of the reboot
250 if(this->server::Host::currentHostState() ==
251 server::Host::HostState::Off)
252 {
253 tranReq = server::Host::Transition::On;
254 }
255 else
256 {
257 tranReq = server::Host::Transition::Off;
258 }
259 }
260
261 executeTransition(tranReq);
Andrew Geissler3e3b84b2016-12-02 15:46:17 -0600262 return server::Host::requestedHostTransition(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600263}
264
Andrew Geissleref3c1842016-12-01 12:33:09 -0600265Host::HostState Host::currentHostState(HostState value)
266{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600267 log<level::INFO>("Change to Host State",
268 entry("CURRENT_HOST_STATE=%s",
269 convertForMessage(value).c_str()));
Andrew Geissleref621162016-12-08 12:56:21 -0600270 return server::Host::currentHostState(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600271}
272
Andrew Geissler36529022016-11-29 15:23:54 -0600273} // namespace manager
274} // namespace state
275} // namepsace phosphor