summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Spinler <spinler@us.ibm.com>2019-07-18 16:09:49 -0500
committerMatt Spinler <spinler@us.ibm.com>2019-08-05 12:49:54 -0500
commit475e574da95a75af6001fdc2198c1892c1bfc041 (patch)
tree300ad665175938de6b3b7a069b04b2cb3bf57260
parent89fa082a68c975128db6fa96eab33200c6bc7bb6 (diff)
downloadphosphor-logging-475e574da95a75af6001fdc2198c1892c1bfc041.tar.gz
phosphor-logging-475e574da95a75af6001fdc2198c1892c1bfc041.zip
PEL: Remove a PEL based on an ID
When someone deletes an OpenBMC event log, the corresponding PEL should also be deleted. This commit adds support for that by keeping an internal map of the IDs to the files that contain the PEL data in the repository in order to find the file to remove. This will then get called in the phosphor-logging extension's delete hook. The actual map key is a structure of both the PEL ID and OpenBMC log ID, so either can be used to find a PEL in the repository, which will be useful in other cases, for example for retrieving PEL data based on the PEL ID. As the map needs to match the actual repository file contents, it will get built on startup, and modified when PELs are added and removed. Signed-off-by: Matt Spinler <spinler@us.ibm.com> Change-Id: I33bb96da297c770e175c5c6b19705dda1c8766b6
-rw-r--r--extensions/openpower-pels/manager.cpp3
-rw-r--r--extensions/openpower-pels/repository.cpp58
-rw-r--r--extensions/openpower-pels/repository.hpp109
-rw-r--r--test/openpower-pels/pel_manager_test.cpp16
-rw-r--r--test/openpower-pels/repository_test.cpp67
5 files changed, 253 insertions, 0 deletions
diff --git a/extensions/openpower-pels/manager.cpp b/extensions/openpower-pels/manager.cpp
index a009188..ef071bd 100644
--- a/extensions/openpower-pels/manager.cpp
+++ b/extensions/openpower-pels/manager.cpp
@@ -94,6 +94,9 @@ void Manager::addRawPEL(const std::string& rawPelPath, uint32_t obmcLogID)
void Manager::erase(uint32_t obmcLogID)
{
+ Repository::LogID id{Repository::LogID::Obmc(obmcLogID)};
+
+ _repo.remove(id);
}
bool Manager::isDeleteProhibited(uint32_t obmcLogID)
diff --git a/extensions/openpower-pels/repository.cpp b/extensions/openpower-pels/repository.cpp
index c9f9521..aa6a18b 100644
--- a/extensions/openpower-pels/repository.cpp
+++ b/extensions/openpower-pels/repository.cpp
@@ -20,6 +20,50 @@ Repository::Repository(const std::filesystem::path& basePath) :
{
fs::create_directories(_logPath);
}
+
+ restore();
+}
+
+void Repository::restore()
+{
+ for (auto& dirEntry : fs::directory_iterator(_logPath))
+ {
+ try
+ {
+ if (!fs::is_regular_file(dirEntry.path()))
+ {
+ continue;
+ }
+
+ std::ifstream file{dirEntry.path()};
+ std::vector<uint8_t> data{std::istreambuf_iterator<char>(file),
+ std::istreambuf_iterator<char>()};
+ file.close();
+
+ PEL pel(std::move(data));
+ if (pel.valid())
+ {
+ using pelID = LogID::Pel;
+ using obmcID = LogID::Obmc;
+ _idsToPELs.emplace(
+ LogID(pelID(pel.id()), obmcID(pel.obmcLogID())),
+ dirEntry.path());
+ }
+ else
+ {
+ log<level::ERR>(
+ "Found invalid PEL file while restoring. Removing.",
+ entry("FILENAME=%s", dirEntry.path().c_str()));
+ fs::remove(dirEntry.path());
+ }
+ }
+ catch (std::exception& e)
+ {
+ log<level::ERR>("Hit exception while restoring PEL File",
+ entry("FILENAME=%s", dirEntry.path().c_str()),
+ entry("ERROR=%s", e.what()));
+ }
+ }
}
std::string Repository::getPELFilename(uint32_t pelID, const BCDTime& time)
@@ -65,6 +109,20 @@ void Repository::add(std::unique_ptr<PEL>& pel)
entry("PATH=%s", path.c_str()));
throw file_error::Write();
}
+
+ using pelID = LogID::Pel;
+ using obmcID = LogID::Obmc;
+ _idsToPELs.emplace(LogID(pelID(pel->id()), obmcID(pel->obmcLogID())), path);
+}
+
+void Repository::remove(const LogID& id)
+{
+ auto pel = findPEL(id);
+ if (pel != _idsToPELs.end())
+ {
+ fs::remove(pel->second);
+ _idsToPELs.erase(pel);
+ }
}
} // namespace pels
diff --git a/extensions/openpower-pels/repository.hpp b/extensions/openpower-pels/repository.hpp
index 5b15506..289541c 100644
--- a/extensions/openpower-pels/repository.hpp
+++ b/extensions/openpower-pels/repository.hpp
@@ -4,6 +4,7 @@
#include <algorithm>
#include <filesystem>
+#include <map>
namespace openpower
{
@@ -18,6 +19,72 @@ namespace pels
class Repository
{
public:
+ /**
+ * @brief A structure that holds both the PEL and corresponding
+ * OpenBMC IDs.
+ * Used for correlating the IDs with their data files for quick
+ * lookup. To find a PEL based on just one of the IDs, just use
+ * the constructor that takes that ID.
+ */
+ struct LogID
+ {
+ struct Pel
+ {
+ uint32_t id;
+ explicit Pel(uint32_t i) : id(i)
+ {
+ }
+ };
+ struct Obmc
+ {
+ uint32_t id;
+ explicit Obmc(uint32_t i) : id(i)
+ {
+ }
+ };
+
+ Pel pelID;
+
+ Obmc obmcID;
+
+ LogID(Pel pel, Obmc obmc) : pelID(pel), obmcID(obmc)
+ {
+ }
+
+ explicit LogID(Pel id) : pelID(id), obmcID(0)
+ {
+ }
+
+ explicit LogID(Obmc id) : pelID(0), obmcID(id)
+ {
+ }
+
+ LogID() = delete;
+
+ /**
+ * @brief A == operator that will match on either ID
+ * being equal if the other is zero, so that
+ * one can look up a PEL with just one of the IDs.
+ */
+ bool operator==(const LogID& id) const
+ {
+ if (id.pelID.id != 0)
+ {
+ return id.pelID.id == pelID.id;
+ }
+ if (id.obmcID.id != 0)
+ {
+ return id.obmcID.id == obmcID.id;
+ }
+ return false;
+ }
+
+ bool operator<(const LogID& id) const
+ {
+ return pelID.id < id.pelID.id;
+ }
+ };
+
Repository() = delete;
~Repository() = default;
Repository(const Repository&) = default;
@@ -42,6 +109,13 @@ class Repository
void add(std::unique_ptr<PEL>& pel);
/**
+ * @brief Removes a PEL from the repository
+ *
+ * @param[in] id - the ID (either the pel ID, OBMC ID, or both) to remove
+ */
+ void remove(const LogID& id);
+
+ /**
* @brief Generates the filename to use for the PEL ID and BCDTime.
*
* @param[in] pelID - the PEL ID
@@ -51,11 +125,46 @@ class Repository
*/
static std::string getPELFilename(uint32_t pelID, const BCDTime& time);
+ /**
+ * @brief Returns true if the PEL with the specified ID is in the repo.
+ *
+ * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
+ * @return bool - true if that PEL is present
+ */
+ inline bool hasPEL(const LogID& id)
+ {
+ return findPEL(id) != _idsToPELs.end();
+ }
+
private:
/**
+ * @brief Finds an entry in the _idsToPELs map.
+ *
+ * @param[in] id - the ID (either the pel ID, OBMC ID, or both)
+ *
+ * @return an iterator to the entry
+ */
+ std::map<LogID, std::filesystem::path>::iterator findPEL(const LogID& id)
+ {
+ return std::find_if(_idsToPELs.begin(), _idsToPELs.end(),
+ [&id](const auto& i) { return i.first == id; });
+ }
+
+ /**
+ * @brief Restores the _idsToPELs map on startup based on the existing
+ * PEL data files.
+ */
+ void restore();
+
+ /**
* @brief The filesystem path to the PEL logs.
*/
const std::filesystem::path _logPath;
+
+ /**
+ * @brief A map of the PEL/OBMC IDs to the PEL data files.
+ */
+ std::map<LogID, std::filesystem::path> _idsToPELs;
};
} // namespace pels
diff --git a/test/openpower-pels/pel_manager_test.cpp b/test/openpower-pels/pel_manager_test.cpp
index a5b16f5..9d788c9 100644
--- a/test/openpower-pels/pel_manager_test.cpp
+++ b/test/openpower-pels/pel_manager_test.cpp
@@ -62,5 +62,21 @@ TEST_F(ManagerTest, TestCreateWithPEL)
EXPECT_TRUE(found);
+ // Now remove it based on its OpenBMC event log ID
+ manager.erase(42);
+
+ found = false;
+
+ for (auto& f : fs::directory_iterator(getPELRepoPath() / "logs"))
+ {
+ if (std::regex_search(f.path().string(), expr))
+ {
+ found = true;
+ break;
+ }
+ }
+
+ EXPECT_FALSE(found);
+
fs::remove_all(pelFilename.parent_path());
}
diff --git a/test/openpower-pels/repository_test.cpp b/test/openpower-pels/repository_test.cpp
index 97019e8..6963184 100644
--- a/test/openpower-pels/repository_test.cpp
+++ b/test/openpower-pels/repository_test.cpp
@@ -71,3 +71,70 @@ TEST_F(RepositoryTest, AddTest)
auto pelData = pel->data();
EXPECT_EQ(*newData, pelData);
}
+
+TEST_F(RepositoryTest, RestoreTest)
+{
+ using pelID = Repository::LogID::Pel;
+ using obmcID = Repository::LogID::Obmc;
+
+ std::vector<Repository::LogID> ids;
+
+ {
+ Repository repo{repoPath};
+
+ // Add some PELs to the repository
+ {
+ auto data = pelDataFactory(TestPelType::pelSimple);
+ auto pel = std::make_unique<PEL>(*data, 1);
+ pel->assignID();
+ repo.add(pel);
+ ids.emplace_back(pelID(pel->id()), obmcID(1));
+ }
+ {
+ auto data = pelDataFactory(TestPelType::pelSimple);
+ auto pel = std::make_unique<PEL>(*data, 2);
+ pel->assignID();
+ repo.add(pel);
+ ids.emplace_back(pelID(pel->id()), obmcID(2));
+ }
+
+ // Check they're there
+ EXPECT_TRUE(repo.hasPEL(ids[0]));
+ EXPECT_TRUE(repo.hasPEL(ids[1]));
+
+ // Do some other search tests while we're here.
+
+ // Search based on PEL ID
+ Repository::LogID id(pelID(ids[0].pelID));
+ EXPECT_TRUE(repo.hasPEL(id));
+
+ // Search based on OBMC log ID
+ id.pelID.id = 0;
+ id.obmcID = ids[0].obmcID;
+ EXPECT_TRUE(repo.hasPEL(id));
+
+ // ... based on the other PEL ID
+ id.pelID = ids[1].pelID;
+ id.obmcID.id = 0;
+ EXPECT_TRUE(repo.hasPEL(id));
+
+ // Not found
+ id.pelID.id = 99;
+ id.obmcID.id = 100;
+ EXPECT_FALSE(repo.hasPEL(id));
+ }
+
+ {
+ // Restore and check they're still there, then
+ // remove them.
+ Repository repo{repoPath};
+ EXPECT_TRUE(repo.hasPEL(ids[0]));
+ EXPECT_TRUE(repo.hasPEL(ids[1]));
+
+ repo.remove(ids[0]);
+ EXPECT_FALSE(repo.hasPEL(ids[0]));
+
+ repo.remove(ids[1]);
+ EXPECT_FALSE(repo.hasPEL(ids[1]));
+ }
+}
OpenPOWER on IntegriCloud