diff options
-rw-r--r-- | extensions/openpower-pels/data_interface.cpp | 123 | ||||
-rw-r--r-- | extensions/openpower-pels/data_interface.hpp | 155 | ||||
-rw-r--r-- | extensions/openpower-pels/entry_points.cpp | 6 | ||||
-rw-r--r-- | extensions/openpower-pels/manager.hpp | 13 | ||||
-rw-r--r-- | extensions/openpower-pels/openpower-pels.mk | 1 | ||||
-rw-r--r-- | test/openpower-pels/Makefile.include | 1 | ||||
-rw-r--r-- | test/openpower-pels/pel_manager_test.cpp | 4 |
7 files changed, 298 insertions, 5 deletions
diff --git a/extensions/openpower-pels/data_interface.cpp b/extensions/openpower-pels/data_interface.cpp new file mode 100644 index 0000000..0b7604b --- /dev/null +++ b/extensions/openpower-pels/data_interface.cpp @@ -0,0 +1,123 @@ +#include "data_interface.hpp" + +namespace openpower +{ +namespace pels +{ + +namespace service_name +{ +constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper"; +} // namespace service_name + +namespace object_path +{ +constexpr auto objectMapper = "/xyz/openbmc_project/object_mapper"; +constexpr auto systemInv = "/xyz/openbmc_project/inventory/system"; +} // namespace object_path + +namespace interface +{ +constexpr auto dbusProperty = "org.freedesktop.DBus.Properties"; +constexpr auto objectMapper = "xyz.openbmc_project.ObjectMapper"; +constexpr auto invAsset = "xyz.openbmc_project.Inventory.Decorator.Asset"; +} // namespace interface + +DataInterface::DataInterface(sdbusplus::bus::bus& bus) : _bus(bus) +{ + readMTMS(); +} + +void DataInterface::readMTMS() +{ + // If this runs when the inventory service isn't running, it will get the + // value whenever it starts via the propertiesChanged callback. + try + { + auto inventoryService = + getService(object_path::systemInv, interface::invAsset); + + if (!inventoryService.empty()) + { + auto properties = getAllProperties( + inventoryService, object_path::systemInv, interface::invAsset); + + _machineTypeModel = std::get<std::string>(properties["Model"]); + + _machineSerialNumber = + std::get<std::string>(properties["SerialNumber"]); + } + } + catch (std::exception& e) + { + // Inventory must not be running at this moment. + } + + // Keep up to date by watching for the propertiesChanged signal. + _sysInventoryPropMatch = std::make_unique<sdbusplus::bus::match_t>( + _bus, + sdbusplus::bus::match::rules::propertiesChanged(object_path::systemInv, + interface::invAsset), + std::bind(std::mem_fn(&DataInterface::sysAssetPropChanged), this, + std::placeholders::_1)); +} + +void DataInterface::sysAssetPropChanged(sdbusplus::message::message& msg) +{ + DBusInterface interface; + DBusPropertyMap properties; + + msg.read(interface, properties); + + auto model = properties.find("Model"); + if (model != properties.end()) + { + _machineTypeModel = std::get<std::string>(model->second); + } + + auto sn = properties.find("SerialNumber"); + if (sn != properties.end()) + { + _machineSerialNumber = std::get<std::string>(sn->second); + } +} + +DBusPropertyMap DataInterface::getAllProperties(const std::string& service, + const std::string& objectPath, + const std::string& interface) +{ + DBusPropertyMap properties; + + auto method = _bus.new_method_call(service.c_str(), objectPath.c_str(), + interface::dbusProperty, "GetAll"); + method.append(interface); + auto reply = _bus.call(method); + + reply.read(properties); + + return properties; +} + +DBusService DataInterface::getService(const std::string& objectPath, + const std::string& interface) +{ + auto method = _bus.new_method_call(service_name::objectMapper, + object_path::objectMapper, + interface::objectMapper, "GetObject"); + + method.append(objectPath, std::vector<std::string>({interface})); + + auto reply = _bus.call(method); + + std::map<DBusService, DBusInterfaceList> response; + reply.read(response); + + if (!response.empty()) + { + return response.begin()->first; + } + + return std::string{}; +} +} // namespace pels +} // namespace openpower diff --git a/extensions/openpower-pels/data_interface.hpp b/extensions/openpower-pels/data_interface.hpp new file mode 100644 index 0000000..34bb173 --- /dev/null +++ b/extensions/openpower-pels/data_interface.hpp @@ -0,0 +1,155 @@ +#pragma once + +#include <sdbusplus/bus.hpp> +#include <sdbusplus/bus/match.hpp> + +namespace openpower +{ +namespace pels +{ + +using DBusValue = sdbusplus::message::variant<std::string>; +using DBusProperty = std::string; +using DBusInterface = std::string; +using DBusService = std::string; +using DBusPath = std::string; +using DBusInterfaceList = std::vector<DBusInterface>; +using DBusPropertyMap = std::map<DBusProperty, DBusValue>; + +/** + * @class DataInterface + * + * An abstract interface class for gathering data about the system + * for use in PELs. Implemented this way to facilitate mocking. + */ +class DataInterfaceBase +{ + public: + DataInterfaceBase() = default; + virtual ~DataInterfaceBase() = default; + DataInterfaceBase(const DataInterfaceBase&) = default; + DataInterfaceBase& operator=(const DataInterfaceBase&) = default; + DataInterfaceBase(DataInterfaceBase&&) = default; + DataInterfaceBase& operator=(DataInterfaceBase&&) = default; + + /** + * @brief Pure virtual for returning the MTM + * + * @return string - The machine Type/Model string + */ + virtual std::string getMachineTypeModel() const = 0; + + /** + * @brief Pure virtual for returning the machine SN + * + * @return string - The machine serial number + */ + virtual std::string getMachineSerialNumber() const = 0; +}; + +/** + * @class DataInterface + * + * Concrete implementation of DataInterfaceBase. + */ +class DataInterface : public DataInterfaceBase +{ + public: + DataInterface() = delete; + ~DataInterface() = default; + DataInterface(const DataInterface&) = default; + DataInterface& operator=(const DataInterface&) = default; + DataInterface(DataInterface&&) = default; + DataInterface& operator=(DataInterface&&) = default; + + /** + * @brief Constructor + * + * @param[in] bus - The sdbusplus bus object + */ + explicit DataInterface(sdbusplus::bus::bus& bus); + + /** + * @brief Returns the machine type/model value + * + * @return string - The machine Type/Model string + */ + std::string getMachineTypeModel() const override + { + return _machineTypeModel; + } + + /** + * @brief Returns the machine SN + * + * @return string - The machine serial number + */ + std::string getMachineSerialNumber() const override + { + return _machineSerialNumber; + } + + private: + /** + * @brief Reads the machine type/model and SN from D-Bus. + * + * Looks for them on the 'system' inventory object, and also + * places a properties changed watch on them to obtain any changes + * (or read them for the first time if the inventory isn't ready + * when this function runs.) + */ + void readMTMS(); + + /** + * @brief Finds the D-Bus service name that hosts the + * passed in path and interface. + * + * @param[in] objectPath - The D-Bus object path + * @param[in] interface - The D-Bus interface + */ + DBusService getService(const std::string& objectPath, + const std::string& interface); + /** + * @brief Wrapper for the 'GetAll' properties method call + * + * @param[in] service - The D-Bus service to call it on + * @param[in] objectPath - The D-Bus object path + * @param[in] interface - The interface to get the props on + * + * @return DBusPropertyMap - The property results + */ + DBusPropertyMap getAllProperties(const std::string& service, + const std::string& objectPath, + const std::string& interface); + + /** + * @brief The properties changed callback for the Asset iface + * on the system inventory object. + * + * @param[in] msg - The sdbusplus message of the signal + */ + void sysAssetPropChanged(sdbusplus::message::message& msg); + + /** + * @brief The machine type-model. Always kept up to date + */ + std::string _machineTypeModel; + + /** + * @brief The machine serial number. Always kept up to date + */ + std::string _machineSerialNumber; + + /** + * @brief The match object for the system path's properties + */ + std::unique_ptr<sdbusplus::bus::match_t> _sysInventoryPropMatch; + + /** + * @brief The sdbusplus bus object for making D-Bus calls. + */ + sdbusplus::bus::bus& _bus; +}; + +} // namespace pels +} // namespace openpower diff --git a/extensions/openpower-pels/entry_points.cpp b/extensions/openpower-pels/entry_points.cpp index 5adeb40..59a93c1 100644 --- a/extensions/openpower-pels/entry_points.cpp +++ b/extensions/openpower-pels/entry_points.cpp @@ -1,3 +1,4 @@ +#include "data_interface.hpp" #include "elog_entry.hpp" #include "extensions.hpp" #include "manager.hpp" @@ -15,7 +16,10 @@ DISABLE_LOG_ENTRY_CAPS(); void pelStartup(internal::Manager& logManager) { - manager = std::make_unique<Manager>(logManager); + std::unique_ptr<DataInterfaceBase> dataIface = + std::make_unique<DataInterface>(logManager.getBus()); + + manager = std::make_unique<Manager>(logManager, std::move(dataIface)); } REGISTER_EXTENSION_FUNCTION(pelStartup); diff --git a/extensions/openpower-pels/manager.hpp b/extensions/openpower-pels/manager.hpp index 3134f23..49ac8bf 100644 --- a/extensions/openpower-pels/manager.hpp +++ b/extensions/openpower-pels/manager.hpp @@ -1,6 +1,6 @@ #pragma once -#include "elog_entry.hpp" +#include "data_interface.hpp" #include "log_manager.hpp" #include "paths.hpp" #include "repository.hpp" @@ -30,8 +30,10 @@ class Manager * * @param[in] logManager - internal::Manager object */ - explicit Manager(internal::Manager& logManager) : - _logManager(logManager), _repo(getPELRepoPath()) + explicit Manager(phosphor::logging::internal::Manager& logManager, + std::unique_ptr<DataInterfaceBase>&& dataIface) : + _logManager(logManager), + _repo(getPELRepoPath()), _dataIface(std::move(dataIface)) { } @@ -104,6 +106,11 @@ class Manager * @brief The PEL repository object */ Repository _repo; + + /** + * @brief The API the PEL sections use to gather data + */ + std::unique_ptr<DataInterfaceBase> _dataIface; }; } // namespace pels diff --git a/extensions/openpower-pels/openpower-pels.mk b/extensions/openpower-pels/openpower-pels.mk index 6a58db8..21eb719 100644 --- a/extensions/openpower-pels/openpower-pels.mk +++ b/extensions/openpower-pels/openpower-pels.mk @@ -1,5 +1,6 @@ phosphor_log_manager_SOURCES += \ extensions/openpower-pels/bcd_time.cpp \ + extensions/openpower-pels/data_interface.cpp \ extensions/openpower-pels/entry_points.cpp \ extensions/openpower-pels/log_id.cpp \ extensions/openpower-pels/manager.cpp \ diff --git a/test/openpower-pels/Makefile.include b/test/openpower-pels/Makefile.include index 51f3ecc..124970d 100644 --- a/test/openpower-pels/Makefile.include +++ b/test/openpower-pels/Makefile.include @@ -101,6 +101,7 @@ pel_manager_test_CXXFLAGS = $(test_cxxflags) pel_manager_test_LDADD = \ $(test_ldadd) \ $(pel_objects) \ + $(top_builddir)/extensions/openpower-pels/data_interface.o \ $(top_builddir)/extensions/openpower-pels/manager.o \ $(top_builddir)/extensions/openpower-pels/repository.o pel_manager_test_LDFLAGS = $(test_ldflags) diff --git a/test/openpower-pels/pel_manager_test.cpp b/test/openpower-pels/pel_manager_test.cpp index 9d788c9..0a82141 100644 --- a/test/openpower-pels/pel_manager_test.cpp +++ b/test/openpower-pels/pel_manager_test.cpp @@ -27,8 +27,10 @@ TEST_F(ManagerTest, TestCreateWithPEL) { auto bus = sdbusplus::bus::new_default(); phosphor::logging::internal::Manager logManager(bus, "logging_path"); + std::unique_ptr<DataInterfaceBase> dataIface = + std::make_unique<DataInterface>(bus); - openpower::pels::Manager manager{logManager}; + openpower::pels::Manager manager{logManager, std::move(dataIface)}; // Create a PEL, write it to a file, and pass that filename into // the create function. |