control: Complete zone configuration parsing
Zone configurations include the ability to configure any properties that
are served by interfaces on each zone object configured. These
properties can optionally be set to values provided within the JSON
configuration per zone along with whether they should be persisted or
not.
Tested:
Zone objects created for each entry in "zones.json"
A "zones.json" configuration is required
Each supported attribute is parsed and stored on each zone object
Zone interfaces/properties are parse and stored per zone object
Change-Id: I2220f3b0a37d166bfff5c1c17acaedc9552a54a0
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/zone.cpp b/control/json/zone.cpp
index 24dceee..84f9c82 100644
--- a/control/json/zone.cpp
+++ b/control/json/zone.cpp
@@ -19,12 +19,23 @@
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>
+#include <any>
+#include <iterator>
+#include <map>
+#include <numeric>
+#include <tuple>
+#include <utility>
+
namespace phosphor::fan::control::json
{
using json = nlohmann::json;
using namespace phosphor::logging;
+const std::map<std::string, propertyHandler> Zone::_props = {
+ {"Supported", zone::property::supported},
+ {"Current", zone::property::current}};
+
Zone::Zone(sdbusplus::bus::bus& bus, const json& jsonObj) :
ConfigBase(jsonObj), _incDelay(0)
{
@@ -43,6 +54,11 @@
setFullSpeed(jsonObj);
setDefaultFloor(jsonObj);
setDecInterval(jsonObj);
+ // Setting properties on interfaces to be served are optional
+ if (jsonObj.contains("interfaces"))
+ {
+ setInterfaces(jsonObj);
+ }
}
void Zone::setFullSpeed(const json& jsonObj)
@@ -78,4 +94,85 @@
_decInterval = jsonObj["decrease_interval"].get<uint64_t>();
}
+void Zone::setInterfaces(const json& jsonObj)
+{
+ for (const auto& interface : jsonObj["interfaces"])
+ {
+ if (!interface.contains("name") || !interface.contains("properties"))
+ {
+ log<level::ERR>("Missing required zone interface attributes",
+ entry("JSON=%s", interface.dump().c_str()));
+ throw std::runtime_error(
+ "Missing required zone interface attributes");
+ }
+ std::map<std::string, std::tuple<std::any, bool>> props;
+ for (const auto& property : interface["properties"])
+ {
+ if (!property.contains("name"))
+ {
+ log<level::ERR>(
+ "Missing required interface property attributes",
+ entry("JSON=%s", property.dump().c_str()));
+ throw std::runtime_error(
+ "Missing required interface property attributes");
+ }
+ // Attribute "persist" is optional, defaults to `false`
+ auto persist = false;
+ if (property.contains("persist"))
+ {
+ persist = property["persist"].get<bool>();
+ }
+ // Property name from JSON must exactly match supported
+ // index names to functions in property namespace
+ auto prop = property["name"].get<std::string>();
+ auto propFunc = _props.find(prop);
+ if (propFunc != _props.end())
+ {
+ auto value = propFunc->second(property);
+ props.emplace(prop, std::make_tuple(value, persist));
+ }
+ else
+ {
+ // Construct list of available properties
+ auto props = std::accumulate(
+ std::next(_props.begin()), _props.end(),
+ _props.begin()->first, [](auto list, auto prop) {
+ return std::move(list) + ", " + prop.first;
+ });
+ log<level::ERR>("Configured property function not available",
+ entry("JSON=%s", property.dump().c_str()),
+ entry("AVAILABLE_PROPS=%s", props.c_str()));
+ throw std::runtime_error(
+ "Configured property function not available");
+ }
+ }
+ _interfaces.emplace(interface["name"].get<std::string>(), props);
+ }
+}
+
+/**
+ * Properties of interfaces supported by the zone configuration
+ */
+namespace zone::property
+{
+// Get an any object for the configured value of the "Supported" property
+std::any supported(const json& jsonObj)
+{
+ std::vector<std::string> values;
+ for (const auto& value : jsonObj["values"])
+ {
+ values.emplace_back(value["value"].get<std::string>());
+ }
+
+ return std::make_any<std::vector<std::string>>(values);
+}
+
+// Get an any object for the configured value of the "Current" property
+std::any current(const json& jsonObj)
+{
+ auto value = jsonObj["value"].get<std::string>();
+ return std::make_any<std::string>(value);
+}
+} // namespace zone::property
+
} // namespace phosphor::fan::control::json
diff --git a/control/json/zone.hpp b/control/json/zone.hpp
index 99c8fa5..ede56e4 100644
--- a/control/json/zone.hpp
+++ b/control/json/zone.hpp
@@ -20,11 +20,19 @@
#include <nlohmann/json.hpp>
#include <sdbusplus/bus.hpp>
+#include <any>
+#include <functional>
+#include <map>
+#include <tuple>
+
namespace phosphor::fan::control::json
{
using json = nlohmann::json;
+/* Interface property handler function */
+using propertyHandler = std::function<std::any(const json&)>;
+
/**
* @class Zone - Represents a configured fan control zone
*
@@ -44,6 +52,13 @@
/* JSON file name for zones */
static constexpr auto confFileName = "zones.json";
+ /* Map of interfaces to properties with their values and persistency */
+ static constexpr auto propValue = 0;
+ static constexpr auto propPersist = 1;
+ using Interfaces =
+ std::map<std::string,
+ std::map<std::string, std::tuple<std::any, bool>>>;
+
Zone() = delete;
Zone(const Zone&) = delete;
Zone(Zone&&) = delete;
@@ -120,6 +135,20 @@
return _decInterval;
}
+ /**
+ * @brief Get the configuration of interfaces
+ *
+ * Interfaces hosted by a zone can optionally be configured to set their
+ * property values and/or persistency. These interfaces must be supported
+ * by the zone object they are configured for.
+ *
+ * @return Map of interfaces to properties with their values and persistency
+ */
+ inline const auto& getInterfaces() const
+ {
+ return _interfaces;
+ }
+
private:
/* The zone's full speed value for fans */
uint64_t _fullSpeed;
@@ -133,6 +162,12 @@
/* Zone's speed decrease interval(in seconds) */
uint64_t _decInterval;
+ /* Map of interfaces to properties with their values and persistency */
+ Interfaces _interfaces;
+
+ /* Interface properties mapping to their associated handler function */
+ static const std::map<std::string, propertyHandler> _props;
+
/**
* @brief Parse and set the zone's full speed value
*
@@ -161,6 +196,43 @@
* configuration object
*/
void setDecInterval(const json& jsonObj);
+
+ /**
+ * @brief Parse and set properties on interfaces the zone serves(OPTIONAL)
+ *
+ * @param[in] jsonObj - JSON object for the zone
+ *
+ * Sets any properties on the interfaces that the zone to serves along
+ * with the property's persistency state (OPTIONAL). A property's "persist"
+ * state is defaulted to not be persisted when not given.
+ */
+ void setInterfaces(const json& jsonObj);
};
+/**
+ * Properties of interfaces supported by the zone configuration
+ */
+namespace zone::property
+{
+
+/**
+ * @brief "Supported" property on the "ThermalMode" interface
+ *
+ * @param[in] jsonObj - JSON object for the "Supported" property
+ *
+ * @return - A std::any object of the "Supported" property's value
+ */
+std::any supported(const json& jsonObj);
+
+/**
+ * @brief "Current property on the "ThermalMode" interface
+ *
+ * @param[in] jsonObj - JSON object for the "Current" property
+ *
+ * @return - A std::any object of the "Current" property's value
+ */
+std::any current(const json& jsonObj);
+
+} // namespace zone::property
+
} // namespace phosphor::fan::control::json