Allow updating of JSON from dbus
This uses json_pointers to lookup the location of a
given property and ammend it during runtime. Currently
this is set to only thresholds. If we find a need later
to make this configurable we can change it from being
hard coded.
Change-Id: Ied6f420b70678a830480327bcca28a378cf86411
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/src/EntityManager.cpp b/src/EntityManager.cpp
index 30b4d12..37e68a2 100644
--- a/src/EntityManager.cpp
+++ b/src/EntityManager.cpp
@@ -68,6 +68,9 @@
{"FOUND", probe_type_codes::FOUND},
{"MATCH_ONE", probe_type_codes::MATCH_ONE}}};
+static constexpr std::array<const char *, 1> SETTABLE_INTERFACES = {
+ "thresholds"};
+
using BasicVariantType =
sdbusplus::message::variant<std::string, int64_t, uint64_t, double, int32_t,
uint32_t, int16_t, uint16_t, uint8_t, bool>;
@@ -521,11 +524,30 @@
}
iface->register_property(name, values);
}
+
+template <typename JsonType>
+bool SetJsonFromPointer(const std::string &ptrStr, const JsonType &value,
+ nlohmann::json &systemConfiguration)
+{
+ try
+ {
+ nlohmann::json::json_pointer ptr(ptrStr);
+ nlohmann::json &ref = systemConfiguration[ptr];
+ ref = value;
+ return true;
+ }
+ catch (const std::out_of_range)
+ {
+ return false;
+ }
+}
// adds simple json types to interface's properties
-void populateInterfaceFromJson(const nlohmann::json &systemConfiguration,
+void populateInterfaceFromJson(nlohmann::json &systemConfiguration,
+ const std::string &jsonPointerPath,
sdbusplus::asio::dbus_interface *iface,
nlohmann::json &dict,
- sdbusplus::asio::object_server &objServer)
+ sdbusplus::asio::object_server &objServer,
+ bool setable = false)
{
for (auto &dictPair : dict.items())
{
@@ -558,6 +580,7 @@
continue; // handled elsewhere
}
}
+ std::string key = jsonPointerPath + "/" + dictPair.key();
switch (type)
{
case (nlohmann::json::value_t::boolean):
@@ -570,12 +593,28 @@
iface);
break;
}
- iface->register_property(
- std::string(dictPair.key()), dictPair.value().get<bool>(),
- [&, dictPair](const bool &newVal, bool &val) {
- val = newVal;
- return 1;
- });
+ if (setable)
+ {
+ iface->register_property(
+ std::string(dictPair.key()),
+ dictPair.value().get<bool>(),
+ [&, key](const bool &newVal, bool &val) {
+ val = newVal;
+ if (!SetJsonFromPointer(key, val,
+ systemConfiguration))
+ {
+ std::cerr << "error writing json\n";
+ return -1;
+ }
+ writeJsonFiles(systemConfiguration);
+ return 1;
+ });
+ }
+ else
+ {
+ iface->register_property(std::string(dictPair.key()),
+ dictPair.value().get<bool>());
+ }
break;
}
case (nlohmann::json::value_t::number_integer):
@@ -586,13 +625,28 @@
iface);
break;
}
- iface->register_property(
- std::string(dictPair.key()),
- dictPair.value().get<int64_t>(),
- [&, dictPair](const int64_t &newVal, int64_t &val) {
- val = newVal;
- return 1;
- });
+ if (setable)
+ {
+ iface->register_property(
+ std::string(dictPair.key()),
+ dictPair.value().get<int64_t>(),
+ [&, key](const int64_t &newVal, int64_t &val) {
+ val = newVal;
+ if (!SetJsonFromPointer(key, val,
+ systemConfiguration))
+ {
+ std::cerr << "error writing json\n";
+ return -1;
+ }
+ writeJsonFiles(systemConfiguration);
+ return 1;
+ });
+ }
+ else
+ {
+ iface->register_property(std::string(dictPair.key()),
+ dictPair.value().get<int64_t>());
+ }
break;
}
case (nlohmann::json::value_t::number_unsigned):
@@ -603,13 +657,28 @@
iface);
break;
}
- iface->register_property(
- std::string(dictPair.key()),
- dictPair.value().get<uint64_t>(),
- [&, dictPair](const uint64_t &newVal, uint64_t &val) {
- val = newVal;
- return 1;
- });
+ if (setable)
+ {
+ iface->register_property(
+ std::string(dictPair.key()),
+ dictPair.value().get<uint64_t>(),
+ [&, key](const uint64_t &newVal, uint64_t &val) {
+ val = newVal;
+ if (!SetJsonFromPointer(key, val,
+ systemConfiguration))
+ {
+ std::cerr << "error writing json\n";
+ return -1;
+ }
+ writeJsonFiles(systemConfiguration);
+ return 1;
+ });
+ }
+ else
+ {
+ iface->register_property(std::string(dictPair.key()),
+ dictPair.value().get<uint64_t>());
+ }
break;
}
case (nlohmann::json::value_t::number_float):
@@ -620,12 +689,27 @@
iface);
break;
}
- iface->register_property(
- std::string(dictPair.key()), dictPair.value().get<double>(),
- [&, dictPair](const double &newVal, double &val) {
- val = newVal;
- return 1;
- });
+ if (setable)
+ {
+ iface->register_property(
+ std::string(dictPair.key()),
+ dictPair.value().get<double>(),
+ [&, key](const double &newVal, double &val) {
+ val = newVal;
+ if (!SetJsonFromPointer(key, val,
+ systemConfiguration))
+ {
+ std::cerr << "error writing json\n";
+ return -1;
+ }
+ return 1;
+ });
+ }
+ else
+ {
+ iface->register_property(std::string(dictPair.key()),
+ dictPair.value().get<double>());
+ }
break;
}
case (nlohmann::json::value_t::string):
@@ -636,13 +720,29 @@
dictPair.value(), iface);
break;
}
- iface->register_property(
- std::string(dictPair.key()),
- dictPair.value().get<std::string>(),
- [&, dictPair](const std::string &newVal, std::string &val) {
- val = newVal;
- return 1;
- });
+ if (setable)
+ {
+ iface->register_property(
+ std::string(dictPair.key()),
+ dictPair.value().get<std::string>(),
+ [&, key](const std::string &newVal, std::string &val) {
+ val = newVal;
+ if (!SetJsonFromPointer(key, val,
+ systemConfiguration))
+ {
+ std::cerr << "error writing json\n";
+ return -1;
+ }
+ writeJsonFiles(systemConfiguration);
+ return 1;
+ });
+ }
+ else
+ {
+ iface->register_property(
+ std::string(dictPair.key()),
+ dictPair.value().get<std::string>());
+ }
break;
}
}
@@ -651,14 +751,20 @@
iface->initialize();
}
-void postToDbus(const nlohmann::json &systemConfiguration,
+void postToDbus(const nlohmann::json &newConfiguration,
+ nlohmann::json &systemConfiguration,
sdbusplus::asio::object_server &objServer)
{
- for (auto &boardPair : systemConfiguration.items())
+ // iterate through boards
+ for (auto &boardPair : newConfiguration.items())
{
std::string boardKey = boardPair.key();
- auto boardValues = boardPair.value();
+ std::vector<std::string> path;
+ std::string jsonPointerPath = "/" + boardKey;
+ // loop through newConfiguration, but use values from system
+ // configuration to be able to modify via dbus later
+ auto boardValues = systemConfiguration[boardKey];
auto findBoardType = boardValues.find("type");
std::string boardType;
if (findBoardType != boardValues.end() &&
@@ -686,25 +792,39 @@
auto boardIface = objServer.add_interface(
boardName, "xyz.openbmc_project.Inventory.Item." + boardType);
- populateInterfaceFromJson(systemConfiguration, boardIface.get(),
- boardValues, objServer);
+ populateInterfaceFromJson(systemConfiguration, jsonPointerPath,
+ boardIface.get(), boardValues, objServer);
+ jsonPointerPath += "/";
+ // iterate through board properties
for (auto &boardField : boardValues.items())
{
if (boardField.value().type() == nlohmann::json::value_t::object)
{
auto iface =
objServer.add_interface(boardName, boardField.key());
- populateInterfaceFromJson(systemConfiguration, iface.get(),
- boardField.value(), objServer);
+ populateInterfaceFromJson(
+ systemConfiguration, jsonPointerPath + boardField.key(),
+ iface.get(), boardField.value(), objServer);
}
}
+
auto exposes = boardValues.find("exposes");
if (exposes == boardValues.end())
{
continue;
}
+ // iterate through exposes
+ jsonPointerPath += "exposes/";
+
+ // store the board level pointer so we can modify it on the way down
+ std::string jsonPointerPathBoard = jsonPointerPath;
+ size_t exposesIndex = -1;
for (auto &item : *exposes)
{
+ exposesIndex++;
+ jsonPointerPath = jsonPointerPathBoard;
+ jsonPointerPath += std::to_string(exposesIndex);
+
auto findName = item.find("name");
if (findName == item.end())
{
@@ -739,11 +859,14 @@
boardName + "/" + itemName,
"xyz.openbmc_project.Configuration." + itemType);
- populateInterfaceFromJson(systemConfiguration, itemIface.get(),
- item, objServer);
+ populateInterfaceFromJson(systemConfiguration, jsonPointerPath,
+ itemIface.get(), item, objServer);
for (auto &objectPair : item.items())
{
+ jsonPointerPath = jsonPointerPathBoard +
+ std::to_string(exposesIndex) + "/" +
+ objectPair.key();
if (objectPair.value().type() ==
nlohmann::json::value_t::object)
{
@@ -751,9 +874,10 @@
boardName + "/" + itemName,
"xyz.openbmc_project.Configuration." + itemType + "." +
objectPair.key());
- populateInterfaceFromJson(systemConfiguration,
- objectIface.get(),
- objectPair.value(), objServer);
+
+ populateInterfaceFromJson(
+ systemConfiguration, jsonPointerPath, objectIface.get(),
+ objectPair.value(), objServer);
}
else if (objectPair.value().type() ==
nlohmann::json::value_t::array)
@@ -788,14 +912,21 @@
for (auto &arrayItem : objectPair.value())
{
+ // limit what interfaces accept set for saftey
+ bool setable = std::find(SETTABLE_INTERFACES.begin(),
+ SETTABLE_INTERFACES.end(),
+ objectPair.key()) !=
+ SETTABLE_INTERFACES.end();
+
auto objectIface = objServer.add_interface(
boardName + "/" + itemName,
"xyz.openbmc_project.Configuration." + itemType +
- "." + objectPair.key() + "." +
+ "." + objectPair.key() +
std::to_string(index++));
- populateInterfaceFromJson(systemConfiguration,
- objectIface.get(), arrayItem,
- objServer);
+ populateInterfaceFromJson(
+ systemConfiguration,
+ jsonPointerPath + "/" + std::to_string(index),
+ objectIface.get(), arrayItem, objServer, setable);
}
}
}
@@ -1091,7 +1222,6 @@
// setup an async wait as we normally get flooded with new requests
timer.async_wait([&](const boost::system::error_code &ec) {
-
if (ec == boost::asio::error::operation_aborted)
{
// we were cancelled
@@ -1137,7 +1267,8 @@
loadOverlays(newConfiguration);
io.post([&]() { writeJsonFiles(systemConfiguration); });
io.post([&, newConfiguration]() {
- postToDbus(newConfiguration, objServer);
+ postToDbus(newConfiguration, systemConfiguration,
+ objServer);
});
});
});