PEL: Delete and delete all support for peltool
Delete 1 PEL:
peltool -d <id>
This is done by reading the corresponding OpenBMC event log's ID out of
the PEL, and then making the Delete D-Bus method call on that event log.
Deleting that event log will also delete the PEL.
Delete all PELs:
peltool -D
This is done by making the DeleteAll method call on
/xyz/openbmc_project/logging. This will delete all event logs and all
PELs.
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Ia807b9b515b9d5b6e04610d884fba578e01ebeb9
diff --git a/extensions/openpower-pels/tools/peltool.cpp b/extensions/openpower-pels/tools/peltool.cpp
index ef59cd7..146b8a9 100644
--- a/extensions/openpower-pels/tools/peltool.cpp
+++ b/extensions/openpower-pels/tools/peltool.cpp
@@ -32,10 +32,30 @@
namespace fs = std::filesystem;
using namespace phosphor::logging;
using namespace openpower::pels;
+using sdbusplus::exception::SdBusError;
namespace file_error = sdbusplus::xyz::openbmc_project::Common::File::Error;
namespace message = openpower::pels::message;
namespace pv = openpower::pels::pel_values;
+using PELFunc = std::function<void(const PEL&)>;
+
+namespace service
+{
+constexpr auto logging = "xyz.openbmc_project.Logging";
+} // namespace service
+
+namespace interface
+{
+constexpr auto deleteObj = "xyz.openbmc_project.Object.Delete";
+constexpr auto deleteAll = "xyz.openbmc_project.Collection.DeleteAll";
+} // namespace interface
+
+namespace object_path
+{
+constexpr auto logEntry = "/xyz/openbmc_project/logging/entry/";
+constexpr auto logging = "/xyz/openbmc_project/logging";
+} // namespace object_path
+
/**
* @brief helper function to get PEL commit timestamp from file name
* @retrun BCDTime - PEL commit timestamp
@@ -332,6 +352,122 @@
}
}
+/**
+ * @brief Calls the function passed in on the PEL with the ID
+ * passed in.
+ *
+ * @param[in] id - The string version of the PEL ID, either with or
+ * without the 0x prefix.
+ * @param[in] func - The std::function<void(const PEL&)> function to run.
+ */
+void callFunctionOnPEL(const std::string& id, const PELFunc& func)
+{
+ std::string pelID{id};
+ std::transform(pelID.begin(), pelID.end(), pelID.begin(), toupper);
+
+ if (pelID.find("0X") == 0)
+ {
+ pelID.erase(0, 2);
+ }
+
+ bool found = false;
+
+ for (auto it = fs::directory_iterator(EXTENSION_PERSIST_DIR "/pels/logs");
+ it != fs::directory_iterator(); ++it)
+ {
+ // The PEL ID is part of the filename, so use that to find the PEL.
+
+ if (!fs::is_regular_file((*it).path()))
+ {
+ continue;
+ }
+
+ if (ends_with((*it).path(), pelID))
+ {
+ found = true;
+
+ auto data = getFileData((*it).path());
+ if (!data.empty())
+ {
+ PEL pel{data};
+
+ try
+ {
+ func(pel);
+ }
+ catch (std::exception& e)
+ {
+ std::cerr
+ << " Internal function threw an exception: " << e.what()
+ << "\n";
+ exit(1);
+ }
+ }
+ else
+ {
+ std::cerr << "Could not read PEL file\n";
+ exit(1);
+ }
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ std::cerr << "PEL not found\n";
+ exit(1);
+ }
+}
+
+/**
+ * @brief Delete a PEL by deleting its corresponding event log.
+ *
+ * @param[in] pel - The PEL to delete
+ */
+void deletePEL(const PEL& pel)
+{
+ std::string path{object_path::logEntry};
+ path += std::to_string(pel.obmcLogID());
+
+ try
+ {
+ auto bus = sdbusplus::bus::new_default();
+ auto method = bus.new_method_call(service::logging, path.c_str(),
+ interface::deleteObj, "Delete");
+ auto reply = bus.call(method);
+ }
+ catch (const SdBusError& e)
+ {
+ std::cerr << "D-Bus call to delete event log " << pel.obmcLogID()
+ << " failed: " << e.what() << "\n";
+ exit(1);
+ }
+}
+
+/**
+ * @brief Delete all PELs by deleting all event logs.
+ */
+void deleteAllPELs()
+{
+ try
+ {
+ // This may move to an audit log some day
+ log<level::INFO>("peltool deleting all event logs");
+
+ auto bus = sdbusplus::bus::new_default();
+ auto method =
+ bus.new_method_call(service::logging, object_path::logging,
+ interface::deleteAll, "DeleteAll");
+ auto reply = bus.call(method);
+ }
+ catch (const SdBusError& e)
+ {
+ std::cerr << "D-Bus call to delete all event logs failed: " << e.what()
+ << "\n";
+ exit(1);
+ }
+}
+
static void exitWithError(const std::string& help, const char* err)
{
std::cerr << "ERROR: " << err << std::endl << help << std::endl;
@@ -343,15 +479,21 @@
CLI::App app{"OpenBMC PEL Tool"};
std::string fileName;
std::string idPEL;
+ std::string idToDelete;
bool listPEL = false;
bool listPELDescOrd = false;
bool listPELShowHidden = false;
+ bool deleteAll = false;
+
app.add_option("-f,--file", fileName,
"Display a PEL using its Raw PEL file");
app.add_option("-i, --id", idPEL, "Display a PEL based on its ID");
app.add_flag("-l", listPEL, "List PELs");
app.add_flag("-r", listPELDescOrd, "Reverse order of output");
app.add_flag("-s", listPELShowHidden, "Show hidden PELs");
+ app.add_option("-d, --delete", idToDelete, "Delete a PEL based on its ID");
+ app.add_flag("-D, --delete-all", deleteAll, "Delete all PELs");
+
CLI11_PARSE(app, argc, argv);
if (!fileName.empty())
@@ -422,6 +564,14 @@
printList(listPELDescOrd, listPELShowHidden);
}
+ else if (!idToDelete.empty())
+ {
+ callFunctionOnPEL(idToDelete, deletePEL);
+ }
+ else if (deleteAll)
+ {
+ deleteAllPELs();
+ }
else
{
exitWithError(app.help("", CLI::AppFormatMode::All),