blob: 446959d7749b90da22363bc6d8342e1680ba8e1b [file] [log] [blame]
Andrew Geissler769a62f2019-12-06 13:36:08 -06001#include "config.h"
Andrew Geisslere426b582020-05-28 12:40:55 -05002
Michael Tritz3ed10082017-03-20 23:28:09 -05003#include "host_state_manager.hpp"
Deepak Kodihalli55f132b2017-07-25 07:36:06 -05004#include "settings.hpp"
5#include "xyz/openbmc_project/Common/error.hpp"
6#include "xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp"
Michael Tritz3ed10082017-03-20 23:28:09 -05007
Andrew Geisslere426b582020-05-28 12:40:55 -05008#include <getopt.h>
9#include <systemd/sd-bus.h>
10
11#include <phosphor-logging/elog-errors.hpp>
Andrew Geissler8ffdb262021-09-20 15:25:19 -050012#include <phosphor-logging/lg2.hpp>
Andrew Geisslere426b582020-05-28 12:40:55 -050013#include <sdbusplus/exception.hpp>
14#include <sdbusplus/server.hpp>
15
16#include <iostream>
17#include <map>
18#include <string>
19
Michael Tritz3ed10082017-03-20 23:28:09 -050020namespace phosphor
21{
22namespace state
23{
24namespace manager
25{
26
Andrew Geissler8ffdb262021-09-20 15:25:19 -050027PHOSPHOR_LOG2_USING;
28
Michael Tritz3ed10082017-03-20 23:28:09 -050029using namespace phosphor::logging;
Deepak Kodihalli55f132b2017-07-25 07:36:06 -050030using namespace sdbusplus::xyz::openbmc_project::Common::Error;
31using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
Michael Tritz3ed10082017-03-20 23:28:09 -050032
33constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
34constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
35constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
36
37constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
38
Michael Tritz3ed10082017-03-20 23:28:09 -050039std::string getService(sdbusplus::bus::bus& bus, std::string path,
40 std::string interface)
41{
Andrew Geissler58a18012018-01-19 19:36:05 -080042 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
43 MAPPER_INTERFACE, "GetObject");
Michael Tritz3ed10082017-03-20 23:28:09 -050044
45 mapper.append(path, std::vector<std::string>({interface}));
Michael Tritz3ed10082017-03-20 23:28:09 -050046
47 std::map<std::string, std::vector<std::string>> mapperResponse;
Anthony Wilson32c532e2018-10-25 21:56:07 -050048 try
Michael Tritz3ed10082017-03-20 23:28:09 -050049 {
Anthony Wilson32c532e2018-10-25 21:56:07 -050050 auto mapperResponseMsg = bus.call(mapper);
51
52 mapperResponseMsg.read(mapperResponse);
53 if (mapperResponse.empty())
54 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050055 error("Mapper response empty, does not have path {PATH} and "
56 "interface {INTERFACE}",
57 "PATH", path, "INTERFACE", interface);
Anthony Wilson32c532e2018-10-25 21:56:07 -050058 throw std::runtime_error("Error reading mapper response");
59 }
60 }
Patrick Williams0a675212021-09-02 09:49:43 -050061 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -050062 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050063 error("Error in mapper call for path {PATH} and interface {INTERFACE} "
64 "with error {ERROR}",
65 "PATH", path, "INTERFACE", interface, "ERROR", e);
Anthony Wilson32c532e2018-10-25 21:56:07 -050066 throw;
Michael Tritz3ed10082017-03-20 23:28:09 -050067 }
68
69 return mapperResponse.begin()->first;
70}
71
72std::string getProperty(sdbusplus::bus::bus& bus, std::string path,
73 std::string interface, std::string propertyName)
74{
Patrick Williams2975e262020-05-13 18:01:09 -050075 std::variant<std::string> property;
Michael Tritz3ed10082017-03-20 23:28:09 -050076 std::string service = getService(bus, path, interface);
77
Andrew Geissler58a18012018-01-19 19:36:05 -080078 auto method = bus.new_method_call(service.c_str(), path.c_str(),
79 PROPERTY_INTERFACE, "Get");
Michael Tritz3ed10082017-03-20 23:28:09 -050080
81 method.append(interface, propertyName);
Michael Tritz3ed10082017-03-20 23:28:09 -050082
Anthony Wilson32c532e2018-10-25 21:56:07 -050083 try
Michael Tritz3ed10082017-03-20 23:28:09 -050084 {
Anthony Wilson32c532e2018-10-25 21:56:07 -050085 auto reply = bus.call(method);
86 reply.read(property);
Michael Tritz3ed10082017-03-20 23:28:09 -050087 }
Patrick Williams0a675212021-09-02 09:49:43 -050088 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -050089 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050090 error("Error in property Get, error {ERROR}, property {PROPERTY}",
91 "ERROR", e, "PROPERTY", propertyName);
Anthony Wilson32c532e2018-10-25 21:56:07 -050092 throw;
93 }
Michael Tritz3ed10082017-03-20 23:28:09 -050094
Patrick Williams37413dc2020-05-13 11:29:54 -050095 if (std::get<std::string>(property).empty())
Michael Tritz3ed10082017-03-20 23:28:09 -050096 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -050097 error("Error reading property response for {PROPERTY}", "PROPERTY",
98 propertyName);
Michael Tritz3ed10082017-03-20 23:28:09 -050099 throw std::runtime_error("Error reading property response");
100 }
101
Patrick Williams37413dc2020-05-13 11:29:54 -0500102 return std::get<std::string>(property);
Michael Tritz3ed10082017-03-20 23:28:09 -0500103}
104
Patrick Venturef2870592018-10-14 14:11:30 -0700105void setProperty(sdbusplus::bus::bus& bus, const std::string& path,
106 const std::string& interface, const std::string& property,
107 const std::string& value)
Michael Tritz3ed10082017-03-20 23:28:09 -0500108{
Patrick Williams2975e262020-05-13 18:01:09 -0500109 std::variant<std::string> variantValue = value;
Michael Tritz3ed10082017-03-20 23:28:09 -0500110 std::string service = getService(bus, path, interface);
111
Andrew Geissler58a18012018-01-19 19:36:05 -0800112 auto method = bus.new_method_call(service.c_str(), path.c_str(),
113 PROPERTY_INTERFACE, "Set");
Michael Tritz3ed10082017-03-20 23:28:09 -0500114
115 method.append(interface, property, variantValue);
116 bus.call_noreply(method);
117
118 return;
119}
120
121} // namespace manager
122} // namespace state
Andrew Geisslera965cf02018-08-31 08:37:05 -0700123} // namespace phosphor
Michael Tritz3ed10082017-03-20 23:28:09 -0500124
Michael Tritzd50f6572017-09-05 16:38:11 -0500125int main(int argc, char** argv)
Michael Tritz3ed10082017-03-20 23:28:09 -0500126{
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500127 using namespace phosphor::logging;
128
Michael Tritzd50f6572017-09-05 16:38:11 -0500129 std::string hostPath = "/xyz/openbmc_project/state/host0";
130 int arg;
131 int optIndex = 0;
132
Andrew Geissler58a18012018-01-19 19:36:05 -0800133 static struct option longOpts[] = {{"host", required_argument, 0, 'h'},
134 {0, 0, 0, 0}};
Michael Tritzd50f6572017-09-05 16:38:11 -0500135
Andrew Geissler58a18012018-01-19 19:36:05 -0800136 while ((arg = getopt_long(argc, argv, "h:", longOpts, &optIndex)) != -1)
Michael Tritzd50f6572017-09-05 16:38:11 -0500137 {
138 switch (arg)
139 {
140 case 'h':
Andrew Geissler58a18012018-01-19 19:36:05 -0800141 hostPath =
142 std::string("/xyz/openbmc_project/state/host") + optarg;
Michael Tritzd50f6572017-09-05 16:38:11 -0500143 break;
144 default:
145 break;
146 }
147 }
148
Michael Tritz3ed10082017-03-20 23:28:09 -0500149 auto bus = sdbusplus::bus::new_default();
150
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500151 using namespace settings;
152 Objects settings(bus);
153
Michael Tritz3ed10082017-03-20 23:28:09 -0500154 using namespace phosphor::state::manager;
155 namespace server = sdbusplus::xyz::openbmc_project::State::server;
156
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500157 // This application is only run if chassis power is off
Michael Tritz3ed10082017-03-20 23:28:09 -0500158
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600159 /* The logic here is to first check the one-time PowerRestorePolicy setting.
160 * If this property is not the default then look at the persistent
161 * user setting in the non one-time object, otherwise honor the one-time
162 * setting.
163 */
164 auto methodOneTime = bus.new_method_call(
165 settings.service(settings.powerRestorePolicy, powerRestoreIntf).c_str(),
166 settings.powerRestorePolicyOneTime.c_str(),
167 "org.freedesktop.DBus.Properties", "Get");
168 methodOneTime.append(powerRestoreIntf, "PowerRestorePolicy");
169
170 auto methodUserSetting = bus.new_method_call(
Andrew Geissler58a18012018-01-19 19:36:05 -0800171 settings.service(settings.powerRestorePolicy, powerRestoreIntf).c_str(),
172 settings.powerRestorePolicy.c_str(), "org.freedesktop.DBus.Properties",
173 "Get");
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600174 methodUserSetting.append(powerRestoreIntf, "PowerRestorePolicy");
Anthony Wilson32c532e2018-10-25 21:56:07 -0500175
Patrick Williams2975e262020-05-13 18:01:09 -0500176 std::variant<std::string> result;
Anthony Wilson32c532e2018-10-25 21:56:07 -0500177 try
Michael Tritz3ed10082017-03-20 23:28:09 -0500178 {
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600179 auto reply = bus.call(methodOneTime);
Anthony Wilson32c532e2018-10-25 21:56:07 -0500180 reply.read(result);
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600181 auto powerPolicy = std::get<std::string>(result);
182
183 if (RestorePolicy::Policy::None ==
184 RestorePolicy::convertPolicyFromString(powerPolicy))
185 {
186 // one_time is set to None so use the customer setting
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500187 info("One time not set, check user setting of power policy");
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600188 auto reply = bus.call(methodUserSetting);
189 reply.read(result);
190 powerPolicy = std::get<std::string>(result);
191 }
192 else
193 {
194 // one_time setting was set so we're going to use it. Reset it
195 // to default for next time.
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500196 info("One time set, use it and reset to default");
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600197 setProperty(bus, settings.powerRestorePolicyOneTime.c_str(),
198 powerRestoreIntf, "PowerRestorePolicy",
199 convertForMessage(RestorePolicy::Policy::None));
200 }
201
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500202 info("Host power is off, processing power policy {POWER_POLICY}",
203 "POWER_POLICY", powerPolicy);
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600204
205 if (RestorePolicy::Policy::AlwaysOn ==
206 RestorePolicy::convertPolicyFromString(powerPolicy))
207 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500208 info("power_policy=ALWAYS_POWER_ON, powering host on");
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600209 setProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition",
210 convertForMessage(server::Host::Transition::On));
211 }
212 else if (RestorePolicy::Policy::Restore ==
213 RestorePolicy::convertPolicyFromString(powerPolicy))
214 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500215 info("power_policy=RESTORE, restoring last state");
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600216
217 // Read last requested state and re-request it to execute it
218 auto hostReqState = getProperty(bus, hostPath, HOST_BUSNAME,
219 "RequestedHostTransition");
220 setProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition",
221 hostReqState);
222 }
Anthony Wilson32c532e2018-10-25 21:56:07 -0500223 }
Patrick Williams0a675212021-09-02 09:49:43 -0500224 catch (const sdbusplus::exception::exception& e)
Anthony Wilson32c532e2018-10-25 21:56:07 -0500225 {
Andrew Geissler8ffdb262021-09-20 15:25:19 -0500226 error("Error in PowerRestorePolicy Get: {ERROR}", "ERROR", e);
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500227 elog<InternalFailure>();
228 }
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500229
Michael Tritz3ed10082017-03-20 23:28:09 -0500230 return 0;
231}