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