blob: 9b773c24b71845088e184f44119e2b92ef8281a2 [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"
21#include "types.hpp"
22
23#include <nlohmann/json.hpp>
24#include <phosphor-logging/log.hpp>
25
26#include <algorithm>
27#include <map>
28#include <memory>
Matthew Barth22ab93b2020-06-08 10:47:56 -050029#include <optional>
Matthew Barth9ea8bee2020-06-04 14:27:19 -050030#include <vector>
31
32namespace phosphor::fan::monitor
33{
34
35using json = nlohmann::json;
36using namespace phosphor::logging;
37
38namespace tClass
39{
40
41// Get a constructed trust group class for a non-zero speed group
42CreateGroupFunction
43 getNonZeroSpeed(const std::vector<trust::GroupDefinition>& group)
44{
45 return [group]() {
46 return std::make_unique<trust::NonzeroSpeed>(std::move(group));
47 };
48}
49
50} // namespace tClass
51
52const std::map<std::string, trustHandler> trusts = {
53 {"nonzerospeed", tClass::getNonZeroSpeed}};
Matthew Barth3ad14342020-06-08 16:17:42 -050054const std::map<std::string, condHandler> conditions = {
55 {"propertiesmatch", condition::getPropertiesMatch}};
Matthew Barth9ea8bee2020-06-04 14:27:19 -050056
57const std::vector<CreateGroupFunction> getTrustGrps(const json& obj)
58{
59 std::vector<CreateGroupFunction> grpFuncs;
60
61 if (obj.contains("sensor_trust_groups"))
62 {
63 for (auto& stg : obj["sensor_trust_groups"])
64 {
65 if (!stg.contains("class") || !stg.contains("group"))
66 {
67 // Log error on missing required parameters
68 log<level::ERR>(
69 "Missing required fan monitor trust group parameters",
70 entry("REQUIRED_PARAMETERS=%s", "{class, group}"));
71 throw std::runtime_error(
72 "Missing required fan trust group parameters");
73 }
74 auto tgClass = stg["class"].get<std::string>();
75 std::vector<trust::GroupDefinition> group;
76 for (auto& member : stg["group"])
77 {
78 // Construct list of group members
79 if (!member.contains("name"))
80 {
81 // Log error on missing required parameter
82 log<level::ERR>(
83 "Missing required fan monitor trust group member name",
84 entry("CLASS=%s", tgClass.c_str()));
85 throw std::runtime_error(
86 "Missing required fan monitor trust group member name");
87 }
88 auto in_trust = true;
89 if (member.contains("in_trust"))
90 {
91 in_trust = member["in_trust"].get<bool>();
92 }
93 group.emplace_back(trust::GroupDefinition{
94 member["name"].get<std::string>(), in_trust});
95 }
96 // The class for fan sensor trust groups
97 // (Must have a supported function within the tClass namespace)
98 std::transform(tgClass.begin(), tgClass.end(), tgClass.begin(),
99 tolower);
100 auto handler = trusts.find(tgClass);
101 if (handler != trusts.end())
102 {
103 // Call function for trust group class
104 grpFuncs.emplace_back(handler->second(group));
105 }
106 else
107 {
108 // Log error on unsupported trust group class
109 log<level::ERR>("Invalid fan monitor trust group class",
110 entry("CLASS=%s", tgClass.c_str()));
111 throw std::runtime_error(
112 "Invalid fan monitor trust group class");
113 }
114 }
115 }
116
117 return grpFuncs;
118}
119
Matthew Barth22ab93b2020-06-08 10:47:56 -0500120const std::vector<SensorDefinition> getSensorDefs(const json& sensors)
121{
122 std::vector<SensorDefinition> sensorDefs;
123
124 for (const auto& sensor : sensors)
125 {
126 if (!sensor.contains("name") || !sensor.contains("has_target"))
127 {
128 // Log error on missing required parameters
129 log<level::ERR>(
130 "Missing required fan sensor definition parameters",
131 entry("REQUIRED_PARAMETERS=%s", "{name, has_target}"));
132 throw std::runtime_error(
133 "Missing required fan sensor definition parameters");
134 }
135 // Target interface is optional and defaults to
136 // 'xyz.openbmc_project.Control.FanSpeed'
137 std::string targetIntf = "xyz.openbmc_project.Control.FanSpeed";
138 if (sensor.contains("target_interface"))
139 {
140 targetIntf = sensor["target_interface"].get<std::string>();
141 }
142 // Factor is optional and defaults to 1
143 auto factor = 1.0;
144 if (sensor.contains("factor"))
145 {
146 factor = sensor["factor"].get<double>();
147 }
148 // Offset is optional and defaults to 0
149 auto offset = 0;
150 if (sensor.contains("offset"))
151 {
152 offset = sensor["offset"].get<int64_t>();
153 }
154
155 sensorDefs.emplace_back(std::tuple(sensor["name"].get<std::string>(),
156 sensor["has_target"].get<bool>(),
157 targetIntf, factor, offset));
158 }
159
160 return sensorDefs;
161}
162
163const std::vector<FanDefinition> getFanDefs(const json& obj)
164{
165 std::vector<FanDefinition> fanDefs;
166
167 for (const auto& fan : obj["fans"])
168 {
169 if (!fan.contains("inventory") ||
170 !fan.contains("allowed_out_of_range_time") ||
171 !fan.contains("deviation") ||
172 !fan.contains("num_sensors_nonfunc_for_fan_nonfunc") ||
173 !fan.contains("sensors"))
174 {
175 // Log error on missing required parameters
176 log<level::ERR>(
177 "Missing required fan monitor definition parameters",
178 entry("REQUIRED_PARAMETERS=%s",
179 "{inventory, allowed_out_of_range_time, deviation, "
180 "num_sensors_nonfunc_for_fan_nonfunc, sensors}"));
181 throw std::runtime_error(
182 "Missing required fan monitor definition parameters");
183 }
184 // Construct the sensor definitions for this fan
185 auto sensorDefs = getSensorDefs(fan["sensors"]);
186
187 // Functional delay is optional and defaults to 0
188 size_t funcDelay = 0;
189 if (fan.contains("functional_delay"))
190 {
191 funcDelay = fan["functional_delay"].get<size_t>();
192 }
193
Matthew Barth3ad14342020-06-08 16:17:42 -0500194 // Handle optional conditions
Matthew Barth22ab93b2020-06-08 10:47:56 -0500195 auto cond = std::experimental::optional<Condition>();
Matthew Barth3ad14342020-06-08 16:17:42 -0500196 if (fan.contains("condition"))
197 {
198 if (!fan["condition"].contains("name"))
199 {
200 // Log error on missing required parameter
201 log<level::ERR>(
202 "Missing required fan monitor condition parameter",
203 entry("REQUIRED_PARAMETER=%s", "{name}"));
204 throw std::runtime_error(
205 "Missing required fan monitor condition parameter");
206 }
207 auto name = fan["condition"]["name"].get<std::string>();
208 // The function for fan monitoring condition
209 // (Must have a supported function within the condition namespace)
210 std::transform(name.begin(), name.end(), name.begin(), tolower);
211 auto handler = conditions.find(name);
212 if (handler != conditions.end())
213 {
214 cond = handler->second(fan["condition"]);
215 }
216 else
217 {
218 log<level::INFO>(
219 "No handler found for configured condition",
220 entry("CONDITION_NAME=%s", name.c_str()),
221 entry("JSON_DUMP=%s", fan["condition"].dump().c_str()));
222 }
223 }
Matthew Barth22ab93b2020-06-08 10:47:56 -0500224
225 fanDefs.emplace_back(
226 std::tuple(fan["inventory"].get<std::string>(), funcDelay,
227 fan["allowed_out_of_range_time"].get<size_t>(),
228 fan["deviation"].get<size_t>(),
229 fan["num_sensors_nonfunc_for_fan_nonfunc"].get<size_t>(),
230 sensorDefs, cond));
231 }
232
233 return fanDefs;
234}
235
Matthew Barth9ea8bee2020-06-04 14:27:19 -0500236} // namespace phosphor::fan::monitor