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