blob: 83f21e72354f265fe8089429d1667c5620fc4377 [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>
Saqib Khana8006a22017-02-14 11:37:08 -06006#include <phosphor-logging/log.hpp>
Deepak Kodihalli55f132b2017-07-25 07:36:06 -05007#include <phosphor-logging/elog-errors.hpp>
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -05008#include <experimental/filesystem>
9#include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
Deepak Kodihalli55f132b2017-07-25 07:36:06 -050010#include <xyz/openbmc_project/Common/error.hpp>
Andrew Geissler36529022016-11-29 15:23:54 -060011#include "host_state_manager.hpp"
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050012#include "host_state_serialize.hpp"
13#include "config.h"
14
Andrew Geissler36529022016-11-29 15:23:54 -060015
16namespace phosphor
17{
18namespace state
19{
20namespace manager
21{
22
Andrew Geissler3e3b84b2016-12-02 15:46:17 -060023// When you see server:: you know we're referencing our base class
24namespace server = sdbusplus::xyz::openbmc_project::State::server;
25
Andrew Geissler1e3bf942016-12-13 15:32:22 -060026using namespace phosphor::logging;
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050027namespace fs = std::experimental::filesystem;
Andrew Geissler1e3bf942016-12-13 15:32:22 -060028
Andrew Geissler4f309e82017-05-24 15:18:01 -050029// host-shutdown notifies host of shutdown and that leads to host-stop being
30// called so initiate a host shutdown with the -shutdown target and consider the
31// host shut down when the -stop target is complete
32constexpr auto HOST_STATE_SOFT_POWEROFF_TGT = "obmc-host-shutdown@0.target";
Josh D. Kingca357922017-04-11 13:44:09 -050033constexpr auto HOST_STATE_POWEROFF_TGT = "obmc-host-stop@0.target";
34constexpr auto HOST_STATE_POWERON_TGT = "obmc-host-start@0.target";
Josh D. Kingcc3fb5d2017-04-19 15:45:10 -050035constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-host-quiesce@0.target";
Andrew Geissler4da7e002017-01-24 15:21:40 -060036
Josh D. King929ef702017-03-02 10:58:11 -060037constexpr auto ACTIVE_STATE = "active";
38constexpr auto ACTIVATING_STATE = "activating";
39
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060040/* Map a transition to it's systemd target */
41const std::map<server::Host::Transition,std::string> SYSTEMD_TARGET_TABLE =
42{
Andrew Geissler4f309e82017-05-24 15:18:01 -050043 {server::Host::Transition::Off, HOST_STATE_SOFT_POWEROFF_TGT},
Andrew Geissler4da7e002017-01-24 15:21:40 -060044 {server::Host::Transition::On, HOST_STATE_POWERON_TGT}
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060045};
46
47constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
48constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
49constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
50
Michael Tritz206a8332017-02-06 16:01:23 -060051constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
Leonel Gonzalezf318d872017-03-16 13:47:49 -050052constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
Michael Tritz206a8332017-02-06 16:01:23 -060053constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
54
Josh D. King929ef702017-03-02 10:58:11 -060055constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
56constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
57
Andrew Geissleref621162016-12-08 12:56:21 -060058/* Map a system state to the HostState */
Andrew Geissleref621162016-12-08 12:56:21 -060059const std::map<std::string, server::Host::HostState> SYS_HOST_STATE_TABLE = {
60 {"HOST_BOOTING", server::Host::HostState::Running},
Saqib Khanadaa7212017-02-23 13:19:28 -060061 {"HOST_POWERED_OFF", server::Host::HostState::Off},
62 {"HOST_QUIESCED", server::Host::HostState::Quiesced}
Andrew Geissleref621162016-12-08 12:56:21 -060063};
64
Andrew Geissler4da7e002017-01-24 15:21:40 -060065void Host::subscribeToSystemdSignals()
66{
67 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
68 SYSTEMD_OBJ_PATH,
69 SYSTEMD_INTERFACE,
70 "Subscribe");
71 this->bus.call_noreply(method);
72
73 return;
74}
75
Andrew Geissleref3c1842016-12-01 12:33:09 -060076void Host::determineInitialState()
77{
Andrew Geissleref3c1842016-12-01 12:33:09 -060078
Josh D. King222014e2017-05-16 13:35:21 -050079 if(stateActive(HOST_STATE_POWERON_TGT))
Andrew Geissleref3c1842016-12-01 12:33:09 -060080 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060081 log<level::INFO>("Initial Host State will be Running",
82 entry("CURRENT_HOST_STATE=%s",
83 convertForMessage(HostState::Running).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060084 server::Host::currentHostState(HostState::Running);
85 server::Host::requestedHostTransition(Transition::On);
Andrew Geissleref3c1842016-12-01 12:33:09 -060086 }
87 else
88 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060089 log<level::INFO>("Initial Host State will be Off",
90 entry("CURRENT_HOST_STATE=%s",
91 convertForMessage(HostState::Off).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060092 server::Host::currentHostState(HostState::Off);
93 server::Host::requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -060094 }
95
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050096 auto restore = getStateRestoreSetting();
97
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -050098 if ((!restore) || (!deserialize(HOST_STATE_PERSIST_PATH, *this)))
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050099 {
100 //set to default value.
101 server::Host::requestedHostTransition(Transition::Off);
102 }
Andrew Geissleref3c1842016-12-01 12:33:09 -0600103
104 return;
105}
106
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500107bool Host::getStateRestoreSetting() const
108{
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500109 using namespace settings;
110 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
111 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500112
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500113 auto method =
114 bus.new_method_call(
115 settings.service(settings.powerRestorePolicy,
116 powerRestoreIntf).c_str(),
117 settings.powerRestorePolicy.c_str(),
118 "org.freedesktop.DBus.Properties",
119 "Get");
120
121 method.append(powerRestoreIntf, "PowerRestorePolicy");
122 auto reply = bus.call(method);
123 if (reply.is_method_error())
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500124 {
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500125 log<level::ERR>("Error in PowerRestorePolicy Get");
126 elog<InternalFailure>();
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500127 }
128
129 sdbusplus::message::variant<std::string> result;
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500130 reply.read(result);
131 auto powerPolicy = result.get<std::string>();
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500132
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500133 if (RestorePolicy::Policy::Restore ==
134 RestorePolicy::convertPolicyFromString(powerPolicy))
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500135 {
136 return true;
137 }
138 return false;
139}
140
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600141void Host::executeTransition(Transition tranReq)
142{
143 auto sysdUnit = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
144
145 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
146 SYSTEMD_OBJ_PATH,
147 SYSTEMD_INTERFACE,
148 "StartUnit");
149
150 method.append(sysdUnit);
151 method.append("replace");
152
Andrew Geissler4da7e002017-01-24 15:21:40 -0600153 this->bus.call_noreply(method);
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600154
155 return;
156}
157
Josh D. King929ef702017-03-02 10:58:11 -0600158bool Host::stateActive(const std::string& target)
159{
160 sdbusplus::message::variant<std::string> currentState;
161 sdbusplus::message::object_path unitTargetPath;
162
163 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
164 SYSTEMD_OBJ_PATH,
165 SYSTEMD_INTERFACE,
166 "GetUnit");
167
168 method.append(target);
169 auto result = this->bus.call(method);
170
171 //Check that the bus call didn't result in an error
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500172 if (result.is_method_error())
Josh D. King929ef702017-03-02 10:58:11 -0600173 {
174 log<level::ERR>("Error in bus call - could not resolve GetUnit for:",
175 entry(" %s", SYSTEMD_INTERFACE));
176 return false;
177 }
178
179 result.read(unitTargetPath);
180
181 method = this->bus.new_method_call(SYSTEMD_SERVICE,
182 static_cast<const std::string&>
183 (unitTargetPath).c_str(),
184 SYSTEMD_PROPERTY_IFACE,
185 "Get");
186
187 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
188 result = this->bus.call(method);
189
190 //Check that the bus call didn't result in an error
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500191 if (result.is_method_error())
Josh D. King929ef702017-03-02 10:58:11 -0600192 {
193 log<level::ERR>("Error in bus call - could not resolve Get for:",
194 entry(" %s", SYSTEMD_PROPERTY_IFACE));
195 return false;
196 }
197
198 result.read(currentState);
199
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500200 if (currentState != ACTIVE_STATE && currentState != ACTIVATING_STATE)
Josh D. King929ef702017-03-02 10:58:11 -0600201 {
202 //False - not active
203 return false;
204 }
205 //True - active
206 return true;
207}
208
Michael Tritz206a8332017-02-06 16:01:23 -0600209bool Host::isAutoReboot()
210{
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500211 using namespace settings;
Michael Tritz206a8332017-02-06 16:01:23 -0600212
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500213 auto method =
214 bus.new_method_call(
215 settings.service(settings.autoReboot, autoRebootIntf).c_str(),
216 settings.autoReboot.c_str(),
217 "org.freedesktop.DBus.Properties",
218 "Get");
219 method.append(autoRebootIntf, "AutoReboot");
220 auto reply = bus.call(method);
Michael Tritz206a8332017-02-06 16:01:23 -0600221 if (reply.is_method_error())
222 {
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500223 log<level::ERR>("Error in AutoReboot Get");
Michael Tritz206a8332017-02-06 16:01:23 -0600224 return false;
225 }
226
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500227 sdbusplus::message::variant<bool> result;
228 reply.read(result);
229 auto autoReboot = result.get<bool>();
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500230 auto rebootCounterParam = attemptsLeft();
Saqib Khancbe08d12017-03-10 01:29:20 -0600231
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500232 if (autoReboot)
Michael Tritz206a8332017-02-06 16:01:23 -0600233 {
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500234 if (rebootCounterParam > 0)
Saqib Khancbe08d12017-03-10 01:29:20 -0600235 {
236 // Reduce BOOTCOUNT by 1
Saqib Khand5ac6352017-04-04 09:53:59 -0500237 log<level::INFO>("Auto reboot enabled. "
238 "Reducing HOST BOOTCOUNT by 1.");
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500239 attemptsLeft(rebootCounterParam - 1);
Saqib Khancbe08d12017-03-10 01:29:20 -0600240 return true;
241 }
Saqib Khand5ac6352017-04-04 09:53:59 -0500242 else if(rebootCounterParam == 0)
Josh D. King929ef702017-03-02 10:58:11 -0600243 {
Saqib Khancbe08d12017-03-10 01:29:20 -0600244 // Reset reboot counter and go to quiesce state
Saqib Khand5ac6352017-04-04 09:53:59 -0500245 log<level::INFO>("Auto reboot enabled. "
246 "HOST BOOTCOUNT already set to 0.");
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500247 attemptsLeft(BOOT_COUNT_MAX_ALLOWED);
Saqib Khand5ac6352017-04-04 09:53:59 -0500248 return false;
249 }
250 else
251 {
252 log<level::INFO>("Auto reboot enabled. "
253 "HOST BOOTCOUNT has an invalid value.");
Saqib Khancbe08d12017-03-10 01:29:20 -0600254 return false;
255 }
Michael Tritz206a8332017-02-06 16:01:23 -0600256 }
Saqib Khand5ac6352017-04-04 09:53:59 -0500257 else
258 {
259 log<level::INFO>("Auto reboot disabled.");
260 return false;
261 }
Michael Tritz206a8332017-02-06 16:01:23 -0600262}
263
Patrick Williamsd22706f2017-05-04 05:42:49 -0500264void Host::sysStateChange(sdbusplus::message::message& msg)
Andrew Geissler4da7e002017-01-24 15:21:40 -0600265{
266 uint32_t newStateID {};
267 sdbusplus::message::object_path newStateObjPath;
268 std::string newStateUnit{};
269 std::string newStateResult{};
270
Andrew Geissler4da7e002017-01-24 15:21:40 -0600271 //Read the msg and populate each variable
Patrick Williamsd22706f2017-05-04 05:42:49 -0500272 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
Andrew Geissler4da7e002017-01-24 15:21:40 -0600273
274 if((newStateUnit == HOST_STATE_POWEROFF_TGT) &&
Josh D. King929ef702017-03-02 10:58:11 -0600275 (newStateResult == "done") &&
276 (!stateActive(HOST_STATE_POWERON_TGT)))
Andrew Geissleref621162016-12-08 12:56:21 -0600277 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930278 log<level::INFO>("Received signal that host is off");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600279 this->currentHostState(server::Host::HostState::Off);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600280
281 // Check if we need to start a new transition (i.e. a Reboot)
Andrew Geissler4da7e002017-01-24 15:21:40 -0600282 if(this->server::Host::requestedHostTransition() ==
283 Transition::Reboot)
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600284 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600285 log<level::DEBUG>("Reached intermediate state, going to next");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600286 this->executeTransition(server::Host::Transition::On);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600287 }
Andrew Geissleref621162016-12-08 12:56:21 -0600288 }
Andrew Geissler4da7e002017-01-24 15:21:40 -0600289 else if((newStateUnit == HOST_STATE_POWERON_TGT) &&
Josh D. King929ef702017-03-02 10:58:11 -0600290 (newStateResult == "done") &&
291 (stateActive(HOST_STATE_POWERON_TGT)))
Andrew Geissler4da7e002017-01-24 15:21:40 -0600292 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930293 log<level::INFO>("Received signal that host is running");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600294 this->currentHostState(server::Host::HostState::Running);
295 }
Michael Tritz206a8332017-02-06 16:01:23 -0600296 else if((newStateUnit == HOST_STATE_QUIESCE_TGT) &&
Josh D. King29d025d2017-04-27 12:40:22 -0500297 (newStateResult == "done") &&
298 (stateActive(HOST_STATE_QUIESCE_TGT)))
Michael Tritz206a8332017-02-06 16:01:23 -0600299 {
300 if (Host::isAutoReboot())
301 {
Saqib Khand5ac6352017-04-04 09:53:59 -0500302 log<level::INFO>("Beginning reboot...");
Michael Tritz206a8332017-02-06 16:01:23 -0600303 Host::requestedHostTransition(server::Host::Transition::Reboot);
304 }
305 else
306 {
Saqib Khand5ac6352017-04-04 09:53:59 -0500307 log<level::INFO>("Maintaining quiesce");
Saqib Khanadaa7212017-02-23 13:19:28 -0600308 this->currentHostState(server::Host::HostState::Quiesced);
Michael Tritz206a8332017-02-06 16:01:23 -0600309 }
310
311 }
Andrew Geissleref621162016-12-08 12:56:21 -0600312}
313
Andrew Geissleref3c1842016-12-01 12:33:09 -0600314Host::Transition Host::requestedHostTransition(Transition value)
315{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600316 log<level::INFO>(
317 "Host State transaction request",
318 entry("REQUESTED_HOST_TRANSITION=%s",
319 convertForMessage(value).c_str()));
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600320
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600321 Transition tranReq = value;
322 if(value == server::Host::Transition::Reboot)
323 {
324 // On reboot requests we just need to do a off if we're on and
325 // vice versa. The handleSysStateChange() code above handles the
326 // second part of the reboot
327 if(this->server::Host::currentHostState() ==
328 server::Host::HostState::Off)
329 {
330 tranReq = server::Host::Transition::On;
331 }
332 else
333 {
334 tranReq = server::Host::Transition::Off;
335 }
336 }
337
338 executeTransition(tranReq);
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500339 auto retVal = server::Host::requestedHostTransition(value);
340 serialize(*this);
341 return retVal;
Andrew Geissleref3c1842016-12-01 12:33:09 -0600342}
343
Andrew Geissleref3c1842016-12-01 12:33:09 -0600344Host::HostState Host::currentHostState(HostState value)
345{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600346 log<level::INFO>("Change to Host State",
347 entry("CURRENT_HOST_STATE=%s",
348 convertForMessage(value).c_str()));
Andrew Geissleref621162016-12-08 12:56:21 -0600349 return server::Host::currentHostState(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600350}
351
Andrew Geissler36529022016-11-29 15:23:54 -0600352} // namespace manager
353} // namespace state
354} // namepsace phosphor