1 /**
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 
18 #include "conditions.hpp"
19 #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>
29 #include <optional>
30 #include <vector>
31 
32 namespace phosphor::fan::monitor
33 {
34 
35 using json = nlohmann::json;
36 using namespace phosphor::logging;
37 
38 namespace tClass
39 {
40 
41 // Get a constructed trust group class for a non-zero speed group
42 CreateGroupFunction
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 
52 const std::map<std::string, trustHandler> trusts = {
53     {"nonzerospeed", tClass::getNonZeroSpeed}};
54 const std::map<std::string, condHandler> conditions = {
55     {"propertiesmatch", condition::getPropertiesMatch}};
56 
57 const 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 
120 const 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 
163 const 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 
194         // Handle optional conditions
195         auto cond = std::optional<Condition>();
196         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         }
224 
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 
236 } // namespace phosphor::fan::monitor
237