Introduce EntityManager class
Reworking Entity-Manager to use OOP, which will help in further
refactoring. It increases maintainability and supports the 'separation
of concern' concept.
Tested:
QEMU/yosemite4 with probe statement set to TRUE.
```
root@yosemite4:~# journalctl | grep entity-manager
Dec 19 13:26:21 yosemite4 entity-manager[502]: Clearing previous configuration
Dec 19 13:26:25 yosemite4 entity-manager[502]: Inventory Added: Yosemite 4 Management Board
root@yosemite4:~# busctl tree xyz.openbmc_project.EntityManager
`- /xyz
`- /xyz/openbmc_project
|- /xyz/openbmc_project/EntityManager
`- /xyz/openbmc_project/inventory
`- /xyz/openbmc_project/inventory/system
`- /xyz/openbmc_project/inventory/system/board
`- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/All_Fan
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_ADC_P0V6_VOLT_
V
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_ADC_P12V_VOLT_
V
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_ADC_P1V0_VOLT_
V
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_ADC_P1V2_VOLT_
V
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_ADC_P1V8_VOLT_
V
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_ADC_P2V5_VOLT_
V
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_ADC_P3V3_RGM_V
OLT_V
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_ADC_P3V3_VOLT_
V
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_ADC_P3V_BAT_VO
LT_V
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_ADC_P5V_USB_VO
LT_V
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_ADC_P5V_VOLT_V
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/MGNT_TEMP_C
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/PID_NIC_TEMP
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/Stepwise_MGNT_TEMP
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/Stepwise_NIC_TEMP
|- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/Stepwise_SENTINEL_D
OME_SLOT_PRESENT_PERCENTAGE
`- /xyz/openbmc_project/inventory/system/board/Yosemite_4_Management_Board/Zone_1
```
Creates the same result as previous commit on qemu/yosemite4 with
adapted config set to TRUE.
Change-Id: I0829e073bedf24cb127ad247827e169894f4e962
Signed-off-by: Christopher Meis <christopher.meis@9elements.com>
diff --git a/src/entity_manager/entity_manager.cpp b/src/entity_manager/entity_manager.cpp
index 2b65604..9a69a25 100644
--- a/src/entity_manager/entity_manager.cpp
+++ b/src/entity_manager/entity_manager.cpp
@@ -54,12 +54,6 @@
"FanProfile", "Pid", "Pid.Zone", "Stepwise", "Thresholds", "Polling"};
// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
-
-// todo: pass this through nicer
-std::shared_ptr<sdbusplus::asio::connection> systemBus;
-nlohmann::json lastJson;
-Topology topology;
-
boost::asio::io_context io;
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
@@ -74,10 +68,28 @@
: sdbusplus::asio::PropertyPermission::readOnly;
}
-void postToDbus(const nlohmann::json& newConfiguration,
- nlohmann::json& systemConfiguration,
- sdbusplus::asio::object_server& objServer)
+EntityManager::EntityManager(
+ std::shared_ptr<sdbusplus::asio::connection>& systemBus) :
+ systemBus(systemBus),
+ objServer(sdbusplus::asio::object_server(systemBus, /*skipManager=*/true)),
+ lastJson(nlohmann::json::object()),
+ systemConfiguration(nlohmann::json::object())
+{
+ // All other objects that EntityManager currently support are under the
+ // inventory subtree.
+ // See the discussion at
+ // https://discord.com/channels/775381525260664832/1018929092009144380
+ objServer.add_manager("/xyz/openbmc_project/inventory");
+ entityIface = objServer.add_interface("/xyz/openbmc_project/EntityManager",
+ "xyz.openbmc_project.EntityManager");
+ entityIface->register_method("ReScan", [this]() {
+ propertiesChangedCallback();
+ });
+ dbus_interface::tryIfaceInitialize(entityIface);
+}
+
+void EntityManager::postToDbus(const nlohmann::json& newConfiguration)
{
std::map<std::string, std::string> newBoards; // path -> name
@@ -361,7 +373,8 @@
}
void startRemovedTimer(boost::asio::steady_timer& timer,
- nlohmann::json& systemConfiguration)
+ nlohmann::json& systemConfiguration,
+ nlohmann::json& lastJson)
{
static bool scannedPowerOff = false;
static bool scannedPowerOn = false;
@@ -382,7 +395,7 @@
timer.expires_after(std::chrono::seconds(10));
timer.async_wait(
- [&systemConfiguration](const boost::system::error_code& ec) {
+ [&systemConfiguration, &lastJson](const boost::system::error_code& ec) {
if (ec == boost::asio::error::operation_aborted)
{
return;
@@ -403,10 +416,8 @@
});
}
-static void pruneConfiguration(nlohmann::json& systemConfiguration,
- sdbusplus::asio::object_server& objServer,
- bool powerOff, const std::string& name,
- const nlohmann::json& device)
+void EntityManager::pruneConfiguration(bool powerOff, const std::string& name,
+ const nlohmann::json& device)
{
if (powerOff && deviceRequiresPowerOn(device))
{
@@ -430,41 +441,37 @@
logDeviceRemoved(device);
}
-static void publishNewConfiguration(
+void EntityManager::publishNewConfiguration(
const size_t& instance, const size_t count,
- boost::asio::steady_timer& timer, nlohmann::json& systemConfiguration,
- // Gerrit discussion:
+ boost::asio::steady_timer& timer, // Gerrit discussion:
// https://gerrit.openbmc-project.xyz/c/openbmc/entity-manager/+/52316/6
//
// Discord discussion:
// https://discord.com/channels/775381525260664832/867820390406422538/958048437729910854
//
// NOLINTNEXTLINE(performance-unnecessary-value-param)
- const nlohmann::json newConfiguration,
- sdbusplus::asio::object_server& objServer)
+ const nlohmann::json newConfiguration)
{
loadOverlays(newConfiguration);
- boost::asio::post(io, [systemConfiguration]() {
+ boost::asio::post(io, [this]() {
if (!configuration::writeJsonFiles(systemConfiguration))
{
std::cerr << "Error writing json files\n";
}
});
- boost::asio::post(io, [&instance, count, &timer, newConfiguration,
- &systemConfiguration, &objServer]() {
- postToDbus(newConfiguration, systemConfiguration, objServer);
+ boost::asio::post(io, [this, &instance, count, &timer, newConfiguration]() {
+ postToDbus(newConfiguration);
if (count == instance)
{
- startRemovedTimer(timer, systemConfiguration);
+ startRemovedTimer(timer, systemConfiguration, lastJson);
}
});
}
// main properties changed entry
-void propertiesChangedCallback(nlohmann::json& systemConfiguration,
- sdbusplus::asio::object_server& objServer)
+void EntityManager::propertiesChangedCallback()
{
static bool inProgress = false;
static boost::asio::steady_timer timer(io);
@@ -475,8 +482,7 @@
timer.expires_after(std::chrono::milliseconds(500));
// setup an async wait as we normally get flooded with new requests
- timer.async_wait([&systemConfiguration, &objServer,
- count](const boost::system::error_code& ec) {
+ timer.async_wait([this, count](const boost::system::error_code& ec) {
if (ec == boost::asio::error::operation_aborted)
{
// we were cancelled
@@ -490,7 +496,7 @@
if (inProgress)
{
- propertiesChangedCallback(systemConfiguration, objServer);
+ propertiesChangedCallback();
return;
}
inProgress = true;
@@ -508,18 +514,15 @@
}
auto perfScan = std::make_shared<scan::PerformScan>(
- systemConfiguration, *missingConfigurations, configurations,
- objServer,
- [&systemConfiguration, &objServer, count, oldConfiguration,
- missingConfigurations]() {
+ *this, *missingConfigurations, configurations,
+ [this, count, oldConfiguration, missingConfigurations]() {
// this is something that since ac has been applied to the bmc
// we saw, and we no longer see it
bool powerOff = !em_utils::isPowerOn();
for (const auto& [name, device] :
missingConfigurations->items())
{
- pruneConfiguration(systemConfiguration, objServer, powerOff,
- name, device);
+ pruneConfiguration(powerOff, name, device);
}
nlohmann::json newConfiguration = systemConfiguration;
@@ -534,11 +537,10 @@
inProgress = false;
- boost::asio::post(
- io, std::bind_front(
- publishNewConfiguration, std::ref(instance), count,
- std::ref(timer), std::ref(systemConfiguration),
- newConfiguration, std::ref(objServer)));
+ boost::asio::post(io, [this, newConfiguration, count] {
+ publishNewConfiguration(std::ref(instance), count,
+ std::ref(timer), newConfiguration);
+ });
});
perfScan->run();
});
@@ -582,42 +584,37 @@
return !intersect.empty();
}
-int main()
+void EntityManager::registerCallback(const std::string& path)
{
- // setup connection to dbus
- systemBus = std::make_shared<sdbusplus::asio::connection>(io);
- systemBus->request_name("xyz.openbmc_project.EntityManager");
+ static boost::container::flat_map<std::string, sdbusplus::bus::match_t>
+ dbusMatches;
- // The EntityManager object itself doesn't expose any properties.
- // No need to set up ObjectManager for the |EntityManager| object.
- sdbusplus::asio::object_server objServer(systemBus, /*skipManager=*/true);
+ if (dbusMatches.contains(path))
+ {
+ return;
+ }
- // All other objects that EntityManager currently support are under the
- // inventory subtree.
- // See the discussion at
- // https://discord.com/channels/775381525260664832/1018929092009144380
- objServer.add_manager("/xyz/openbmc_project/inventory");
+ std::function<void(sdbusplus::message_t & message)> eventHandler =
+ [&](sdbusplus::message_t&) { propertiesChangedCallback(); };
- std::shared_ptr<sdbusplus::asio::dbus_interface> entityIface =
- objServer.add_interface("/xyz/openbmc_project/EntityManager",
- "xyz.openbmc_project.EntityManager");
+ sdbusplus::bus::match_t match(
+ static_cast<sdbusplus::bus_t&>(*systemBus),
+ "type='signal',member='PropertiesChanged',path='" + path + "'",
+ eventHandler);
+ dbusMatches.emplace(path, std::move(match));
+}
- // to keep reference to the match / filter objects so they don't get
- // destroyed
-
- nlohmann::json systemConfiguration = nlohmann::json::object();
-
- std::set<std::string> probeInterfaces = configuration::getProbeInterfaces();
-
- // We need a poke from DBus for static providers that create all their
- // objects prior to claiming a well-known name, and thus don't emit any
- // org.freedesktop.DBus.Properties signals. Similarly if a process exits
- // for any reason, expected or otherwise, we'll need a poke to remove
- // entities from DBus.
- sdbusplus::bus::match_t nameOwnerChangedMatch(
+// We need a poke from DBus for static providers that create all their
+// objects prior to claiming a well-known name, and thus don't emit any
+// org.freedesktop.DBus.Properties signals. Similarly if a process exits
+// for any reason, expected or otherwise, we'll need a poke to remove
+// entities from DBus.
+void EntityManager::initFilters(const std::set<std::string>& probeInterfaces)
+{
+ static sdbusplus::bus::match_t nameOwnerChangedMatch(
static_cast<sdbusplus::bus_t&>(*systemBus),
sdbusplus::bus::match::rules::nameOwnerChanged(),
- [&](sdbusplus::message_t& m) {
+ [this](sdbusplus::message_t& m) {
auto [name, oldOwner,
newOwner] = m.unpack<std::string, std::string, std::string>();
@@ -627,37 +624,45 @@
return;
}
- propertiesChangedCallback(systemConfiguration, objServer);
+ propertiesChangedCallback();
});
+
// We also need a poke from DBus when new interfaces are created or
// destroyed.
- sdbusplus::bus::match_t interfacesAddedMatch(
+ static sdbusplus::bus::match_t interfacesAddedMatch(
static_cast<sdbusplus::bus_t&>(*systemBus),
sdbusplus::bus::match::rules::interfacesAdded(),
- [&](sdbusplus::message_t& msg) {
+ [this, probeInterfaces](sdbusplus::message_t& msg) {
if (iaContainsProbeInterface(msg, probeInterfaces))
{
- propertiesChangedCallback(systemConfiguration, objServer);
+ propertiesChangedCallback();
}
});
- sdbusplus::bus::match_t interfacesRemovedMatch(
+
+ static sdbusplus::bus::match_t interfacesRemovedMatch(
static_cast<sdbusplus::bus_t&>(*systemBus),
sdbusplus::bus::match::rules::interfacesRemoved(),
- [&](sdbusplus::message_t& msg) {
+ [this, probeInterfaces](sdbusplus::message_t& msg) {
if (irContainsProbeInterface(msg, probeInterfaces))
{
- propertiesChangedCallback(systemConfiguration, objServer);
+ propertiesChangedCallback();
}
});
+}
- boost::asio::post(io, [&]() {
- propertiesChangedCallback(systemConfiguration, objServer);
- });
+int main()
+{
+ auto systemBus = std::make_shared<sdbusplus::asio::connection>(io);
+ systemBus->request_name("xyz.openbmc_project.EntityManager");
+ EntityManager em(systemBus);
- entityIface->register_method("ReScan", [&]() {
- propertiesChangedCallback(systemConfiguration, objServer);
- });
- dbus_interface::tryIfaceInitialize(entityIface);
+ nlohmann::json systemConfiguration = nlohmann::json::object();
+
+ std::set<std::string> probeInterfaces = configuration::getProbeInterfaces();
+
+ em.initFilters(probeInterfaces);
+
+ boost::asio::post(io, [&]() { em.propertiesChangedCallback(); });
if (em_utils::fwVersionIsSame())
{
@@ -682,7 +687,7 @@
}
else
{
- lastJson = std::move(data);
+ em.lastJson = std::move(data);
}
}
else
@@ -700,7 +705,7 @@
// some boards only show up after power is on, we want to not say they are
// removed until the same state happens
- em_utils::setupPowerMatch(systemBus);
+ em_utils::setupPowerMatch(em.systemBus);
io.run();
diff --git a/src/entity_manager/entity_manager.hpp b/src/entity_manager/entity_manager.hpp
index ccd106e..97ef441 100644
--- a/src/entity_manager/entity_manager.hpp
+++ b/src/entity_manager/entity_manager.hpp
@@ -18,15 +18,42 @@
#pragma once
#include "../utils.hpp"
+#include "topology.hpp"
#include <systemd/sd-journal.h>
#include <boost/container/flat_map.hpp>
#include <nlohmann/json.hpp>
+#include <sdbusplus/asio/connection.hpp>
#include <sdbusplus/asio/object_server.hpp>
#include <string>
+class EntityManager
+{
+ public:
+ explicit EntityManager(
+ std::shared_ptr<sdbusplus::asio::connection>& systemBus);
+
+ std::shared_ptr<sdbusplus::asio::connection> systemBus;
+ sdbusplus::asio::object_server objServer;
+ std::shared_ptr<sdbusplus::asio::dbus_interface> entityIface;
+ nlohmann::json lastJson;
+ nlohmann::json systemConfiguration;
+ Topology topology;
+
+ void propertiesChangedCallback();
+ void registerCallback(const std::string& path);
+ void publishNewConfiguration(const size_t& instance, size_t count,
+ boost::asio::steady_timer& timer,
+ nlohmann::json newConfiguration);
+ void postToDbus(const nlohmann::json& newConfiguration);
+ void pruneConfiguration(bool powerOff, const std::string& name,
+ const nlohmann::json& device);
+
+ void initFilters(const std::set<std::string>& probeInterfaces);
+};
+
inline void logDeviceAdded(const nlohmann::json& record)
{
if (!deviceHasLogging(record))
diff --git a/src/entity_manager/perform_scan.cpp b/src/entity_manager/perform_scan.cpp
index a31e7a1..04d3c67 100644
--- a/src/entity_manager/perform_scan.cpp
+++ b/src/entity_manager/perform_scan.cpp
@@ -28,15 +28,6 @@
#include <charconv>
#include <iostream>
-/* Hacks from splitting entity_manager.cpp */
-// NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables)
-extern std::shared_ptr<sdbusplus::asio::connection> systemBus;
-extern nlohmann::json lastJson;
-extern void propertiesChangedCallback(
- nlohmann::json& systemConfiguration,
- sdbusplus::asio::object_server& objServer);
-// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
-
using GetSubTreeType = std::vector<
std::pair<std::string,
std::vector<std::pair<std::string, std::vector<std::string>>>>>;
@@ -62,7 +53,7 @@
return;
}
- systemBus->async_method_call(
+ scan->_em.systemBus->async_method_call(
[instance, scan, probeVector,
retries](boost::system::error_code& errc, const DBusInterface& resp) {
if (errc)
@@ -87,31 +78,6 @@
"GetAll", instance.interface);
}
-static void registerCallback(nlohmann::json& systemConfiguration,
- sdbusplus::asio::object_server& objServer,
- const std::string& path)
-{
- static boost::container::flat_map<std::string, sdbusplus::bus::match_t>
- dbusMatches;
-
- auto find = dbusMatches.find(path);
- if (find != dbusMatches.end())
- {
- return;
- }
-
- std::function<void(sdbusplus::message_t & message)> eventHandler =
- [&](sdbusplus::message_t&) {
- propertiesChangedCallback(systemConfiguration, objServer);
- };
-
- sdbusplus::bus::match_t match(
- static_cast<sdbusplus::bus_t&>(*systemBus),
- "type='signal',member='PropertiesChanged',path='" + path + "'",
- eventHandler);
- dbusMatches.emplace(path, std::move(match));
-}
-
static void processDbusObjects(
std::vector<std::shared_ptr<probe::PerformProbe>>& probeVector,
const std::shared_ptr<scan::PerformScan>& scan,
@@ -120,7 +86,7 @@
for (const auto& [path, object] : interfaceSubtree)
{
// Get a PropertiesChanged callback for all interfaces on this path.
- registerCallback(scan->_systemConfiguration, scan->objServer, path);
+ scan->_em.registerCallback(path);
for (const auto& [busname, ifaces] : object)
{
@@ -160,7 +126,7 @@
}
// find all connections in the mapper that expose a specific type
- systemBus->async_method_call(
+ scan->_em.systemBus->async_method_call(
[interfaces, probeVector{std::move(probeVector)}, scan,
retries](boost::system::error_code& ec,
const GetSubTreeType& interfaceSubtree) mutable {
@@ -225,15 +191,12 @@
return std::to_string(std::hash<std::string>{}(probeName + device.dump()));
}
-scan::PerformScan::PerformScan(nlohmann::json& systemConfiguration,
+scan::PerformScan::PerformScan(EntityManager& em,
nlohmann::json& missingConfigurations,
std::list<nlohmann::json>& configurations,
- sdbusplus::asio::object_server& objServerIn,
std::function<void()>&& callback) :
- _systemConfiguration(systemConfiguration),
- _missingConfigurations(missingConfigurations),
- _configurations(configurations), objServer(objServerIn),
- _callback(std::move(callback))
+ _em(em), _missingConfigurations(missingConfigurations),
+ _configurations(configurations), _callback(std::move(callback))
{}
static void pruneRecordExposes(nlohmann::json& record)
@@ -471,11 +434,11 @@
{
std::string recordName = getRecordName(itr->interface, probeName);
- auto record = _systemConfiguration.find(recordName);
- if (record == _systemConfiguration.end())
+ auto record = _em.systemConfiguration.find(recordName);
+ if (record == _em.systemConfiguration.end())
{
- record = lastJson.find(recordName);
- if (record == lastJson.end())
+ record = _em.lastJson.find(recordName);
+ if (record == _em.lastJson.end())
{
itr++;
continue;
@@ -483,7 +446,7 @@
pruneRecordExposes(*record);
- _systemConfiguration[recordName] = *record;
+ _em.systemConfiguration[recordName] = *record;
}
_missingConfigurations.erase(recordName);
@@ -542,7 +505,7 @@
// insert into configuration temporarily to be able to
// reference ourselves
- _systemConfiguration[recordName] = record;
+ _em.systemConfiguration[recordName] = record;
auto findExpose = record.find("Exposes");
if (findExpose == record.end())
@@ -558,13 +521,13 @@
em_utils::templateCharReplace(keyPair, dbusObject,
foundDeviceIdx, replaceStr);
- applyExposeActions(_systemConfiguration, recordName, expose,
+ applyExposeActions(_em.systemConfiguration, recordName, expose,
keyPair);
}
}
// overwrite ourselves with cleaned up version
- _systemConfiguration[recordName] = record;
+ _em.systemConfiguration[recordName] = record;
_missingConfigurations.erase(recordName);
}
}
@@ -653,8 +616,7 @@
if (_passed)
{
auto nextScan = std::make_shared<PerformScan>(
- _systemConfiguration, _missingConfigurations, _configurations,
- objServer, std::move(_callback));
+ _em, _missingConfigurations, _configurations, std::move(_callback));
nextScan->passedProbes = std::move(passedProbes);
nextScan->dbusProbeObjects = std::move(dbusProbeObjects);
nextScan->run();
diff --git a/src/entity_manager/perform_scan.hpp b/src/entity_manager/perform_scan.hpp
index ae57582..54d0e67 100644
--- a/src/entity_manager/perform_scan.hpp
+++ b/src/entity_manager/perform_scan.hpp
@@ -1,6 +1,7 @@
#pragma once
#include "../utils.hpp"
+#include "entity_manager.hpp"
#include <systemd/sd-journal.h>
@@ -24,10 +25,8 @@
struct PerformScan : std::enable_shared_from_this<PerformScan>
{
- PerformScan(nlohmann::json& systemConfiguration,
- nlohmann::json& missingConfigurations,
+ PerformScan(EntityManager& em, nlohmann::json& missingConfigurations,
std::list<nlohmann::json>& configurations,
- sdbusplus::asio::object_server& objServer,
std::function<void()>&& callback);
void updateSystemConfiguration(const nlohmann::json& recordRef,
@@ -35,10 +34,9 @@
FoundDevices& foundDevices);
void run();
virtual ~PerformScan();
- nlohmann::json& _systemConfiguration;
+ EntityManager& _em;
nlohmann::json& _missingConfigurations;
std::list<nlohmann::json> _configurations;
- sdbusplus::asio::object_server& objServer;
std::function<void()> _callback;
bool _passed = false;
MapperGetSubTreeResponse dbusProbeObjects;