blob: 6e2fd22c1cd58a15a65ae2d711daf9a3d252ea34 [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
Saqib Khancbe08d12017-03-10 01:29:20 -060055constexpr auto REBOOTCOUNTER_SERVICE("org.openbmc.Sensors");
56constexpr auto REBOOTCOUNTER_PATH("/org/openbmc/sensors/host/BootCount");
57constexpr auto REBOOTCOUNTER_INTERFACE("org.openbmc.SensorValue");
58
Josh D. King929ef702017-03-02 10:58:11 -060059constexpr auto SYSTEMD_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
60constexpr auto SYSTEMD_INTERFACE_UNIT = "org.freedesktop.systemd1.Unit";
61
Andrew Geissler48696ce2017-05-22 14:41:58 -050062// TODO openbmc/openbmc#1646 - boot count needs to be defined in 1 place
63constexpr auto DEFAULT_BOOTCOUNT = 3;
Josh D. King929ef702017-03-02 10:58:11 -060064
Andrew Geissleref621162016-12-08 12:56:21 -060065/* Map a system state to the HostState */
Andrew Geissleref621162016-12-08 12:56:21 -060066const std::map<std::string, server::Host::HostState> SYS_HOST_STATE_TABLE = {
67 {"HOST_BOOTING", server::Host::HostState::Running},
Saqib Khanadaa7212017-02-23 13:19:28 -060068 {"HOST_POWERED_OFF", server::Host::HostState::Off},
69 {"HOST_QUIESCED", server::Host::HostState::Quiesced}
Andrew Geissleref621162016-12-08 12:56:21 -060070};
71
Andrew Geissler4da7e002017-01-24 15:21:40 -060072void Host::subscribeToSystemdSignals()
73{
74 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
75 SYSTEMD_OBJ_PATH,
76 SYSTEMD_INTERFACE,
77 "Subscribe");
78 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
Josh D. King222014e2017-05-16 13:35:21 -050086 if(stateActive(HOST_STATE_POWERON_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
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500103 auto restore = getStateRestoreSetting();
104
105 if ((!restore) || (!deserialize(HOST_STATE_PERSIST_PATH,*this)))
106 {
107 //set to default value.
108 server::Host::requestedHostTransition(Transition::Off);
109 }
Andrew Geissleref3c1842016-12-01 12:33:09 -0600110
111 return;
112}
113
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500114bool Host::getStateRestoreSetting() const
115{
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500116 using namespace settings;
117 using namespace sdbusplus::xyz::openbmc_project::Common::Error;
118 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500119
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500120 auto method =
121 bus.new_method_call(
122 settings.service(settings.powerRestorePolicy,
123 powerRestoreIntf).c_str(),
124 settings.powerRestorePolicy.c_str(),
125 "org.freedesktop.DBus.Properties",
126 "Get");
127
128 method.append(powerRestoreIntf, "PowerRestorePolicy");
129 auto reply = bus.call(method);
130 if (reply.is_method_error())
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500131 {
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500132 log<level::ERR>("Error in PowerRestorePolicy Get");
133 elog<InternalFailure>();
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500134 }
135
136 sdbusplus::message::variant<std::string> result;
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500137 reply.read(result);
138 auto powerPolicy = result.get<std::string>();
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500139
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500140 if (RestorePolicy::Policy::Restore ==
141 RestorePolicy::convertPolicyFromString(powerPolicy))
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500142 {
143 return true;
144 }
145 return false;
146}
147
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600148void Host::executeTransition(Transition tranReq)
149{
150 auto sysdUnit = SYSTEMD_TARGET_TABLE.find(tranReq)->second;
151
152 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
153 SYSTEMD_OBJ_PATH,
154 SYSTEMD_INTERFACE,
155 "StartUnit");
156
157 method.append(sysdUnit);
158 method.append("replace");
159
Andrew Geissler4da7e002017-01-24 15:21:40 -0600160 this->bus.call_noreply(method);
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600161
162 return;
163}
164
Josh D. King929ef702017-03-02 10:58:11 -0600165bool Host::stateActive(const std::string& target)
166{
167 sdbusplus::message::variant<std::string> currentState;
168 sdbusplus::message::object_path unitTargetPath;
169
170 auto method = this->bus.new_method_call(SYSTEMD_SERVICE,
171 SYSTEMD_OBJ_PATH,
172 SYSTEMD_INTERFACE,
173 "GetUnit");
174
175 method.append(target);
176 auto result = this->bus.call(method);
177
178 //Check that the bus call didn't result in an error
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500179 if (result.is_method_error())
Josh D. King929ef702017-03-02 10:58:11 -0600180 {
181 log<level::ERR>("Error in bus call - could not resolve GetUnit for:",
182 entry(" %s", SYSTEMD_INTERFACE));
183 return false;
184 }
185
186 result.read(unitTargetPath);
187
188 method = this->bus.new_method_call(SYSTEMD_SERVICE,
189 static_cast<const std::string&>
190 (unitTargetPath).c_str(),
191 SYSTEMD_PROPERTY_IFACE,
192 "Get");
193
194 method.append(SYSTEMD_INTERFACE_UNIT, "ActiveState");
195 result = this->bus.call(method);
196
197 //Check that the bus call didn't result in an error
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500198 if (result.is_method_error())
Josh D. King929ef702017-03-02 10:58:11 -0600199 {
200 log<level::ERR>("Error in bus call - could not resolve Get for:",
201 entry(" %s", SYSTEMD_PROPERTY_IFACE));
202 return false;
203 }
204
205 result.read(currentState);
206
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500207 if (currentState != ACTIVE_STATE && currentState != ACTIVATING_STATE)
Josh D. King929ef702017-03-02 10:58:11 -0600208 {
209 //False - not active
210 return false;
211 }
212 //True - active
213 return true;
214}
215
Saqib Khand5ac6352017-04-04 09:53:59 -0500216void Host::setHostbootCount(int bootCount)
217{
218 auto method = this->bus.new_method_call(REBOOTCOUNTER_SERVICE,
219 REBOOTCOUNTER_PATH,
220 REBOOTCOUNTER_INTERFACE,
221 "setValue");
222 sdbusplus::message::variant<int> newParam = bootCount;
223 method.append(newParam);
224 this->bus.call_noreply(method);
225}
Josh D. King929ef702017-03-02 10:58:11 -0600226
Michael Tritz206a8332017-02-06 16:01:23 -0600227bool Host::isAutoReboot()
228{
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500229 using namespace settings;
Michael Tritz206a8332017-02-06 16:01:23 -0600230
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500231 auto method =
232 bus.new_method_call(
233 settings.service(settings.autoReboot, autoRebootIntf).c_str(),
234 settings.autoReboot.c_str(),
235 "org.freedesktop.DBus.Properties",
236 "Get");
237 method.append(autoRebootIntf, "AutoReboot");
238 auto reply = bus.call(method);
Michael Tritz206a8332017-02-06 16:01:23 -0600239 if (reply.is_method_error())
240 {
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500241 log<level::ERR>("Error in AutoReboot Get");
Michael Tritz206a8332017-02-06 16:01:23 -0600242 return false;
243 }
244
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500245 sdbusplus::message::variant<bool> result;
246 reply.read(result);
247 auto autoReboot = result.get<bool>();
Michael Tritz206a8332017-02-06 16:01:23 -0600248
Saqib Khand5ac6352017-04-04 09:53:59 -0500249 sdbusplus::message::variant<int> rebootCounterParam = 0;
Saqib Khancbe08d12017-03-10 01:29:20 -0600250 method = this->bus.new_method_call(REBOOTCOUNTER_SERVICE,
251 REBOOTCOUNTER_PATH,
252 REBOOTCOUNTER_INTERFACE,
253 "getValue");
254 reply = this->bus.call(method);
255 if (reply.is_method_error())
256 {
257 log<level::ERR>("Error in BOOTCOUNT getValue");
258 return false;
259 }
260 reply.read(rebootCounterParam);
261
Deepak Kodihalli3dd08a52017-07-25 07:34:44 -0500262 if (autoReboot)
Michael Tritz206a8332017-02-06 16:01:23 -0600263 {
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500264 if ( rebootCounterParam > 0)
Saqib Khancbe08d12017-03-10 01:29:20 -0600265 {
266 // Reduce BOOTCOUNT by 1
Saqib Khand5ac6352017-04-04 09:53:59 -0500267 log<level::INFO>("Auto reboot enabled. "
268 "Reducing HOST BOOTCOUNT by 1.");
269 Host::setHostbootCount((sdbusplus::message::variant_ns::
270 get<int>(rebootCounterParam)) - 1);
Saqib Khancbe08d12017-03-10 01:29:20 -0600271 return true;
272 }
Saqib Khand5ac6352017-04-04 09:53:59 -0500273 else if(rebootCounterParam == 0)
Josh D. King929ef702017-03-02 10:58:11 -0600274 {
Saqib Khancbe08d12017-03-10 01:29:20 -0600275 // Reset reboot counter and go to quiesce state
Saqib Khand5ac6352017-04-04 09:53:59 -0500276 log<level::INFO>("Auto reboot enabled. "
277 "HOST BOOTCOUNT already set to 0.");
278 Host::setHostbootCount(DEFAULT_BOOTCOUNT);
279 return false;
280 }
281 else
282 {
283 log<level::INFO>("Auto reboot enabled. "
284 "HOST BOOTCOUNT has an invalid value.");
Saqib Khancbe08d12017-03-10 01:29:20 -0600285 return false;
286 }
Michael Tritz206a8332017-02-06 16:01:23 -0600287 }
Saqib Khand5ac6352017-04-04 09:53:59 -0500288 else
289 {
290 log<level::INFO>("Auto reboot disabled.");
291 return false;
292 }
Michael Tritz206a8332017-02-06 16:01:23 -0600293}
294
Patrick Williamsd22706f2017-05-04 05:42:49 -0500295void Host::sysStateChange(sdbusplus::message::message& msg)
Andrew Geissler4da7e002017-01-24 15:21:40 -0600296{
297 uint32_t newStateID {};
298 sdbusplus::message::object_path newStateObjPath;
299 std::string newStateUnit{};
300 std::string newStateResult{};
301
Andrew Geissler4da7e002017-01-24 15:21:40 -0600302 //Read the msg and populate each variable
Patrick Williamsd22706f2017-05-04 05:42:49 -0500303 msg.read(newStateID, newStateObjPath, newStateUnit, newStateResult);
Andrew Geissler4da7e002017-01-24 15:21:40 -0600304
305 if((newStateUnit == HOST_STATE_POWEROFF_TGT) &&
Josh D. King929ef702017-03-02 10:58:11 -0600306 (newStateResult == "done") &&
307 (!stateActive(HOST_STATE_POWERON_TGT)))
Andrew Geissleref621162016-12-08 12:56:21 -0600308 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930309 log<level::INFO>("Received signal that host is off");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600310 this->currentHostState(server::Host::HostState::Off);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600311
312 // Check if we need to start a new transition (i.e. a Reboot)
Andrew Geissler4da7e002017-01-24 15:21:40 -0600313 if(this->server::Host::requestedHostTransition() ==
314 Transition::Reboot)
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600315 {
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600316 log<level::DEBUG>("Reached intermediate state, going to next");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600317 this->executeTransition(server::Host::Transition::On);
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600318 }
Andrew Geissleref621162016-12-08 12:56:21 -0600319 }
Andrew Geissler4da7e002017-01-24 15:21:40 -0600320 else if((newStateUnit == HOST_STATE_POWERON_TGT) &&
Josh D. King929ef702017-03-02 10:58:11 -0600321 (newStateResult == "done") &&
322 (stateActive(HOST_STATE_POWERON_TGT)))
Andrew Geissler4da7e002017-01-24 15:21:40 -0600323 {
Andrew Jeffery55b983e2017-04-19 11:11:26 +0930324 log<level::INFO>("Received signal that host is running");
Andrew Geissler4da7e002017-01-24 15:21:40 -0600325 this->currentHostState(server::Host::HostState::Running);
326 }
Michael Tritz206a8332017-02-06 16:01:23 -0600327 else if((newStateUnit == HOST_STATE_QUIESCE_TGT) &&
Josh D. King29d025d2017-04-27 12:40:22 -0500328 (newStateResult == "done") &&
329 (stateActive(HOST_STATE_QUIESCE_TGT)))
Michael Tritz206a8332017-02-06 16:01:23 -0600330 {
331 if (Host::isAutoReboot())
332 {
Saqib Khand5ac6352017-04-04 09:53:59 -0500333 log<level::INFO>("Beginning reboot...");
Michael Tritz206a8332017-02-06 16:01:23 -0600334 Host::requestedHostTransition(server::Host::Transition::Reboot);
335 }
336 else
337 {
Saqib Khand5ac6352017-04-04 09:53:59 -0500338 log<level::INFO>("Maintaining quiesce");
Saqib Khanadaa7212017-02-23 13:19:28 -0600339 this->currentHostState(server::Host::HostState::Quiesced);
Michael Tritz206a8332017-02-06 16:01:23 -0600340 }
341
342 }
Andrew Geissleref621162016-12-08 12:56:21 -0600343}
344
Andrew Geissleref3c1842016-12-01 12:33:09 -0600345Host::Transition Host::requestedHostTransition(Transition value)
346{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600347 log<level::INFO>(
348 "Host State transaction request",
349 entry("REQUESTED_HOST_TRANSITION=%s",
350 convertForMessage(value).c_str()));
Andrew Geissler0cd2eaf2016-12-07 10:50:13 -0600351
Andrew Geissler06dbc5b2016-12-13 11:46:16 -0600352 Transition tranReq = value;
353 if(value == server::Host::Transition::Reboot)
354 {
355 // On reboot requests we just need to do a off if we're on and
356 // vice versa. The handleSysStateChange() code above handles the
357 // second part of the reboot
358 if(this->server::Host::currentHostState() ==
359 server::Host::HostState::Off)
360 {
361 tranReq = server::Host::Transition::On;
362 }
363 else
364 {
365 tranReq = server::Host::Transition::Off;
366 }
367 }
368
369 executeTransition(tranReq);
Dhruvaraj Subhashchandran3f475242017-07-12 00:44:27 -0500370 auto retVal = server::Host::requestedHostTransition(value);
371 serialize(*this);
372 return retVal;
Andrew Geissleref3c1842016-12-01 12:33:09 -0600373}
374
Andrew Geissleref3c1842016-12-01 12:33:09 -0600375Host::HostState Host::currentHostState(HostState value)
376{
Andrew Geissler1e3bf942016-12-13 15:32:22 -0600377 log<level::INFO>("Change to Host State",
378 entry("CURRENT_HOST_STATE=%s",
379 convertForMessage(value).c_str()));
Andrew Geissleref621162016-12-08 12:56:21 -0600380 return server::Host::currentHostState(value);
Andrew Geissleref3c1842016-12-01 12:33:09 -0600381}
382
Andrew Geissler36529022016-11-29 15:23:54 -0600383} // namespace manager
384} // namespace state
385} // namepsace phosphor