control: Create ZoneHandlers directly from JSON
Instead of creating the ZoneHandler functions from the configuration
data provided in the zones.json, create them at the time of parsing the
JSON. This simplifies the creation of the zone definitions structure
that's shared between a YAML configuration or a JSON configuration.
Tested:
Verified ZoneHandler functions returned for zone properties
Change-Id: Ida85e78bf88e9c82e9402b7fd183485020a70631
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/zone.cpp b/control/json/zone.cpp
index 84f9c82..33ab048 100644
--- a/control/json/zone.cpp
+++ b/control/json/zone.cpp
@@ -15,16 +15,20 @@
*/
#include "zone.hpp"
+#include "../zone.hpp"
+#include "functor.hpp"
+#include "handlers.hpp"
+#include "types.hpp"
+
#include <nlohmann/json.hpp>
#include <phosphor-logging/log.hpp>
#include <sdbusplus/bus.hpp>
-#include <any>
#include <iterator>
#include <map>
#include <numeric>
-#include <tuple>
#include <utility>
+#include <vector>
namespace phosphor::fan::control::json
{
@@ -32,9 +36,10 @@
using json = nlohmann::json;
using namespace phosphor::logging;
-const std::map<std::string, propertyHandler> Zone::_props = {
- {"Supported", zone::property::supported},
- {"Current", zone::property::current}};
+const std::map<std::string, std::map<std::string, propHandler>>
+ Zone::_intfPropHandlers = {{thermModeIntf,
+ {{supportedProp, zone::property::supported},
+ {currentProp, zone::property::current}}}};
Zone::Zone(sdbusplus::bus::bus& bus, const json& jsonObj) :
ConfigBase(jsonObj), _incDelay(0)
@@ -105,7 +110,22 @@
throw std::runtime_error(
"Missing required zone interface attributes");
}
- std::map<std::string, std::tuple<std::any, bool>> props;
+ auto propFuncs =
+ _intfPropHandlers.find(interface["name"].get<std::string>());
+ if (propFuncs == _intfPropHandlers.end())
+ {
+ // Construct list of available configurable interfaces
+ auto intfs = std::accumulate(
+ std::next(_intfPropHandlers.begin()), _intfPropHandlers.end(),
+ _intfPropHandlers.begin()->first, [](auto list, auto intf) {
+ return std::move(list) + ", " + intf.first;
+ });
+ log<level::ERR>("Configured interface not available",
+ entry("JSON=%s", interface.dump().c_str()),
+ entry("AVAILABLE_INTFS=%s", intfs.c_str()));
+ throw std::runtime_error("Configured interface not available");
+ }
+
for (const auto& property : interface["properties"])
{
if (!property.contains("name"))
@@ -124,54 +144,88 @@
}
// 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 propFunc =
+ propFuncs->second.find(property["name"].get<std::string>());
+ if (propFunc == propFuncs->second.end())
{
- auto value = propFunc->second(property);
- props.emplace(prop, std::make_tuple(value, persist));
- }
- else
- {
- // Construct list of available properties
+ // Construct list of available configurable properties
auto props = std::accumulate(
- std::next(_props.begin()), _props.end(),
- _props.begin()->first, [](auto list, auto prop) {
+ std::next(propFuncs->second.begin()),
+ propFuncs->second.end(), propFuncs->second.begin()->first,
+ [](auto list, auto prop) {
return std::move(list) + ", " + prop.first;
});
- log<level::ERR>("Configured property function not available",
+ log<level::ERR>("Configured property 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");
}
+ auto zHandler = propFunc->second(property, persist);
+ // Only add non-null zone handler functions
+ if (zHandler)
+ {
+ _zoneHandlers.emplace_back(zHandler);
+ }
}
- _interfaces.emplace(interface["name"].get<std::string>(), props);
}
}
/**
- * Properties of interfaces supported by the zone configuration
+ * Properties of interfaces supported by the zone configuration that return
+ * a ZoneHandler function that sets the zone's property value(s).
*/
namespace zone::property
{
-// Get an any object for the configured value of the "Supported" property
-std::any supported(const json& jsonObj)
+// Get a zone handler function for the configured values of the "Supported"
+// property
+ZoneHandler supported(const json& jsonObj, bool persist)
{
std::vector<std::string> values;
- for (const auto& value : jsonObj["values"])
+ if (!jsonObj.contains("values"))
{
- values.emplace_back(value["value"].get<std::string>());
+ log<level::ERR>(
+ "No 'values' found for \"Supported\" property, using an empty list",
+ entry("JSON=%s", jsonObj.dump().c_str()));
+ }
+ else
+ {
+ for (const auto& value : jsonObj["values"])
+ {
+ if (!value.contains("value"))
+ {
+ log<level::ERR>("No 'value' found for \"Supported\" property "
+ "entry, skipping",
+ entry("JSON=%s", value.dump().c_str()));
+ }
+ else
+ {
+ values.emplace_back(value["value"].get<std::string>());
+ }
+ }
}
- return std::make_any<std::vector<std::string>>(values);
+ return make_zoneHandler(handler::setZoneProperty<std::vector<std::string>>(
+ Zone::thermModeIntf, Zone::supportedProp, &control::Zone::supported,
+ std::move(values), persist));
}
-// Get an any object for the configured value of the "Current" property
-std::any current(const json& jsonObj)
+// Get a zone handler function for a configured value of the "Current"
+// property
+ZoneHandler current(const json& jsonObj, bool persist)
{
- auto value = jsonObj["value"].get<std::string>();
- return std::make_any<std::string>(value);
+ // Use default value for "Current" property if no "value" entry given
+ if (!jsonObj.contains("value"))
+ {
+ log<level::ERR>("No 'value' found for \"Current\" property, "
+ "using default",
+ entry("JSON=%s", jsonObj.dump().c_str()));
+ return {};
+ }
+
+ return make_zoneHandler(handler::setZoneProperty<std::string>(
+ Zone::thermModeIntf, Zone::currentProp, &control::Zone::current,
+ jsonObj["value"].get<std::string>(), persist));
}
} // namespace zone::property
diff --git a/control/json/zone.hpp b/control/json/zone.hpp
index ede56e4..4f7742c 100644
--- a/control/json/zone.hpp
+++ b/control/json/zone.hpp
@@ -16,6 +16,7 @@
#pragma once
#include "config_base.hpp"
+#include "types.hpp"
#include <nlohmann/json.hpp>
#include <sdbusplus/bus.hpp>
@@ -31,7 +32,7 @@
using json = nlohmann::json;
/* Interface property handler function */
-using propertyHandler = std::function<std::any(const json&)>;
+using propHandler = std::function<ZoneHandler(const json&, bool)>;
/**
* @class Zone - Represents a configured fan control zone
@@ -51,13 +52,10 @@
public:
/* 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>>>;
+ static constexpr auto thermModeIntf =
+ "xyz.openbmc_project.Control.ThermalMode";
+ static constexpr auto supportedProp = "Supported";
+ static constexpr auto currentProp = "Current";
Zone() = delete;
Zone(const Zone&) = delete;
@@ -136,17 +134,18 @@
}
/**
- * @brief Get the configuration of interfaces
+ * @brief Get the configuration of zone interface handlers
*
* 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
+ * @return List of zone interface handler functions that set an interface's
+ * property values and persistency states
*/
- inline const auto& getInterfaces() const
+ inline const auto& getZoneHandlers() const
{
- return _interfaces;
+ return _zoneHandlers;
}
private:
@@ -162,11 +161,15 @@
/* Zone's speed decrease interval(in seconds) */
uint64_t _decInterval;
- /* Map of interfaces to properties with their values and persistency */
- Interfaces _interfaces;
+ /**
+ * Zone interface handler functions for its
+ * configured interfaces (OPTIONAL)
+ */
+ std::vector<ZoneHandler> _zoneHandlers;
- /* Interface properties mapping to their associated handler function */
- static const std::map<std::string, propertyHandler> _props;
+ /* Interface to property mapping of their associated handler function */
+ static const std::map<std::string, std::map<std::string, propHandler>>
+ _intfPropHandlers;
/**
* @brief Parse and set the zone's full speed value
@@ -198,13 +201,14 @@
void setDecInterval(const json& jsonObj);
/**
- * @brief Parse and set properties on interfaces the zone serves(OPTIONAL)
+ * @brief Parse and set the interfaces served by the zone(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.
+ * Constructs any zone interface handler functions for interfaces that the
+ * zone serves which contains the interface's property's value and
+ * persistency state (OPTIONAL). A property's "persist" state is defaulted
+ * to not be persisted when not given.
*/
void setInterfaces(const json& jsonObj);
};
@@ -216,22 +220,26 @@
{
/**
- * @brief "Supported" property on the "ThermalMode" interface
+ * @brief "Supported" property on the "xyz.openbmc_project.Control.ThermalMode"
+ * interface
*
* @param[in] jsonObj - JSON object for the "Supported" property
+ * @param[in] persist - Whether to persist the value or not
*
- * @return - A std::any object of the "Supported" property's value
+ * @return Zone interface handler function for the property
*/
-std::any supported(const json& jsonObj);
+ZoneHandler supported(const json& jsonObj, bool persist);
/**
- * @brief "Current property on the "ThermalMode" interface
+ * @brief "Current" property on the "xyz.openbmc_project.Control.ThermalMode"
+ * interface
*
* @param[in] jsonObj - JSON object for the "Current" property
+ * @param[in] persist - Whether to persist the value or not
*
- * @return - A std::any object of the "Current" property's value
+ * @return Zone interface handler function for the property
*/
-std::any current(const json& jsonObj);
+ZoneHandler current(const json& jsonObj, bool persist);
} // namespace zone::property