blob: 88fa4ab53753a3340c7d47f9b843c74bd96f151a [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>
12#include <phosphor-logging/log.hpp>
13#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
27using namespace phosphor::logging;
Deepak Kodihalli55f132b2017-07-25 07:36:06 -050028using namespace sdbusplus::xyz::openbmc_project::Common::Error;
29using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
Anthony Wilson32c532e2018-10-25 21:56:07 -050030using sdbusplus::exception::SdBusError;
Michael Tritz3ed10082017-03-20 23:28:09 -050031
32constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
33constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
34constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
35
36constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
37
Michael Tritz3ed10082017-03-20 23:28:09 -050038std::string getService(sdbusplus::bus::bus& bus, std::string path,
39 std::string interface)
40{
Andrew Geissler58a18012018-01-19 19:36:05 -080041 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
42 MAPPER_INTERFACE, "GetObject");
Michael Tritz3ed10082017-03-20 23:28:09 -050043
44 mapper.append(path, std::vector<std::string>({interface}));
Michael Tritz3ed10082017-03-20 23:28:09 -050045
46 std::map<std::string, std::vector<std::string>> mapperResponse;
Anthony Wilson32c532e2018-10-25 21:56:07 -050047 try
Michael Tritz3ed10082017-03-20 23:28:09 -050048 {
Anthony Wilson32c532e2018-10-25 21:56:07 -050049 auto mapperResponseMsg = bus.call(mapper);
50
51 mapperResponseMsg.read(mapperResponse);
52 if (mapperResponse.empty())
53 {
54 log<level::ERR>("Error reading mapper response",
55 entry("PATH=%s", path.c_str()),
56 entry("INTERFACE=%s", interface.c_str()));
57 throw std::runtime_error("Error reading mapper response");
58 }
59 }
60 catch (const SdBusError& e)
61 {
62 log<level::ERR>("Error in mapper call", entry("ERROR=%s", e.what()),
Michael Tritz3ed10082017-03-20 23:28:09 -050063 entry("PATH=%s", path.c_str()),
64 entry("INTERFACE=%s", interface.c_str()));
Anthony Wilson32c532e2018-10-25 21:56:07 -050065 throw;
Michael Tritz3ed10082017-03-20 23:28:09 -050066 }
67
68 return mapperResponse.begin()->first;
69}
70
71std::string getProperty(sdbusplus::bus::bus& bus, std::string path,
72 std::string interface, std::string propertyName)
73{
Patrick Williams2975e262020-05-13 18:01:09 -050074 std::variant<std::string> property;
Michael Tritz3ed10082017-03-20 23:28:09 -050075 std::string service = getService(bus, path, interface);
76
Andrew Geissler58a18012018-01-19 19:36:05 -080077 auto method = bus.new_method_call(service.c_str(), path.c_str(),
78 PROPERTY_INTERFACE, "Get");
Michael Tritz3ed10082017-03-20 23:28:09 -050079
80 method.append(interface, propertyName);
Michael Tritz3ed10082017-03-20 23:28:09 -050081
Anthony Wilson32c532e2018-10-25 21:56:07 -050082 try
Michael Tritz3ed10082017-03-20 23:28:09 -050083 {
Anthony Wilson32c532e2018-10-25 21:56:07 -050084 auto reply = bus.call(method);
85 reply.read(property);
Michael Tritz3ed10082017-03-20 23:28:09 -050086 }
Anthony Wilson32c532e2018-10-25 21:56:07 -050087 catch (const SdBusError& e)
88 {
89 log<level::ERR>("Error in property Get", entry("ERROR=%s", e.what()),
90 entry("PROPERTY=%s", propertyName.c_str()));
91 throw;
92 }
Michael Tritz3ed10082017-03-20 23:28:09 -050093
Patrick Williams37413dc2020-05-13 11:29:54 -050094 if (std::get<std::string>(property).empty())
Michael Tritz3ed10082017-03-20 23:28:09 -050095 {
96 log<level::ERR>("Error reading property response",
97 entry("PROPERTY=%s", propertyName.c_str()));
98 throw std::runtime_error("Error reading property response");
99 }
100
Patrick Williams37413dc2020-05-13 11:29:54 -0500101 return std::get<std::string>(property);
Michael Tritz3ed10082017-03-20 23:28:09 -0500102}
103
Patrick Venturef2870592018-10-14 14:11:30 -0700104void setProperty(sdbusplus::bus::bus& bus, const std::string& path,
105 const std::string& interface, const std::string& property,
106 const std::string& value)
Michael Tritz3ed10082017-03-20 23:28:09 -0500107{
Patrick Williams2975e262020-05-13 18:01:09 -0500108 std::variant<std::string> variantValue = value;
Michael Tritz3ed10082017-03-20 23:28:09 -0500109 std::string service = getService(bus, path, interface);
110
Andrew Geissler58a18012018-01-19 19:36:05 -0800111 auto method = bus.new_method_call(service.c_str(), path.c_str(),
112 PROPERTY_INTERFACE, "Set");
Michael Tritz3ed10082017-03-20 23:28:09 -0500113
114 method.append(interface, property, variantValue);
115 bus.call_noreply(method);
116
117 return;
118}
119
120} // namespace manager
121} // namespace state
Andrew Geisslera965cf02018-08-31 08:37:05 -0700122} // namespace phosphor
Michael Tritz3ed10082017-03-20 23:28:09 -0500123
Michael Tritzd50f6572017-09-05 16:38:11 -0500124int main(int argc, char** argv)
Michael Tritz3ed10082017-03-20 23:28:09 -0500125{
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500126 using namespace phosphor::logging;
127
Michael Tritzd50f6572017-09-05 16:38:11 -0500128 std::string hostPath = "/xyz/openbmc_project/state/host0";
129 int arg;
130 int optIndex = 0;
131
Andrew Geissler58a18012018-01-19 19:36:05 -0800132 static struct option longOpts[] = {{"host", required_argument, 0, 'h'},
133 {0, 0, 0, 0}};
Michael Tritzd50f6572017-09-05 16:38:11 -0500134
Andrew Geissler58a18012018-01-19 19:36:05 -0800135 while ((arg = getopt_long(argc, argv, "h:", longOpts, &optIndex)) != -1)
Michael Tritzd50f6572017-09-05 16:38:11 -0500136 {
137 switch (arg)
138 {
139 case 'h':
Andrew Geissler58a18012018-01-19 19:36:05 -0800140 hostPath =
141 std::string("/xyz/openbmc_project/state/host") + optarg;
Michael Tritzd50f6572017-09-05 16:38:11 -0500142 break;
143 default:
144 break;
145 }
146 }
147
Michael Tritz3ed10082017-03-20 23:28:09 -0500148 auto bus = sdbusplus::bus::new_default();
149
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500150 using namespace settings;
151 Objects settings(bus);
152
Michael Tritz3ed10082017-03-20 23:28:09 -0500153 using namespace phosphor::state::manager;
154 namespace server = sdbusplus::xyz::openbmc_project::State::server;
155
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500156 // This application is only run if chassis power is off
Michael Tritz3ed10082017-03-20 23:28:09 -0500157
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600158 /* The logic here is to first check the one-time PowerRestorePolicy setting.
159 * If this property is not the default then look at the persistent
160 * user setting in the non one-time object, otherwise honor the one-time
161 * setting.
162 */
163 auto methodOneTime = bus.new_method_call(
164 settings.service(settings.powerRestorePolicy, powerRestoreIntf).c_str(),
165 settings.powerRestorePolicyOneTime.c_str(),
166 "org.freedesktop.DBus.Properties", "Get");
167 methodOneTime.append(powerRestoreIntf, "PowerRestorePolicy");
168
169 auto methodUserSetting = bus.new_method_call(
Andrew Geissler58a18012018-01-19 19:36:05 -0800170 settings.service(settings.powerRestorePolicy, powerRestoreIntf).c_str(),
171 settings.powerRestorePolicy.c_str(), "org.freedesktop.DBus.Properties",
172 "Get");
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600173 methodUserSetting.append(powerRestoreIntf, "PowerRestorePolicy");
Anthony Wilson32c532e2018-10-25 21:56:07 -0500174
Patrick Williams2975e262020-05-13 18:01:09 -0500175 std::variant<std::string> result;
Anthony Wilson32c532e2018-10-25 21:56:07 -0500176 try
Michael Tritz3ed10082017-03-20 23:28:09 -0500177 {
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600178 auto reply = bus.call(methodOneTime);
Anthony Wilson32c532e2018-10-25 21:56:07 -0500179 reply.read(result);
Andrew Geissler35ca2e32021-02-09 13:54:26 -0600180 auto powerPolicy = std::get<std::string>(result);
181
182 if (RestorePolicy::Policy::None ==
183 RestorePolicy::convertPolicyFromString(powerPolicy))
184 {
185 // one_time is set to None so use the customer setting
186 log<level::INFO>(
187 "One time not set, check user setting of power policy");
188 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.
196 log<level::INFO>("One time set, use it and reset to default");
197 setProperty(bus, settings.powerRestorePolicyOneTime.c_str(),
198 powerRestoreIntf, "PowerRestorePolicy",
199 convertForMessage(RestorePolicy::Policy::None));
200 }
201
202 log<level::INFO>("Host power is off, processing power policy",
203 entry("POWER_POLICY=%s", powerPolicy.c_str()));
204
205 if (RestorePolicy::Policy::AlwaysOn ==
206 RestorePolicy::convertPolicyFromString(powerPolicy))
207 {
208 log<level::INFO>("power_policy=ALWAYS_POWER_ON, powering host on");
209 setProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition",
210 convertForMessage(server::Host::Transition::On));
211 }
212 else if (RestorePolicy::Policy::Restore ==
213 RestorePolicy::convertPolicyFromString(powerPolicy))
214 {
215 log<level::INFO>("power_policy=RESTORE, restoring last state");
216
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 }
224 catch (const SdBusError& e)
225 {
226 log<level::ERR>("Error in PowerRestorePolicy Get",
227 entry("ERROR=%s", e.what()));
Andrew Geissler033fc3b2017-08-30 15:11:44 -0500228 elog<InternalFailure>();
229 }
Deepak Kodihalli55f132b2017-07-25 07:36:06 -0500230
Michael Tritz3ed10082017-03-20 23:28:09 -0500231 return 0;
232}