monitor:JSON: Parse fan monitoring conditions
Optional conditions can be used to include monitoring a fan or not based
on the results of the condition function configured. These condition
functions have their own required set of parameters, so parsing the JSON
for these conditions are done per supported condition function. This
adds the JSON parsing support for the current condition functions.
Tested:
`propertiesMatch` JSON parameters parsed into condition function
Any required parameters missing throws an exception
The `propertiesMatch` condition functions the same using JSON
Change-Id: I0f843951f4e83f2a5d44068820694010538788c1
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/monitor/conditions.cpp b/monitor/conditions.cpp
index 09f5852..19e9cd8 100644
--- a/monitor/conditions.cpp
+++ b/monitor/conditions.cpp
@@ -1,6 +1,10 @@
#include "conditions.hpp"
#include "sdbusplus.hpp"
+#include "types.hpp"
+
+#include <nlohmann/json.hpp>
+#include <phosphor-logging/log.hpp>
#include <algorithm>
@@ -13,6 +17,9 @@
namespace condition
{
+using json = nlohmann::json;
+using namespace phosphor::logging;
+
Condition propertiesMatch(std::vector<PropertyState>&& propStates)
{
return [pStates = std::move(propStates)](sdbusplus::bus::bus& bus) {
@@ -26,6 +33,58 @@
};
}
+Condition getPropertiesMatch(const json& condParams)
+{
+ if (!condParams.contains("properties"))
+ {
+ // Log error on missing required parameter
+ log<level::ERR>(
+ "Missing fan monitor condition properties",
+ entry("NAME=%s", condParams["name"].get<std::string>().c_str()));
+ throw std::runtime_error("Missing fan monitor condition properties");
+ }
+ std::vector<PropertyState> propStates;
+ for (auto& param : condParams["properties"])
+ {
+ if (!param.contains("object") || !param.contains("interface") ||
+ !param.contains("property"))
+ {
+ // Log error on missing required parameters
+ log<level::ERR>("Missing propertiesMatch condition parameters",
+ entry("REQUIRED_PARAMETERS=%s",
+ "{object, interface, property}"));
+ throw std::runtime_error(
+ "Missing propertiesMatch condition parameters");
+ }
+
+ auto propAttrs = param["property"];
+ if (!propAttrs.contains("name") || !propAttrs.contains("value"))
+ {
+ // Log error on missing required parameters
+ log<level::ERR>(
+ "Missing propertiesMatch condition property attributes",
+ entry("REQUIRED_ATTRIBUTES=%s", "{name, value}"));
+ throw std::runtime_error(
+ "Missing propertiesMatch condition property attributes");
+ }
+
+ std::string type = "";
+ if (propAttrs.contains("type"))
+ {
+ type = propAttrs["type"].get<std::string>();
+ }
+
+ // Add property for propertiesMatch condition
+ propStates.emplace_back(PropertyState(
+ {param["object"].get<std::string>(),
+ param["interface"].get<std::string>(),
+ propAttrs["name"].get<std::string>()},
+ JsonTypeHandler::getPropValue(propAttrs["value"], type)));
+ }
+
+ return make_condition(condition::propertiesMatch(std::move(propStates)));
+}
+
} // namespace condition
} // namespace monitor
} // namespace fan
diff --git a/monitor/conditions.hpp b/monitor/conditions.hpp
index 76aa0de..687dfee 100644
--- a/monitor/conditions.hpp
+++ b/monitor/conditions.hpp
@@ -2,6 +2,8 @@
#include "types.hpp"
+#include <nlohmann/json.hpp>
+
namespace phosphor
{
namespace fan
@@ -9,6 +11,8 @@
namespace monitor
{
+using json = nlohmann::json;
+
/**
* @brief Create a condition function object
*
@@ -37,6 +41,21 @@
*/
Condition propertiesMatch(std::vector<PropertyState>&& propStates);
+/**
+ * @brief Parse the propertiesMatch condition's parameters from the given JSON
+ * configuration
+ * @details Parses and verifies all the required parameters are given in the
+ * JSON configuration to construct and return a function pointer to the
+ * propertiesMatch condition function.
+ *
+ * @param[in] condParams - JSON object containing all the propertiesMatch
+ * condition parameters
+ *
+ * @return Condition lambda function
+ * The propertiesMatch condition function that checks all properties match
+ */
+Condition getPropertiesMatch(const json& condParams);
+
} // namespace condition
} // namespace monitor
} // namespace fan
diff --git a/monitor/json_parser.cpp b/monitor/json_parser.cpp
index 34d1995..9b773c2 100644
--- a/monitor/json_parser.cpp
+++ b/monitor/json_parser.cpp
@@ -51,6 +51,8 @@
const std::map<std::string, trustHandler> trusts = {
{"nonzerospeed", tClass::getNonZeroSpeed}};
+const std::map<std::string, condHandler> conditions = {
+ {"propertiesmatch", condition::getPropertiesMatch}};
const std::vector<CreateGroupFunction> getTrustGrps(const json& obj)
{
@@ -189,8 +191,36 @@
funcDelay = fan["functional_delay"].get<size_t>();
}
- // TODO Handle optional conditions
+ // Handle optional conditions
auto cond = std::experimental::optional<Condition>();
+ if (fan.contains("condition"))
+ {
+ if (!fan["condition"].contains("name"))
+ {
+ // Log error on missing required parameter
+ log<level::ERR>(
+ "Missing required fan monitor condition parameter",
+ entry("REQUIRED_PARAMETER=%s", "{name}"));
+ throw std::runtime_error(
+ "Missing required fan monitor condition parameter");
+ }
+ auto name = fan["condition"]["name"].get<std::string>();
+ // The function for fan monitoring condition
+ // (Must have a supported function within the condition namespace)
+ std::transform(name.begin(), name.end(), name.begin(), tolower);
+ auto handler = conditions.find(name);
+ if (handler != conditions.end())
+ {
+ cond = handler->second(fan["condition"]);
+ }
+ else
+ {
+ log<level::INFO>(
+ "No handler found for configured condition",
+ entry("CONDITION_NAME=%s", name.c_str()),
+ entry("JSON_DUMP=%s", fan["condition"].dump().c_str()));
+ }
+ }
fanDefs.emplace_back(
std::tuple(fan["inventory"].get<std::string>(), funcDelay,
diff --git a/monitor/json_parser.hpp b/monitor/json_parser.hpp
index 514d76b..ac91463 100644
--- a/monitor/json_parser.hpp
+++ b/monitor/json_parser.hpp
@@ -33,6 +33,8 @@
// Trust group class handler function
using trustHandler = std::function<CreateGroupFunction(
const std::vector<trust::GroupDefinition>&)>;
+// Fan monitoring condition handler function
+using condHandler = std::function<Condition(const json&)>;
/**
* @brief Get the JSON object
diff --git a/monitor/main.cpp b/monitor/main.cpp
index 52d5bdb..84f2fcc 100644
--- a/monitor/main.cpp
+++ b/monitor/main.cpp
@@ -70,6 +70,23 @@
// Retrieve and set trust groups within the trust manager
auto trust =
std::make_unique<phosphor::fan::trust::Manager>(getTrustGrps(jsonObj));
+
+ // Retrieve fan definitions and create fan objects to be monitored
+ for (const auto& fanDef : getFanDefs(jsonObj))
+ {
+ // Check if a condition exists on the fan
+ auto condition = std::get<conditionField>(fanDef);
+ if (condition)
+ {
+ // Condition exists, skip adding fan if it fails
+ if (!(*condition)(bus))
+ {
+ continue;
+ }
+ }
+ fans.emplace_back(
+ std::make_unique<Fan>(mode, bus, event, trust, fanDef));
+ }
#else
auto trust = std::make_unique<phosphor::fan::trust::Manager>(trustGroups);