blob: c87e4f029b7b5beb8199c249c73375a43f105bf2 [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)
Patrick Williams957e03c2021-09-02 16:38:42 -0500325 error(
326 "ASSERT: sensor {SENSOR} is above the upper threshold critical high",
327 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700328 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300329 return;
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700330 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300331
332 if (CriticalInterface::criticalAlarmHigh())
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700333 {
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300334 CriticalInterface::criticalAlarmHigh(false);
335 if (sensorConfig.criticalLog)
336 info(
337 "DEASSERT: sensor {SENSOR} is under the upper threshold critical high",
338 "SENSOR", sensorConfig.name);
339 }
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700340
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300341 if (std::isfinite(sensorConfig.warningHigh) &&
342 (value > sensorConfig.warningHigh))
343 {
344 if (!WarningInterface::warningAlarmHigh())
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700345 {
346 WarningInterface::warningAlarmHigh(true);
347 if (sensorConfig.warningLog)
Patrick Williams957e03c2021-09-02 16:38:42 -0500348 error(
349 "ASSERT: sensor {SENSOR} is above the upper threshold warning high",
350 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700351 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300352 return;
353 }
354
355 if (WarningInterface::warningAlarmHigh())
356 {
357 WarningInterface::warningAlarmHigh(false);
358 if (sensorConfig.warningLog)
359 info(
360 "DEASSERT: sensor {SENSOR} is under the upper threshold warning high",
361 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700362 }
363}
364
Vijay Khemkab38fd582020-07-23 13:21:23 -0700365void HealthSensor::readHealthSensor()
366{
367 /* Read current sensor value */
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800368 double value;
369
370 if (sensorConfig.name.rfind(storage, 0) == 0)
371 {
372 value = readSensors.find(storage)->second(sensorConfig.path);
373 }
374 else if (sensorConfig.name.rfind(inode, 0) == 0)
375 {
376 value = readSensors.find(inode)->second(sensorConfig.path);
377 }
378 else
379 {
380 value = readSensors.find(sensorConfig.name)->second(sensorConfig.path);
381 }
382
Vijay Khemkab38fd582020-07-23 13:21:23 -0700383 if (value < 0)
384 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500385 error("Reading Sensor Utilization failed: {SENSOR}", "SENSOR",
386 sensorConfig.name);
Vijay Khemkab38fd582020-07-23 13:21:23 -0700387 return;
388 }
389
390 /* Remove first item from the queue */
391 valQueue.pop_front();
392 /* Add new item at the back */
393 valQueue.push_back(value);
394
395 /* Calculate average values for the given window size */
396 double avgValue = 0;
397 avgValue = accumulate(valQueue.begin(), valQueue.end(), avgValue);
398 avgValue = avgValue / sensorConfig.windowSize;
399
400 /* Set this new value to dbus */
401 setSensorValueToDbus(avgValue);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700402
403 /* Check the sensor threshold and log required message */
404 checkSensorThreshold(avgValue);
Vijay Khemka15537762020-07-22 11:44:56 -0700405}
406
Sui Chen036f1612021-07-22 01:31:49 -0700407void HealthMon::recreateSensors()
408{
409 PHOSPHOR_LOG2_USING;
410 healthSensors.clear();
411 std::vector<std::string> bmcIds = {};
412 if (FindSystemInventoryInObjectMapper(bus))
413 {
414 try
415 {
416 // Find all BMCs (DBus objects implementing the
417 // Inventory.Item.Bmc interface that may be created by
418 // configuring the Inventory Manager)
419 sdbusplus::message::message msg = bus.new_method_call(
420 "xyz.openbmc_project.ObjectMapper",
421 "/xyz/openbmc_project/object_mapper",
422 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
423
424 // Search term
425 msg.append(InventoryPath);
426
427 // Limit the depth to 2. Example of "depth":
428 // /xyz/openbmc_project/inventory/system/chassis has a depth of
429 // 1 since it has 1 '/' after
430 // "/xyz/openbmc_project/inventory/system".
431 msg.append(2);
432
433 // Must have the Inventory.Item.Bmc interface
434 msg.append(std::vector<std::string>{
435 "xyz.openbmc_project.Inventory.Item.Bmc"});
436
437 sdbusplus::message::message reply = bus.call(msg, 0);
438 reply.read(bmcIds);
439 info("BMC inventory found");
440 }
441 catch (std::exception& e)
442 {
443 error("Exception occurred while calling {PATH}: {ERROR}", "PATH",
444 InventoryPath, "ERROR", e);
445 }
446 }
447 else
448 {
449 error("Path {PATH} does not exist in ObjectMapper, cannot "
450 "create association",
451 "PATH", InventoryPath);
452 }
453 // Create health sensors
454 createHealthSensors(bmcIds);
455}
456
Vijay Khemka15537762020-07-22 11:44:56 -0700457void printConfig(HealthConfig& cfg)
458{
459 std::cout << "Name: " << cfg.name << "\n";
460 std::cout << "Freq: " << (int)cfg.freq << "\n";
461 std::cout << "Window Size: " << (int)cfg.windowSize << "\n";
462 std::cout << "Critical value: " << (int)cfg.criticalHigh << "\n";
463 std::cout << "warning value: " << (int)cfg.warningHigh << "\n";
464 std::cout << "Critical log: " << (int)cfg.criticalLog << "\n";
465 std::cout << "Warning log: " << (int)cfg.warningLog << "\n";
466 std::cout << "Critical Target: " << cfg.criticalTgt << "\n";
467 std::cout << "Warning Target: " << cfg.warningTgt << "\n\n";
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800468 std::cout << "Path : " << cfg.path << "\n\n";
Vijay Khemka15537762020-07-22 11:44:56 -0700469}
470
Vijay Khemkae2795302020-07-15 17:28:45 -0700471/* Create dbus utilization sensor object for each configured sensors */
Sui Chen670cc132021-04-13 09:27:22 -0700472void HealthMon::createHealthSensors(const std::vector<std::string>& chassisIds)
Vijay Khemkae2795302020-07-15 17:28:45 -0700473{
474 for (auto& cfg : sensorConfigs)
475 {
476 std::string objPath = std::string(HEALTH_SENSOR_PATH) + cfg.name;
Sui Chen670cc132021-04-13 09:27:22 -0700477 auto healthSensor = std::make_shared<HealthSensor>(bus, objPath.c_str(),
478 cfg, chassisIds);
Vijay Khemkae2795302020-07-15 17:28:45 -0700479 healthSensors.emplace(cfg.name, healthSensor);
480
Patrick Williams957e03c2021-09-02 16:38:42 -0500481 info("{SENSOR} Health Sensor created", "SENSOR", cfg.name);
Vijay Khemkae2795302020-07-15 17:28:45 -0700482
483 /* Set configured values of crtical and warning high to dbus */
484 healthSensor->setSensorThreshold(cfg.criticalHigh, cfg.warningHigh);
485 }
486}
487
488/** @brief Parsing Health config JSON file */
489Json HealthMon::parseConfigFile(std::string configFile)
490{
491 std::ifstream jsonFile(configFile);
492 if (!jsonFile.is_open())
493 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500494 error("config JSON file not found: {PATH}", "PATH", configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700495 }
496
497 auto data = Json::parse(jsonFile, nullptr, false);
498 if (data.is_discarded())
499 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500500 error("config readings JSON parser failure: {PATH}", "PATH",
501 configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700502 }
503
504 return data;
505}
506
Vijay Khemkae2795302020-07-15 17:28:45 -0700507void HealthMon::getConfigData(Json& data, HealthConfig& cfg)
508{
509
510 static const Json empty{};
511
Vijay Khemka15537762020-07-22 11:44:56 -0700512 /* Default frerquency of sensor polling is 1 second */
513 cfg.freq = data.value("Frequency", 1);
514
515 /* Default window size sensor queue is 1 */
516 cfg.windowSize = data.value("Window_size", 1);
517
Vijay Khemkae2795302020-07-15 17:28:45 -0700518 auto threshold = data.value("Threshold", empty);
519 if (!threshold.empty())
520 {
521 auto criticalData = threshold.value("Critical", empty);
522 if (!criticalData.empty())
523 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700524 cfg.criticalHigh =
525 criticalData.value("Value", defaultHighThreshold);
Vijay Khemkae2795302020-07-15 17:28:45 -0700526 cfg.criticalLog = criticalData.value("Log", true);
527 cfg.criticalTgt = criticalData.value("Target", "");
528 }
529 auto warningData = threshold.value("Warning", empty);
530 if (!warningData.empty())
531 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700532 cfg.warningHigh = warningData.value("Value", defaultHighThreshold);
533 cfg.warningLog = warningData.value("Log", false);
Vijay Khemkae2795302020-07-15 17:28:45 -0700534 cfg.warningTgt = warningData.value("Target", "");
535 }
536 }
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800537 cfg.path = data.value("Path", "");
Vijay Khemkae2795302020-07-15 17:28:45 -0700538}
539
Vijay Khemka15537762020-07-22 11:44:56 -0700540std::vector<HealthConfig> HealthMon::getHealthConfig()
Vijay Khemkae2795302020-07-15 17:28:45 -0700541{
542
543 std::vector<HealthConfig> cfgs;
544 HealthConfig cfg;
545 auto data = parseConfigFile(HEALTH_CONFIG_FILE);
546
547 // print values
548 if (DEBUG)
549 std::cout << "Config json data:\n" << data << "\n\n";
550
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800551 /* Get data items from config json data*/
Vijay Khemkae2795302020-07-15 17:28:45 -0700552 for (auto& j : data.items())
553 {
554 auto key = j.key();
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800555 /* key need match default value in map readSensors or match the key
556 * start with "Storage" or "Inode" */
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800557 bool isStorageOrInode =
558 (key.rfind(storage, 0) == 0 || key.rfind(inode, 0) == 0);
559 if (readSensors.find(key) != readSensors.end() || isStorageOrInode)
Vijay Khemkae2795302020-07-15 17:28:45 -0700560 {
561 HealthConfig cfg = HealthConfig();
562 cfg.name = j.key();
563 getConfigData(j.value(), cfg);
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800564 if (isStorageOrInode)
565 {
566 struct statvfs buffer
567 {};
568 int ret = statvfs(cfg.path.c_str(), &buffer);
569 if (ret != 0)
570 {
571 auto e = errno;
572 std::cerr << "Error from statvfs: " << strerror(e)
573 << ", name: " << cfg.name
574 << ", path: " << cfg.path
575 << ", please check your settings in config file."
576 << std::endl;
577 continue;
578 }
579 }
Vijay Khemkae2795302020-07-15 17:28:45 -0700580 cfgs.push_back(cfg);
581 if (DEBUG)
582 printConfig(cfg);
583 }
584 else
585 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500586 error("{SENSOR} Health Sensor not supported", "SENSOR", key);
Vijay Khemkae2795302020-07-15 17:28:45 -0700587 }
588 }
589 return cfgs;
590}
591
592} // namespace health
593} // namespace phosphor
594
595/**
596 * @brief Main
597 */
598int main()
599{
Sui Chen036f1612021-07-22 01:31:49 -0700600 // The io_context is needed for the timer
601 boost::asio::io_context io;
602
603 // DBus connection
604 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
605
606 conn->request_name(HEALTH_BUS_NAME);
607
Vijay Khemkae2795302020-07-15 17:28:45 -0700608 // Get a default event loop
609 auto event = sdeventplus::Event::get_default();
610
Vijay Khemkae2795302020-07-15 17:28:45 -0700611 // Create an health monitor object
Sui Chen036f1612021-07-22 01:31:49 -0700612 healthMon = std::make_shared<phosphor::health::HealthMon>(*conn);
Vijay Khemkae2795302020-07-15 17:28:45 -0700613
Yong Lif8d79732021-03-12 09:12:19 +0800614 // Add object manager through object_server
615 sdbusplus::asio::object_server objectServer(conn);
Vijay Khemka1d0d0122020-09-29 12:17:43 -0700616
Sui Chen036f1612021-07-22 01:31:49 -0700617 sdbusplus::asio::sd_event_wrapper sdEvents(io);
618
619 sensorRecreateTimer = std::make_shared<boost::asio::deadline_timer>(io);
620
621 // If the SystemInventory does not exist: wait for the InterfaceAdded signal
622 auto interfacesAddedSignalHandler =
623 std::make_unique<sdbusplus::bus::match::match>(
624 static_cast<sdbusplus::bus::bus&>(*conn),
625 sdbusplus::bus::match::rules::interfacesAdded(
626 phosphor::health::BMCActivationPath),
627 [conn](sdbusplus::message::message& msg) {
628 sdbusplus::message::object_path o;
629 msg.read(o);
Willy Tu7fc0aa12022-06-20 20:49:03 -0700630 if (!needUpdate && o.str == phosphor::health::BMCActivationPath)
Sui Chen036f1612021-07-22 01:31:49 -0700631 {
632 info("should recreate sensors now");
633 needUpdate = true;
634 }
635 });
636
637 // Start the timer
638 io.post([]() { sensorRecreateTimerCallback(sensorRecreateTimer); });
639
640 io.run();
Vijay Khemkae2795302020-07-15 17:28:45 -0700641
642 return 0;
643}