blob: f02a590af7130b9c38298ee389122db2113ffc23 [file] [log] [blame]
Matthew Barth3174e722020-09-15 15:13:40 -05001/**
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 "event.hpp"
17
Matthew Barth776ca562021-03-31 09:50:58 -050018#include "action.hpp"
Matthew Barthe5578602021-03-30 12:53:24 -050019#include "config_base.hpp"
Matthew Barth391ade02021-01-15 14:33:21 -060020#include "group.hpp"
Matthew Barthe5578602021-03-30 12:53:24 -050021#include "manager.hpp"
22
23#include <fmt/format.h>
Matthew Barth391ade02021-01-15 14:33:21 -060024
Matthew Barth3174e722020-09-15 15:13:40 -050025#include <nlohmann/json.hpp>
26#include <phosphor-logging/log.hpp>
27#include <sdbusplus/bus.hpp>
28
Matthew Barthe5578602021-03-30 12:53:24 -050029#include <algorithm>
Matthew Barth12bae962021-01-15 16:18:11 -060030#include <optional>
Matthew Barth12bae962021-01-15 16:18:11 -060031
Matthew Barth3174e722020-09-15 15:13:40 -050032namespace phosphor::fan::control::json
33{
34
35using json = nlohmann::json;
36using namespace phosphor::logging;
37
Matthew Barth44ab7692021-03-26 11:40:10 -050038Event::Event(const json& jsonObj, sdbusplus::bus::bus& bus,
Matthew Barth9f1632e2021-03-31 15:51:50 -050039 std::map<configKey, std::unique_ptr<Group>>& groups,
40 std::map<configKey, std::unique_ptr<Zone>>& zones) :
Matthew Barth44ab7692021-03-26 11:40:10 -050041 ConfigBase(jsonObj),
Matthew Barth9f1632e2021-03-31 15:51:50 -050042 _bus(bus), _zones(zones)
Matthew Barth3174e722020-09-15 15:13:40 -050043{
Matthew Barth3174e722020-09-15 15:13:40 -050044 // Event could have a precondition
45 if (!jsonObj.contains("precondition"))
46 {
47 // Event groups are optional
48 if (jsonObj.contains("groups"))
49 {
Matthew Barth44ab7692021-03-26 11:40:10 -050050 setGroups(jsonObj, groups);
Matthew Barth3174e722020-09-15 15:13:40 -050051 }
Matthew Barth3174e722020-09-15 15:13:40 -050052 // Event actions are optional
53 if (jsonObj.contains("actions"))
54 {
Matthew Barth9f1632e2021-03-31 15:51:50 -050055 setActions(jsonObj, groups);
Matthew Barth3174e722020-09-15 15:13:40 -050056 }
Matthew Barth9f1632e2021-03-31 15:51:50 -050057 setTriggers(jsonObj);
Matthew Barth3174e722020-09-15 15:13:40 -050058 }
59 else
60 {
Matthew Barth44ab7692021-03-26 11:40:10 -050061 setPrecond(jsonObj, groups);
Matthew Barth3174e722020-09-15 15:13:40 -050062 }
63}
64
Matthew Barth44ab7692021-03-26 11:40:10 -050065void Event::setPrecond(const json& jsonObj,
66 std::map<configKey, std::unique_ptr<Group>>& groups)
Matthew Barth3174e722020-09-15 15:13:40 -050067{
68 const auto& precond = jsonObj["precondition"];
69 if (!precond.contains("name") || !precond.contains("groups") ||
70 !precond.contains("triggers") || !precond.contains("events"))
71 {
72 log<level::ERR>("Missing required event precondition attributes",
73 entry("JSON=%s", precond.dump().c_str()));
74 throw std::runtime_error(
75 "Missing required event precondition attributes");
76 }
Matthew Barth44ab7692021-03-26 11:40:10 -050077 setGroups(precond, groups);
Matthew Barth3174e722020-09-15 15:13:40 -050078 setTriggers(precond);
79}
80
Matthew Barth44ab7692021-03-26 11:40:10 -050081void Event::setGroups(const json& jsonObj,
82 std::map<configKey, std::unique_ptr<Group>>& groups)
Matthew Barth3174e722020-09-15 15:13:40 -050083{
84 for (const auto& group : jsonObj["groups"])
85 {
86 if (!group.contains("name") || !group.contains("interface") ||
Matthew Barth12bae962021-01-15 16:18:11 -060087 !group.contains("property") || !group["property"].contains("name"))
Matthew Barth3174e722020-09-15 15:13:40 -050088 {
89 log<level::ERR>("Missing required event group attributes",
90 entry("JSON=%s", group.dump().c_str()));
91 throw std::runtime_error("Missing required event group attributes");
92 }
Matthew Barth12bae962021-01-15 16:18:11 -060093
Matthew Barthe5578602021-03-30 12:53:24 -050094 // Get the group members' interface
95 auto intf = group["interface"].get<std::string>();
96
97 // Get the group members' property name
98 auto prop = group["property"]["name"].get<std::string>();
99
100 // Get the group members' data type
Matthew Barth12bae962021-01-15 16:18:11 -0600101 std::optional<std::string> type = std::nullopt;
102 if (group["property"].contains("type"))
103 {
104 type = group["property"]["type"].get<std::string>();
105 }
106
Matthew Barthe5578602021-03-30 12:53:24 -0500107 // Get the group members' expected value
Matthew Barth12bae962021-01-15 16:18:11 -0600108 std::optional<PropertyVariantType> value = std::nullopt;
109 if (group["property"].contains("value"))
110 {
111 value = getJsonValue(group["property"]["value"]);
112 }
113
Matthew Barth0206c722021-03-30 15:20:05 -0500114 configKey eventProfile =
Matthew Barth12bae962021-01-15 16:18:11 -0600115 std::make_pair(group["name"].get<std::string>(), _profiles);
Matthew Barth0206c722021-03-30 15:20:05 -0500116 auto grpEntry = std::find_if(
117 groups.begin(), groups.end(), [&eventProfile](const auto& grp) {
118 return Manager::inConfig(grp.first, eventProfile);
Matthew Barthe5578602021-03-30 12:53:24 -0500119 });
Matthew Barth44ab7692021-03-26 11:40:10 -0500120 if (grpEntry != groups.end())
Matthew Barth12bae962021-01-15 16:18:11 -0600121 {
Matthew Barthe5578602021-03-30 12:53:24 -0500122 auto grp = Group(*grpEntry->second);
123 grp.setInterface(intf);
124 grp.setProperty(prop);
125 grp.setType(type);
126 grp.setValue(value);
Matthew Barth12bae962021-01-15 16:18:11 -0600127 _groups.emplace_back(grp);
128 }
Matthew Barthe5578602021-03-30 12:53:24 -0500129 }
130
131 if (_groups.empty())
132 {
133 auto msg = fmt::format(
134 "No groups configured for event {} in its active profile(s)",
135 getName());
136 log<level::ERR>(msg.c_str());
137 throw std::runtime_error(msg);
Matthew Barth3174e722020-09-15 15:13:40 -0500138 }
139}
140
Matthew Barth9f1632e2021-03-31 15:51:50 -0500141void Event::setActions(const json& jsonObj,
142 std::map<configKey, std::unique_ptr<Group>>& groups)
Matthew Barth3174e722020-09-15 15:13:40 -0500143{
144 for (const auto& action : jsonObj["actions"])
145 {
146 if (!action.contains("name"))
147 {
148 log<level::ERR>("Missing required event action name",
149 entry("JSON=%s", action.dump().c_str()));
150 throw std::runtime_error("Missing required event action name");
151 }
Matthew Barth9f1632e2021-03-31 15:51:50 -0500152 // TODO Append action specific groups to event groups list separate from
153 // each action in the event and pass reference of group to action
154 // TODO Consider supporting zones per action and pass a reference to the
155 // zone(s) the action should be run against
Matthew Barth776ca562021-03-31 09:50:58 -0500156 auto actObj =
157 ActionFactory::getAction(action["name"].get<std::string>(), action);
158 if (actObj)
159 {
160 _actions.emplace_back(std::move(actObj));
161 }
Matthew Barth3174e722020-09-15 15:13:40 -0500162 }
163}
164
Matthew Barth9f1632e2021-03-31 15:51:50 -0500165void Event::setTriggers(const json& jsonObj)
166{
167 if (!jsonObj.contains("triggers"))
168 {
169 log<level::ERR>("Missing required event triggers list",
170 entry("JSON=%s", jsonObj.dump().c_str()));
171 throw std::runtime_error("Missing required event triggers list");
172 }
173}
174
Matthew Barth3174e722020-09-15 15:13:40 -0500175} // namespace phosphor::fan::control::json