blob: aaa27ee02b5625a3d94229b5a1929cbb4c6cf301 [file] [log] [blame]
Vijay Khemkae2795302020-07-15 17:28:45 -07001#include "config.h"
2
3#include "healthMonitor.hpp"
4
Sui Chen036f1612021-07-22 01:31:49 -07005#include <unistd.h>
6
7#include <boost/asio/deadline_timer.hpp>
8#include <sdbusplus/asio/connection.hpp>
9#include <sdbusplus/asio/object_server.hpp>
10#include <sdbusplus/asio/sd_event.hpp>
11#include <sdbusplus/bus/match.hpp>
Vijay Khemka1d0d0122020-09-29 12:17:43 -070012#include <sdbusplus/server/manager.hpp>
Vijay Khemkae2795302020-07-15 17:28:45 -070013#include <sdeventplus/event.hpp>
14
15#include <fstream>
16#include <iostream>
Sui Chen036f1612021-07-22 01:31:49 -070017#include <memory>
Vijay Khemka15537762020-07-22 11:44:56 -070018#include <numeric>
19#include <sstream>
20
21extern "C"
22{
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +080023#include <sys/statvfs.h>
Vijay Khemka15537762020-07-22 11:44:56 -070024#include <sys/sysinfo.h>
25}
Vijay Khemkae2795302020-07-15 17:28:45 -070026
Patrick Williams957e03c2021-09-02 16:38:42 -050027PHOSPHOR_LOG2_USING;
28
Vijay Khemkae2795302020-07-15 17:28:45 -070029static constexpr bool DEBUG = false;
Vijay Khemka415dcd22020-09-21 15:58:21 -070030static constexpr uint8_t defaultHighThreshold = 100;
Vijay Khemkae2795302020-07-15 17:28:45 -070031
Sui Chen036f1612021-07-22 01:31:49 -070032// Limit sensor recreation interval to 10s
33bool needUpdate;
34static constexpr int TIMER_INTERVAL = 10;
35std::shared_ptr<boost::asio::deadline_timer> sensorRecreateTimer;
36std::shared_ptr<phosphor::health::HealthMon> healthMon;
37
38void sensorRecreateTimerCallback(
39 std::shared_ptr<boost::asio::deadline_timer> timer)
40{
41 timer->expires_from_now(boost::posix_time::seconds(TIMER_INTERVAL));
42 timer->async_wait([timer](const boost::system::error_code& ec) {
43 if (ec == boost::asio::error::operation_aborted)
44 {
45 return;
46 }
47 if (needUpdate)
48 {
49 healthMon->recreateSensors();
50 needUpdate = false;
51 }
52 sensorRecreateTimerCallback(timer);
53 });
54}
55
Vijay Khemkae2795302020-07-15 17:28:45 -070056namespace phosphor
57{
58namespace health
59{
60
Vijay Khemka15537762020-07-22 11:44:56 -070061enum CPUStatesTime
62{
63 USER_IDX = 0,
64 NICE_IDX,
65 SYSTEM_IDX,
66 IDLE_IDX,
67 IOWAIT_IDX,
68 IRQ_IDX,
69 SOFTIRQ_IDX,
70 STEAL_IDX,
71 GUEST_USER_IDX,
72 GUEST_NICE_IDX,
73 NUM_CPU_STATES_TIME
74};
75
Patrick Williams957e03c2021-09-02 16:38:42 -050076double readCPUUtilization([[maybe_unused]] std::string path)
Vijay Khemka15537762020-07-22 11:44:56 -070077{
Patrick Williams957e03c2021-09-02 16:38:42 -050078 auto proc_stat = "/proc/stat";
79 std::ifstream fileStat(proc_stat);
Vijay Khemka15537762020-07-22 11:44:56 -070080 if (!fileStat.is_open())
81 {
Patrick Williams957e03c2021-09-02 16:38:42 -050082 error("cpu file not available: {PATH}", "PATH", proc_stat);
Vijay Khemka15537762020-07-22 11:44:56 -070083 return -1;
84 }
85
86 std::string firstLine, labelName;
87 std::size_t timeData[NUM_CPU_STATES_TIME];
88
89 std::getline(fileStat, firstLine);
90 std::stringstream ss(firstLine);
91 ss >> labelName;
92
93 if (DEBUG)
94 std::cout << "CPU stats first Line is " << firstLine << "\n";
95
96 if (labelName.compare("cpu"))
97 {
Patrick Williams957e03c2021-09-02 16:38:42 -050098 error("CPU data not available");
Vijay Khemka15537762020-07-22 11:44:56 -070099 return -1;
100 }
101
102 int i;
103 for (i = 0; i < NUM_CPU_STATES_TIME; i++)
104 {
105 if (!(ss >> timeData[i]))
106 break;
107 }
108
109 if (i != NUM_CPU_STATES_TIME)
110 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500111 error("CPU data not correct");
Vijay Khemka15537762020-07-22 11:44:56 -0700112 return -1;
113 }
114
115 static double preActiveTime = 0, preIdleTime = 0;
116 double activeTime, activeTimeDiff, idleTime, idleTimeDiff, totalTime,
117 activePercValue;
118
119 idleTime = timeData[IDLE_IDX] + timeData[IOWAIT_IDX];
120 activeTime = timeData[USER_IDX] + timeData[NICE_IDX] +
121 timeData[SYSTEM_IDX] + timeData[IRQ_IDX] +
122 timeData[SOFTIRQ_IDX] + timeData[STEAL_IDX] +
123 timeData[GUEST_USER_IDX] + timeData[GUEST_NICE_IDX];
124
125 idleTimeDiff = idleTime - preIdleTime;
126 activeTimeDiff = activeTime - preActiveTime;
127
128 /* Store current idle and active time for next calculation */
129 preIdleTime = idleTime;
130 preActiveTime = activeTime;
131
132 totalTime = idleTimeDiff + activeTimeDiff;
133
134 activePercValue = activeTimeDiff / totalTime * 100;
135
136 if (DEBUG)
137 std::cout << "CPU Utilization is " << activePercValue << "\n";
138
139 return activePercValue;
140}
141
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800142double readMemoryUtilization(std::string path)
Vijay Khemka15537762020-07-22 11:44:56 -0700143{
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800144 /* Unused var: path */
145 std::ignore = path;
Potin Laib7d7bd52022-08-23 01:47:13 +0000146 std::ifstream meminfo("/proc/meminfo");
147 std::string line;
148 double memTotal = -1;
149 double memAvail = -1;
Vijay Khemka15537762020-07-22 11:44:56 -0700150
Potin Laib7d7bd52022-08-23 01:47:13 +0000151 while (std::getline(meminfo, line))
152 {
153 std::string name;
154 double value;
155 std::istringstream iss(line);
156
157 if (!(iss >> name >> value))
158 {
159 continue;
160 }
161
162 if (name.starts_with("MemTotal"))
163 {
164 memTotal = value;
165 }
166 else if (name.starts_with("MemAvailable"))
167 {
168 memAvail = value;
169 }
170 }
171
172 if (memTotal <= 0 || memAvail <= 0)
173 {
174 return std::numeric_limits<double>::quiet_NaN();
175 }
Vijay Khemka15537762020-07-22 11:44:56 -0700176
177 if (DEBUG)
178 {
Potin Laib7d7bd52022-08-23 01:47:13 +0000179 std::cout << "MemTotal: " << memTotal << " MemAvailable: " << memAvail
180 << std::endl;
Vijay Khemka15537762020-07-22 11:44:56 -0700181 }
182
Potin Laib7d7bd52022-08-23 01:47:13 +0000183 return (memTotal - memAvail) / memTotal * 100;
Vijay Khemka15537762020-07-22 11:44:56 -0700184}
185
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800186double readStorageUtilization(std::string path)
187{
188
189 struct statvfs buffer
190 {};
191 int ret = statvfs(path.c_str(), &buffer);
192 double total = 0;
193 double available = 0;
194 double used = 0;
195 double usedPercentage = 0;
196
197 if (ret != 0)
198 {
199 auto e = errno;
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800200 std::cerr << "Error from statvfs: " << strerror(e) << ",path: " << path
201 << std::endl;
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800202 return 0;
203 }
204
205 total = buffer.f_blocks * (buffer.f_frsize / 1024);
206 available = buffer.f_bfree * (buffer.f_frsize / 1024);
207 used = total - available;
208 usedPercentage = (used / total) * 100;
209
210 if (DEBUG)
211 {
212 std::cout << "Total:" << total << "\n";
213 std::cout << "Available:" << available << "\n";
214 std::cout << "Used:" << used << "\n";
215 std::cout << "Storage utilization is:" << usedPercentage << "\n";
216 }
217
218 return usedPercentage;
219}
220
221double readInodeUtilization(std::string path)
222{
223
224 struct statvfs buffer
225 {};
226 int ret = statvfs(path.c_str(), &buffer);
227 double totalInodes = 0;
228 double availableInodes = 0;
229 double used = 0;
230 double usedPercentage = 0;
231
232 if (ret != 0)
233 {
234 auto e = errno;
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800235 std::cerr << "Error from statvfs: " << strerror(e) << ",path: " << path
236 << std::endl;
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800237 return 0;
238 }
239
240 totalInodes = buffer.f_files;
241 availableInodes = buffer.f_ffree;
242 used = totalInodes - availableInodes;
243 usedPercentage = (used / totalInodes) * 100;
244
245 if (DEBUG)
246 {
247 std::cout << "Total Inodes:" << totalInodes << "\n";
248 std::cout << "Available Inodes:" << availableInodes << "\n";
249 std::cout << "Used:" << used << "\n";
250 std::cout << "Inodes utilization is:" << usedPercentage << "\n";
251 }
252
253 return usedPercentage;
254}
255
256constexpr auto storage = "Storage";
257constexpr auto inode = "Inode";
Vijay Khemka15537762020-07-22 11:44:56 -0700258/** Map of read function for each health sensors supported */
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800259const std::map<std::string, std::function<double(std::string path)>>
260 readSensors = {{"CPU", readCPUUtilization},
261 {"Memory", readMemoryUtilization},
262 {storage, readStorageUtilization},
263 {inode, readInodeUtilization}};
Vijay Khemka15537762020-07-22 11:44:56 -0700264
265void HealthSensor::setSensorThreshold(double criticalHigh, double warningHigh)
Vijay Khemkae2795302020-07-15 17:28:45 -0700266{
267 CriticalInterface::criticalHigh(criticalHigh);
Yong Lif8d79732021-03-12 09:12:19 +0800268 CriticalInterface::criticalLow(std::numeric_limits<double>::quiet_NaN());
269
Vijay Khemkae2795302020-07-15 17:28:45 -0700270 WarningInterface::warningHigh(warningHigh);
Yong Lif8d79732021-03-12 09:12:19 +0800271 WarningInterface::warningLow(std::numeric_limits<double>::quiet_NaN());
Vijay Khemkae2795302020-07-15 17:28:45 -0700272}
273
Vijay Khemka15537762020-07-22 11:44:56 -0700274void HealthSensor::setSensorValueToDbus(const double value)
Vijay Khemkae2795302020-07-15 17:28:45 -0700275{
276 ValueIface::value(value);
277}
278
Sui Chen670cc132021-04-13 09:27:22 -0700279void HealthSensor::initHealthSensor(const std::vector<std::string>& chassisIds)
Vijay Khemka15537762020-07-22 11:44:56 -0700280{
Vijay Khemka08797702020-09-21 14:53:57 -0700281 /* Initialize unit value (Percent) for utilization sensor */
282 ValueIface::unit(ValueIface::Unit::Percent);
283
Konstantin Aladyshev9d29b372021-12-21 15:45:02 +0300284 ValueIface::maxValue(100);
285 ValueIface::minValue(0);
Potin Laic82e6162022-08-02 10:22:56 +0000286 ValueIface::value(std::numeric_limits<double>::quiet_NaN());
Vijay Khemkab38fd582020-07-23 13:21:23 -0700287
Sui Chen670cc132021-04-13 09:27:22 -0700288 // Associate the sensor to chassis
289 std::vector<AssociationTuple> associationTuples;
290 for (const auto& chassisId : chassisIds)
291 {
292 associationTuples.push_back({"bmc", "all_sensors", chassisId});
293 }
294 AssociationDefinitionInterface::associations(associationTuples);
295
Vijay Khemkab38fd582020-07-23 13:21:23 -0700296 /* Start the timer for reading sensor data at regular interval */
297 readTimer.restart(std::chrono::milliseconds(sensorConfig.freq * 1000));
298}
299
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700300void HealthSensor::checkSensorThreshold(const double value)
301{
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300302 if (std::isfinite(sensorConfig.criticalHigh) &&
303 (value > sensorConfig.criticalHigh))
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700304 {
305 if (!CriticalInterface::criticalAlarmHigh())
306 {
307 CriticalInterface::criticalAlarmHigh(true);
308 if (sensorConfig.criticalLog)
Potin Lai156ecf32022-07-11 17:09:10 +0800309 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500310 error(
311 "ASSERT: sensor {SENSOR} is above the upper threshold critical high",
312 "SENSOR", sensorConfig.name);
Potin Lai156ecf32022-07-11 17:09:10 +0800313 startUnit(sensorConfig.criticalTgt);
314 }
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700315 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300316 return;
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700317 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300318
319 if (CriticalInterface::criticalAlarmHigh())
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700320 {
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300321 CriticalInterface::criticalAlarmHigh(false);
322 if (sensorConfig.criticalLog)
323 info(
324 "DEASSERT: sensor {SENSOR} is under the upper threshold critical high",
325 "SENSOR", sensorConfig.name);
326 }
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700327
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300328 if (std::isfinite(sensorConfig.warningHigh) &&
329 (value > sensorConfig.warningHigh))
330 {
331 if (!WarningInterface::warningAlarmHigh())
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700332 {
333 WarningInterface::warningAlarmHigh(true);
334 if (sensorConfig.warningLog)
Potin Lai156ecf32022-07-11 17:09:10 +0800335 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500336 error(
337 "ASSERT: sensor {SENSOR} is above the upper threshold warning high",
338 "SENSOR", sensorConfig.name);
Potin Lai156ecf32022-07-11 17:09:10 +0800339 startUnit(sensorConfig.warningTgt);
340 }
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700341 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300342 return;
343 }
344
345 if (WarningInterface::warningAlarmHigh())
346 {
347 WarningInterface::warningAlarmHigh(false);
348 if (sensorConfig.warningLog)
349 info(
350 "DEASSERT: sensor {SENSOR} is under the upper threshold warning high",
351 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700352 }
353}
354
Vijay Khemkab38fd582020-07-23 13:21:23 -0700355void HealthSensor::readHealthSensor()
356{
357 /* Read current sensor value */
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800358 double value;
359
360 if (sensorConfig.name.rfind(storage, 0) == 0)
361 {
362 value = readSensors.find(storage)->second(sensorConfig.path);
363 }
364 else if (sensorConfig.name.rfind(inode, 0) == 0)
365 {
366 value = readSensors.find(inode)->second(sensorConfig.path);
367 }
368 else
369 {
370 value = readSensors.find(sensorConfig.name)->second(sensorConfig.path);
371 }
372
Vijay Khemkab38fd582020-07-23 13:21:23 -0700373 if (value < 0)
374 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500375 error("Reading Sensor Utilization failed: {SENSOR}", "SENSOR",
376 sensorConfig.name);
Vijay Khemkab38fd582020-07-23 13:21:23 -0700377 return;
378 }
379
380 /* Remove first item from the queue */
Potin Laic82e6162022-08-02 10:22:56 +0000381 if (valQueue.size() >= sensorConfig.windowSize)
382 {
383 valQueue.pop_front();
384 }
Vijay Khemkab38fd582020-07-23 13:21:23 -0700385 /* Add new item at the back */
386 valQueue.push_back(value);
Potin Laic82e6162022-08-02 10:22:56 +0000387 /* Wait until the queue is filled with enough reference*/
388 if (valQueue.size() < sensorConfig.windowSize)
389 {
390 return;
391 }
Vijay Khemkab38fd582020-07-23 13:21:23 -0700392
393 /* Calculate average values for the given window size */
394 double avgValue = 0;
395 avgValue = accumulate(valQueue.begin(), valQueue.end(), avgValue);
396 avgValue = avgValue / sensorConfig.windowSize;
397
398 /* Set this new value to dbus */
399 setSensorValueToDbus(avgValue);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700400
401 /* Check the sensor threshold and log required message */
402 checkSensorThreshold(avgValue);
Vijay Khemka15537762020-07-22 11:44:56 -0700403}
404
Potin Lai156ecf32022-07-11 17:09:10 +0800405void HealthSensor::startUnit(const std::string& sysdUnit)
406{
407 if (sysdUnit.empty())
408 {
409 return;
410 }
411
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500412 sdbusplus::message_t msg = bus.new_method_call(
Potin Lai156ecf32022-07-11 17:09:10 +0800413 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
414 "org.freedesktop.systemd1.Manager", "StartUnit");
415 msg.append(sysdUnit, "replace");
416 bus.call_noreply(msg);
417}
418
Sui Chen036f1612021-07-22 01:31:49 -0700419void HealthMon::recreateSensors()
420{
421 PHOSPHOR_LOG2_USING;
422 healthSensors.clear();
423 std::vector<std::string> bmcIds = {};
424 if (FindSystemInventoryInObjectMapper(bus))
425 {
426 try
427 {
428 // Find all BMCs (DBus objects implementing the
429 // Inventory.Item.Bmc interface that may be created by
430 // configuring the Inventory Manager)
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500431 sdbusplus::message_t msg = bus.new_method_call(
Sui Chen036f1612021-07-22 01:31:49 -0700432 "xyz.openbmc_project.ObjectMapper",
433 "/xyz/openbmc_project/object_mapper",
434 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
435
436 // Search term
437 msg.append(InventoryPath);
438
439 // Limit the depth to 2. Example of "depth":
440 // /xyz/openbmc_project/inventory/system/chassis has a depth of
441 // 1 since it has 1 '/' after
442 // "/xyz/openbmc_project/inventory/system".
443 msg.append(2);
444
445 // Must have the Inventory.Item.Bmc interface
446 msg.append(std::vector<std::string>{
447 "xyz.openbmc_project.Inventory.Item.Bmc"});
448
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500449 sdbusplus::message_t reply = bus.call(msg, 0);
Sui Chen036f1612021-07-22 01:31:49 -0700450 reply.read(bmcIds);
451 info("BMC inventory found");
452 }
453 catch (std::exception& e)
454 {
455 error("Exception occurred while calling {PATH}: {ERROR}", "PATH",
456 InventoryPath, "ERROR", e);
457 }
458 }
459 else
460 {
461 error("Path {PATH} does not exist in ObjectMapper, cannot "
462 "create association",
463 "PATH", InventoryPath);
464 }
465 // Create health sensors
466 createHealthSensors(bmcIds);
467}
468
Vijay Khemka15537762020-07-22 11:44:56 -0700469void printConfig(HealthConfig& cfg)
470{
471 std::cout << "Name: " << cfg.name << "\n";
472 std::cout << "Freq: " << (int)cfg.freq << "\n";
473 std::cout << "Window Size: " << (int)cfg.windowSize << "\n";
474 std::cout << "Critical value: " << (int)cfg.criticalHigh << "\n";
475 std::cout << "warning value: " << (int)cfg.warningHigh << "\n";
476 std::cout << "Critical log: " << (int)cfg.criticalLog << "\n";
477 std::cout << "Warning log: " << (int)cfg.warningLog << "\n";
478 std::cout << "Critical Target: " << cfg.criticalTgt << "\n";
479 std::cout << "Warning Target: " << cfg.warningTgt << "\n\n";
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800480 std::cout << "Path : " << cfg.path << "\n\n";
Vijay Khemka15537762020-07-22 11:44:56 -0700481}
482
Vijay Khemkae2795302020-07-15 17:28:45 -0700483/* Create dbus utilization sensor object for each configured sensors */
Sui Chen670cc132021-04-13 09:27:22 -0700484void HealthMon::createHealthSensors(const std::vector<std::string>& chassisIds)
Vijay Khemkae2795302020-07-15 17:28:45 -0700485{
486 for (auto& cfg : sensorConfigs)
487 {
488 std::string objPath = std::string(HEALTH_SENSOR_PATH) + cfg.name;
Sui Chen670cc132021-04-13 09:27:22 -0700489 auto healthSensor = std::make_shared<HealthSensor>(bus, objPath.c_str(),
490 cfg, chassisIds);
Vijay Khemkae2795302020-07-15 17:28:45 -0700491 healthSensors.emplace(cfg.name, healthSensor);
492
Patrick Williams957e03c2021-09-02 16:38:42 -0500493 info("{SENSOR} Health Sensor created", "SENSOR", cfg.name);
Vijay Khemkae2795302020-07-15 17:28:45 -0700494
495 /* Set configured values of crtical and warning high to dbus */
496 healthSensor->setSensorThreshold(cfg.criticalHigh, cfg.warningHigh);
497 }
498}
499
500/** @brief Parsing Health config JSON file */
501Json HealthMon::parseConfigFile(std::string configFile)
502{
503 std::ifstream jsonFile(configFile);
504 if (!jsonFile.is_open())
505 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500506 error("config JSON file not found: {PATH}", "PATH", configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700507 }
508
509 auto data = Json::parse(jsonFile, nullptr, false);
510 if (data.is_discarded())
511 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500512 error("config readings JSON parser failure: {PATH}", "PATH",
513 configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700514 }
515
516 return data;
517}
518
Vijay Khemkae2795302020-07-15 17:28:45 -0700519void HealthMon::getConfigData(Json& data, HealthConfig& cfg)
520{
521
522 static const Json empty{};
523
Vijay Khemka15537762020-07-22 11:44:56 -0700524 /* Default frerquency of sensor polling is 1 second */
525 cfg.freq = data.value("Frequency", 1);
526
527 /* Default window size sensor queue is 1 */
528 cfg.windowSize = data.value("Window_size", 1);
529
Vijay Khemkae2795302020-07-15 17:28:45 -0700530 auto threshold = data.value("Threshold", empty);
531 if (!threshold.empty())
532 {
533 auto criticalData = threshold.value("Critical", empty);
534 if (!criticalData.empty())
535 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700536 cfg.criticalHigh =
537 criticalData.value("Value", defaultHighThreshold);
Vijay Khemkae2795302020-07-15 17:28:45 -0700538 cfg.criticalLog = criticalData.value("Log", true);
539 cfg.criticalTgt = criticalData.value("Target", "");
540 }
541 auto warningData = threshold.value("Warning", empty);
542 if (!warningData.empty())
543 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700544 cfg.warningHigh = warningData.value("Value", defaultHighThreshold);
545 cfg.warningLog = warningData.value("Log", false);
Vijay Khemkae2795302020-07-15 17:28:45 -0700546 cfg.warningTgt = warningData.value("Target", "");
547 }
548 }
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800549 cfg.path = data.value("Path", "");
Vijay Khemkae2795302020-07-15 17:28:45 -0700550}
551
Vijay Khemka15537762020-07-22 11:44:56 -0700552std::vector<HealthConfig> HealthMon::getHealthConfig()
Vijay Khemkae2795302020-07-15 17:28:45 -0700553{
554
555 std::vector<HealthConfig> cfgs;
556 HealthConfig cfg;
557 auto data = parseConfigFile(HEALTH_CONFIG_FILE);
558
559 // print values
560 if (DEBUG)
561 std::cout << "Config json data:\n" << data << "\n\n";
562
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800563 /* Get data items from config json data*/
Vijay Khemkae2795302020-07-15 17:28:45 -0700564 for (auto& j : data.items())
565 {
566 auto key = j.key();
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800567 /* key need match default value in map readSensors or match the key
568 * start with "Storage" or "Inode" */
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800569 bool isStorageOrInode =
570 (key.rfind(storage, 0) == 0 || key.rfind(inode, 0) == 0);
571 if (readSensors.find(key) != readSensors.end() || isStorageOrInode)
Vijay Khemkae2795302020-07-15 17:28:45 -0700572 {
573 HealthConfig cfg = HealthConfig();
574 cfg.name = j.key();
575 getConfigData(j.value(), cfg);
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800576 if (isStorageOrInode)
577 {
578 struct statvfs buffer
579 {};
580 int ret = statvfs(cfg.path.c_str(), &buffer);
581 if (ret != 0)
582 {
583 auto e = errno;
584 std::cerr << "Error from statvfs: " << strerror(e)
585 << ", name: " << cfg.name
586 << ", path: " << cfg.path
587 << ", please check your settings in config file."
588 << std::endl;
589 continue;
590 }
591 }
Vijay Khemkae2795302020-07-15 17:28:45 -0700592 cfgs.push_back(cfg);
593 if (DEBUG)
594 printConfig(cfg);
595 }
596 else
597 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500598 error("{SENSOR} Health Sensor not supported", "SENSOR", key);
Vijay Khemkae2795302020-07-15 17:28:45 -0700599 }
600 }
601 return cfgs;
602}
603
604} // namespace health
605} // namespace phosphor
606
607/**
608 * @brief Main
609 */
610int main()
611{
Sui Chen036f1612021-07-22 01:31:49 -0700612 // The io_context is needed for the timer
613 boost::asio::io_context io;
614
615 // DBus connection
616 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
617
618 conn->request_name(HEALTH_BUS_NAME);
619
Vijay Khemkae2795302020-07-15 17:28:45 -0700620 // Get a default event loop
621 auto event = sdeventplus::Event::get_default();
622
Vijay Khemkae2795302020-07-15 17:28:45 -0700623 // Create an health monitor object
Sui Chen036f1612021-07-22 01:31:49 -0700624 healthMon = std::make_shared<phosphor::health::HealthMon>(*conn);
Vijay Khemkae2795302020-07-15 17:28:45 -0700625
Yong Lif8d79732021-03-12 09:12:19 +0800626 // Add object manager through object_server
627 sdbusplus::asio::object_server objectServer(conn);
Vijay Khemka1d0d0122020-09-29 12:17:43 -0700628
Sui Chen036f1612021-07-22 01:31:49 -0700629 sdbusplus::asio::sd_event_wrapper sdEvents(io);
630
631 sensorRecreateTimer = std::make_shared<boost::asio::deadline_timer>(io);
632
633 // If the SystemInventory does not exist: wait for the InterfaceAdded signal
634 auto interfacesAddedSignalHandler =
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500635 std::make_unique<sdbusplus::bus::match_t>(
636 static_cast<sdbusplus::bus_t&>(*conn),
Sui Chen036f1612021-07-22 01:31:49 -0700637 sdbusplus::bus::match::rules::interfacesAdded(
638 phosphor::health::BMCActivationPath),
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500639 [conn](sdbusplus::message_t& msg) {
Sui Chen036f1612021-07-22 01:31:49 -0700640 sdbusplus::message::object_path o;
641 msg.read(o);
Willy Tu7fc0aa12022-06-20 20:49:03 -0700642 if (!needUpdate && o.str == phosphor::health::BMCActivationPath)
Sui Chen036f1612021-07-22 01:31:49 -0700643 {
644 info("should recreate sensors now");
645 needUpdate = true;
646 }
647 });
648
649 // Start the timer
650 io.post([]() { sensorRecreateTimerCallback(sensorRecreateTimer); });
651
652 io.run();
Vijay Khemkae2795302020-07-15 17:28:45 -0700653
654 return 0;
655}