xref: /openbmc/phosphor-state-manager/host_state_manager.hpp (revision 4ccaeaa79b16004d35f3cdba335780e2316c2ebd)
1 #pragma once
2 
3 #include "config.h"
4 
5 #include "settings.hpp"
6 #include "utils.hpp"
7 
8 #include <cereal/access.hpp>
9 #include <cereal/cereal.hpp>
10 #include <phosphor-logging/lg2.hpp>
11 #include <sdbusplus/bus.hpp>
12 #include <xyz/openbmc_project/Control/Boot/RebootAttempts/server.hpp>
13 #include <xyz/openbmc_project/State/Boot/Progress/server.hpp>
14 #include <xyz/openbmc_project/State/Host/server.hpp>
15 #include <xyz/openbmc_project/State/OperatingSystem/Status/server.hpp>
16 
17 #include <filesystem>
18 #include <string>
19 
20 namespace phosphor
21 {
22 namespace state
23 {
24 namespace manager
25 {
26 
27 using HostInherit = sdbusplus::server::object_t<
28     sdbusplus::server::xyz::openbmc_project::state::Host,
29     sdbusplus::server::xyz::openbmc_project::state::boot::Progress,
30     sdbusplus::server::xyz::openbmc_project::control::boot::RebootAttempts,
31     sdbusplus::server::xyz::openbmc_project::state::operating_system::Status>;
32 
33 PHOSPHOR_LOG2_USING;
34 
35 namespace sdbusRule = sdbusplus::bus::match::rules;
36 namespace fs = std::filesystem;
37 
38 /** @class Host
39  *  @brief OpenBMC host state management implementation.
40  *  @details A concrete implementation for xyz.openbmc_project.State.Host
41  *  DBus API.
42  */
43 class Host : public HostInherit
44 {
45   public:
46     /** @brief Constructs Host State Manager
47      *
48      * @note This constructor passes 'true' to the base class in order to
49      *       defer dbus object registration until we can run
50      *       determineInitialState() and set our properties
51      *
52      * @param[in] bus       - The Dbus bus object
53      * @param[in] objPath   - The Dbus object path
54      * @param[in] id        - The Host id
55      */
Host(sdbusplus::bus_t & bus,const char * objPath,size_t id)56     Host(sdbusplus::bus_t& bus, const char* objPath, size_t id) :
57         HostInherit(bus, objPath, HostInherit::action::defer_emit), bus(bus),
58         systemdSignalJobRemoved(
59             bus,
60             sdbusRule::type::signal() + sdbusRule::member("JobRemoved") +
61                 sdbusRule::path("/org/freedesktop/systemd1") +
62                 sdbusRule::interface("org.freedesktop.systemd1.Manager"),
63             [this](sdbusplus::message_t& m) { sysStateChangeJobRemoved(m); }),
64         systemdSignalJobNew(
65             bus,
66             sdbusRule::type::signal() + sdbusRule::member("JobNew") +
67                 sdbusRule::path("/org/freedesktop/systemd1") +
68                 sdbusRule::interface("org.freedesktop.systemd1.Manager"),
__anon553c66d80202(sdbusplus::message_t& m) 69             [this](sdbusplus::message_t& m) { sysStateChangeJobNew(m); }),
70         settings(bus, id), id(id)
71     {
72         // Enable systemd signals
73         utils::subscribeToSystemdSignals(bus);
74 
75         // create map of target name base on host id
76         createSystemdTargetMaps();
77 
78         // Will throw exception on fail
79         determineInitialState();
80 
81         // Setup supported transitions against this host object
82         setupSupportedTransitions();
83 
84         // Sets auto-reboot attempts to max-allowed
85         attemptsLeft(sdbusplus::server::xyz::openbmc_project::control::boot::
86                          RebootAttempts::retryAttempts());
87 
88         // We deferred this until we could get our property correct
89         this->emit_object_added();
90     }
91 
92     /** @brief Set value of HostTransition */
93     Transition requestedHostTransition(Transition value) override;
94 
95     /** @brief Set Value for boot progress */
96     ProgressStages bootProgress(ProgressStages value) override;
97 
98     /** @brief Updated whenever BootProgress is updated */
99     uint64_t bootProgressLastUpdate(uint64_t value) override;
100 
101     /** @brief Set Value for Operating System Status */
102     OSStatus operatingSystemState(OSStatus value) override;
103 
104     /** @brief Set value of CurrentHostState */
105     HostState currentHostState(HostState value) override;
106 
107     /**
108      * @brief Set value for allowable auto-reboot count
109      *
110      * This override is responsible for ensuring that when external users
111      * set the number of automatic retry attempts that the number of
112      * automatic reboot attempts left will update accordingly.
113      *
114      * @param[in] value - desired Reboot count value
115      *
116      * @return number of reboot attempts allowed.
117      */
retryAttempts(uint32_t value)118     uint32_t retryAttempts(uint32_t value) override
119     {
120         if (sdbusplus::server::xyz::openbmc_project::control::boot::
121                 RebootAttempts::attemptsLeft() != value)
122         {
123             info("Automatic reboot retry attempts set to: {VALUE} ", "VALUE",
124                  value);
125             sdbusplus::server::xyz::openbmc_project::control::boot::
126                 RebootAttempts::attemptsLeft(value);
127         }
128 
129         return (sdbusplus::server::xyz::openbmc_project::control::boot::
130                     RebootAttempts::retryAttempts(value));
131     }
132 
133     /**
134      * @brief Set host reboot count to default
135      *
136      * OpenBMC software controls the number of allowed reboot attempts so
137      * any external set request of this property will be overridden by
138      * this function and set to the number of the allowed auto-reboot
139      * retry attempts found on the system.
140      *
141      * The only code responsible for decrementing the boot count resides
142      * within this process and that will use the sub class interface
143      * directly
144      *
145      * @param[in] value  - Reboot count value
146      *
147      * @return number of reboot attempts left(allowed by retry attempts
148      * property)
149      */
attemptsLeft(uint32_t value)150     uint32_t attemptsLeft(uint32_t value) override
151     {
152         debug("External request to reset reboot count");
153         auto retryAttempts = sdbusplus::xyz::openbmc_project::Control::Boot::
154             server::RebootAttempts::retryAttempts();
155         return (
156             sdbusplus::server::xyz::openbmc_project::control::boot::
157                 RebootAttempts::attemptsLeft(std::min(value, retryAttempts)));
158     }
159 
160   private:
161     /**
162      * @brief Determine initial host state and set internally
163      *
164      * @return Will throw exceptions on failure
165      **/
166     void determineInitialState();
167 
168     /**
169      * @brief Configure supported transitions for system
170      *
171      * @return Will throw exceptions on failure
172      **/
173     void setupSupportedTransitions();
174 
175     /**
176      * create systemd target instance names and mapping table
177      **/
178     void createSystemdTargetMaps();
179 
180     /** @brief Execute the transition request
181      *
182      * This function assumes the state has been validated and the host
183      * is in an appropriate state for the transition to be started.
184      *
185      * @param[in] tranReq    - Transition requested
186      */
187     void executeTransition(Transition tranReq);
188 
189     /**
190      * @brief Determine if target is active
191      *
192      * This function determines if the target is active and
193      * helps prevent misleading log recorded states.
194      *
195      * @param[in] target - Target string to check on
196      *
197      * @return boolean corresponding to state active
198      **/
199     bool stateActive(const std::string& target);
200 
201     /**
202      * @brief Determine if auto reboot flag is set
203      *
204      * @return boolean corresponding to current auto_reboot setting
205      **/
206     bool isAutoReboot();
207 
208     /** @brief Check if systemd state change is relevant to this object
209      *
210      * Instance specific interface to handle the detected systemd state
211      * change
212      *
213      * @param[in]  msg       - Data associated with subscribed signal
214      *
215      */
216     void sysStateChangeJobRemoved(sdbusplus::message_t& msg);
217 
218     /** @brief Check if JobNew systemd signal is relevant to this object
219      *
220      * In certain instances phosphor-state-manager needs to monitor for the
221      * entry into a systemd target. This function will be used for these cases.
222      *
223      * Instance specific interface to handle the detected systemd state
224      * change
225      *
226      * @param[in]  msg       - Data associated with subscribed signal
227      *
228      */
229     void sysStateChangeJobNew(sdbusplus::message_t& msg);
230 
231     /** @brief Decrement reboot count
232      *
233      * This is used internally to this application to decrement the boot
234      * count on each boot attempt. The host will use the external
235      * attemptsLeft() interface to reset the count when a boot is successful
236      *
237      * @return number of reboot count attempts left
238      */
239     uint32_t decrementRebootCount();
240 
241     // Allow cereal class access to allow these next two function to be
242     // private
243     friend class cereal::access;
244 
245     /** @brief Function required by Cereal to perform serialization.
246      *
247      *  @tparam Archive - Cereal archive type (binary in our case).
248      *  @param[in] archive - reference to Cereal archive.
249      *  @param[in] version - Class version that enables handling
250      *                       a serialized data across code levels
251      */
252     template <class Archive>
save(Archive & archive,const std::uint32_t version) const253     void save(Archive& archive, const std::uint32_t version) const
254     {
255         // version is not used currently
256         (void)(version);
257         archive(sdbusplus::server::xyz::openbmc_project::control::boot::
258                     RebootAttempts::retryAttempts(),
259                 convertForMessage(sdbusplus::xyz::openbmc_project::State::
260                                       server::Host::requestedHostTransition()),
261                 convertForMessage(sdbusplus::xyz::openbmc_project::State::Boot::
262                                       server::Progress::bootProgress()),
263                 convertForMessage(
264                     sdbusplus::xyz::openbmc_project::State::OperatingSystem::
265                         server::Status::operatingSystemState()));
266     }
267 
268     /** @brief Function required by Cereal to perform deserialization.
269      *
270      *  @tparam Archive - Cereal archive type (binary in our case).
271      *  @param[in] archive - reference to Cereal archive.
272      *  @param[in] version - Class version that enables handling
273      *                       a serialized data across code levels
274      */
275     template <class Archive>
load(Archive & archive,const std::uint32_t version)276     void load(Archive& archive, const std::uint32_t version)
277     {
278         std::string reqTranState;
279         std::string bootProgress;
280         std::string osState;
281         // Older cereal archive without RetryAttempt may be implemented
282         // just set to (BOOT_COUNT_MAX_ALLOWED)
283         uint32_t retryAttempts = BOOT_COUNT_MAX_ALLOWED;
284         switch (version)
285         {
286             case 2:
287                 archive(retryAttempts);
288                 [[fallthrough]];
289             case 1:
290                 archive(reqTranState, bootProgress, osState);
291                 break;
292         }
293         auto reqTran = Host::convertTransitionFromString(reqTranState);
294         // When restoring, set the requested state with persistent value
295         // but don't call the override which would execute it
296         sdbusplus::server::xyz::openbmc_project::state::Host::
297             requestedHostTransition(reqTran, true);
298         sdbusplus::server::xyz::openbmc_project::state::boot::Progress::
299             bootProgress(Host::convertProgressStagesFromString(bootProgress),
300                          true);
301         sdbusplus::server::xyz::openbmc_project::state::operating_system::
302             Status::operatingSystemState(
303                 Host::convertOSStatusFromString(osState), true);
304         sdbusplus::server::xyz::openbmc_project::control::boot::RebootAttempts::
305             retryAttempts(retryAttempts, true);
306     }
307 
308     /** @brief Serialize and persist requested host state
309      *
310      *  @return fs::path - pathname of persisted requested host state.
311      */
312     fs::path serialize();
313 
314     /** @brief Deserialize a persisted requested host state.
315      *
316      *  @return bool - true if the deserialization was successful, false
317      *                 otherwise.
318      */
319     bool deserialize();
320 
321     /**
322      * @brief Get target name of a HostState
323      *
324      * @param[in] state      -  The state of the host
325      *
326      * @return string - systemd target name of the state
327      */
328     const std::string& getTarget(HostState state);
329 
330     /**
331      * @brief Get target name of a TransitionRequest
332      *
333      * @param[in] tranReq      -  Transition requested
334      *
335      * @return string - systemd target name of Requested transition
336      */
337     const std::string& getTarget(Transition tranReq);
338 
339     /** @brief Persistent sdbusplus DBus bus connection. */
340     sdbusplus::bus_t& bus;
341 
342     /** @brief Used to subscribe to dbus systemd JobRemoved signal **/
343     sdbusplus::bus::match_t systemdSignalJobRemoved;
344 
345     /** @brief Used to subscribe to dbus systemd JobNew signal **/
346     sdbusplus::bus::match_t systemdSignalJobNew;
347 
348     // Settings host objects of interest
349     settings::HostObjects settings;
350 
351     /** @brief Host id. **/
352     const size_t id = 0;
353 
354     /** @brief HostState to systemd target mapping table. **/
355     std::map<HostState, std::string> stateTargetTable;
356 
357     /** @brief Requested Transition to systemd target mapping table. **/
358     std::map<Transition, std::string> transitionTargetTable;
359 
360     /** @brief Target called when a host crash occurs **/
361     std::string hostCrashTarget;
362 };
363 
364 } // namespace manager
365 } // namespace state
366 } // namespace phosphor
367