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