PEL: Deleted PELs moved to new folder under logs
- PELs whose corresponding event logs have been deleted
will be available in the archive folder.
- Archive folder size is tracked under sizeWarning() function.
- Archived PELs log can be viewed using peltool with flag --archive.
- PELs deleted using peltool is not archived.
- Updated README.md
Change-Id: Ie2c1b4c2ca30fb79904bc9d582a01ef8102aed0e
Signed-off-by: Sumit Kumar <sumit_kumar@in.ibm.com>
diff --git a/extensions/openpower-pels/README.md b/extensions/openpower-pels/README.md
index 9c13374..637a389 100644
--- a/extensions/openpower-pels/README.md
+++ b/extensions/openpower-pels/README.md
@@ -686,4 +686,18 @@
Note: "phal" build-time configure option should be "enabled" to enable this
feature.
+## PEL Archiving
+
+When an OpenBMC event log is deleted its corresponding PEL is moved to
+an archive folder. These archived PELs will be available in BMC dump.
+The archive path: /var/lib/phosphor-logging/extensions/pels/logs/archive.
+
+Highlighted points are:
+- PELs whose corresponding event logs have been deleted will be available
+ in the archive folder.
+- Archive folder size is tracked along with logs folder size and if
+ combined size exceeds warning size all archived PELs will be deleted.
+- Archived PEL logs can be viewed using peltool with flag --archive.
+- If a PEL is deleted using peltool its not archived.
+
[1]: https://github.com/openbmc/docs/blob/master/designs/fail-boot-on-hw-error.md
diff --git a/extensions/openpower-pels/repository.cpp b/extensions/openpower-pels/repository.cpp
index fd5c238..f552a75 100644
--- a/extensions/openpower-pels/repository.cpp
+++ b/extensions/openpower-pels/repository.cpp
@@ -61,13 +61,19 @@
Repository::Repository(const std::filesystem::path& basePath, size_t repoSize,
size_t maxNumPELs) :
_logPath(basePath / "logs"),
- _maxRepoSize(repoSize), _maxNumPELs(maxNumPELs)
+ _maxRepoSize(repoSize), _maxNumPELs(maxNumPELs),
+ _archivePath(basePath / "logs" / "archive")
{
if (!fs::exists(_logPath))
{
fs::create_directories(_logPath);
}
+ if (!fs::exists(_archivePath))
+ {
+ fs::create_directories(_archivePath);
+ }
+
restore();
}
@@ -138,6 +144,12 @@
entry("ERROR=%s", e.what()));
}
}
+
+ // Get size of archive folder
+ for (auto& dirEntry : fs::directory_iterator(_archivePath))
+ {
+ _archiveSize += getFileDiskSize(dirEntry);
+ }
}
std::string Repository::getPELFilename(uint32_t pelID, const BCDTime& time)
@@ -223,7 +235,23 @@
log<level::DEBUG>("Removing PEL from repository",
entry("PEL_ID=0x%X", actualID.pelID.id),
entry("OBMC_LOG_ID=%d", actualID.obmcID.id));
- fs::remove(pel->second.path);
+
+ if (fs::exists(pel->second.path))
+ {
+ // Check for existense of new archive folder
+ if (!fs::exists(_archivePath))
+ {
+ fs::create_directories(_archivePath);
+ }
+
+ // Move log file to archive folder
+ auto fileName = _archivePath / pel->second.path.filename();
+ fs::rename(pel->second.path, fileName);
+
+ // Update size of file
+ _archiveSize += getFileDiskSize(fileName);
+ }
+
_pelAttributes.erase(pel);
processDeleteCallbacks(actualID.pelID.id);
@@ -504,6 +532,21 @@
bool Repository::sizeWarning() const
{
+ if ((_archiveSize > 0) && ((_sizes.total + _archiveSize) >
+ ((_maxRepoSize * warningPercentage) / 100)))
+ {
+ log<level::INFO>(
+ "Repository::sizeWarning function:Deleting the files in archive");
+
+ std::string cmd = "rm " + _archivePath.string() + "/*_*";
+ auto rc = system(cmd.c_str());
+ if (rc)
+ {
+ log<level::ERR>("Repository::sizeWarning function:Could not delete "
+ "files in archive");
+ }
+ }
+
return (_sizes.total > (_maxRepoSize * warningPercentage / 100)) ||
(_pelAttributes.size() > _maxNumPELs);
}
diff --git a/extensions/openpower-pels/repository.hpp b/extensions/openpower-pels/repository.hpp
index e2f497b..31c569c 100644
--- a/extensions/openpower-pels/repository.hpp
+++ b/extensions/openpower-pels/repository.hpp
@@ -575,6 +575,16 @@
* @brief The ID of the most recently added PEL.
*/
uint32_t _lastPelID = 0;
+
+ /**
+ * @brief The filesystem path to the archive PEL logs.
+ */
+ const std::filesystem::path _archivePath;
+
+ /**
+ * @brief The size of archive folder.
+ */
+ uint64_t _archiveSize = 0;
};
} // namespace pels
diff --git a/extensions/openpower-pels/tools/peltool.cpp b/extensions/openpower-pels/tools/peltool.cpp
index fcea8af..6dc2ef0 100644
--- a/extensions/openpower-pels/tools/peltool.cpp
+++ b/extensions/openpower-pels/tools/peltool.cpp
@@ -289,7 +289,8 @@
std::string genPELJSON(T itr, bool hidden, bool includeInfo, bool critSysTerm,
bool fullPEL, bool& foundPEL,
const std::optional<std::regex>& scrubRegex,
- const std::vector<std::string>& plugins, bool hexDump)
+ const std::vector<std::string>& plugins, bool hexDump,
+ bool archive)
{
std::size_t found;
std::string val;
@@ -300,7 +301,7 @@
itr.second.yearLSB, itr.second.month, itr.second.day,
itr.second.hour, itr.second.minutes, itr.second.seconds,
itr.second.hundredths, itr.first);
- auto fileName = pelLogDir() + name;
+ auto fileName = (archive ? pelLogDir() + "/archive" : pelLogDir()) + name;
try
{
std::vector<uint8_t> data = getFileData(fileName);
@@ -450,13 +451,14 @@
*/
void printPELs(bool order, bool hidden, bool includeInfo, bool critSysTerm,
bool fullPEL, const std::optional<std::regex>& scrubRegex,
- bool hexDump)
+ bool hexDump, bool archive = false)
{
std::string listStr;
std::map<uint32_t, BCDTime> PELs;
std::vector<std::string> plugins;
listStr = "{\n";
- for (auto it = fs::directory_iterator(pelLogDir());
+ for (auto it = (archive ? fs::directory_iterator(pelLogDir() + "/archive")
+ : fs::directory_iterator(pelLogDir()));
it != fs::directory_iterator(); ++it)
{
if (!fs::is_regular_file((*it).path()))
@@ -469,6 +471,7 @@
fileNameToTimestamp((*it).path().filename()));
}
}
+
bool foundPEL = false;
if (fullPEL && !hexDump)
@@ -476,10 +479,10 @@
plugins = getPlugins();
}
auto buildJSON = [&listStr, &hidden, &includeInfo, &critSysTerm, &fullPEL,
- &foundPEL, &scrubRegex, &plugins,
- &hexDump](const auto& i) {
+ &foundPEL, &scrubRegex, &plugins, &hexDump,
+ &archive](const auto& i) {
listStr += genPELJSON(i, hidden, includeInfo, critSysTerm, fullPEL,
- foundPEL, scrubRegex, plugins, hexDump);
+ foundPEL, scrubRegex, plugins, hexDump, archive);
};
if (order)
{
@@ -530,7 +533,8 @@
* @param[in] hexDump - Boolean to print hexdump of PEL instead of JSON
*/
void callFunctionOnPEL(const std::string& id, const PELFunc& func,
- bool useBMC = false, bool hexDump = false)
+ bool useBMC = false, bool hexDump = false,
+ bool archive = false)
{
std::string pelID{id};
if (!useBMC)
@@ -545,7 +549,8 @@
bool found = false;
- for (auto it = fs::directory_iterator(pelLogDir());
+ for (auto it = (archive ? fs::directory_iterator(pelLogDir() + "/archive")
+ : fs::directory_iterator(pelLogDir()));
it != fs::directory_iterator(); ++it)
{
// The PEL ID is part of the filename, so use that to find the PEL if
@@ -629,6 +634,10 @@
for (const auto& entry : fs::directory_iterator(pelLogDir()))
{
+ if (!fs::is_regular_file(entry.path()))
+ {
+ continue;
+ }
fs::remove(entry.path());
}
}
@@ -820,6 +829,7 @@
bool showPELCount = false;
bool fullPEL = false;
bool hexDump = false;
+ bool archive = false;
app.set_help_flag("--help", "Print this help message and exit");
app.add_option("--file", fileName, "Display a PEL using its Raw PEL file");
@@ -839,6 +849,7 @@
app.add_option("-s, --scrub", scrubFile,
"File containing SRC regular expressions to ignore");
app.add_flag("-x", hexDump, "Display PEL(s) in hexdump instead of JSON");
+ app.add_flag("--archive", archive, "List or display archived PELs");
CLI11_PARSE(app, argc, argv);
@@ -868,11 +879,11 @@
}
else if (!idPEL.empty())
{
- callFunctionOnPEL(idPEL, displayPEL, false, hexDump);
+ callFunctionOnPEL(idPEL, displayPEL, false, hexDump, archive);
}
else if (!bmcId.empty())
{
- callFunctionOnPEL(bmcId, displayPEL, true, hexDump);
+ callFunctionOnPEL(bmcId, displayPEL, true, hexDump, archive);
}
else if (fullPEL || listPEL)
{
@@ -881,7 +892,7 @@
scrubRegex = genRegex(scrubFile);
}
printPELs(listPELDescOrd, hidden, includeInfo, critSysTerm, fullPEL,
- scrubRegex, hexDump);
+ scrubRegex, hexDump, archive);
}
else if (showPELCount)
{
diff --git a/test/openpower-pels/pel_manager_test.cpp b/test/openpower-pels/pel_manager_test.cpp
index 9285c13..cd940ff 100644
--- a/test/openpower-pels/pel_manager_test.cpp
+++ b/test/openpower-pels/pel_manager_test.cpp
@@ -816,7 +816,7 @@
// Delete them all at once
auto logPath = getPELRepoPath() / "logs";
- std::string cmd = "rm " + logPath.string() + "/*";
+ std::string cmd = "rm " + logPath.string() + "/*_*";
{
auto rc = system(cmd.c_str());
diff --git a/test/openpower-pels/repository_test.cpp b/test/openpower-pels/repository_test.cpp
index f1a4a31..42a921b 100644
--- a/test/openpower-pels/repository_test.cpp
+++ b/test/openpower-pels/repository_test.cpp
@@ -868,3 +868,95 @@
EXPECT_TRUE(repo.sizeWarning());
}
+
+// Test existense of archive file
+TEST_F(RepositoryTest, TestArchiveFile)
+{
+ using pelID = Repository::LogID::Pel;
+ using obmcID = Repository::LogID::Obmc;
+
+ // Add and remove a PEL from the repo
+
+ Repository repo{repoPath};
+
+ fs::path archivePath = repoPath / "logs" / "archive";
+ EXPECT_TRUE(fs::exists(archivePath));
+
+ auto data = pelDataFactory(TestPELType::pelSimple);
+ auto pel = std::make_unique<PEL>(data, 1);
+
+ pel->assignID();
+ Repository::LogID id{pelID{pel->id()}, obmcID{pel->obmcLogID()}};
+
+ repo.add(pel);
+
+ auto path = repoPath / "logs" /
+ Repository::getPELFilename(pel->id(), pel->commitTime());
+ EXPECT_TRUE(fs::exists(path));
+
+ auto removedID = repo.remove(id);
+ ASSERT_TRUE(removedID);
+ EXPECT_EQ(*removedID, id);
+
+ archivePath /= Repository::getPELFilename(pel->id(), pel->commitTime());
+ EXPECT_TRUE(fs::exists(archivePath));
+
+ EXPECT_FALSE(repo.hasPEL(id));
+}
+
+// Test archive folder size with sizeWarning function
+TEST_F(RepositoryTest, TestArchiveSize)
+{
+ using pelID = Repository::LogID::Pel;
+ using obmcID = Repository::LogID::Obmc;
+
+ // Create repo with max PEL=500 and space=4096*100
+ Repository repo{repoPath, 100 * 4096, 500};
+
+ // Fill 94% (disk size for these is 4096)
+ for (uint32_t i = 1; i <= 94; i++)
+ {
+ auto data = pelFactory(i, 'O', 0x20, 0x8800, 500);
+ auto pel = std::make_unique<PEL>(data);
+ repo.add(pel);
+ }
+
+ // Add another PEL which makes 95% still ok
+ auto data = pelDataFactory(TestPELType::pelSimple);
+ auto pel = std::make_unique<PEL>(data, 1);
+ pel->assignID();
+ Repository::LogID id{pelID{pel->id()}, obmcID{pel->obmcLogID()}};
+ repo.add(pel);
+
+ // With 95% full expect no size warning
+ EXPECT_FALSE(repo.sizeWarning());
+
+ // Remove last created PEL
+ repo.remove(id);
+
+ // Repo is 94% full with one PEL in archive log
+ // Total repo size 95% full (including archive) still ok
+ EXPECT_FALSE(repo.sizeWarning());
+
+ // Confirm the repo size 94% full
+ const auto& sizes = repo.getSizeStats();
+ EXPECT_EQ(sizes.total, 4096 * 94);
+
+ // Make sure archive contain the one deleted file
+ fs::path archivePath = repoPath / "logs" / "archive";
+ archivePath /= Repository::getPELFilename(pel->id(), pel->commitTime());
+ EXPECT_TRUE(fs::exists(archivePath));
+
+ // Add another PEL which makes repo 95% full
+ data = pelDataFactory(TestPELType::pelSimple);
+ pel = std::make_unique<PEL>(data, 1);
+ pel->assignID();
+ Repository::LogID idx{pelID{pel->id()}, obmcID{pel->obmcLogID()}};
+ repo.add(pel);
+
+ // Repo with 95% full + one archive file becomes 96%
+ // which is greater than the warning
+ // expect archive file to be deleted to get repo size back to 95%
+ EXPECT_FALSE(repo.sizeWarning());
+ EXPECT_FALSE(fs::exists(archivePath));
+}