blob: 05f9cbc431fe90117142210be565438588796866 [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;
Vijay Khemka15537762020-07-22 11:44:56 -0700146 struct sysinfo s_info;
147
148 sysinfo(&s_info);
149 double usedRam = s_info.totalram - s_info.freeram;
150 double memUsePerc = usedRam / s_info.totalram * 100;
151
152 if (DEBUG)
153 {
154 std::cout << "Memory Utilization is " << memUsePerc << "\n";
155
156 std::cout << "TotalRam: " << s_info.totalram
157 << " FreeRam: " << s_info.freeram << "\n";
158 std::cout << "UseRam: " << usedRam << "\n";
159 }
160
161 return memUsePerc;
162}
163
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800164double readStorageUtilization(std::string path)
165{
166
167 struct statvfs buffer
168 {};
169 int ret = statvfs(path.c_str(), &buffer);
170 double total = 0;
171 double available = 0;
172 double used = 0;
173 double usedPercentage = 0;
174
175 if (ret != 0)
176 {
177 auto e = errno;
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800178 std::cerr << "Error from statvfs: " << strerror(e) << ",path: " << path
179 << std::endl;
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800180 return 0;
181 }
182
183 total = buffer.f_blocks * (buffer.f_frsize / 1024);
184 available = buffer.f_bfree * (buffer.f_frsize / 1024);
185 used = total - available;
186 usedPercentage = (used / total) * 100;
187
188 if (DEBUG)
189 {
190 std::cout << "Total:" << total << "\n";
191 std::cout << "Available:" << available << "\n";
192 std::cout << "Used:" << used << "\n";
193 std::cout << "Storage utilization is:" << usedPercentage << "\n";
194 }
195
196 return usedPercentage;
197}
198
199double readInodeUtilization(std::string path)
200{
201
202 struct statvfs buffer
203 {};
204 int ret = statvfs(path.c_str(), &buffer);
205 double totalInodes = 0;
206 double availableInodes = 0;
207 double used = 0;
208 double usedPercentage = 0;
209
210 if (ret != 0)
211 {
212 auto e = errno;
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800213 std::cerr << "Error from statvfs: " << strerror(e) << ",path: " << path
214 << std::endl;
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800215 return 0;
216 }
217
218 totalInodes = buffer.f_files;
219 availableInodes = buffer.f_ffree;
220 used = totalInodes - availableInodes;
221 usedPercentage = (used / totalInodes) * 100;
222
223 if (DEBUG)
224 {
225 std::cout << "Total Inodes:" << totalInodes << "\n";
226 std::cout << "Available Inodes:" << availableInodes << "\n";
227 std::cout << "Used:" << used << "\n";
228 std::cout << "Inodes utilization is:" << usedPercentage << "\n";
229 }
230
231 return usedPercentage;
232}
233
234constexpr auto storage = "Storage";
235constexpr auto inode = "Inode";
Vijay Khemka15537762020-07-22 11:44:56 -0700236/** Map of read function for each health sensors supported */
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800237const std::map<std::string, std::function<double(std::string path)>>
238 readSensors = {{"CPU", readCPUUtilization},
239 {"Memory", readMemoryUtilization},
240 {storage, readStorageUtilization},
241 {inode, readInodeUtilization}};
Vijay Khemka15537762020-07-22 11:44:56 -0700242
243void HealthSensor::setSensorThreshold(double criticalHigh, double warningHigh)
Vijay Khemkae2795302020-07-15 17:28:45 -0700244{
245 CriticalInterface::criticalHigh(criticalHigh);
Yong Lif8d79732021-03-12 09:12:19 +0800246 CriticalInterface::criticalLow(std::numeric_limits<double>::quiet_NaN());
247
Vijay Khemkae2795302020-07-15 17:28:45 -0700248 WarningInterface::warningHigh(warningHigh);
Yong Lif8d79732021-03-12 09:12:19 +0800249 WarningInterface::warningLow(std::numeric_limits<double>::quiet_NaN());
Vijay Khemkae2795302020-07-15 17:28:45 -0700250}
251
Vijay Khemka15537762020-07-22 11:44:56 -0700252void HealthSensor::setSensorValueToDbus(const double value)
Vijay Khemkae2795302020-07-15 17:28:45 -0700253{
254 ValueIface::value(value);
255}
256
Sui Chen670cc132021-04-13 09:27:22 -0700257void HealthSensor::initHealthSensor(const std::vector<std::string>& chassisIds)
Vijay Khemka15537762020-07-22 11:44:56 -0700258{
Patrick Williams957e03c2021-09-02 16:38:42 -0500259 info("{SENSOR} Health Sensor initialized", "SENSOR", sensorConfig.name);
Vijay Khemka15537762020-07-22 11:44:56 -0700260
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800261 /* Look for sensor read functions and Read Sensor values */
262 double value;
263 std::map<std::string,
264 std::function<double(std::string path)>>::const_iterator it;
265 it = readSensors.find(sensorConfig.name);
266
267 if (sensorConfig.name.rfind(storage, 0) == 0)
268 {
269 it = readSensors.find(storage);
270 }
271 else if (sensorConfig.name.rfind(inode, 0) == 0)
272 {
273 it = readSensors.find(inode);
274 }
275 else if (it == readSensors.end())
Vijay Khemka15537762020-07-22 11:44:56 -0700276 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500277 error("Sensor read function not available");
Vijay Khemka15537762020-07-22 11:44:56 -0700278 return;
279 }
280
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800281 value = it->second(sensorConfig.path);
Vijay Khemka15537762020-07-22 11:44:56 -0700282
283 if (value < 0)
284 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500285 error("Reading Sensor Utilization failed: {SENSOR}", "SENSOR",
286 sensorConfig.name);
Vijay Khemka15537762020-07-22 11:44:56 -0700287 return;
288 }
289
Vijay Khemka08797702020-09-21 14:53:57 -0700290 /* Initialize value queue with initial sensor reading */
Vijay Khemka15537762020-07-22 11:44:56 -0700291 for (int i = 0; i < sensorConfig.windowSize; i++)
292 {
293 valQueue.push_back(value);
294 }
Vijay Khemka08797702020-09-21 14:53:57 -0700295
296 /* Initialize unit value (Percent) for utilization sensor */
297 ValueIface::unit(ValueIface::Unit::Percent);
298
Konstantin Aladyshev9d29b372021-12-21 15:45:02 +0300299 ValueIface::maxValue(100);
300 ValueIface::minValue(0);
301
Vijay Khemka15537762020-07-22 11:44:56 -0700302 setSensorValueToDbus(value);
Vijay Khemkab38fd582020-07-23 13:21:23 -0700303
Sui Chen670cc132021-04-13 09:27:22 -0700304 // Associate the sensor to chassis
305 std::vector<AssociationTuple> associationTuples;
306 for (const auto& chassisId : chassisIds)
307 {
308 associationTuples.push_back({"bmc", "all_sensors", chassisId});
309 }
310 AssociationDefinitionInterface::associations(associationTuples);
311
Vijay Khemkab38fd582020-07-23 13:21:23 -0700312 /* Start the timer for reading sensor data at regular interval */
313 readTimer.restart(std::chrono::milliseconds(sensorConfig.freq * 1000));
314}
315
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700316void HealthSensor::checkSensorThreshold(const double value)
317{
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300318 if (std::isfinite(sensorConfig.criticalHigh) &&
319 (value > sensorConfig.criticalHigh))
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700320 {
321 if (!CriticalInterface::criticalAlarmHigh())
322 {
323 CriticalInterface::criticalAlarmHigh(true);
324 if (sensorConfig.criticalLog)
Potin Lai156ecf32022-07-11 17:09:10 +0800325 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500326 error(
327 "ASSERT: sensor {SENSOR} is above the upper threshold critical high",
328 "SENSOR", sensorConfig.name);
Potin Lai156ecf32022-07-11 17:09:10 +0800329 startUnit(sensorConfig.criticalTgt);
330 }
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700331 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300332 return;
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700333 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300334
335 if (CriticalInterface::criticalAlarmHigh())
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700336 {
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300337 CriticalInterface::criticalAlarmHigh(false);
338 if (sensorConfig.criticalLog)
339 info(
340 "DEASSERT: sensor {SENSOR} is under the upper threshold critical high",
341 "SENSOR", sensorConfig.name);
342 }
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700343
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300344 if (std::isfinite(sensorConfig.warningHigh) &&
345 (value > sensorConfig.warningHigh))
346 {
347 if (!WarningInterface::warningAlarmHigh())
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700348 {
349 WarningInterface::warningAlarmHigh(true);
350 if (sensorConfig.warningLog)
Potin Lai156ecf32022-07-11 17:09:10 +0800351 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500352 error(
353 "ASSERT: sensor {SENSOR} is above the upper threshold warning high",
354 "SENSOR", sensorConfig.name);
Potin Lai156ecf32022-07-11 17:09:10 +0800355 startUnit(sensorConfig.warningTgt);
356 }
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700357 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300358 return;
359 }
360
361 if (WarningInterface::warningAlarmHigh())
362 {
363 WarningInterface::warningAlarmHigh(false);
364 if (sensorConfig.warningLog)
365 info(
366 "DEASSERT: sensor {SENSOR} is under the upper threshold warning high",
367 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700368 }
369}
370
Vijay Khemkab38fd582020-07-23 13:21:23 -0700371void HealthSensor::readHealthSensor()
372{
373 /* Read current sensor value */
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800374 double value;
375
376 if (sensorConfig.name.rfind(storage, 0) == 0)
377 {
378 value = readSensors.find(storage)->second(sensorConfig.path);
379 }
380 else if (sensorConfig.name.rfind(inode, 0) == 0)
381 {
382 value = readSensors.find(inode)->second(sensorConfig.path);
383 }
384 else
385 {
386 value = readSensors.find(sensorConfig.name)->second(sensorConfig.path);
387 }
388
Vijay Khemkab38fd582020-07-23 13:21:23 -0700389 if (value < 0)
390 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500391 error("Reading Sensor Utilization failed: {SENSOR}", "SENSOR",
392 sensorConfig.name);
Vijay Khemkab38fd582020-07-23 13:21:23 -0700393 return;
394 }
395
396 /* Remove first item from the queue */
397 valQueue.pop_front();
398 /* Add new item at the back */
399 valQueue.push_back(value);
400
401 /* Calculate average values for the given window size */
402 double avgValue = 0;
403 avgValue = accumulate(valQueue.begin(), valQueue.end(), avgValue);
404 avgValue = avgValue / sensorConfig.windowSize;
405
406 /* Set this new value to dbus */
407 setSensorValueToDbus(avgValue);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700408
409 /* Check the sensor threshold and log required message */
410 checkSensorThreshold(avgValue);
Vijay Khemka15537762020-07-22 11:44:56 -0700411}
412
Potin Lai156ecf32022-07-11 17:09:10 +0800413void HealthSensor::startUnit(const std::string& sysdUnit)
414{
415 if (sysdUnit.empty())
416 {
417 return;
418 }
419
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500420 sdbusplus::message_t msg = bus.new_method_call(
Potin Lai156ecf32022-07-11 17:09:10 +0800421 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
422 "org.freedesktop.systemd1.Manager", "StartUnit");
423 msg.append(sysdUnit, "replace");
424 bus.call_noreply(msg);
425}
426
Sui Chen036f1612021-07-22 01:31:49 -0700427void HealthMon::recreateSensors()
428{
429 PHOSPHOR_LOG2_USING;
430 healthSensors.clear();
431 std::vector<std::string> bmcIds = {};
432 if (FindSystemInventoryInObjectMapper(bus))
433 {
434 try
435 {
436 // Find all BMCs (DBus objects implementing the
437 // Inventory.Item.Bmc interface that may be created by
438 // configuring the Inventory Manager)
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500439 sdbusplus::message_t msg = bus.new_method_call(
Sui Chen036f1612021-07-22 01:31:49 -0700440 "xyz.openbmc_project.ObjectMapper",
441 "/xyz/openbmc_project/object_mapper",
442 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
443
444 // Search term
445 msg.append(InventoryPath);
446
447 // Limit the depth to 2. Example of "depth":
448 // /xyz/openbmc_project/inventory/system/chassis has a depth of
449 // 1 since it has 1 '/' after
450 // "/xyz/openbmc_project/inventory/system".
451 msg.append(2);
452
453 // Must have the Inventory.Item.Bmc interface
454 msg.append(std::vector<std::string>{
455 "xyz.openbmc_project.Inventory.Item.Bmc"});
456
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500457 sdbusplus::message_t reply = bus.call(msg, 0);
Sui Chen036f1612021-07-22 01:31:49 -0700458 reply.read(bmcIds);
459 info("BMC inventory found");
460 }
461 catch (std::exception& e)
462 {
463 error("Exception occurred while calling {PATH}: {ERROR}", "PATH",
464 InventoryPath, "ERROR", e);
465 }
466 }
467 else
468 {
469 error("Path {PATH} does not exist in ObjectMapper, cannot "
470 "create association",
471 "PATH", InventoryPath);
472 }
473 // Create health sensors
474 createHealthSensors(bmcIds);
475}
476
Vijay Khemka15537762020-07-22 11:44:56 -0700477void printConfig(HealthConfig& cfg)
478{
479 std::cout << "Name: " << cfg.name << "\n";
480 std::cout << "Freq: " << (int)cfg.freq << "\n";
481 std::cout << "Window Size: " << (int)cfg.windowSize << "\n";
482 std::cout << "Critical value: " << (int)cfg.criticalHigh << "\n";
483 std::cout << "warning value: " << (int)cfg.warningHigh << "\n";
484 std::cout << "Critical log: " << (int)cfg.criticalLog << "\n";
485 std::cout << "Warning log: " << (int)cfg.warningLog << "\n";
486 std::cout << "Critical Target: " << cfg.criticalTgt << "\n";
487 std::cout << "Warning Target: " << cfg.warningTgt << "\n\n";
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800488 std::cout << "Path : " << cfg.path << "\n\n";
Vijay Khemka15537762020-07-22 11:44:56 -0700489}
490
Vijay Khemkae2795302020-07-15 17:28:45 -0700491/* Create dbus utilization sensor object for each configured sensors */
Sui Chen670cc132021-04-13 09:27:22 -0700492void HealthMon::createHealthSensors(const std::vector<std::string>& chassisIds)
Vijay Khemkae2795302020-07-15 17:28:45 -0700493{
494 for (auto& cfg : sensorConfigs)
495 {
496 std::string objPath = std::string(HEALTH_SENSOR_PATH) + cfg.name;
Sui Chen670cc132021-04-13 09:27:22 -0700497 auto healthSensor = std::make_shared<HealthSensor>(bus, objPath.c_str(),
498 cfg, chassisIds);
Vijay Khemkae2795302020-07-15 17:28:45 -0700499 healthSensors.emplace(cfg.name, healthSensor);
500
Patrick Williams957e03c2021-09-02 16:38:42 -0500501 info("{SENSOR} Health Sensor created", "SENSOR", cfg.name);
Vijay Khemkae2795302020-07-15 17:28:45 -0700502
503 /* Set configured values of crtical and warning high to dbus */
504 healthSensor->setSensorThreshold(cfg.criticalHigh, cfg.warningHigh);
505 }
506}
507
508/** @brief Parsing Health config JSON file */
509Json HealthMon::parseConfigFile(std::string configFile)
510{
511 std::ifstream jsonFile(configFile);
512 if (!jsonFile.is_open())
513 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500514 error("config JSON file not found: {PATH}", "PATH", configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700515 }
516
517 auto data = Json::parse(jsonFile, nullptr, false);
518 if (data.is_discarded())
519 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500520 error("config readings JSON parser failure: {PATH}", "PATH",
521 configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700522 }
523
524 return data;
525}
526
Vijay Khemkae2795302020-07-15 17:28:45 -0700527void HealthMon::getConfigData(Json& data, HealthConfig& cfg)
528{
529
530 static const Json empty{};
531
Vijay Khemka15537762020-07-22 11:44:56 -0700532 /* Default frerquency of sensor polling is 1 second */
533 cfg.freq = data.value("Frequency", 1);
534
535 /* Default window size sensor queue is 1 */
536 cfg.windowSize = data.value("Window_size", 1);
537
Vijay Khemkae2795302020-07-15 17:28:45 -0700538 auto threshold = data.value("Threshold", empty);
539 if (!threshold.empty())
540 {
541 auto criticalData = threshold.value("Critical", empty);
542 if (!criticalData.empty())
543 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700544 cfg.criticalHigh =
545 criticalData.value("Value", defaultHighThreshold);
Vijay Khemkae2795302020-07-15 17:28:45 -0700546 cfg.criticalLog = criticalData.value("Log", true);
547 cfg.criticalTgt = criticalData.value("Target", "");
548 }
549 auto warningData = threshold.value("Warning", empty);
550 if (!warningData.empty())
551 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700552 cfg.warningHigh = warningData.value("Value", defaultHighThreshold);
553 cfg.warningLog = warningData.value("Log", false);
Vijay Khemkae2795302020-07-15 17:28:45 -0700554 cfg.warningTgt = warningData.value("Target", "");
555 }
556 }
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800557 cfg.path = data.value("Path", "");
Vijay Khemkae2795302020-07-15 17:28:45 -0700558}
559
Vijay Khemka15537762020-07-22 11:44:56 -0700560std::vector<HealthConfig> HealthMon::getHealthConfig()
Vijay Khemkae2795302020-07-15 17:28:45 -0700561{
562
563 std::vector<HealthConfig> cfgs;
564 HealthConfig cfg;
565 auto data = parseConfigFile(HEALTH_CONFIG_FILE);
566
567 // print values
568 if (DEBUG)
569 std::cout << "Config json data:\n" << data << "\n\n";
570
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800571 /* Get data items from config json data*/
Vijay Khemkae2795302020-07-15 17:28:45 -0700572 for (auto& j : data.items())
573 {
574 auto key = j.key();
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800575 /* key need match default value in map readSensors or match the key
576 * start with "Storage" or "Inode" */
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800577 bool isStorageOrInode =
578 (key.rfind(storage, 0) == 0 || key.rfind(inode, 0) == 0);
579 if (readSensors.find(key) != readSensors.end() || isStorageOrInode)
Vijay Khemkae2795302020-07-15 17:28:45 -0700580 {
581 HealthConfig cfg = HealthConfig();
582 cfg.name = j.key();
583 getConfigData(j.value(), cfg);
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800584 if (isStorageOrInode)
585 {
586 struct statvfs buffer
587 {};
588 int ret = statvfs(cfg.path.c_str(), &buffer);
589 if (ret != 0)
590 {
591 auto e = errno;
592 std::cerr << "Error from statvfs: " << strerror(e)
593 << ", name: " << cfg.name
594 << ", path: " << cfg.path
595 << ", please check your settings in config file."
596 << std::endl;
597 continue;
598 }
599 }
Vijay Khemkae2795302020-07-15 17:28:45 -0700600 cfgs.push_back(cfg);
601 if (DEBUG)
602 printConfig(cfg);
603 }
604 else
605 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500606 error("{SENSOR} Health Sensor not supported", "SENSOR", key);
Vijay Khemkae2795302020-07-15 17:28:45 -0700607 }
608 }
609 return cfgs;
610}
611
612} // namespace health
613} // namespace phosphor
614
615/**
616 * @brief Main
617 */
618int main()
619{
Sui Chen036f1612021-07-22 01:31:49 -0700620 // The io_context is needed for the timer
621 boost::asio::io_context io;
622
623 // DBus connection
624 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
625
626 conn->request_name(HEALTH_BUS_NAME);
627
Vijay Khemkae2795302020-07-15 17:28:45 -0700628 // Get a default event loop
629 auto event = sdeventplus::Event::get_default();
630
Vijay Khemkae2795302020-07-15 17:28:45 -0700631 // Create an health monitor object
Sui Chen036f1612021-07-22 01:31:49 -0700632 healthMon = std::make_shared<phosphor::health::HealthMon>(*conn);
Vijay Khemkae2795302020-07-15 17:28:45 -0700633
Yong Lif8d79732021-03-12 09:12:19 +0800634 // Add object manager through object_server
635 sdbusplus::asio::object_server objectServer(conn);
Vijay Khemka1d0d0122020-09-29 12:17:43 -0700636
Sui Chen036f1612021-07-22 01:31:49 -0700637 sdbusplus::asio::sd_event_wrapper sdEvents(io);
638
639 sensorRecreateTimer = std::make_shared<boost::asio::deadline_timer>(io);
640
641 // If the SystemInventory does not exist: wait for the InterfaceAdded signal
642 auto interfacesAddedSignalHandler =
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500643 std::make_unique<sdbusplus::bus::match_t>(
644 static_cast<sdbusplus::bus_t&>(*conn),
Sui Chen036f1612021-07-22 01:31:49 -0700645 sdbusplus::bus::match::rules::interfacesAdded(
646 phosphor::health::BMCActivationPath),
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500647 [conn](sdbusplus::message_t& msg) {
Sui Chen036f1612021-07-22 01:31:49 -0700648 sdbusplus::message::object_path o;
649 msg.read(o);
Willy Tu7fc0aa12022-06-20 20:49:03 -0700650 if (!needUpdate && o.str == phosphor::health::BMCActivationPath)
Sui Chen036f1612021-07-22 01:31:49 -0700651 {
652 info("should recreate sensors now");
653 needUpdate = true;
654 }
655 });
656
657 // Start the timer
658 io.post([]() { sensorRecreateTimerCallback(sensorRecreateTimer); });
659
660 io.run();
Vijay Khemkae2795302020-07-15 17:28:45 -0700661
662 return 0;
663}