1 /**
2  * Copyright © 2021 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 "net_target_increase.hpp"
17 
18 #include "../manager.hpp"
19 #include "../zone.hpp"
20 #include "action.hpp"
21 #include "group.hpp"
22 
23 #include <fmt/format.h>
24 
25 #include <nlohmann/json.hpp>
26 #include <phosphor-logging/log.hpp>
27 
28 #include <algorithm>
29 #include <variant>
30 
31 namespace phosphor::fan::control::json
32 {
33 
34 using json = nlohmann::json;
35 using namespace phosphor::logging;
36 
37 NetTargetIncrease::NetTargetIncrease(const json& jsonObj,
38                                      const std::vector<Group>& groups) :
39     ActionBase(jsonObj, groups)
40 {
41     setState(jsonObj);
42     setDelta(jsonObj);
43 }
44 
45 void NetTargetIncrease::run(Zone& zone)
46 {
47     if (!_stateParameter.empty())
48     {
49         auto s = Manager::getParameter(_stateParameter);
50         if (!s)
51         {
52             return;
53         }
54         _state = *s;
55     }
56 
57     auto netDelta = zone.getIncDelta();
58     for (const auto& group : _groups)
59     {
60         const auto& members = group.getMembers();
61         std::for_each(members.begin(), members.end(),
62                       [this, &zone, &group, &netDelta](const auto& member) {
63             try
64             {
65                 auto value = Manager::getObjValueVariant(
66                     member, group.getInterface(), group.getProperty());
67                 if (std::holds_alternative<int64_t>(value) ||
68                     std::holds_alternative<double>(value))
69                 {
70                     // Where a group of int/doubles are greater than or
71                     // equal to the state(some value) provided, request an
72                     // increase of the configured delta times the difference
73                     // between the group member's value and configured state
74                     // value.
75                     if (value >= _state)
76                     {
77                         uint64_t incDelta = 0;
78                         if (auto dblPtr = std::get_if<double>(&value))
79                         {
80                             incDelta = static_cast<uint64_t>(
81                                 (*dblPtr - std::get<double>(_state)) * _delta);
82                         }
83                         else
84                         {
85                             // Increase by at least a single delta
86                             // to attempt bringing under provided 'state'
87                             auto deltaFactor =
88                                 std::max((std::get<int64_t>(value) -
89                                           std::get<int64_t>(_state)),
90                                          int64_t(1));
91                             incDelta =
92                                 static_cast<uint64_t>(deltaFactor * _delta);
93                         }
94                         netDelta = std::max(netDelta, incDelta);
95                     }
96                 }
97                 else if (std::holds_alternative<bool>(value))
98                 {
99                     // Where a group of booleans equal the state(`true` or
100                     // `false`) provided, request an increase of the
101                     // configured delta
102                     if (_state == value)
103                     {
104                         netDelta = std::max(netDelta, _delta);
105                     }
106                 }
107                 else if (std::holds_alternative<std::string>(value))
108                 {
109                     // Where a group of strings equal the state(some string)
110                     // provided, request an increase of the configured delta
111                     if (_state == value)
112                     {
113                         netDelta = std::max(netDelta, _delta);
114                     }
115                 }
116                 else
117                 {
118                     // Unsupported group member type for this action
119                     log<level::ERR>(
120                         fmt::format("Action {}: Unsupported group member type "
121                                     "given. [object = {} : {} : {}]",
122                                     ActionBase::getName(), member,
123                                     group.getInterface(), group.getProperty())
124                             .c_str());
125                 }
126             }
127             catch (const std::out_of_range& oore)
128             {
129                 // Property value not found, netDelta unchanged
130             }
131         });
132     }
133     // Request increase to target
134     zone.requestIncrease(netDelta);
135 }
136 
137 void NetTargetIncrease::setState(const json& jsonObj)
138 {
139     if (jsonObj.contains("state"))
140     {
141         _state = getJsonValue(jsonObj["state"]);
142     }
143     else if (jsonObj.contains("state_parameter_name"))
144     {
145         _stateParameter = jsonObj["state_parameter_name"].get<std::string>();
146     }
147     else
148     {
149         throw ActionParseError{
150             ActionBase::getName(),
151             "Missing required state or state_parameter_name value"};
152     }
153 }
154 
155 void NetTargetIncrease::setDelta(const json& jsonObj)
156 {
157     if (!jsonObj.contains("delta"))
158     {
159         throw ActionParseError{ActionBase::getName(),
160                                "Missing required delta value"};
161     }
162     _delta = jsonObj["delta"].get<uint64_t>();
163 }
164 
165 } // namespace phosphor::fan::control::json
166