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 "profile.hpp"
17
18 #include "sdbusplus.hpp"
19
20 #include <nlohmann/json.hpp>
21 #include <phosphor-logging/log.hpp>
22
23 #include <algorithm>
24 #include <iterator>
25 #include <numeric>
26
27 namespace phosphor::fan::control::json
28 {
29
30 using json = nlohmann::json;
31 using namespace phosphor::logging;
32
33 // String key must be in all lowercase for method lookup
34 const std::map<std::string, methodHandler> Profile::_methods = {
35 {"all_of", Profile::allOf}};
36
Profile(const json & jsonObj)37 Profile::Profile(const json& jsonObj) : ConfigBase(jsonObj), _active(false)
38 {
39 setActive(jsonObj);
40 }
41
setActive(const json & jsonObj)42 void Profile::setActive(const json& jsonObj)
43 {
44 if (!jsonObj.contains("method") || !jsonObj["method"].contains("name"))
45 {
46 // Log error on missing profile method
47 log<level::ERR>("Missing required profile method",
48 entry("JSON=%s", jsonObj.dump().c_str()));
49 throw std::runtime_error("Missing required profile method");
50 }
51 // The method to use in determining if the profile is active
52 auto method = jsonObj["method"]["name"].get<std::string>();
53 std::transform(method.begin(), method.end(), method.begin(), tolower);
54 auto handler = _methods.find(method);
55 if (handler != _methods.end())
56 {
57 // Call method for determining profile's active state
58 _active = handler->second(jsonObj["method"]);
59 }
60 else
61 {
62 // Construct list of available methods
63 auto methods = std::accumulate(
64 std::next(_methods.begin()), _methods.end(),
65 _methods.begin()->first, [](auto list, auto method) {
66 return std::move(list) + ", " + method.first;
67 });
68 log<level::ERR>("Configured method not available",
69 entry("JSON=%s", jsonObj["method"].dump().c_str()),
70 entry("METHODS_AVAILABLE=%s", methods.c_str()));
71 }
72 }
73
allOf(const json & method)74 bool Profile::allOf(const json& method)
75 {
76 if (!method.contains("properties"))
77 {
78 log<level::ERR>("Missing required all_of method properties list",
79 entry("JSON=%s", method.dump().c_str()));
80 throw std::runtime_error(
81 "Missing required all_of method properties list");
82 }
83
84 return std::all_of(
85 method["properties"].begin(), method["properties"].end(),
86 [](const json& obj) {
87 if (!obj.contains("path") || !obj.contains("interface") ||
88 !obj.contains("property") || !obj.contains("value"))
89 {
90 log<level::ERR>(
91 "Missing required all_of method property parameters",
92 entry("JSON=%s", obj.dump().c_str()));
93 throw std::runtime_error(
94 "Missing required all_of method parameters");
95 }
96 auto variant =
97 util::SDBusPlus::getPropertyVariant<PropertyVariantType>(
98 obj["path"].get<std::string>(),
99 obj["interface"].get<std::string>(),
100 obj["property"].get<std::string>());
101
102 return getJsonValue(obj["value"]) == variant;
103 });
104 }
105
106 } // namespace phosphor::fan::control::json
107