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_decrease.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 NetTargetDecrease::NetTargetDecrease(const json& jsonObj,
38                                      const std::vector<Group>& groups) :
39     ActionBase(jsonObj, groups)
40 {
41     setState(jsonObj);
42     setDelta(jsonObj);
43 }
44 
45 void NetTargetDecrease::run(Zone& zone)
46 {
47     auto netDelta = zone.getDecDelta();
48     for (const auto& group : _groups)
49     {
50         for (const auto& member : group.getMembers())
51         {
52             try
53             {
54                 auto value = Manager::getObjValueVariant(
55                     member, group.getInterface(), group.getProperty());
56                 if (std::holds_alternative<int64_t>(value) ||
57                     std::holds_alternative<double>(value))
58                 {
59                     if (value >= _state)
60                     {
61                         // No decrease allowed for this group
62                         netDelta = 0;
63                         break;
64                     }
65                     else
66                     {
67                         // Decrease factor is the difference in configured state
68                         // to the current value's state
69                         uint64_t deltaFactor = 0;
70                         if (auto dblPtr = std::get_if<double>(&value))
71                         {
72                             deltaFactor = static_cast<uint64_t>(
73                                 std::get<double>(_state) - *dblPtr);
74                         }
75                         else
76                         {
77                             deltaFactor = static_cast<uint64_t>(
78                                 std::get<int64_t>(_state) -
79                                 std::get<int64_t>(value));
80                         }
81 
82                         // Multiply the decrease factor by the configured delta
83                         // to get the net decrease delta for the given group
84                         // member. The lowest net decrease delta of the entire
85                         // group is the decrease requested.
86                         if (netDelta == 0)
87                         {
88                             netDelta = deltaFactor * _delta;
89                         }
90                         else
91                         {
92                             netDelta = std::min(netDelta, deltaFactor * _delta);
93                         }
94                     }
95                 }
96                 else if (std::holds_alternative<bool>(value) ||
97                          std::holds_alternative<std::string>(value))
98                 {
99                     // Where a group of booleans or strings equal the state
100                     // provided, request a decrease of the configured delta
101                     if (_state == value)
102                     {
103                         if (netDelta == 0)
104                         {
105                             netDelta = _delta;
106                         }
107                         else
108                         {
109                             netDelta = std::min(netDelta, _delta);
110                         }
111                     }
112                 }
113                 else
114                 {
115                     // Unsupported group member type for this action
116                     log<level::ERR>(
117                         fmt::format("Action {}: Unsupported group member type "
118                                     "given. [object = {} : {} : {}]",
119                                     ActionBase::getName(), member,
120                                     group.getInterface(), group.getProperty())
121                             .c_str());
122                 }
123             }
124             catch (const std::out_of_range& oore)
125             {
126                 // Property value not found, netDelta unchanged
127             }
128         }
129         // Update group's decrease allowed state
130         zone.setDecreaseAllow(group.getName(), !(netDelta == 0));
131     }
132     // Request target decrease to occur on decrease interval
133     zone.requestDecrease(netDelta);
134 }
135 
136 void NetTargetDecrease::setState(const json& jsonObj)
137 {
138     if (!jsonObj.contains("state"))
139     {
140         throw ActionParseError{ActionBase::getName(),
141                                "Missing required state value"};
142     }
143     _state = getJsonValue(jsonObj["state"]);
144 }
145 
146 void NetTargetDecrease::setDelta(const json& jsonObj)
147 {
148     if (!jsonObj.contains("delta"))
149     {
150         throw ActionParseError{ActionBase::getName(),
151                                "Missing required delta value"};
152     }
153     _delta = jsonObj["delta"].get<uint64_t>();
154 }
155 
156 } // namespace phosphor::fan::control::json
157