blob: ca94d9ac0d8d209d1d681d4834c4625c3bd91ed0 [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 Barthe5578602021-03-30 12:53:24 -050018#include "config_base.hpp"
Matthew Barth391ade02021-01-15 14:33:21 -060019#include "group.hpp"
Matthew Barthe5578602021-03-30 12:53:24 -050020#include "manager.hpp"
21
22#include <fmt/format.h>
Matthew Barth391ade02021-01-15 14:33:21 -060023
Matthew Barth3174e722020-09-15 15:13:40 -050024#include <nlohmann/json.hpp>
25#include <phosphor-logging/log.hpp>
26#include <sdbusplus/bus.hpp>
27
Matthew Barthe5578602021-03-30 12:53:24 -050028#include <algorithm>
Matthew Barth12bae962021-01-15 16:18:11 -060029#include <optional>
Matthew Barth12bae962021-01-15 16:18:11 -060030
Matthew Barth3174e722020-09-15 15:13:40 -050031namespace phosphor::fan::control::json
32{
33
34using json = nlohmann::json;
35using namespace phosphor::logging;
36
Matthew Barth44ab7692021-03-26 11:40:10 -050037Event::Event(const json& jsonObj, sdbusplus::bus::bus& bus,
38 std::map<configKey, std::unique_ptr<Group>>& groups) :
39 ConfigBase(jsonObj),
40 _bus(bus)
Matthew Barth3174e722020-09-15 15:13:40 -050041{
Matthew Barth3174e722020-09-15 15:13:40 -050042 // Event could have a precondition
43 if (!jsonObj.contains("precondition"))
44 {
45 // Event groups are optional
46 if (jsonObj.contains("groups"))
47 {
Matthew Barth44ab7692021-03-26 11:40:10 -050048 setGroups(jsonObj, groups);
Matthew Barth3174e722020-09-15 15:13:40 -050049 }
50 setTriggers(jsonObj);
51 // Event actions are optional
52 if (jsonObj.contains("actions"))
53 {
54 setActions(jsonObj);
55 }
56 }
57 else
58 {
Matthew Barth44ab7692021-03-26 11:40:10 -050059 setPrecond(jsonObj, groups);
Matthew Barth3174e722020-09-15 15:13:40 -050060 }
61}
62
Matthew Barth44ab7692021-03-26 11:40:10 -050063void Event::setPrecond(const json& jsonObj,
64 std::map<configKey, std::unique_ptr<Group>>& groups)
Matthew Barth3174e722020-09-15 15:13:40 -050065{
66 const auto& precond = jsonObj["precondition"];
67 if (!precond.contains("name") || !precond.contains("groups") ||
68 !precond.contains("triggers") || !precond.contains("events"))
69 {
70 log<level::ERR>("Missing required event precondition attributes",
71 entry("JSON=%s", precond.dump().c_str()));
72 throw std::runtime_error(
73 "Missing required event precondition attributes");
74 }
Matthew Barth44ab7692021-03-26 11:40:10 -050075 setGroups(precond, groups);
Matthew Barth3174e722020-09-15 15:13:40 -050076 setTriggers(precond);
77}
78
Matthew Barth44ab7692021-03-26 11:40:10 -050079void Event::setGroups(const json& jsonObj,
80 std::map<configKey, std::unique_ptr<Group>>& groups)
Matthew Barth3174e722020-09-15 15:13:40 -050081{
82 for (const auto& group : jsonObj["groups"])
83 {
84 if (!group.contains("name") || !group.contains("interface") ||
Matthew Barth12bae962021-01-15 16:18:11 -060085 !group.contains("property") || !group["property"].contains("name"))
Matthew Barth3174e722020-09-15 15:13:40 -050086 {
87 log<level::ERR>("Missing required event group attributes",
88 entry("JSON=%s", group.dump().c_str()));
89 throw std::runtime_error("Missing required event group attributes");
90 }
Matthew Barth12bae962021-01-15 16:18:11 -060091
Matthew Barthe5578602021-03-30 12:53:24 -050092 // Get the group members' interface
93 auto intf = group["interface"].get<std::string>();
94
95 // Get the group members' property name
96 auto prop = group["property"]["name"].get<std::string>();
97
98 // Get the group members' data type
Matthew Barth12bae962021-01-15 16:18:11 -060099 std::optional<std::string> type = std::nullopt;
100 if (group["property"].contains("type"))
101 {
102 type = group["property"]["type"].get<std::string>();
103 }
104
Matthew Barthe5578602021-03-30 12:53:24 -0500105 // Get the group members' expected value
Matthew Barth12bae962021-01-15 16:18:11 -0600106 std::optional<PropertyVariantType> value = std::nullopt;
107 if (group["property"].contains("value"))
108 {
109 value = getJsonValue(group["property"]["value"]);
110 }
111
Matthew Barth12bae962021-01-15 16:18:11 -0600112 configKey key =
113 std::make_pair(group["name"].get<std::string>(), _profiles);
Matthew Barthe5578602021-03-30 12:53:24 -0500114 auto grpEntry =
115 std::find_if(groups.begin(), groups.end(), [&key](const auto& grp) {
116 if (grp.first.first != key.first)
117 {
118 return false;
119 }
120 // Groups with no profiles specified can be used in any event
121 if (grp.first.second.empty())
122 {
123 return true;
124 }
125 else
126 {
127 // Groups with profiles must have one match in the event's
128 // profiles(and they must be an active profile) to be used
129 // in the event
130 return std::any_of(
131 grp.first.second.begin(), grp.first.second.end(),
132 [&key](const auto& grpProfile) {
133 return std::any_of(
134 key.second.begin(), key.second.end(),
135 [&grpProfile](const auto& eventProfile) {
136 if (grpProfile != eventProfile)
137 {
138 return false;
139 }
140 auto activeProfs =
141 Manager::getActiveProfiles();
142 return std::find(activeProfs.begin(),
143 activeProfs.end(),
144 grpProfile) !=
145 activeProfs.end();
146 });
147 });
148 }
149 });
Matthew Barth44ab7692021-03-26 11:40:10 -0500150 if (grpEntry != groups.end())
Matthew Barth12bae962021-01-15 16:18:11 -0600151 {
Matthew Barthe5578602021-03-30 12:53:24 -0500152 auto grp = Group(*grpEntry->second);
153 grp.setInterface(intf);
154 grp.setProperty(prop);
155 grp.setType(type);
156 grp.setValue(value);
Matthew Barth12bae962021-01-15 16:18:11 -0600157 _groups.emplace_back(grp);
158 }
Matthew Barthe5578602021-03-30 12:53:24 -0500159 }
160
161 if (_groups.empty())
162 {
163 auto msg = fmt::format(
164 "No groups configured for event {} in its active profile(s)",
165 getName());
166 log<level::ERR>(msg.c_str());
167 throw std::runtime_error(msg);
Matthew Barth3174e722020-09-15 15:13:40 -0500168 }
169}
170
171void Event::setTriggers(const json& jsonObj)
172{
173 if (!jsonObj.contains("triggers"))
174 {
175 log<level::ERR>("Missing required event triggers list",
176 entry("JSON=%s", jsonObj.dump().c_str()));
177 throw std::runtime_error("Missing required event triggers list");
178 }
179}
180
181void Event::setActions(const json& jsonObj)
182{
183 for (const auto& action : jsonObj["actions"])
184 {
185 if (!action.contains("name"))
186 {
187 log<level::ERR>("Missing required event action name",
188 entry("JSON=%s", action.dump().c_str()));
189 throw std::runtime_error("Missing required event action name");
190 }
191 }
192}
193
194} // namespace phosphor::fan::control::json