blob: f24fd613a04bcc00fbd553d9bdf66fccf7766c4d [file] [log] [blame]
Matthew Barth9ea8bee2020-06-04 14:27:19 -05001/**
2 * Copyright © 2020 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include "json_parser.hpp"
17
Matthew Barth22ab93b2020-06-08 10:47:56 -050018#include "conditions.hpp"
Matthew Barth9ea8bee2020-06-04 14:27:19 -050019#include "json_config.hpp"
20#include "nonzero_speed_trust.hpp"
Matt Spinlerf06ab072020-10-14 12:58:22 -050021#include "power_interface.hpp"
22#include "power_off_rule.hpp"
Jolie Ku69f2f482020-10-21 09:59:43 +080023#include "tach_sensor.hpp"
Matthew Barth9ea8bee2020-06-04 14:27:19 -050024#include "types.hpp"
25
26#include <nlohmann/json.hpp>
Anwaar Hadia00f6832025-03-27 15:03:11 +000027#include <phosphor-logging/lg2.hpp>
Matthew Barth9ea8bee2020-06-04 14:27:19 -050028
29#include <algorithm>
30#include <map>
31#include <memory>
Matthew Barth22ab93b2020-06-08 10:47:56 -050032#include <optional>
Matthew Barth9ea8bee2020-06-04 14:27:19 -050033#include <vector>
34
35namespace phosphor::fan::monitor
36{
37
38using json = nlohmann::json;
39using namespace phosphor::logging;
40
41namespace tClass
42{
43
44// Get a constructed trust group class for a non-zero speed group
Patrick Williams4fa67aa2025-02-03 14:28:47 -050045CreateGroupFunction getNonZeroSpeed(
46 const std::vector<trust::GroupDefinition>& group)
Matthew Barth9ea8bee2020-06-04 14:27:19 -050047{
48 return [group]() {
49 return std::make_unique<trust::NonzeroSpeed>(std::move(group));
50 };
51}
52
53} // namespace tClass
54
55const std::map<std::string, trustHandler> trusts = {
56 {"nonzerospeed", tClass::getNonZeroSpeed}};
Matthew Barth3ad14342020-06-08 16:17:42 -050057const std::map<std::string, condHandler> conditions = {
58 {"propertiesmatch", condition::getPropertiesMatch}};
Jolie Ku69f2f482020-10-21 09:59:43 +080059const std::map<std::string, size_t> methods = {
60 {"timebased", MethodMode::timebased}, {"count", MethodMode::count}};
Matthew Barth9ea8bee2020-06-04 14:27:19 -050061
62const std::vector<CreateGroupFunction> getTrustGrps(const json& obj)
63{
64 std::vector<CreateGroupFunction> grpFuncs;
65
66 if (obj.contains("sensor_trust_groups"))
67 {
68 for (auto& stg : obj["sensor_trust_groups"])
69 {
70 if (!stg.contains("class") || !stg.contains("group"))
71 {
72 // Log error on missing required parameters
Anwaar Hadia00f6832025-03-27 15:03:11 +000073 lg2::error(
74 "Missing required fan monitor trust group parameters 'class, group'");
Matthew Barth9ea8bee2020-06-04 14:27:19 -050075 throw std::runtime_error(
76 "Missing required fan trust group parameters");
77 }
78 auto tgClass = stg["class"].get<std::string>();
79 std::vector<trust::GroupDefinition> group;
80 for (auto& member : stg["group"])
81 {
82 // Construct list of group members
83 if (!member.contains("name"))
84 {
85 // Log error on missing required parameter
Anwaar Hadia00f6832025-03-27 15:03:11 +000086 lg2::error(
87 "Missing required fan monitor trust group member name for class {CLASS}",
88 "CLASS", tgClass);
Matthew Barth9ea8bee2020-06-04 14:27:19 -050089 throw std::runtime_error(
90 "Missing required fan monitor trust group member name");
91 }
92 auto in_trust = true;
93 if (member.contains("in_trust"))
94 {
95 in_trust = member["in_trust"].get<bool>();
96 }
97 group.emplace_back(trust::GroupDefinition{
98 member["name"].get<std::string>(), in_trust});
99 }
100 // The class for fan sensor trust groups
101 // (Must have a supported function within the tClass namespace)
102 std::transform(tgClass.begin(), tgClass.end(), tgClass.begin(),
103 tolower);
104 auto handler = trusts.find(tgClass);
105 if (handler != trusts.end())
106 {
107 // Call function for trust group class
108 grpFuncs.emplace_back(handler->second(group));
109 }
110 else
111 {
112 // Log error on unsupported trust group class
Anwaar Hadia00f6832025-03-27 15:03:11 +0000113 lg2::error("Invalid fan monitor trust group class {CLASS}",
114 "CLASS", tgClass);
Matthew Barth9ea8bee2020-06-04 14:27:19 -0500115 throw std::runtime_error(
116 "Invalid fan monitor trust group class");
117 }
118 }
119 }
120
121 return grpFuncs;
122}
123
Matthew Barth22ab93b2020-06-08 10:47:56 -0500124const std::vector<SensorDefinition> getSensorDefs(const json& sensors)
125{
126 std::vector<SensorDefinition> sensorDefs;
127
128 for (const auto& sensor : sensors)
129 {
130 if (!sensor.contains("name") || !sensor.contains("has_target"))
131 {
132 // Log error on missing required parameters
Anwaar Hadia00f6832025-03-27 15:03:11 +0000133 lg2::error(
134 "Missing required fan sensor definition parameters 'name, has_target'");
Matthew Barth22ab93b2020-06-08 10:47:56 -0500135 throw std::runtime_error(
136 "Missing required fan sensor definition parameters");
137 }
138 // Target interface is optional and defaults to
139 // 'xyz.openbmc_project.Control.FanSpeed'
140 std::string targetIntf = "xyz.openbmc_project.Control.FanSpeed";
141 if (sensor.contains("target_interface"))
142 {
143 targetIntf = sensor["target_interface"].get<std::string>();
144 }
Chau Ly27cc39f2022-09-20 08:16:56 +0000145 // Target path is optional
146 std::string targetPath;
147 if (sensor.contains("target_path"))
148 {
149 targetPath = sensor["target_path"].get<std::string>();
150 }
Matthew Barth22ab93b2020-06-08 10:47:56 -0500151 // Factor is optional and defaults to 1
Matt Spinler18fb12b2023-05-09 11:17:42 -0500152 double factor = 1.0;
Matthew Barth22ab93b2020-06-08 10:47:56 -0500153 if (sensor.contains("factor"))
154 {
155 factor = sensor["factor"].get<double>();
156 }
157 // Offset is optional and defaults to 0
Matt Spinler18fb12b2023-05-09 11:17:42 -0500158 int64_t offset = 0;
Matthew Barth22ab93b2020-06-08 10:47:56 -0500159 if (sensor.contains("offset"))
160 {
161 offset = sensor["offset"].get<int64_t>();
162 }
Jolie Ku69f2f482020-10-21 09:59:43 +0800163 // Threshold is optional and defaults to 1
Matt Spinler18fb12b2023-05-09 11:17:42 -0500164 size_t threshold = 1;
Jolie Ku69f2f482020-10-21 09:59:43 +0800165 if (sensor.contains("threshold"))
166 {
167 threshold = sensor["threshold"].get<size_t>();
168 }
Matthew Barth8a8aa442021-11-19 14:13:13 -0600169 // Ignore being above the allowed max is optional, defaults to not
170 bool ignoreAboveMax = false;
171 if (sensor.contains("ignore_above_max"))
172 {
173 ignoreAboveMax = sensor["ignore_above_max"].get<bool>();
174 }
Matthew Barth22ab93b2020-06-08 10:47:56 -0500175
Patrick Williamsdfddd642024-08-16 15:21:51 -0400176 SensorDefinition def{
177 .name = sensor["name"].get<std::string>(),
178 .hasTarget = sensor["has_target"].get<bool>(),
179 .targetInterface = targetIntf,
180 .targetPath = targetPath,
181 .factor = factor,
182 .offset = offset,
183 .threshold = threshold,
184 .ignoreAboveMax = ignoreAboveMax};
Matt Spinler18fb12b2023-05-09 11:17:42 -0500185
186 sensorDefs.push_back(std::move(def));
Matthew Barth22ab93b2020-06-08 10:47:56 -0500187 }
188
189 return sensorDefs;
190}
191
192const std::vector<FanDefinition> getFanDefs(const json& obj)
193{
194 std::vector<FanDefinition> fanDefs;
195
196 for (const auto& fan : obj["fans"])
197 {
Jolie Ku69f2f482020-10-21 09:59:43 +0800198 if (!fan.contains("inventory") || !fan.contains("deviation") ||
199 !fan.contains("sensors"))
Matthew Barth22ab93b2020-06-08 10:47:56 -0500200 {
201 // Log error on missing required parameters
Anwaar Hadia00f6832025-03-27 15:03:11 +0000202 lg2::error(
203 "Missing required fan monitor definition parameters 'inventory, deviation, sensors'");
Matthew Barth22ab93b2020-06-08 10:47:56 -0500204 throw std::runtime_error(
205 "Missing required fan monitor definition parameters");
206 }
Matthew Barth4c4de262021-02-17 13:03:02 -0600207 // Valid deviation range is 0 - 100%
208 auto deviation = fan["deviation"].get<size_t>();
Mike Capps808d7fe2022-06-13 10:12:16 -0400209 if (100 < deviation)
Matthew Barth4c4de262021-02-17 13:03:02 -0600210 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000211 lg2::error(
212 "Invalid deviation of {DEVIATION} found, must be between 0 and 100",
213 "DEVIATION", deviation);
214 throw std::runtime_error(
215 "Invalid deviation found, must be between 0 and 100");
Matthew Barth4c4de262021-02-17 13:03:02 -0600216 }
217
Matt Spinlerf724c162023-05-10 11:14:37 -0500218 // Upper deviation defaults to the deviation value and
219 // can also be separately specified.
220 size_t upperDeviation = deviation;
221 if (fan.contains("upper_deviation"))
222 {
223 upperDeviation = fan["upper_deviation"].get<size_t>();
224 if (100 < upperDeviation)
225 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000226 lg2::error(
227 "Invalid upper_deviation of {UPPER_DEVIATION} found, must be between 0 and 100",
228 "UPPER_DEVIATION", upperDeviation);
229 throw std::runtime_error(
230 "Invalid upper_deviation found, must be between 0 and 100");
Matt Spinlerf724c162023-05-10 11:14:37 -0500231 }
232 }
233
Matthew Barth22ab93b2020-06-08 10:47:56 -0500234 // Construct the sensor definitions for this fan
235 auto sensorDefs = getSensorDefs(fan["sensors"]);
236
237 // Functional delay is optional and defaults to 0
238 size_t funcDelay = 0;
239 if (fan.contains("functional_delay"))
240 {
241 funcDelay = fan["functional_delay"].get<size_t>();
242 }
243
Jolie Ku69f2f482020-10-21 09:59:43 +0800244 // Method is optional and defaults to time based functional
245 // determination
246 size_t method = MethodMode::timebased;
Matt Spinler623635c2021-03-29 13:13:59 -0500247 size_t countInterval = 1;
Jolie Ku69f2f482020-10-21 09:59:43 +0800248 if (fan.contains("method"))
249 {
250 auto methodConf = fan["method"].get<std::string>();
251 auto methodFunc = methods.find(methodConf);
252 if (methodFunc != methods.end())
253 {
254 method = methodFunc->second;
255 }
256 else
257 {
258 // Log error on unsupported method parameter
Anwaar Hadia00f6832025-03-27 15:03:11 +0000259 lg2::error("Invalid fan method");
Jolie Ku69f2f482020-10-21 09:59:43 +0800260 throw std::runtime_error("Invalid fan method");
261 }
Matt Spinler623635c2021-03-29 13:13:59 -0500262
263 // Read the count interval value used with the count method.
264 if (method == MethodMode::count)
265 {
266 if (fan.contains("count_interval"))
267 {
268 countInterval = fan["count_interval"].get<size_t>();
269 }
270 }
Jolie Ku69f2f482020-10-21 09:59:43 +0800271 }
272
273 // Timeout defaults to 0
274 size_t timeout = 0;
275 if (method == MethodMode::timebased)
276 {
277 if (!fan.contains("allowed_out_of_range_time"))
278 {
279 // Log error on missing required parameter
Anwaar Hadia00f6832025-03-27 15:03:11 +0000280 lg2::error(
281 "Missing required fan monitor definition parameters 'allowed_out_of_range_time'");
Jolie Ku69f2f482020-10-21 09:59:43 +0800282 throw std::runtime_error(
283 "Missing required fan monitor definition parameters");
284 }
285 else
286 {
287 timeout = fan["allowed_out_of_range_time"].get<size_t>();
288 }
289 }
290
Matt Spinlerb0412d02020-10-12 16:53:52 -0500291 // Monitor start delay is optional and defaults to 0
292 size_t monitorDelay = 0;
293 if (fan.contains("monitor_start_delay"))
294 {
295 monitorDelay = fan["monitor_start_delay"].get<size_t>();
296 }
297
Matt Spinlerae1f8ef2020-10-14 16:15:51 -0500298 // num_sensors_nonfunc_for_fan_nonfunc is optional and defaults
299 // to zero if not present, meaning the code will not set the
300 // parent fan to nonfunctional based on sensors.
301 size_t nonfuncSensorsCount = 0;
302 if (fan.contains("num_sensors_nonfunc_for_fan_nonfunc"))
303 {
304 nonfuncSensorsCount =
305 fan["num_sensors_nonfunc_for_fan_nonfunc"].get<size_t>();
306 }
307
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500308 // nonfunc_rotor_error_delay is optional, though it will
309 // default to zero if 'fault_handling' is present.
310 std::optional<size_t> nonfuncRotorErrorDelay;
311 if (fan.contains("nonfunc_rotor_error_delay"))
312 {
313 nonfuncRotorErrorDelay =
314 fan["nonfunc_rotor_error_delay"].get<size_t>();
315 }
316 else if (obj.contains("fault_handling"))
317 {
318 nonfuncRotorErrorDelay = 0;
319 }
320
Matt Spinler27f6b682020-10-27 08:43:37 -0500321 // fan_missing_error_delay is optional.
322 std::optional<size_t> fanMissingErrorDelay;
323 if (fan.contains("fan_missing_error_delay"))
324 {
325 fanMissingErrorDelay =
326 fan.at("fan_missing_error_delay").get<size_t>();
327 }
328
Matthew Barth3ad14342020-06-08 16:17:42 -0500329 // Handle optional conditions
Matthew Barth8a0c2322020-06-17 09:53:10 -0500330 auto cond = std::optional<Condition>();
Matthew Barth3ad14342020-06-08 16:17:42 -0500331 if (fan.contains("condition"))
332 {
333 if (!fan["condition"].contains("name"))
334 {
335 // Log error on missing required parameter
Anwaar Hadia00f6832025-03-27 15:03:11 +0000336 lg2::error(
337 "Missing required fan monitor condition parameter 'name'");
Matthew Barth3ad14342020-06-08 16:17:42 -0500338 throw std::runtime_error(
339 "Missing required fan monitor condition parameter");
340 }
341 auto name = fan["condition"]["name"].get<std::string>();
342 // The function for fan monitoring condition
343 // (Must have a supported function within the condition namespace)
344 std::transform(name.begin(), name.end(), name.begin(), tolower);
345 auto handler = conditions.find(name);
346 if (handler != conditions.end())
347 {
348 cond = handler->second(fan["condition"]);
349 }
350 else
351 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000352 lg2::info(
353 "No handler found for configured condition {CONDITION_NAME}",
354 "CONDITION_NAME", name, "JSON_DUMP",
355 fan["condition"].dump());
Matthew Barth3ad14342020-06-08 16:17:42 -0500356 }
357 }
Jolie Ku69f2f482020-10-21 09:59:43 +0800358
Matt Spinlera3584bd2021-03-29 15:48:30 -0500359 // if the fan should be set to functional when plugged in
360 bool setFuncOnPresent = false;
361 if (fan.contains("set_func_on_present"))
362 {
363 setFuncOnPresent = fan["set_func_on_present"].get<bool>();
364 }
365
Patrick Williamsdfddd642024-08-16 15:21:51 -0400366 FanDefinition def{
367 .name = fan["inventory"].get<std::string>(),
368 .method = method,
369 .funcDelay = funcDelay,
370 .timeout = timeout,
371 .deviation = deviation,
372 .upperDeviation = upperDeviation,
373 .numSensorFailsForNonfunc = nonfuncSensorsCount,
374 .monitorStartDelay = monitorDelay,
375 .countInterval = countInterval,
376 .nonfuncRotorErrDelay = nonfuncRotorErrorDelay,
377 .fanMissingErrDelay = fanMissingErrorDelay,
378 .sensorList = std::move(sensorDefs),
379 .condition = cond,
380 .funcOnPresent = setFuncOnPresent};
Matt Spinler18fb12b2023-05-09 11:17:42 -0500381
382 fanDefs.push_back(std::move(def));
Matthew Barth22ab93b2020-06-08 10:47:56 -0500383 }
384
385 return fanDefs;
386}
387
Matt Spinlerf06ab072020-10-14 12:58:22 -0500388PowerRuleState getPowerOffPowerRuleState(const json& powerOffConfig)
389{
390 // The state is optional and defaults to runtime
391 PowerRuleState ruleState{PowerRuleState::runtime};
392
393 if (powerOffConfig.contains("state"))
394 {
395 auto state = powerOffConfig.at("state").get<std::string>();
396 if (state == "at_pgood")
397 {
398 ruleState = PowerRuleState::atPgood;
399 }
400 else if (state != "runtime")
401 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000402 lg2::error("Invalid power off state entry {STATE}", "STATE", state);
403 throw std::runtime_error("Invalid power off state entry");
Matt Spinlerf06ab072020-10-14 12:58:22 -0500404 }
405 }
406
407 return ruleState;
408}
409
410std::unique_ptr<PowerOffCause> getPowerOffCause(const json& powerOffConfig)
411{
412 std::unique_ptr<PowerOffCause> cause;
413
414 if (!powerOffConfig.contains("count") || !powerOffConfig.contains("cause"))
415 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000416 lg2::error("Missing 'count' or 'cause' entries in power off config");
417 throw std::runtime_error(
418 "Missing 'count' or 'cause' entries in power off config");
Matt Spinlerf06ab072020-10-14 12:58:22 -0500419 }
420
421 auto count = powerOffConfig.at("count").get<size_t>();
422 auto powerOffCause = powerOffConfig.at("cause").get<std::string>();
423
424 const std::map<std::string, std::function<std::unique_ptr<PowerOffCause>()>>
425 causes{
426 {"missing_fan_frus",
427 [count]() { return std::make_unique<MissingFanFRUCause>(count); }},
Matt Spinler4c62fc72024-02-14 16:10:19 -0600428 {"nonfunc_fan_rotors",
429 [count]() {
Patrick Williamsdfddd642024-08-16 15:21:51 -0400430 return std::make_unique<NonfuncFanRotorCause>(count);
431 }},
Matt Spinler4c62fc72024-02-14 16:10:19 -0600432 {"fan_frus_with_nonfunc_rotors", [count]() {
Patrick Williamsdfddd642024-08-16 15:21:51 -0400433 return std::make_unique<FanFRUsWithNonfuncRotorsCause>(count);
434 }}};
Matt Spinlerf06ab072020-10-14 12:58:22 -0500435
436 auto it = causes.find(powerOffCause);
437 if (it != causes.end())
438 {
439 cause = it->second();
440 }
441 else
442 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000443 lg2::error(
444 "Invalid power off cause {POWER_OFF_CAUSE} in power off config JSON",
445 "POWER_OFF_CAUSE", powerOffCause);
446 throw std::runtime_error(
447 "Invalid power off cause in power off config JSON");
Matt Spinlerf06ab072020-10-14 12:58:22 -0500448 }
449
450 return cause;
451}
452
Patrick Williams4fa67aa2025-02-03 14:28:47 -0500453std::unique_ptr<PowerOffAction> getPowerOffAction(
454 const json& powerOffConfig,
455 std::shared_ptr<PowerInterfaceBase>& powerInterface,
456 PowerOffAction::PrePowerOffFunc& func)
Matt Spinlerf06ab072020-10-14 12:58:22 -0500457{
458 std::unique_ptr<PowerOffAction> action;
459 if (!powerOffConfig.contains("type"))
460 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000461 lg2::error("Missing 'type' entry in power off config");
462 throw std::runtime_error("Missing 'type' entry in power off config");
Matt Spinlerf06ab072020-10-14 12:58:22 -0500463 }
464
465 auto type = powerOffConfig.at("type").get<std::string>();
466
467 if (((type == "hard") || (type == "soft")) &&
468 !powerOffConfig.contains("delay"))
469 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000470 lg2::error("Missing 'delay' entry in power off config");
471 throw std::runtime_error("Missing 'delay' entry in power off config");
Matt Spinlerf06ab072020-10-14 12:58:22 -0500472 }
473 else if ((type == "epow") &&
474 (!powerOffConfig.contains("service_mode_delay") ||
475 !powerOffConfig.contains("meltdown_delay")))
476 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000477 lg2::error(
478 "Missing 'service_mode_delay' or 'meltdown_delay' entry in power off config");
479 throw std::runtime_error(
480 "Missing 'service_mode_delay' or 'meltdown_delay' entry in power off config");
Matt Spinlerf06ab072020-10-14 12:58:22 -0500481 }
482
483 if (type == "hard")
484 {
485 action = std::make_unique<HardPowerOff>(
Matt Spinlerac1efc12020-10-27 10:20:11 -0500486 powerOffConfig.at("delay").get<uint32_t>(), powerInterface, func);
Matt Spinlerf06ab072020-10-14 12:58:22 -0500487 }
488 else if (type == "soft")
489 {
490 action = std::make_unique<SoftPowerOff>(
Matt Spinlerac1efc12020-10-27 10:20:11 -0500491 powerOffConfig.at("delay").get<uint32_t>(), powerInterface, func);
Matt Spinlerf06ab072020-10-14 12:58:22 -0500492 }
493 else if (type == "epow")
494 {
495 action = std::make_unique<EpowPowerOff>(
496 powerOffConfig.at("service_mode_delay").get<uint32_t>(),
Matt Spinlerac1efc12020-10-27 10:20:11 -0500497 powerOffConfig.at("meltdown_delay").get<uint32_t>(), powerInterface,
498 func);
Matt Spinlerf06ab072020-10-14 12:58:22 -0500499 }
500 else
501 {
Anwaar Hadia00f6832025-03-27 15:03:11 +0000502 lg2::error("Invalid 'type' entry {TYPE} in power off config", "TYPE",
503 type);
504 throw std::runtime_error("Invalid 'type' entry in power off config");
Matt Spinlerf06ab072020-10-14 12:58:22 -0500505 }
506
507 return action;
508}
509
Patrick Williamsdfddd642024-08-16 15:21:51 -0400510std::vector<std::unique_ptr<PowerOffRule>> getPowerOffRules(
511 const json& obj, std::shared_ptr<PowerInterfaceBase>& powerInterface,
512 PowerOffAction::PrePowerOffFunc& func)
Matt Spinlerf06ab072020-10-14 12:58:22 -0500513{
514 std::vector<std::unique_ptr<PowerOffRule>> rules;
515
516 if (!(obj.contains("fault_handling") &&
517 obj.at("fault_handling").contains("power_off_config")))
518 {
519 return rules;
520 }
521
522 for (const auto& config : obj.at("fault_handling").at("power_off_config"))
523 {
524 auto state = getPowerOffPowerRuleState(config);
525 auto cause = getPowerOffCause(config);
Matt Spinlerac1efc12020-10-27 10:20:11 -0500526 auto action = getPowerOffAction(config, powerInterface, func);
Matt Spinlerf06ab072020-10-14 12:58:22 -0500527
528 auto rule = std::make_unique<PowerOffRule>(
529 std::move(state), std::move(cause), std::move(action));
530 rules.push_back(std::move(rule));
531 }
532
533 return rules;
534}
535
Matt Spinlerf13b42e2020-10-26 15:29:49 -0500536std::optional<size_t> getNumNonfuncRotorsBeforeError(const json& obj)
537{
538 std::optional<size_t> num;
539
540 if (obj.contains("fault_handling"))
541 {
542 // Defaults to 1 if not present inside of 'fault_handling'.
543 num = obj.at("fault_handling")
544 .value("num_nonfunc_rotors_before_error", 1);
545 }
546
547 return num;
548}
549
Matthew Barth9ea8bee2020-06-04 14:27:19 -0500550} // namespace phosphor::fan::monitor