blob: b65d097af75520bb2dc9b6a4c39807ec34637b41 [file] [log] [blame]
Carol Wang71230ef2020-02-18 17:39:49 +08001#include "scheduled_host_transition.hpp"
2
Carol Wang4ca6f3f2020-02-19 16:28:59 +08003#include <phosphor-logging/elog-errors.hpp>
4#include <phosphor-logging/elog.hpp>
5#include <phosphor-logging/log.hpp>
6#include <xyz/openbmc_project/ScheduledTime/error.hpp>
7#include <chrono>
8
Carol Wang71230ef2020-02-18 17:39:49 +08009namespace phosphor
10{
11namespace state
12{
13namespace manager
14{
15
Carol Wang4ca6f3f2020-02-19 16:28:59 +080016using namespace std::chrono;
17using namespace phosphor::logging;
18using namespace xyz::openbmc_project::ScheduledTime;
Carol Wang6a5db3d2020-02-21 10:12:01 +080019using sdbusplus::exception::SdBusError;
Carol Wang4ca6f3f2020-02-19 16:28:59 +080020using InvalidTimeError =
21 sdbusplus::xyz::openbmc_project::ScheduledTime::Error::InvalidTime;
Carol Wang71230ef2020-02-18 17:39:49 +080022using HostTransition =
23 sdbusplus::xyz::openbmc_project::State::server::ScheduledHostTransition;
24
Carol Wang6a5db3d2020-02-21 10:12:01 +080025constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
26constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
27constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
28constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
29constexpr auto PROPERTY_TRANSITION = "RequestedHostTransition";
30
Carol Wang71230ef2020-02-18 17:39:49 +080031uint64_t ScheduledHostTransition::scheduledTime(uint64_t value)
32{
Carol Wang4ca6f3f2020-02-19 16:28:59 +080033 if (value == 0)
34 {
35 // 0 means the function Scheduled Host Transition is disabled
Carol Wang6a5db3d2020-02-21 10:12:01 +080036 // Stop the timer if it's running
37 if (timer.isEnabled())
38 {
39 timer.setEnabled(false);
40 }
Carol Wang4ca6f3f2020-02-19 16:28:59 +080041
Carol Wang6a5db3d2020-02-21 10:12:01 +080042 log<level::INFO>("The function Scheduled Host Transition is disabled.");
Carol Wang4ca6f3f2020-02-19 16:28:59 +080043 }
44 else
45 {
Carol Wang6a5db3d2020-02-21 10:12:01 +080046 auto deltaTime = seconds(value) - getTime();
47 if (deltaTime < seconds(0))
48 {
49 log<level::ERR>(
50 "Scheduled time is earlier than current time. Fail to "
51 "schedule host transition.");
52 elog<InvalidTimeError>(
53 InvalidTime::REASON("Scheduled time is in the past"));
54 }
55 else
56 {
57 // Start a timer to do host transition at scheduled time
58 timer.restart(deltaTime);
59 }
Carol Wang4ca6f3f2020-02-19 16:28:59 +080060 }
Carol Wang6a5db3d2020-02-21 10:12:01 +080061
62 // Set and return the scheduled time
Carol Wang71230ef2020-02-18 17:39:49 +080063 return HostTransition::scheduledTime(value);
64}
65
Carol Wang4ca6f3f2020-02-19 16:28:59 +080066seconds ScheduledHostTransition::getTime()
67{
68 auto now = system_clock::now();
69 return duration_cast<seconds>(now.time_since_epoch());
70}
71
Carol Wang6a5db3d2020-02-21 10:12:01 +080072std::string getService(sdbusplus::bus::bus& bus, std::string path,
73 std::string interface)
74{
75 auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
76 MAPPER_INTERFACE, "GetObject");
77
78 mapper.append(path, std::vector<std::string>({interface}));
79
80 std::vector<std::pair<std::string, std::vector<std::string>>>
81 mapperResponse;
82
83 try
84 {
85 auto mapperResponseMsg = bus.call(mapper);
86
87 mapperResponseMsg.read(mapperResponse);
88 if (mapperResponse.empty())
89 {
90 log<level::ERR>("Error no matching service",
91 entry("PATH=%s", path.c_str()),
92 entry("INTERFACE=%s", interface.c_str()));
93 throw std::runtime_error("Error no matching service");
94 }
95 }
96 catch (const SdBusError& e)
97 {
98 log<level::ERR>("Error in mapper call", entry("ERROR=%s", e.what()),
99 entry("PATH=%s", path.c_str()),
100 entry("INTERFACE=%s", interface.c_str()));
101 throw;
102 }
103
104 return mapperResponse.begin()->first;
105}
106
107void setProperty(sdbusplus::bus::bus& bus, const std::string& path,
108 const std::string& interface, const std::string& property,
109 const std::string& value)
110{
111 sdbusplus::message::variant<std::string> variantValue = value;
112 std::string service = getService(bus, path, interface);
113
114 auto method = bus.new_method_call(service.c_str(), path.c_str(),
115 PROPERTY_INTERFACE, "Set");
116
117 method.append(interface, property, variantValue);
118 bus.call_noreply(method);
119
120 return;
121}
122
123void ScheduledHostTransition::hostTransition()
124{
125 auto hostPath = std::string{HOST_OBJPATH} + '0';
126
127 auto reqTrans = convertForMessage(HostTransition::scheduledTransition());
128
129 setProperty(bus, hostPath, HOST_BUSNAME, PROPERTY_TRANSITION, reqTrans);
130
131 log<level::INFO>("Set requestedTransition",
132 entry("REQUESTED_TRANSITION=%s", reqTrans.c_str()));
133}
134
135void ScheduledHostTransition::callback()
136{
137 // Stop timer, since we need to do host transition once only
138 timer.setEnabled(false);
139 hostTransition();
140 // Set scheduledTime to 0 to disable host transition
141 HostTransition::scheduledTime(0);
142}
143
Carol Wang71230ef2020-02-18 17:39:49 +0800144} // namespace manager
145} // namespace state
146} // namespace phosphor