blob: 23420b684af46dd3c16589dd8f5ec6b46a3fec5b [file] [log] [blame]
Matthew Barthfd05d642019-11-14 15:01:57 -06001/**
2 * Copyright © 2019 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 */
Jolie Ku1a568652020-08-24 16:32:15 +080016#include "json_parser.hpp"
Matthew Barth2d2caa32020-05-26 11:07:24 -050017
18#include "anyof.hpp"
19#include "fallback.hpp"
20#include "gpio.hpp"
Jolie Ku1a568652020-08-24 16:32:15 +080021#include "json_config.hpp"
Matthew Barth2d2caa32020-05-26 11:07:24 -050022#include "sdbusplus.hpp"
23#include "tach.hpp"
24
Matthew Barth0961fae2019-11-15 09:00:27 -060025#include <nlohmann/json.hpp>
26#include <phosphor-logging/log.hpp>
Matthew Barth5060b102019-12-16 10:46:35 -060027#include <sdbusplus/bus.hpp>
Matthew Barthfd05d642019-11-14 15:01:57 -060028
Matthew Barth2d2caa32020-05-26 11:07:24 -050029#include <filesystem>
30#include <fstream>
31#include <string>
Matthew Barthfd05d642019-11-14 15:01:57 -060032
33namespace phosphor
34{
35namespace fan
36{
37namespace presence
38{
39
Matthew Barth0961fae2019-11-15 09:00:27 -060040using json = nlohmann::json;
41namespace fs = std::filesystem;
42using namespace phosphor::logging;
43
Matthew Barthfd05d642019-11-14 15:01:57 -060044policies JsonConfig::_policies;
Matthew Barth2d2caa32020-05-26 11:07:24 -050045const std::map<std::string, methodHandler> JsonConfig::_methods = {
46 {"tach", method::getTach}, {"gpio", method::getGpio}};
47const std::map<std::string, rpolicyHandler> JsonConfig::_rpolicies = {
48 {"anyof", rpolicy::getAnyof}, {"fallback", rpolicy::getFallback}};
Matthew Barthfd05d642019-11-14 15:01:57 -060049
Matthew Barth2d2caa32020-05-26 11:07:24 -050050JsonConfig::JsonConfig(sdbusplus::bus::bus& bus) : _bus(bus)
Matthew Barthfd05d642019-11-14 15:01:57 -060051{
Jolie Ku1a568652020-08-24 16:32:15 +080052 using config = fan::JsonConfig;
53
Matthew Barth5060b102019-12-16 10:46:35 -060054 // Load and process the json configuration
Jolie Ku1a568652020-08-24 16:32:15 +080055 process(config::load(config::getConfFile(bus, confAppName, confFileName)));
Matthew Barthfd05d642019-11-14 15:01:57 -060056}
57
58const policies& JsonConfig::get()
59{
60 return _policies;
61}
62
Matthew Barthf3e70472019-12-03 13:33:20 -060063void JsonConfig::sighupHandler(sdeventplus::source::Signal& sigSrc,
64 const struct signalfd_siginfo* sigInfo)
65{
66 try
67 {
Jolie Ku1a568652020-08-24 16:32:15 +080068 using config = fan::JsonConfig;
69
Matthew Barthf3e70472019-12-03 13:33:20 -060070 // Load and process the json configuration
Jolie Ku1a568652020-08-24 16:32:15 +080071 process(
72 config::load(config::getConfFile(_bus, confAppName, confFileName)));
73
Matthew Barth2d2caa32020-05-26 11:07:24 -050074 for (auto& p : _policies)
Matthew Barthf3e70472019-12-03 13:33:20 -060075 {
76 p->monitor();
77 }
78 log<level::INFO>("Configuration loaded successfully");
79 }
80 catch (std::runtime_error& re)
81 {
82 log<level::ERR>("Error loading config, no config changes made",
83 entry("LOAD_ERROR=%s", re.what()));
84 }
85}
86
Matthew Barth4a94dec2019-11-15 10:40:47 -060087void JsonConfig::process(const json& jsonConf)
88{
Matthew Barthf3e70472019-12-03 13:33:20 -060089 policies policies;
90 std::vector<fanPolicy> fans;
Matt Spinlere8122392020-09-24 13:22:18 -050091 const json* fanJSON;
92
93 // The original JSON had the fan array at the root, but the new JSON
94 // has it under a 'fans' element. Support both.
95 // This can be removed after the new JSON is in the image.
96 if (jsonConf.is_array())
97 {
98 fanJSON = &jsonConf;
99 }
100 else
101 {
102 fanJSON = &jsonConf["fans"];
103 }
104
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600105 // Set the expected number of fan entries
106 // to be size of the list of fan json config entries
107 // (Must be done to eliminate vector reallocation of fan references)
Matt Spinlere8122392020-09-24 13:22:18 -0500108 fans.reserve(fanJSON->size());
109 for (auto& member : *fanJSON)
Matthew Barth4a94dec2019-11-15 10:40:47 -0600110 {
Matthew Barthe7566632019-11-18 16:13:04 -0600111 if (!member.contains("name") || !member.contains("path") ||
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600112 !member.contains("methods") || !member.contains("rpolicy"))
Matthew Barth4a94dec2019-11-15 10:40:47 -0600113 {
Matthew Barth2d2caa32020-05-26 11:07:24 -0500114 log<level::ERR>("Missing required fan presence properties",
115 entry("REQUIRED_PROPERTIES=%s",
116 "{name, path, methods, rpolicy}"));
Matthew Barth4a94dec2019-11-15 10:40:47 -0600117 throw std::runtime_error(
118 "Missing required fan presence properties");
119 }
Matthew Barthe7566632019-11-18 16:13:04 -0600120
121 // Loop thru the configured methods of presence detection
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600122 std::vector<std::unique_ptr<PresenceSensor>> sensors;
Matthew Barthe7566632019-11-18 16:13:04 -0600123 for (auto& method : member["methods"].items())
124 {
125 if (!method.value().contains("type"))
126 {
127 log<level::ERR>(
128 "Missing required fan presence method type",
129 entry("FAN_NAME=%s",
Matthew Barth2d2caa32020-05-26 11:07:24 -0500130 member["name"].get<std::string>().c_str()));
Matthew Barthe7566632019-11-18 16:13:04 -0600131 throw std::runtime_error(
132 "Missing required fan presence method type");
133 }
134 // The method type of fan presence detection
135 // (Must have a supported function within the method namespace)
136 auto type = method.value()["type"].get<std::string>();
137 std::transform(type.begin(), type.end(), type.begin(), tolower);
138 auto func = _methods.find(type);
139 if (func != _methods.end())
140 {
141 // Call function for method type
Matthew Barthf3e70472019-12-03 13:33:20 -0600142 auto sensor = func->second(fans.size(), method.value());
Matthew Barthe7566632019-11-18 16:13:04 -0600143 if (sensor)
144 {
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600145 sensors.emplace_back(std::move(sensor));
Matthew Barthe7566632019-11-18 16:13:04 -0600146 }
147 }
148 else
149 {
Matthew Barth2d2caa32020-05-26 11:07:24 -0500150 log<level::ERR>(
151 "Invalid fan presence method type",
152 entry("FAN_NAME=%s",
153 member["name"].get<std::string>().c_str()),
154 entry("METHOD_TYPE=%s", type.c_str()));
Matthew Barthe7566632019-11-18 16:13:04 -0600155 throw std::runtime_error("Invalid fan presence method type");
156 }
157 }
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600158 auto fan = std::make_tuple(member["name"], member["path"]);
159 // Create a fan object
Matthew Barthf3e70472019-12-03 13:33:20 -0600160 fans.emplace_back(std::make_tuple(fan, std::move(sensors)));
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600161
162 // Add fan presence policy
Matthew Barthf3e70472019-12-03 13:33:20 -0600163 auto policy = getPolicy(member["rpolicy"], fans.back());
164 if (policy)
165 {
166 policies.emplace_back(std::move(policy));
167 }
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600168 }
Matthew Barthf3e70472019-12-03 13:33:20 -0600169
170 // Success, refresh fans and policies lists
171 _fans.clear();
172 _fans.swap(fans);
173
174 _policies.clear();
175 _policies.swap(policies);
Matt Spinlere8122392020-09-24 13:22:18 -0500176
177 // Create the error reporter class if necessary
178 if (jsonConf.contains("reporting"))
179 {
180 _reporter = std::make_unique<ErrorReporter>(
181 _bus, jsonConf.at("reporting"), _fans);
182 }
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600183}
184
Matthew Barth2d2caa32020-05-26 11:07:24 -0500185std::unique_ptr<RedundancyPolicy>
186 JsonConfig::getPolicy(const json& rpolicy, const fanPolicy& fpolicy)
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600187{
188 if (!rpolicy.contains("type"))
189 {
Matthew Barth2d2caa32020-05-26 11:07:24 -0500190 log<level::ERR>(
191 "Missing required fan presence policy type",
192 entry("FAN_NAME=%s",
193 std::get<fanPolicyFanPos>(std::get<Fan>(fpolicy)).c_str()),
194 entry("REQUIRED_PROPERTIES=%s", "{type}"));
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600195 throw std::runtime_error("Missing required fan presence policy type");
196 }
197
198 // The redundancy policy type for fan presence detection
199 // (Must have a supported function within the rpolicy namespace)
200 auto type = rpolicy["type"].get<std::string>();
201 std::transform(type.begin(), type.end(), type.begin(), tolower);
202 auto func = _rpolicies.find(type);
203 if (func != _rpolicies.end())
204 {
Matthew Barthf3e70472019-12-03 13:33:20 -0600205 // Call function for redundancy policy type and return the policy
206 return func->second(fpolicy);
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600207 }
208 else
209 {
Matthew Barth2d2caa32020-05-26 11:07:24 -0500210 log<level::ERR>(
211 "Invalid fan presence policy type",
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600212 entry("FAN_NAME=%s",
Matthew Barth2d2caa32020-05-26 11:07:24 -0500213 std::get<fanPolicyFanPos>(std::get<Fan>(fpolicy)).c_str()),
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600214 entry("RPOLICY_TYPE=%s", type.c_str()));
215 throw std::runtime_error("Invalid fan presence methods policy type");
Matthew Barth4a94dec2019-11-15 10:40:47 -0600216 }
217}
218
Matthew Barthe7566632019-11-18 16:13:04 -0600219/**
220 * Methods of fan presence detection function definitions
221 */
222namespace method
223{
Matthew Barth2d2caa32020-05-26 11:07:24 -0500224// Get a constructed presence sensor for fan presence detection by tach
225std::unique_ptr<PresenceSensor> getTach(size_t fanIndex, const json& method)
226{
227 if (!method.contains("sensors") || method["sensors"].size() == 0)
Matthew Barthe7566632019-11-18 16:13:04 -0600228 {
Matthew Barth2d2caa32020-05-26 11:07:24 -0500229 log<level::ERR>("Missing required tach method properties",
230 entry("FAN_ENTRY=%d", fanIndex),
231 entry("REQUIRED_PROPERTIES=%s", "{sensors}"));
232 throw std::runtime_error("Missing required tach method properties");
Matthew Barthe7566632019-11-18 16:13:04 -0600233 }
234
Matthew Barth2d2caa32020-05-26 11:07:24 -0500235 std::vector<std::string> sensors;
236 for (auto& sensor : method["sensors"])
Matthew Barthe7566632019-11-18 16:13:04 -0600237 {
Matthew Barth2d2caa32020-05-26 11:07:24 -0500238 sensors.emplace_back(sensor.get<std::string>());
Matthew Barthe7566632019-11-18 16:13:04 -0600239 }
240
Matthew Barth2d2caa32020-05-26 11:07:24 -0500241 return std::make_unique<PolicyAccess<Tach, JsonConfig>>(fanIndex,
242 std::move(sensors));
243}
244
245// Get a constructed presence sensor for fan presence detection by gpio
246std::unique_ptr<PresenceSensor> getGpio(size_t fanIndex, const json& method)
247{
248 if (!method.contains("physpath") || !method.contains("devpath") ||
249 !method.contains("key"))
250 {
251 log<level::ERR>(
252 "Missing required gpio method properties",
253 entry("FAN_ENTRY=%d", fanIndex),
254 entry("REQUIRED_PROPERTIES=%s", "{physpath, devpath, key}"));
255 throw std::runtime_error("Missing required gpio method properties");
256 }
257
258 auto physpath = method["physpath"].get<std::string>();
259 auto devpath = method["devpath"].get<std::string>();
260 auto key = method["key"].get<unsigned int>();
261
262 return std::make_unique<PolicyAccess<Gpio, JsonConfig>>(fanIndex, physpath,
263 devpath, key);
264}
265
Matthew Barthe7566632019-11-18 16:13:04 -0600266} // namespace method
267
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600268/**
269 * Redundancy policies for fan presence detection function definitions
270 */
271namespace rpolicy
272{
Matthew Barth2d2caa32020-05-26 11:07:24 -0500273// Get an `Anyof` redundancy policy for the fan
274std::unique_ptr<RedundancyPolicy> getAnyof(const fanPolicy& fan)
275{
276 std::vector<std::reference_wrapper<PresenceSensor>> pSensors;
277 for (auto& fanSensor : std::get<fanPolicySensorListPos>(fan))
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600278 {
Matthew Barth2d2caa32020-05-26 11:07:24 -0500279 pSensors.emplace_back(*fanSensor);
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600280 }
281
Matthew Barth2d2caa32020-05-26 11:07:24 -0500282 return std::make_unique<AnyOf>(std::get<fanPolicyFanPos>(fan), pSensors);
283}
Matthew Barth26ad44a2019-11-22 15:37:14 -0600284
Matthew Barth2d2caa32020-05-26 11:07:24 -0500285// Get a `Fallback` redundancy policy for the fan
286std::unique_ptr<RedundancyPolicy> getFallback(const fanPolicy& fan)
287{
288 std::vector<std::reference_wrapper<PresenceSensor>> pSensors;
289 for (auto& fanSensor : std::get<fanPolicySensorListPos>(fan))
290 {
291 // Place in the order given to fallback correctly
292 pSensors.emplace_back(*fanSensor);
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600293 }
294
Matthew Barth2d2caa32020-05-26 11:07:24 -0500295 return std::make_unique<Fallback>(std::get<fanPolicyFanPos>(fan), pSensors);
296}
297
298} // namespace rpolicy
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600299
Matthew Barthfd05d642019-11-14 15:01:57 -0600300} // namespace presence
301} // namespace fan
302} // namespace phosphor