blob: 90c0ae5c4733b06f28a08792b89a46c4e8335f55 [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 Geissler7b90a622017-08-08 11:41:08 -050023// When you see server:: or reboot:: you know we're referencing our base class
Andrew Geissler3e3b84b2016-12-02 15:46:17 -060024namespace server = sdbusplus::xyz::openbmc_project::State::server;
Andrew Geissler7b90a622017-08-08 11:41:08 -050025namespace reboot = sdbusplus::xyz::openbmc_project::Control::Boot::server;
Andrew Geissler3e3b84b2016-12-02 15:46:17 -060026
Andrew Geissler1e3bf942016-12-13 15:32:22 -060027using namespace phosphor::logging;
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050028namespace fs = std::experimental::filesystem;
Andrew Geissler1e3bf942016-12-13 15:32:22 -060029
Andrew Geissler4f309e82017-05-24 15:18:01 -050030// host-shutdown notifies host of shutdown and that leads to host-stop being
31// called so initiate a host shutdown with the -shutdown target and consider the
32// host shut down when the -stop target is complete
33constexpr auto HOST_STATE_SOFT_POWEROFF_TGT = "obmc-host-shutdown@0.target";
Josh D. Kingca357922017-04-11 13:44:09 -050034constexpr auto HOST_STATE_POWEROFF_TGT = "obmc-host-stop@0.target";
35constexpr auto HOST_STATE_POWERON_TGT = "obmc-host-start@0.target";
Andrew Geisslera27a6e82017-07-27 16:44:43 -050036constexpr auto HOST_STATE_REBOOT_TGT = "obmc-host-reboot@0.target";
Josh D. Kingcc3fb5d2017-04-19 15:45:10 -050037constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-host-quiesce@0.target";
Andrew Geissler4da7e002017-01-24 15:21:40 -060038
Josh D. King929ef702017-03-02 10:58:11 -060039constexpr auto ACTIVE_STATE = "active";
40constexpr auto ACTIVATING_STATE = "activating";
41
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060042/* Map a transition to it's systemd target */
43const std::map<server::Host::Transition,std::string> SYSTEMD_TARGET_TABLE =
44{
Andrew Geissler4f309e82017-05-24 15:18:01 -050045 {server::Host::Transition::Off, HOST_STATE_SOFT_POWEROFF_TGT},
Andrew Geisslera27a6e82017-07-27 16:44:43 -050046 {server::Host::Transition::On, HOST_STATE_POWERON_TGT},
47 {server::Host::Transition::Reboot, HOST_STATE_REBOOT_TGT}
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060048};
49
50constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
51constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
52constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
53
Michael Tritz206a8332017-02-06 16:01:23 -060054constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
Leonel Gonzalezf318d872017-03-16 13:47:49 -050055constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
Michael Tritz206a8332017-02-06 16:01:23 -060056constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
57
Josh D. King929ef702017-03-02 10:58:11 -060058constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
59constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
60
Andrew Geissleref621162016-12-08 12:56:21 -060061/* Map a system state to the HostState */
Andrew Geissleref621162016-12-08 12:56:21 -060062const std::map<std::string, server::Host::HostState> SYS_HOST_STATE_TABLE = {
63 {"HOST_BOOTING", server::Host::HostState::Running},
Saqib Khanadaa7212017-02-23 13:19:28 -060064 {"HOST_POWERED_OFF", server::Host::HostState::Off},
65 {"HOST_QUIESCED", server::Host::HostState::Quiesced}
Andrew Geissleref621162016-12-08 12:56:21 -060066};
67
Andrew Geissler4da7e002017-01-24 15:21:40 -060068void Host::subscribeToSystemdSignals()
69{
70 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
71 SYSTEMD_OBJ_PATH,
72 SYSTEMD_INTERFACE,
73 "Subscribe");
74 this->bus.call_noreply(method);
75
76 return;
77}
78
Andrew Geissleref3c1842016-12-01 12:33:09 -060079void Host::determineInitialState()
80{
Andrew Geissleref3c1842016-12-01 12:33:09 -060081
Josh D. King222014e2017-05-16 13:35:21 -050082 if(stateActive(HOST_STATE_POWERON_TGT))
Andrew Geissleref3c1842016-12-01 12:33:09 -060083 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060084 log<level::INFO>("Initial Host State will be Running",
85 entry("CURRENT_HOST_STATE=%s",
86 convertForMessage(HostState::Running).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060087 server::Host::currentHostState(HostState::Running);
88 server::Host::requestedHostTransition(Transition::On);
Andrew Geissleref3c1842016-12-01 12:33:09 -060089 }
90 else
91 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060092 log<level::INFO>("Initial Host State will be Off",
93 entry("CURRENT_HOST_STATE=%s",
94 convertForMessage(HostState::Off).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060095 server::Host::currentHostState(HostState::Off);
96 server::Host::requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -060097 }
98
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050099 auto restore = getStateRestoreSetting();
100
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500101 if ((!restore) || (!deserialize(HOST_STATE_PERSIST_PATH, *this)))
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500102 {
103 //set to default value.
104 server::Host::requestedHostTransition(Transition::Off);
105 }
Andrew Geissleref3c1842016-12-01 12:33:09 -0600106
107 return;
108}
109
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500110bool Host::getStateRestoreSetting() const
111{
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500112 using namespace settings;
113 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
114 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500115
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500116 auto method =
117 bus.new_method_call(
118 settings.service(settings.powerRestorePolicy,
119 powerRestoreIntf).c_str(),
120 settings.powerRestorePolicy.c_str(),
121 "org.freedesktop.DBus.Properties",
122 "Get");
123
124 method.append(powerRestoreIntf, "PowerRestorePolicy");
125 auto reply = bus.call(method);
126 if (reply.is_method_error())
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500127 {
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500128 log<level::ERR>("Error in PowerRestorePolicy Get");
129 elog<InternalFailure>();
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500130 }
131
132 sdbusplus::message::variant<std::string> result;
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500133 reply.read(result);
134 auto powerPolicy = result.get<std::string>();
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500135
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500136 if (RestorePolicy::Policy::Restore ==
137 RestorePolicy::convertPolicyFromString(powerPolicy))
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500138 {
139 return true;
140 }
141 return false;
142}
143
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600144void Host::executeTransition(Transition tranReq)
145{
146 auto sysdUnit = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
147
148 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
149 SYSTEMD_OBJ_PATH,
150 SYSTEMD_INTERFACE,
151 "StartUnit");
152
153 method.append(sysdUnit);
154 method.append("replace");
155
Andrew Geissler4da7e002017-01-24 15:21:40 -0600156 this->bus.call_noreply(method);
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600157
158 return;
159}
160
Josh D. King929ef702017-03-02 10:58:11 -0600161bool Host::stateActive(const std::string& target)
162{
163 sdbusplus::message::variant<std::string> currentState;
164 sdbusplus::message::object_path unitTargetPath;
165
166 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
167 SYSTEMD_OBJ_PATH,
168 SYSTEMD_INTERFACE,
169 "GetUnit");
170
171 method.append(target);
172 auto result = this->bus.call(method);
173
174 //Check that the bus call didn't result in an error
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500175 if (result.is_method_error())
Josh D. King929ef702017-03-02 10:58:11 -0600176 {
177 log<level::ERR>("Error in bus call - could not resolve GetUnit for:",
178 entry(" %s", SYSTEMD_INTERFACE));
179 return false;
180 }
181
182 result.read(unitTargetPath);
183
184 method = this->bus.new_method_call(SYSTEMD_SERVICE,
185 static_cast<const std::string&>
186 (unitTargetPath).c_str(),
187 SYSTEMD_PROPERTY_IFACE,
188 "Get");
189
190 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
191 result = this->bus.call(method);
192
193 //Check that the bus call didn't result in an error
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500194 if (result.is_method_error())
Josh D. King929ef702017-03-02 10:58:11 -0600195 {
196 log<level::ERR>("Error in bus call - could not resolve Get for:",
197 entry(" %s", SYSTEMD_PROPERTY_IFACE));
198 return false;
199 }
200
201 result.read(currentState);
202
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500203 if (currentState != ACTIVE_STATE && currentState != ACTIVATING_STATE)
Josh D. King929ef702017-03-02 10:58:11 -0600204 {
205 //False - not active
206 return false;
207 }
208 //True - active
209 return true;
210}
211
Michael Tritz206a8332017-02-06 16:01:23 -0600212bool Host::isAutoReboot()
213{
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500214 using namespace settings;
Michael Tritz206a8332017-02-06 16:01:23 -0600215
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500216 auto method =
217 bus.new_method_call(
218 settings.service(settings.autoReboot, autoRebootIntf).c_str(),
219 settings.autoReboot.c_str(),
220 "org.freedesktop.DBus.Properties",
221 "Get");
222 method.append(autoRebootIntf, "AutoReboot");
223 auto reply = bus.call(method);
Michael Tritz206a8332017-02-06 16:01:23 -0600224 if (reply.is_method_error())
225 {
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500226 log<level::ERR>("Error in AutoReboot Get");
Michael Tritz206a8332017-02-06 16:01:23 -0600227 return false;
228 }
229
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500230 sdbusplus::message::variant<bool> result;
231 reply.read(result);
232 auto autoReboot = result.get<bool>();
Andrew Geissler7b90a622017-08-08 11:41:08 -0500233 auto rebootCounterParam = reboot::RebootAttempts::attemptsLeft();
Saqib Khancbe08d12017-03-10 01:29:20 -0600234
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500235 if (autoReboot)
Michael Tritz206a8332017-02-06 16:01:23 -0600236 {
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500237 if (rebootCounterParam > 0)
Saqib Khancbe08d12017-03-10 01:29:20 -0600238 {
239 // Reduce BOOTCOUNT by 1
Andrew Geissler7b90a622017-08-08 11:41:08 -0500240 log<level::INFO>("Auto reboot enabled, rebooting");
Saqib Khancbe08d12017-03-10 01:29:20 -0600241 return true;
242 }
Saqib Khand5ac6352017-04-04 09:53:59 -0500243 else if(rebootCounterParam == 0)
Josh D. King929ef702017-03-02 10:58:11 -0600244 {
Saqib Khancbe08d12017-03-10 01:29:20 -0600245 // Reset reboot counter and go to quiesce state
Saqib Khand5ac6352017-04-04 09:53:59 -0500246 log<level::INFO>("Auto reboot enabled. "
247 "HOST BOOTCOUNT already set to 0.");
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500248 attemptsLeft(BOOT_COUNT_MAX_ALLOWED);
Saqib Khand5ac6352017-04-04 09:53:59 -0500249 return false;
250 }
251 else
252 {
253 log<level::INFO>("Auto reboot enabled. "
254 "HOST BOOTCOUNT has an invalid value.");
Saqib Khancbe08d12017-03-10 01:29:20 -0600255 return false;
256 }
Michael Tritz206a8332017-02-06 16:01:23 -0600257 }
Saqib Khand5ac6352017-04-04 09:53:59 -0500258 else
259 {
260 log<level::INFO>("Auto reboot disabled.");
261 return false;
262 }
Michael Tritz206a8332017-02-06 16:01:23 -0600263}
264
Patrick Williamsd22706f2017-05-04 05:42:49 -0500265void Host::sysStateChange(sdbusplus::message::message& msg)
Andrew Geissler4da7e002017-01-24 15:21:40 -0600266{
267 uint32_t newStateID {};
268 sdbusplus::message::object_path newStateObjPath;
269 std::string newStateUnit{};
270 std::string newStateResult{};
271
Andrew Geissler4da7e002017-01-24 15:21:40 -0600272 //Read the msg and populate each variable
Patrick Williamsd22706f2017-05-04 05:42:49 -0500273 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
Andrew Geissler4da7e002017-01-24 15:21:40 -0600274
275 if((newStateUnit == HOST_STATE_POWEROFF_TGT) &&
Josh D. King929ef702017-03-02 10:58:11 -0600276 (newStateResult == "done") &&
277 (!stateActive(HOST_STATE_POWERON_TGT)))
Andrew Geissleref621162016-12-08 12:56:21 -0600278 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930279 log<level::INFO>("Received signal that host is off");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600280 this->currentHostState(server::Host::HostState::Off);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600281
Andrew Geissleref621162016-12-08 12:56:21 -0600282 }
Andrew Geissler4da7e002017-01-24 15:21:40 -0600283 else if((newStateUnit == HOST_STATE_POWERON_TGT) &&
Josh D. King929ef702017-03-02 10:58:11 -0600284 (newStateResult == "done") &&
285 (stateActive(HOST_STATE_POWERON_TGT)))
Andrew Geissler4da7e002017-01-24 15:21:40 -0600286 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930287 log<level::INFO>("Received signal that host is running");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600288 this->currentHostState(server::Host::HostState::Running);
289 }
Michael Tritz206a8332017-02-06 16:01:23 -0600290 else if((newStateUnit == HOST_STATE_QUIESCE_TGT) &&
Josh D. King29d025d2017-04-27 12:40:22 -0500291 (newStateResult == "done") &&
292 (stateActive(HOST_STATE_QUIESCE_TGT)))
Michael Tritz206a8332017-02-06 16:01:23 -0600293 {
294 if (Host::isAutoReboot())
295 {
Saqib Khand5ac6352017-04-04 09:53:59 -0500296 log<level::INFO>("Beginning reboot...");
Michael Tritz206a8332017-02-06 16:01:23 -0600297 Host::requestedHostTransition(server::Host::Transition::Reboot);
298 }
299 else
300 {
Saqib Khand5ac6352017-04-04 09:53:59 -0500301 log<level::INFO>("Maintaining quiesce");
Saqib Khanadaa7212017-02-23 13:19:28 -0600302 this->currentHostState(server::Host::HostState::Quiesced);
Michael Tritz206a8332017-02-06 16:01:23 -0600303 }
304
305 }
Andrew Geissleref621162016-12-08 12:56:21 -0600306}
307
Andrew Geissler7b90a622017-08-08 11:41:08 -0500308uint32_t Host::decrementRebootCount()
309{
310 auto rebootCount = reboot::RebootAttempts::attemptsLeft();
311 if(rebootCount > 0)
312 {
313 return(reboot::RebootAttempts::attemptsLeft(rebootCount - 1));
314 }
315 return rebootCount;
316}
317
Andrew Geissleref3c1842016-12-01 12:33:09 -0600318Host::Transition Host::requestedHostTransition(Transition value)
319{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600320 log<level::INFO>(
321 "Host State transaction request",
322 entry("REQUESTED_HOST_TRANSITION=%s",
323 convertForMessage(value).c_str()));
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600324
Andrew Geissler7b90a622017-08-08 11:41:08 -0500325 // If this is not a power off request then we need to
326 // decrement the reboot counter. This code should
327 // never prevent a power on, it should just decrement
328 // the count to 0. The quiesce handling is where the
329 // check of this count will occur
330 if(value != server::Host::Transition::Off)
331 {
332 decrementRebootCount();
333 }
334
Andrew Geisslera27a6e82017-07-27 16:44:43 -0500335 executeTransition(value);
Andrew Geissler7b90a622017-08-08 11:41:08 -0500336
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500337 auto retVal = server::Host::requestedHostTransition(value);
338 serialize(*this);
339 return retVal;
Andrew Geissleref3c1842016-12-01 12:33:09 -0600340}
341
Andrew Geissleref3c1842016-12-01 12:33:09 -0600342Host::HostState Host::currentHostState(HostState value)
343{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600344 log<level::INFO>("Change to Host State",
345 entry("CURRENT_HOST_STATE=%s",
346 convertForMessage(value).c_str()));
Andrew Geissleref621162016-12-08 12:56:21 -0600347 return server::Host::currentHostState(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600348}
349
Andrew Geissler36529022016-11-29 15:23:54 -0600350} // namespace manager
351} // namespace state
352} // namepsace phosphor