blob: 44a3075606bf10bc67a012225f2d17c9ce5d1d75 [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 */
16#include <string>
Matthew Barth0961fae2019-11-15 09:00:27 -060017#include <filesystem>
18#include <fstream>
19#include <nlohmann/json.hpp>
20#include <phosphor-logging/log.hpp>
Matthew Barthfd05d642019-11-14 15:01:57 -060021
22#include "json_config.hpp"
Matthew Barthe7566632019-11-18 16:13:04 -060023#include "tach.hpp"
24#include "gpio.hpp"
Matthew Barthaa8d81d2019-11-21 14:07:31 -060025#include "anyof.hpp"
26#include "fallback.hpp"
Matthew Barthfd05d642019-11-14 15:01:57 -060027
28namespace phosphor
29{
30namespace fan
31{
32namespace presence
33{
34
Matthew Barth0961fae2019-11-15 09:00:27 -060035using json = nlohmann::json;
36namespace fs = std::filesystem;
37using namespace phosphor::logging;
38
Matthew Barthfd05d642019-11-14 15:01:57 -060039policies JsonConfig::_policies;
Matthew Barthe7566632019-11-18 16:13:04 -060040const std::map<std::string, methodHandler> JsonConfig::_methods =
41{
42 {"tach", method::getTach},
43 {"gpio", method::getGpio}
44};
Matthew Barthaa8d81d2019-11-21 14:07:31 -060045const std::map<std::string, rpolicyHandler> JsonConfig::_rpolicies =
46{
47 {"anyof", rpolicy::getAnyof},
48 {"fallback", rpolicy::getFallback}
49};
Matthew Barthfd05d642019-11-14 15:01:57 -060050
51JsonConfig::JsonConfig(const std::string& jsonFile)
52{
Matthew Barth0961fae2019-11-15 09:00:27 -060053 fs::path confFile{jsonFile};
54 std::ifstream file;
55 json jsonConf;
Matthew Barthfd05d642019-11-14 15:01:57 -060056
Matthew Barth0961fae2019-11-15 09:00:27 -060057 if (fs::exists(confFile))
58 {
59 file.open(confFile);
60 try
61 {
62 jsonConf = json::parse(file);
63 }
64 catch (std::exception& e)
65 {
66 log<level::ERR>("Failed to parse JSON config file",
67 entry("JSON_FILE=%s", jsonFile.c_str()),
68 entry("JSON_ERROR=%s", e.what()));
69 throw std::runtime_error("Failed to parse JSON config file");
70 }
71 }
72 else
73 {
74 log<level::ERR>("Unable to open JSON config file",
75 entry("JSON_FILE=%s", jsonFile.c_str()));
76 throw std::runtime_error("Unable to open JSON config file");
77 }
Matthew Barth4a94dec2019-11-15 10:40:47 -060078
79 process(jsonConf);
Matthew Barthfd05d642019-11-14 15:01:57 -060080}
81
82const policies& JsonConfig::get()
83{
84 return _policies;
85}
86
Matthew Barth4a94dec2019-11-15 10:40:47 -060087void JsonConfig::process(const json& jsonConf)
88{
Matthew Barthaa8d81d2019-11-21 14:07:31 -060089 // Set the expected number of fan entries
90 // to be size of the list of fan json config entries
91 // (Must be done to eliminate vector reallocation of fan references)
92 _fans.reserve(jsonConf.size());
Matthew Barth4a94dec2019-11-15 10:40:47 -060093 for (auto& member : jsonConf)
94 {
Matthew Barthe7566632019-11-18 16:13:04 -060095 if (!member.contains("name") || !member.contains("path") ||
Matthew Barthaa8d81d2019-11-21 14:07:31 -060096 !member.contains("methods") || !member.contains("rpolicy"))
Matthew Barth4a94dec2019-11-15 10:40:47 -060097 {
98 log<level::ERR>(
99 "Missing required fan presence properties",
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600100 entry("REQUIRED_PROPERTIES=%s",
101 "{name, path, methods, rpolicy}"));
Matthew Barth4a94dec2019-11-15 10:40:47 -0600102 throw std::runtime_error(
103 "Missing required fan presence properties");
104 }
Matthew Barthe7566632019-11-18 16:13:04 -0600105
106 // Loop thru the configured methods of presence detection
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600107 std::vector<std::unique_ptr<PresenceSensor>> sensors;
Matthew Barthe7566632019-11-18 16:13:04 -0600108 for (auto& method : member["methods"].items())
109 {
110 if (!method.value().contains("type"))
111 {
112 log<level::ERR>(
113 "Missing required fan presence method type",
114 entry("FAN_NAME=%s",
115 member["name"].get<std::string>().c_str()));
116 throw std::runtime_error(
117 "Missing required fan presence method type");
118 }
119 // The method type of fan presence detection
120 // (Must have a supported function within the method namespace)
121 auto type = method.value()["type"].get<std::string>();
122 std::transform(type.begin(), type.end(), type.begin(), tolower);
123 auto func = _methods.find(type);
124 if (func != _methods.end())
125 {
126 // Call function for method type
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600127 auto sensor = func->second(_fans.size(), method.value());
Matthew Barthe7566632019-11-18 16:13:04 -0600128 if (sensor)
129 {
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600130 sensors.emplace_back(std::move(sensor));
Matthew Barthe7566632019-11-18 16:13:04 -0600131 }
132 }
133 else
134 {
135 log<level::ERR>("Invalid fan presence method type",
136 entry("FAN_NAME=%s",
137 member["name"].get<std::string>().c_str()),
138 entry("METHOD_TYPE=%s", type.c_str()));
139 throw std::runtime_error("Invalid fan presence method type");
140 }
141 }
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600142 auto fan = std::make_tuple(member["name"], member["path"]);
143 // Create a fan object
144 _fans.emplace_back(std::make_tuple(fan, std::move(sensors)));
145
146 // Add fan presence policy
147 addPolicy(member["rpolicy"]);
148 }
149}
150
151void JsonConfig::addPolicy(const json& rpolicy)
152{
153 if (!rpolicy.contains("type"))
154 {
155 log<level::ERR>("Missing required fan presence policy type",
156 entry("FAN_NAME=%s",
157 std::get<fanPolicyFanPos>(
158 std::get<Fan>(_fans.back())).c_str()),
159 entry("REQUIRED_PROPERTIES=%s", "{type}"));
160 throw std::runtime_error("Missing required fan presence policy type");
161 }
162
163 // The redundancy policy type for fan presence detection
164 // (Must have a supported function within the rpolicy namespace)
165 auto type = rpolicy["type"].get<std::string>();
166 std::transform(type.begin(), type.end(), type.begin(), tolower);
167 auto func = _rpolicies.find(type);
168 if (func != _rpolicies.end())
169 {
170 // Call function for redundancy policy type
171 auto policy = func->second(_fans.back());
172 if (policy)
173 {
174 _policies.emplace_back(std::move(policy));
175 }
176 }
177 else
178 {
179 log<level::ERR>("Invalid fan presence policy type",
180 entry("FAN_NAME=%s",
181 std::get<fanPolicyFanPos>(std::get<Fan>(_fans.back())).c_str()),
182 entry("RPOLICY_TYPE=%s", type.c_str()));
183 throw std::runtime_error("Invalid fan presence methods policy type");
Matthew Barth4a94dec2019-11-15 10:40:47 -0600184 }
185}
186
Matthew Barthe7566632019-11-18 16:13:04 -0600187/**
188 * Methods of fan presence detection function definitions
189 */
190namespace method
191{
192 // Get a constructed presence sensor for fan presence detection by tach
193 std::unique_ptr<PresenceSensor> getTach(size_t fanIndex, const json& method)
194 {
Matthew Barthe0d98a32019-11-19 15:40:57 -0600195 if (!method.contains("sensors") ||
196 method["sensors"].size() == 0)
197 {
198 log<level::ERR>(
199 "Missing required tach method properties",
200 entry("FAN_ENTRY=%d", fanIndex),
201 entry("REQUIRED_PROPERTIES=%s", "{sensors}"));
202 throw std::runtime_error("Missing required tach method properties");
203 }
204
205 std::vector<std::string> sensors;
206 for (auto& sensor : method["sensors"])
207 {
208 sensors.emplace_back(sensor.get<std::string>());
209 }
210
211 return std::make_unique<PolicyAccess<Tach, JsonConfig>>(
212 fanIndex, std::move(sensors));
Matthew Barthe7566632019-11-18 16:13:04 -0600213 }
214
215 // Get a constructed presence sensor for fan presence detection by gpio
216 std::unique_ptr<PresenceSensor> getGpio(size_t fanIndex, const json& method)
217 {
Matthew Barthe0d98a32019-11-19 15:40:57 -0600218 if (!method.contains("physpath") ||
219 !method.contains("devpath") ||
220 !method.contains("key"))
221 {
222 log<level::ERR>(
223 "Missing required gpio method properties",
224 entry("FAN_ENTRY=%d", fanIndex),
225 entry("REQUIRED_PROPERTIES=%s", "{physpath, devpath, key}"));
226 throw std::runtime_error("Missing required gpio method properties");
227 }
228
229 auto physpath = method["physpath"].get<std::string>();
230 auto devpath = method["devpath"].get<std::string>();
231 auto key = method["key"].get<unsigned int>();
232
233 return std::make_unique<PolicyAccess<Gpio, JsonConfig>>(
234 fanIndex, physpath, devpath, key);
Matthew Barthe7566632019-11-18 16:13:04 -0600235 }
236
237} // namespace method
238
Matthew Barthaa8d81d2019-11-21 14:07:31 -0600239/**
240 * Redundancy policies for fan presence detection function definitions
241 */
242namespace rpolicy
243{
244 // Get an `Anyof` redundancy policy for the fan
245 std::unique_ptr<RedundancyPolicy> getAnyof(const fanPolicy& fan)
246 {
247 return nullptr;
248 }
249
250 // Get a `Fallback` redundancy policy for the fan
251 std::unique_ptr<RedundancyPolicy> getFallback(const fanPolicy& fan)
252 {
253 return nullptr;
254 }
255
256} // namespace policy
257
Matthew Barthfd05d642019-11-14 15:01:57 -0600258} // namespace presence
259} // namespace fan
260} // namespace phosphor