Add storage utilization functions
1. Add "path" in HealthConfig for storage and inode functions.
2. Add storage and inode functions to calculate each utilization by
"path" (filesystem path).
Tested: verified the storage object path will auto generate when
bmc_health_config.json setting correct and collect the storage utilization.
Signed-off-by: Bruce Lee <Bruce_Lee@quantatw.com>
Change-Id: I4a8fb51b5e85190f908a40d9bf0545ec8167923a
diff --git a/healthMonitor.cpp b/healthMonitor.cpp
index 361fe74..dac0751 100644
--- a/healthMonitor.cpp
+++ b/healthMonitor.cpp
@@ -13,6 +13,7 @@
extern "C"
{
+#include <sys/statvfs.h>
#include <sys/sysinfo.h>
}
@@ -41,8 +42,10 @@
NUM_CPU_STATES_TIME
};
-double readCPUUtilization()
+double readCPUUtilization(std::string path)
{
+ /* Unused var: path */
+ std::ignore = path;
std::ifstream fileStat("/proc/stat");
if (!fileStat.is_open())
{
@@ -107,8 +110,10 @@
return activePercValue;
}
-double readMemoryUtilization()
+double readMemoryUtilization(std::string path)
{
+ /* Unused var: path */
+ std::ignore = path;
struct sysinfo s_info;
sysinfo(&s_info);
@@ -127,9 +132,82 @@
return memUsePerc;
}
+double readStorageUtilization(std::string path)
+{
+
+ struct statvfs buffer
+ {};
+ int ret = statvfs(path.c_str(), &buffer);
+ double total = 0;
+ double available = 0;
+ double used = 0;
+ double usedPercentage = 0;
+
+ if (ret != 0)
+ {
+ auto e = errno;
+ std::cerr << "Error from statvfs" << e << std::endl;
+ return 0;
+ }
+
+ total = buffer.f_blocks * (buffer.f_frsize / 1024);
+ available = buffer.f_bfree * (buffer.f_frsize / 1024);
+ used = total - available;
+ usedPercentage = (used / total) * 100;
+
+ if (DEBUG)
+ {
+ std::cout << "Total:" << total << "\n";
+ std::cout << "Available:" << available << "\n";
+ std::cout << "Used:" << used << "\n";
+ std::cout << "Storage utilization is:" << usedPercentage << "\n";
+ }
+
+ return usedPercentage;
+}
+
+double readInodeUtilization(std::string path)
+{
+
+ struct statvfs buffer
+ {};
+ int ret = statvfs(path.c_str(), &buffer);
+ double totalInodes = 0;
+ double availableInodes = 0;
+ double used = 0;
+ double usedPercentage = 0;
+
+ if (ret != 0)
+ {
+ auto e = errno;
+ std::cerr << "Error from statvfs" << e << std::endl;
+ return 0;
+ }
+
+ totalInodes = buffer.f_files;
+ availableInodes = buffer.f_ffree;
+ used = totalInodes - availableInodes;
+ usedPercentage = (used / totalInodes) * 100;
+
+ if (DEBUG)
+ {
+ std::cout << "Total Inodes:" << totalInodes << "\n";
+ std::cout << "Available Inodes:" << availableInodes << "\n";
+ std::cout << "Used:" << used << "\n";
+ std::cout << "Inodes utilization is:" << usedPercentage << "\n";
+ }
+
+ return usedPercentage;
+}
+
+constexpr auto storage = "Storage";
+constexpr auto inode = "Inode";
/** Map of read function for each health sensors supported */
-std::map<std::string, std::function<double()>> readSensors = {
- {"CPU", readCPUUtilization}, {"Memory", readMemoryUtilization}};
+const std::map<std::string, std::function<double(std::string path)>>
+ readSensors = {{"CPU", readCPUUtilization},
+ {"Memory", readMemoryUtilization},
+ {storage, readStorageUtilization},
+ {inode, readInodeUtilization}};
void HealthSensor::setSensorThreshold(double criticalHigh, double warningHigh)
{
@@ -147,15 +225,27 @@
std::string logMsg = sensorConfig.name + " Health Sensor initialized";
log<level::INFO>(logMsg.c_str());
- /* Look for sensor read functions */
- if (readSensors.find(sensorConfig.name) == readSensors.end())
+ /* Look for sensor read functions and Read Sensor values */
+ double value;
+ std::map<std::string,
+ std::function<double(std::string path)>>::const_iterator it;
+ it = readSensors.find(sensorConfig.name);
+
+ if (sensorConfig.name.rfind(storage, 0) == 0)
+ {
+ it = readSensors.find(storage);
+ }
+ else if (sensorConfig.name.rfind(inode, 0) == 0)
+ {
+ it = readSensors.find(inode);
+ }
+ else if (it == readSensors.end())
{
log<level::ERR>("Sensor read function not available");
return;
}
- /* Read Sensor values */
- auto value = readSensors[sensorConfig.name]();
+ value = it->second(sensorConfig.path);
if (value < 0)
{
@@ -231,7 +321,21 @@
void HealthSensor::readHealthSensor()
{
/* Read current sensor value */
- double value = readSensors[sensorConfig.name]();
+ double value;
+
+ if (sensorConfig.name.rfind(storage, 0) == 0)
+ {
+ value = readSensors.find(storage)->second(sensorConfig.path);
+ }
+ else if (sensorConfig.name.rfind(inode, 0) == 0)
+ {
+ value = readSensors.find(inode)->second(sensorConfig.path);
+ }
+ else
+ {
+ value = readSensors.find(sensorConfig.name)->second(sensorConfig.path);
+ }
+
if (value < 0)
{
log<level::ERR>("Reading Sensor Utilization failed",
@@ -267,6 +371,7 @@
std::cout << "Warning log: " << (int)cfg.warningLog << "\n";
std::cout << "Critical Target: " << cfg.criticalTgt << "\n";
std::cout << "Warning Target: " << cfg.warningTgt << "\n\n";
+ std::cout << "Path : " << cfg.path << "\n\n";
}
/* Create dbus utilization sensor object for each configured sensors */
@@ -337,6 +442,7 @@
cfg.warningTgt = warningData.value("Target", "");
}
}
+ cfg.path = data.value("Path", "");
}
std::vector<HealthConfig> HealthMon::getHealthConfig()
@@ -354,7 +460,10 @@
for (auto& j : data.items())
{
auto key = j.key();
- if (readSensors.find(key) != readSensors.end())
+ /* key need match default value in map readSensors or match the key
+ * start with "Storage" or "Inode" */
+ if (readSensors.find(key) != readSensors.end() ||
+ (key.rfind(storage, 0) == 0) || (key.rfind(inode, 0) == 0))
{
HealthConfig cfg = HealthConfig();
cfg.name = j.key();