control: Use Group objects in events
Use the generated Group objects in configured events. Group objects are
temporarily generated from the `groups.json` configuration and passed to
each event. When the event is generated from its JSON configuration, the
group(s) its configured to use in the event are first copied from the
list of Group objects and then populated with the remaining details for
the group configuration that's provided in the event. Groups to be used
in the event must either have no profiles restricting their use or have
a profile that matches the event's profile where that profile is also
active.
Change-Id: Ifda7493ab256fa2fbf869e984609888c418b1f9b
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/config_base.hpp b/control/json/config_base.hpp
index 3db6907..4f7a425 100644
--- a/control/json/config_base.hpp
+++ b/control/json/config_base.hpp
@@ -47,7 +47,6 @@
{
public:
ConfigBase() = delete;
- ConfigBase(const ConfigBase&) = delete;
ConfigBase(ConfigBase&&) = delete;
ConfigBase& operator=(const ConfigBase&) = delete;
ConfigBase& operator=(ConfigBase&&) = delete;
@@ -67,6 +66,19 @@
}
/**
+ * Copy Constructor
+ * Creates a config base from another config base's originally parsed JSON
+ * object data
+ *
+ * @param[in] origObj - Original ConfigBase object to be created from
+ */
+ ConfigBase(const ConfigBase& origObj)
+ {
+ _name = origObj._name;
+ _profiles = origObj._profiles;
+ }
+
+ /**
* @brief Get the configuration object's name
*
* @return Name of the configuration object
diff --git a/control/json/event.cpp b/control/json/event.cpp
index 7fec581..ca94d9a 100644
--- a/control/json/event.cpp
+++ b/control/json/event.cpp
@@ -15,14 +15,18 @@
*/
#include "event.hpp"
+#include "config_base.hpp"
#include "group.hpp"
+#include "manager.hpp"
+
+#include <fmt/format.h>
#include <nlohmann/json.hpp>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>
+#include <algorithm>
#include <optional>
-#include <tuple>
namespace phosphor::fan::control::json
{
@@ -85,54 +89,82 @@
throw std::runtime_error("Missing required event group attributes");
}
- // Get the group memebers' data type
+ // Get the group members' interface
+ auto intf = group["interface"].get<std::string>();
+
+ // Get the group members' property name
+ auto prop = group["property"]["name"].get<std::string>();
+
+ // Get the group members' data type
std::optional<std::string> type = std::nullopt;
if (group["property"].contains("type"))
{
type = group["property"]["type"].get<std::string>();
}
- // Get the group memebers' expected value
+ // Get the group members' expected value
std::optional<PropertyVariantType> value = std::nullopt;
if (group["property"].contains("value"))
{
value = getJsonValue(group["property"]["value"]);
}
- // Groups with the same profiles as the event can be used
configKey key =
std::make_pair(group["name"].get<std::string>(), _profiles);
- auto grpEntry = groups.find(key);
+ auto grpEntry =
+ std::find_if(groups.begin(), groups.end(), [&key](const auto& grp) {
+ if (grp.first.first != key.first)
+ {
+ return false;
+ }
+ // Groups with no profiles specified can be used in any event
+ if (grp.first.second.empty())
+ {
+ return true;
+ }
+ else
+ {
+ // Groups with profiles must have one match in the event's
+ // profiles(and they must be an active profile) to be used
+ // in the event
+ return std::any_of(
+ grp.first.second.begin(), grp.first.second.end(),
+ [&key](const auto& grpProfile) {
+ return std::any_of(
+ key.second.begin(), key.second.end(),
+ [&grpProfile](const auto& eventProfile) {
+ if (grpProfile != eventProfile)
+ {
+ return false;
+ }
+ auto activeProfs =
+ Manager::getActiveProfiles();
+ return std::find(activeProfs.begin(),
+ activeProfs.end(),
+ grpProfile) !=
+ activeProfs.end();
+ });
+ });
+ }
+ });
if (grpEntry != groups.end())
{
- eGroup grp;
- for (const auto& member : grpEntry->second->getMembers())
- {
- grp.emplace_back(std::make_tuple(
- member, group["interface"].get<std::string>(),
- group["property"]["name"].get<std::string>(), type, value));
- }
+ auto grp = Group(*grpEntry->second);
+ grp.setInterface(intf);
+ grp.setProperty(prop);
+ grp.setType(type);
+ grp.setValue(value);
_groups.emplace_back(grp);
}
- else
- {
- // Groups with no profiles specified can be used in any event
- key = std::make_pair(group["name"].get<std::string>(),
- std::vector<std::string>{});
- grpEntry = groups.find(key);
- if (grpEntry != groups.end())
- {
- eGroup grp;
- for (const auto& member : grpEntry->second->getMembers())
- {
- grp.emplace_back(std::make_tuple(
- member, group["interface"].get<std::string>(),
- group["property"]["name"].get<std::string>(), type,
- value));
- }
- _groups.emplace_back(grp);
- }
- }
+ }
+
+ if (_groups.empty())
+ {
+ auto msg = fmt::format(
+ "No groups configured for event {} in its active profile(s)",
+ getName());
+ log<level::ERR>(msg.c_str());
+ throw std::runtime_error(msg);
}
}
diff --git a/control/json/event.hpp b/control/json/event.hpp
index 8c48f35..4806763 100644
--- a/control/json/event.hpp
+++ b/control/json/event.hpp
@@ -49,15 +49,6 @@
*/
class Event : public ConfigBase
{
- static constexpr auto pathPos = 0;
- static constexpr auto intfPos = 1;
- static constexpr auto propPos = 2;
- static constexpr auto typePos = 3;
- static constexpr auto valuePos = 4;
- using eGroup = std::vector<std::tuple<std::string, std::string, std::string,
- std::optional<std::string>,
- std::optional<PropertyVariantType>>>;
-
static constexpr auto precondName = 0;
static constexpr auto precondGroups = 1;
static constexpr auto precondEvents = 2;
@@ -127,7 +118,7 @@
Precondition _precond;
/* List of groups associated with the event */
- std::vector<eGroup> _groups;
+ std::vector<Group> _groups;
/* List of actions for this event */
std::vector<std::unique_ptr<ActionBase>> _actions;
diff --git a/control/json/group.cpp b/control/json/group.cpp
index 2930aac..0532b43 100644
--- a/control/json/group.cpp
+++ b/control/json/group.cpp
@@ -34,6 +34,13 @@
}
}
+Group::Group(const Group& origObj) : ConfigBase(origObj)
+{
+ // Only what was parsed by the original Group object is copied
+ _members = origObj._members;
+ _service = origObj._service;
+}
+
void Group::setMembers(const json& jsonObj)
{
if (!jsonObj.contains("members"))
diff --git a/control/json/group.hpp b/control/json/group.hpp
index 6b30b9f..8e931e5 100644
--- a/control/json/group.hpp
+++ b/control/json/group.hpp
@@ -45,7 +45,6 @@
static constexpr auto confFileName = "groups.json";
Group() = delete;
- Group(const Group&) = delete;
Group(Group&&) = delete;
Group& operator=(const Group&) = delete;
Group& operator=(Group&&) = delete;
@@ -60,6 +59,14 @@
Group(const json& jsonObj);
/**
+ * Copy Constructor
+ * Creates a group from another group's originally parsed JSON object data
+ *
+ * @param[in] origObj - Original Group object to be created from
+ */
+ Group(const Group& origObj);
+
+ /**
* @brief Get the members
*
* @return List of dbus paths representing the members of the group
@@ -111,6 +118,38 @@
return _property;
}
+ /**
+ * @brief Set the dbus property's data type for the group
+ */
+ inline void setType(std::optional<std::string>& type)
+ {
+ _type = type;
+ }
+
+ /**
+ * @brief Get the group's dbus property's data type
+ */
+ inline const auto& getType() const
+ {
+ return _type;
+ }
+
+ /**
+ * @brief Set the dbus property's expected value for the group
+ */
+ inline void setValue(std::optional<PropertyVariantType>& value)
+ {
+ _value = value;
+ }
+
+ /**
+ * @brief Get the group's dbus property's expected value
+ */
+ inline const auto& getValue() const
+ {
+ return _value;
+ }
+
private:
/* Members of the group */
std::vector<std::string> _members;
@@ -124,6 +163,12 @@
/* Dbus property name for all the members */
std::string _property;
+ /* Optional property's data type for all members */
+ std::optional<std::string> _type;
+
+ /* Optional property value for all the members */
+ std::optional<PropertyVariantType> _value;
+
/**
* @brief Parse and set the members list
*