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