blob: ec1f95fe8545ae052e04ae0203a8616b251c5302 [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>
Andrew Geissler033fc3b2017-08-30 15:11:44 -05005#include <cereal/cereal.hpp>
6#include <cereal/types/string.hpp>
7#include <cereal/types/vector.hpp>
8#include <cereal/types/tuple.hpp>
9#include <cereal/archives/json.hpp>
10#include <fstream>
Michael Tritz206a8332017-02-06 16:01:23 -060011#include <sdbusplus/server.hpp>
Saqib Khana8006a22017-02-14 11:37:08 -060012#include <phosphor-logging/log.hpp>
Deepak Kodihalli55f132b2017-07-25 07:36:06 -050013#include <phosphor-logging/elog-errors.hpp>
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050014#include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp>
Deepak Kodihalli55f132b2017-07-25 07:36:06 -050015#include <xyz/openbmc_project/Common/error.hpp>
Andrew Geissler36529022016-11-29 15:23:54 -060016#include "host_state_manager.hpp"
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050017#include "config.h"
18
Vishwanatha Subbanna0a838732017-10-05 12:43:19 +053019// Register class version with Cereal
20CEREAL_CLASS_VERSION(phosphor::state::manager::Host, CLASS_VERSION);
Andrew Geissler36529022016-11-29 15:23:54 -060021
22namespace phosphor
23{
24namespace state
25{
26namespace manager
27{
28
Andrew Geissler7b90a622017-08-08 11:41:08 -050029// When you see server:: or reboot:: you know we're referencing our base class
Andrew Geissler3e3b84b2016-12-02 15:46:17 -060030namespace server = sdbusplus::xyz::openbmc_project::State::server;
Andrew Geissler7b90a622017-08-08 11:41:08 -050031namespace reboot = sdbusplus::xyz::openbmc_project::Control::Boot::server;
Dhruvaraj Subhashchandrana3b8d7e2017-08-10 05:40:04 -050032namespace bootprogress = sdbusplus::xyz::openbmc_project::State::Boot::server;
33namespace osstatus =
34 sdbusplus::xyz::openbmc_project::State::OperatingSystem::server;
Andrew Geissler1e3bf942016-12-13 15:32:22 -060035using namespace phosphor::logging;
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -050036namespace fs = std::experimental::filesystem;
Andrew Geissler1e3bf942016-12-13 15:32:22 -060037
Andrew Geissler4f309e82017-05-24 15:18:01 -050038// host-shutdown notifies host of shutdown and that leads to host-stop being
39// called so initiate a host shutdown with the -shutdown target and consider the
40// host shut down when the -stop target is complete
41constexpr auto HOST_STATE_SOFT_POWEROFF_TGT = "obmc-host-shutdown@0.target";
Josh D. Kingca357922017-04-11 13:44:09 -050042constexpr auto HOST_STATE_POWEROFF_TGT = "obmc-host-stop@0.target";
43constexpr auto HOST_STATE_POWERON_TGT = "obmc-host-start@0.target";
Andrew Geissler969b2612018-03-29 10:16:51 -070044constexpr auto HOST_STATE_POWERON_MIN_TGT = "obmc-host-startmin@0.target";
Andrew Geisslera27a6e82017-07-27 16:44:43 -050045constexpr auto HOST_STATE_REBOOT_TGT = "obmc-host-reboot@0.target";
Josh D. Kingcc3fb5d2017-04-19 15:45:10 -050046constexpr auto HOST_STATE_QUIESCE_TGT = "obmc-host-quiesce@0.target";
Andrew Geissler4da7e002017-01-24 15:21:40 -060047
Josh D. King929ef702017-03-02 10:58:11 -060048constexpr auto ACTIVE_STATE = "active";
49constexpr auto ACTIVATING_STATE = "activating";
50
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060051/* Map a transition to it's systemd target */
Andrew Geissler58a18012018-01-19 19:36:05 -080052const std::map<server::Host::Transition, std::string> SYSTEMD_TARGET_TABLE = {
53 {server::Host::Transition::Off, HOST_STATE_SOFT_POWEROFF_TGT},
54 {server::Host::Transition::On, HOST_STATE_POWERON_TGT},
55 {server::Host::Transition::Reboot, HOST_STATE_REBOOT_TGT}};
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060056
Andrew Geissler58a18012018-01-19 19:36:05 -080057constexpr auto SYSTEMD_SERVICE = "org.freedesktop.systemd1";
58constexpr auto SYSTEMD_OBJ_PATH = "/org/freedesktop/systemd1";
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -060059constexpr auto SYSTEMD_INTERFACE = "org.freedesktop.systemd1.Manager";
60
Michael Tritz206a8332017-02-06 16:01:23 -060061constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
Leonel Gonzalezf318d872017-03-16 13:47:49 -050062constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
Michael Tritz206a8332017-02-06 16:01:23 -060063constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
64
Josh D. King929ef702017-03-02 10:58:11 -060065constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
66constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
67
Andrew Geissleref621162016-12-08 12:56:21 -060068/* Map a system state to the HostState */
Andrew Geissleref621162016-12-08 12:56:21 -060069const std::map<std::string, server::Host::HostState> SYS_HOST_STATE_TABLE = {
Andrew Geissler58a18012018-01-19 19:36:05 -080070 {"HOST_BOOTING", server::Host::HostState::Running},
71 {"HOST_POWERED_OFF", server::Host::HostState::Off},
72 {"HOST_QUIESCED", server::Host::HostState::Quiesced}};
Andrew Geissleref621162016-12-08 12:56:21 -060073
Andrew Geissler4da7e002017-01-24 15:21:40 -060074void Host::subscribeToSystemdSignals()
75{
Andrew Geissler58a18012018-01-19 19:36:05 -080076 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
77 SYSTEMD_INTERFACE, "Subscribe");
Andrew Geissler4da7e002017-01-24 15:21:40 -060078 this->bus.call_noreply(method);
79
80 return;
81}
82
Andrew Geissleref3c1842016-12-01 12:33:09 -060083void Host::determineInitialState()
84{
Andrew Geissleref3c1842016-12-01 12:33:09 -060085
Andrew Geissler969b2612018-03-29 10:16:51 -070086 if (stateActive(HOST_STATE_POWERON_MIN_TGT))
Andrew Geissleref3c1842016-12-01 12:33:09 -060087 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060088 log<level::INFO>("Initial Host State will be Running",
89 entry("CURRENT_HOST_STATE=%s",
90 convertForMessage(HostState::Running).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060091 server::Host::currentHostState(HostState::Running);
92 server::Host::requestedHostTransition(Transition::On);
Andrew Geissleref3c1842016-12-01 12:33:09 -060093 }
94 else
95 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -060096 log<level::INFO>("Initial Host State will be Off",
97 entry("CURRENT_HOST_STATE=%s",
98 convertForMessage(HostState::Off).c_str()));
Andrew Geissler97924142017-01-24 16:10:18 -060099 server::Host::currentHostState(HostState::Off);
100 server::Host::requestedHostTransition(Transition::Off);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600101 }
102
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500103 if (!deserialize(HOST_STATE_PERSIST_PATH))
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500104 {
Andrew Geissler58a18012018-01-19 19:36:05 -0800105 // set to default value.
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500106 server::Host::requestedHostTransition(Transition::Off);
107 }
Andrew Geissleref3c1842016-12-01 12:33:09 -0600108
109 return;
110}
111
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600112void Host::executeTransition(Transition tranReq)
113{
114 auto sysdUnit = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
115
Andrew Geissler58a18012018-01-19 19:36:05 -0800116 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
117 SYSTEMD_INTERFACE, "StartUnit");
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600118
119 method.append(sysdUnit);
120 method.append("replace");
121
Andrew Geissler4da7e002017-01-24 15:21:40 -0600122 this->bus.call_noreply(method);
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600123
124 return;
125}
126
Josh D. King929ef702017-03-02 10:58:11 -0600127bool Host::stateActive(const std::string& target)
128{
129 sdbusplus::message::variant<std::string> currentState;
130 sdbusplus::message::object_path unitTargetPath;
131
Andrew Geissler58a18012018-01-19 19:36:05 -0800132 auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
133 SYSTEMD_INTERFACE, "GetUnit");
Josh D. King929ef702017-03-02 10:58:11 -0600134
135 method.append(target);
136 auto result = this->bus.call(method);
137
Andrew Geissler58a18012018-01-19 19:36:05 -0800138 // Check that the bus call didn't result in an error
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500139 if (result.is_method_error())
Josh D. King929ef702017-03-02 10:58:11 -0600140 {
141 log<level::ERR>("Error in bus call - could not resolve GetUnit for:",
142 entry(" %s", SYSTEMD_INTERFACE));
143 return false;
144 }
145
146 result.read(unitTargetPath);
147
Andrew Geissler58a18012018-01-19 19:36:05 -0800148 method = this->bus.new_method_call(
149 SYSTEMD_SERVICE,
150 static_cast<const std::string&>(unitTargetPath).c_str(),
151 SYSTEMD_PROPERTY_IFACE, "Get");
Josh D. King929ef702017-03-02 10:58:11 -0600152
153 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
154 result = this->bus.call(method);
155
Andrew Geissler58a18012018-01-19 19:36:05 -0800156 // Check that the bus call didn't result in an error
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500157 if (result.is_method_error())
Josh D. King929ef702017-03-02 10:58:11 -0600158 {
159 log<level::ERR>("Error in bus call - could not resolve Get for:",
160 entry(" %s", SYSTEMD_PROPERTY_IFACE));
161 return false;
162 }
163
164 result.read(currentState);
165
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500166 if (currentState != ACTIVE_STATE && currentState != ACTIVATING_STATE)
Josh D. King929ef702017-03-02 10:58:11 -0600167 {
Andrew Geissler58a18012018-01-19 19:36:05 -0800168 // False - not active
Josh D. King929ef702017-03-02 10:58:11 -0600169 return false;
170 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800171 // True - active
Josh D. King929ef702017-03-02 10:58:11 -0600172 return true;
173}
174
Michael Tritz206a8332017-02-06 16:01:23 -0600175bool Host::isAutoReboot()
176{
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500177 using namespace settings;
Michael Tritz206a8332017-02-06 16:01:23 -0600178
Andrew Geissler58a18012018-01-19 19:36:05 -0800179 auto method = bus.new_method_call(
180 settings.service(settings.autoReboot, autoRebootIntf).c_str(),
181 settings.autoReboot.c_str(), "org.freedesktop.DBus.Properties", "Get");
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500182 method.append(autoRebootIntf, "AutoReboot");
183 auto reply = bus.call(method);
Michael Tritz206a8332017-02-06 16:01:23 -0600184 if (reply.is_method_error())
185 {
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500186 log<level::ERR>("Error in AutoReboot Get");
Michael Tritz206a8332017-02-06 16:01:23 -0600187 return false;
188 }
189
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500190 sdbusplus::message::variant<bool> result;
191 reply.read(result);
192 auto autoReboot = result.get<bool>();
Andrew Geissler7b90a622017-08-08 11:41:08 -0500193 auto rebootCounterParam = reboot::RebootAttempts::attemptsLeft();
Saqib Khancbe08d12017-03-10 01:29:20 -0600194
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500195 if (autoReboot)
Michael Tritz206a8332017-02-06 16:01:23 -0600196 {
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500197 if (rebootCounterParam > 0)
Saqib Khancbe08d12017-03-10 01:29:20 -0600198 {
199 // Reduce BOOTCOUNT by 1
Andrew Geissler7b90a622017-08-08 11:41:08 -0500200 log<level::INFO>("Auto reboot enabled, rebooting");
Saqib Khancbe08d12017-03-10 01:29:20 -0600201 return true;
202 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800203 else if (rebootCounterParam == 0)
Josh D. King929ef702017-03-02 10:58:11 -0600204 {
Saqib Khancbe08d12017-03-10 01:29:20 -0600205 // Reset reboot counter and go to quiesce state
Saqib Khand5ac6352017-04-04 09:53:59 -0500206 log<level::INFO>("Auto reboot enabled. "
207 "HOST BOOTCOUNT already set to 0.");
Dhruvaraj Subhashchandran2710e732017-06-19 06:43:22 -0500208 attemptsLeft(BOOT_COUNT_MAX_ALLOWED);
Saqib Khand5ac6352017-04-04 09:53:59 -0500209 return false;
210 }
211 else
212 {
213 log<level::INFO>("Auto reboot enabled. "
214 "HOST BOOTCOUNT has an invalid value.");
Saqib Khancbe08d12017-03-10 01:29:20 -0600215 return false;
216 }
Michael Tritz206a8332017-02-06 16:01:23 -0600217 }
Saqib Khand5ac6352017-04-04 09:53:59 -0500218 else
219 {
220 log<level::INFO>("Auto reboot disabled.");
221 return false;
222 }
Michael Tritz206a8332017-02-06 16:01:23 -0600223}
224
Patrick Williamsd22706f2017-05-04 05:42:49 -0500225void Host::sysStateChange(sdbusplus::message::message& msg)
Andrew Geissler4da7e002017-01-24 15:21:40 -0600226{
Andrew Geissler58a18012018-01-19 19:36:05 -0800227 uint32_t newStateID{};
Andrew Geissler4da7e002017-01-24 15:21:40 -0600228 sdbusplus::message::object_path newStateObjPath;
229 std::string newStateUnit{};
230 std::string newStateResult{};
231
Andrew Geissler58a18012018-01-19 19:36:05 -0800232 // Read the msg and populate each variable
Patrick Williamsd22706f2017-05-04 05:42:49 -0500233 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
Andrew Geissler4da7e002017-01-24 15:21:40 -0600234
Andrew Geissler58a18012018-01-19 19:36:05 -0800235 if ((newStateUnit == HOST_STATE_POWEROFF_TGT) &&
Andrew Geissler969b2612018-03-29 10:16:51 -0700236 (newStateResult == "done") &&
237 (!stateActive(HOST_STATE_POWERON_MIN_TGT)))
Andrew Geissleref621162016-12-08 12:56:21 -0600238 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930239 log<level::INFO>("Received signal that host is off");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600240 this->currentHostState(server::Host::HostState::Off);
Dhruvaraj Subhashchandrana3b8d7e2017-08-10 05:40:04 -0500241 this->bootProgress(bootprogress::Progress::ProgressStages::Unspecified);
242 this->operatingSystemState(osstatus::Status::OSStatus::Inactive);
Andrew Geissleref621162016-12-08 12:56:21 -0600243 }
Andrew Geissler969b2612018-03-29 10:16:51 -0700244 else if ((newStateUnit == HOST_STATE_POWERON_MIN_TGT) &&
Andrew Geissler58a18012018-01-19 19:36:05 -0800245 (newStateResult == "done") &&
Andrew Geissler969b2612018-03-29 10:16:51 -0700246 (stateActive(HOST_STATE_POWERON_MIN_TGT)))
Andrew Geissler58a18012018-01-19 19:36:05 -0800247 {
248 log<level::INFO>("Received signal that host is running");
249 this->currentHostState(server::Host::HostState::Running);
250 }
251 else if ((newStateUnit == HOST_STATE_QUIESCE_TGT) &&
Josh D. King29d025d2017-04-27 12:40:22 -0500252 (newStateResult == "done") &&
253 (stateActive(HOST_STATE_QUIESCE_TGT)))
Andrew Geissler58a18012018-01-19 19:36:05 -0800254 {
255 if (Host::isAutoReboot())
256 {
257 log<level::INFO>("Beginning reboot...");
258 Host::requestedHostTransition(server::Host::Transition::Reboot);
259 }
260 else
261 {
262 log<level::INFO>("Maintaining quiesce");
263 this->currentHostState(server::Host::HostState::Quiesced);
264 }
265 }
Andrew Geissleref621162016-12-08 12:56:21 -0600266}
267
Andrew Geissler7b90a622017-08-08 11:41:08 -0500268uint32_t Host::decrementRebootCount()
269{
270 auto rebootCount = reboot::RebootAttempts::attemptsLeft();
Andrew Geissler58a18012018-01-19 19:36:05 -0800271 if (rebootCount > 0)
Andrew Geissler7b90a622017-08-08 11:41:08 -0500272 {
Andrew Geissler58a18012018-01-19 19:36:05 -0800273 return (reboot::RebootAttempts::attemptsLeft(rebootCount - 1));
Andrew Geissler7b90a622017-08-08 11:41:08 -0500274 }
275 return rebootCount;
276}
277
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500278fs::path Host::serialize(const fs::path& dir)
279{
280 std::ofstream os(dir.c_str(), std::ios::binary);
281 cereal::JSONOutputArchive oarchive(os);
282 oarchive(*this);
283 return dir;
284}
285
286bool Host::deserialize(const fs::path& path)
287{
Jayanth Othayothe39f3792017-09-19 23:53:31 -0500288 try
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500289 {
Jayanth Othayothe39f3792017-09-19 23:53:31 -0500290 if (fs::exists(path))
291 {
292 std::ifstream is(path.c_str(), std::ios::in | std::ios::binary);
293 cereal::JSONInputArchive iarchive(is);
294 iarchive(*this);
295 return true;
296 }
297 return false;
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500298 }
Andrew Geissler58a18012018-01-19 19:36:05 -0800299 catch (cereal::Exception& e)
Jayanth Othayothe39f3792017-09-19 23:53:31 -0500300 {
301 log<level::ERR>(e.what());
302 fs::remove(path);
303 return false;
304 }
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500305}
306
Andrew Geissleref3c1842016-12-01 12:33:09 -0600307Host::Transition Host::requestedHostTransition(Transition value)
308{
Andrew Geissler58a18012018-01-19 19:36:05 -0800309 log<level::INFO>("Host State transaction request",
310 entry("REQUESTED_HOST_TRANSITION=%s",
311 convertForMessage(value).c_str()));
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600312
Andrew Geissler7b90a622017-08-08 11:41:08 -0500313 // If this is not a power off request then we need to
314 // decrement the reboot counter. This code should
315 // never prevent a power on, it should just decrement
316 // the count to 0. The quiesce handling is where the
317 // check of this count will occur
Andrew Geissler58a18012018-01-19 19:36:05 -0800318 if (value != server::Host::Transition::Off)
Andrew Geissler7b90a622017-08-08 11:41:08 -0500319 {
320 decrementRebootCount();
321 }
322
Andrew Geisslera27a6e82017-07-27 16:44:43 -0500323 executeTransition(value);
Andrew Geissler7b90a622017-08-08 11:41:08 -0500324
Andrew Geissler58a18012018-01-19 19:36:05 -0800325 auto retVal = server::Host::requestedHostTransition(value);
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500326 serialize();
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500327 return retVal;
Andrew Geissleref3c1842016-12-01 12:33:09 -0600328}
329
Dhruvaraj Subhashchandran4e6534f2017-09-19 06:13:20 -0500330Host::ProgressStages Host::bootProgress(ProgressStages value)
331{
332 auto retVal = bootprogress::Progress::bootProgress(value);
333 serialize();
334 return retVal;
335}
336
337Host::OSStatus Host::operatingSystemState(OSStatus value)
338{
339 auto retVal = osstatus::Status::operatingSystemState(value);
340 serialize();
341 return retVal;
342}
343
Andrew Geissleref3c1842016-12-01 12:33:09 -0600344Host::HostState Host::currentHostState(HostState value)
345{
Andrew Geissler58a18012018-01-19 19:36:05 -0800346 log<level::INFO>(
347 "Change to Host State",
348 entry("CURRENT_HOST_STATE=%s", 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