Create the Callout objects
If a new error log has the association interface, and the
inventory item it points to implements the Asset interface,
create a Callout object for it and persist it.
It will be persisted to a file like:
/var/lib/ibm-logging/errors/N/callouts/M where N is an error
log entry ID and M is the callout instance number.
Tested: Verify new D-Bus objects for callouts.
Change-Id: I90e9cf76edd7c2517de22cee64c3b979c482efa8
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
diff --git a/configure.ac b/configure.ac
index 574bd1a..2074692 100644
--- a/configure.ac
+++ b/configure.ac
@@ -76,6 +76,10 @@
[The xyz logging busname])
AC_DEFINE(IBM_LOGGING_BUSNAME, "com.ibm.Logging",
[The IBM log manager DBus busname to own])
+AC_DEFINE(ASSOC_IFACE, "org.openbmc.Associations",
+ [The associations interface])
+AC_DEFINE(ASSET_IFACE, "xyz.openbmc_project.Inventory.Decorator.Asset",
+ [The asset interface])
AC_DEFINE(DEFAULT_POLICY_EID, "None",
[The default event ID to use])
@@ -86,6 +90,12 @@
AS_IF([test "x$POLICY_JSON_PATH" == "x"], [POLICY_JSON_PATH="/usr/share/ibm-logging/policy.json"])
AC_DEFINE_UNQUOTED([POLICY_JSON_PATH], ["$POLICY_JSON_PATH"], [The path to the policy json file on the BMC])
+AC_ARG_VAR(ERRLOG_PERSIST_PATH, [Path to save errors in])
+AS_IF([test "x$ERRLOG_PERSIST_PATH" == "x"], \
+ [ERRLOG_PERSIST_PATH="/var/lib/ibm-logging/errors"])
+AC_DEFINE_UNQUOTED([ERRLOG_PERSIST_PATH], ["$ERRLOG_PERSIST_PATH"], \
+ [Path to save errors in])
+
AC_ARG_VAR(CALLOUT_CLASS_VERSION,
[Callout class version to register with Cereal])
AS_IF([test "x$CALLOUT_CLASS_VERSION" == "x"],
diff --git a/dbus.hpp b/dbus.hpp
index 392dd8a..c572d99 100644
--- a/dbus.hpp
+++ b/dbus.hpp
@@ -14,8 +14,16 @@
using DbusProperty = std::string;
using DbusService = std::string;
using DbusPath = std::string;
+
+static constexpr auto forwardPos = 0;
+static constexpr auto reversePos = 1;
+static constexpr auto endpointPos = 2;
+using AssociationsPropertyType =
+ std::vector<std::tuple<std::string, std::string, std::string>>;
+
using Value = sdbusplus::message::variant<bool, uint32_t, uint64_t, std::string,
- std::vector<std::string>>;
+ std::vector<std::string>,
+ AssociationsPropertyType>;
using DbusPropertyMap = std::map<DbusProperty, Value>;
using DbusInterfaceMap = std::map<DbusInterface, DbusPropertyMap>;
diff --git a/manager.cpp b/manager.cpp
index a2c262d..44c1adf 100644
--- a/manager.cpp
+++ b/manager.cpp
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+#include "callout.hpp"
#include "config.h"
#include "manager.hpp"
#include "policy_find.hpp"
@@ -22,6 +23,8 @@
namespace logging
{
+namespace fs = std::experimental::filesystem;
+
Manager::Manager(sdbusplus::bus::bus& bus) :
bus(bus),
addMatch(bus,
@@ -73,8 +76,7 @@
{
createObject(objectPath, interfaces);
- // TODO
- // createCalloutObjects(objectPath, interfaces);
+ createCalloutObjects(objectPath, interfaces);
}
void Manager::createObject(const std::string& objectPath,
@@ -88,6 +90,7 @@
void Manager::erase(EntryID id)
{
+ fs::remove_all(getSaveDir(id));
childEntries.erase(id);
entries.erase(id);
}
@@ -163,6 +166,77 @@
}
#endif
+void Manager::createCalloutObjects(const std::string& objectPath,
+ const DbusInterfaceMap& interfaces)
+{
+ // Use the associations property in the org.openbmc.Associations
+ // interface to find any callouts. Then grab all properties on
+ // the Asset interface for that object in the inventory to use
+ // in our callout objects.
+
+ auto associations = interfaces.find(ASSOC_IFACE);
+ if (associations == interfaces.end())
+ {
+ return;
+ }
+
+ const auto& properties = associations->second;
+ auto assocProperty = properties.find("associations");
+ auto assocValue = assocProperty->second.get<AssociationsPropertyType>();
+
+ auto id = getEntryID(objectPath);
+ auto calloutNum = 0;
+ DbusSubtree subtree;
+
+ for (const auto& association : assocValue)
+ {
+ if (std::get<forwardPos>(association) != "callout")
+ {
+ continue;
+ }
+
+ auto callout = std::get<endpointPos>(association);
+
+ if (subtree.empty())
+ {
+ subtree = getSubtree(bus, "/", 0, ASSET_IFACE);
+ if (subtree.empty())
+ {
+ break;
+ }
+ }
+
+ auto service = getService(callout, ASSET_IFACE, subtree);
+ if (service.empty())
+ {
+ continue;
+ }
+
+ auto properties = getAllProperties(bus, service, callout, ASSET_IFACE);
+ if (properties.empty())
+ {
+ continue;
+ }
+
+ auto calloutPath = getCalloutObjectPath(objectPath, calloutNum);
+
+ auto object =
+ std::make_shared<Callout>(bus, calloutPath, callout, calloutNum,
+ getLogTimestamp(interfaces), properties);
+
+ auto dir = getCalloutSaveDir(id);
+ if (!fs::exists(dir))
+ {
+ fs::create_directories(dir);
+ }
+ object->serialize(dir);
+
+ std::experimental::any anyObject = object;
+ addChildInterface(objectPath, InterfaceType::CALLOUT, anyObject);
+ calloutNum++;
+ }
+}
+
void Manager::interfaceAdded(sdbusplus::message::message& msg)
{
sdbusplus::message::object_path path;
@@ -178,6 +252,37 @@
}
}
+uint64_t Manager::getLogTimestamp(const DbusInterfaceMap& interfaces)
+{
+ auto interface = interfaces.find(LOGGING_IFACE);
+ if (interface != interfaces.end())
+ {
+ auto property = interface->second.find("Timestamp");
+ if (property != interface->second.end())
+ {
+ return property->second.get<uint64_t>();
+ }
+ }
+
+ return 0;
+}
+
+fs::path Manager::getSaveDir(EntryID id)
+{
+ return fs::path{ERRLOG_PERSIST_PATH} / std::to_string(id);
+}
+
+fs::path Manager::getCalloutSaveDir(EntryID id)
+{
+ return getSaveDir(id) / "callouts";
+}
+
+std::string Manager::getCalloutObjectPath(const std::string& objectPath,
+ uint32_t calloutNum)
+{
+ return fs::path{objectPath} / "callouts" / std::to_string(calloutNum);
+}
+
void Manager::interfaceRemoved(sdbusplus::message::message& msg)
{
sdbusplus::message::object_path path;
diff --git a/manager.hpp b/manager.hpp
index 0c8a095..b84a4c7 100644
--- a/manager.hpp
+++ b/manager.hpp
@@ -124,6 +124,47 @@
const DbusInterfaceMap& interfaces);
/**
+ * Returns the error log timestamp property value from
+ * the passed in map of all interfaces and property names/values
+ * on an error log D-Bus object.
+ *
+ * @param[in] interfaces - map of all interfaces and properties
+ * on a phosphor-logging error log.
+ *
+ * @return uint64_t - the timestamp
+ */
+ uint64_t getLogTimestamp(const DbusInterfaceMap& interfaces);
+
+ /**
+ * Returns the filesystem directory to use for persisting
+ * information about a particular error log.
+ *
+ * @param[in] id - the error log ID
+ * @return path - the directory path
+ */
+ std::experimental::filesystem::path getSaveDir(EntryID id);
+
+ /**
+ * Returns the directory to use to save the callout information in
+ *
+ * @param[in] id - the error log ID
+ *
+ * @return path - the directory path
+ */
+ std::experimental::filesystem::path getCalloutSaveDir(EntryID id);
+
+ /**
+ * Returns the D-Bus object path to use for a callout D-Bus object.
+ *
+ * @param[in] objectPath - the object path for the error log
+ * @param[in] calloutNum - the callout instance number
+ *
+ * @return path - the object path to use for a callout object
+ */
+ std::string getCalloutObjectPath(const std::string& objectPath,
+ uint32_t calloutNum);
+
+ /**
* Creates the IBM policy interface for a single error log
* and saves it in the list of interfaces.
*
@@ -137,6 +178,25 @@
#endif
/**
+ * Creates D-Bus objects for any callouts in an error log
+ * that map to an inventory object with an Asset interface.
+ *
+ * The created object will also host the Asset interface.
+ *
+ * A callout object path would look like:
+ * /xyz/openbmc_project/logging/entry/5/callouts/0.
+ *
+ * Any objects created are serialized so the asset information
+ * can always be restored.
+ *
+ * @param[in] objectPath - object path of the error log
+ * @param[in] interfaces - map of all interfaces and properties
+ * on a phosphor-logging error log.
+ */
+ void createCalloutObjects(const std::string& objectPath,
+ const DbusInterfaceMap& interfaces);
+
+ /**
* Returns the entry ID for a log
*
* @param[in] objectPath - the object path of the log