blob: 3c5cd8904119dd6741dc76e9998ed40022b8f46b [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{
Vijay Khemka08797702020-09-21 14:53:57 -0700259 /* Initialize unit value (Percent) for utilization sensor */
260 ValueIface::unit(ValueIface::Unit::Percent);
261
Konstantin Aladyshev9d29b372021-12-21 15:45:02 +0300262 ValueIface::maxValue(100);
263 ValueIface::minValue(0);
Potin Laic82e6162022-08-02 10:22:56 +0000264 ValueIface::value(std::numeric_limits<double>::quiet_NaN());
Vijay Khemkab38fd582020-07-23 13:21:23 -0700265
Sui Chen670cc132021-04-13 09:27:22 -0700266 // Associate the sensor to chassis
267 std::vector<AssociationTuple> associationTuples;
268 for (const auto& chassisId : chassisIds)
269 {
270 associationTuples.push_back({"bmc", "all_sensors", chassisId});
271 }
272 AssociationDefinitionInterface::associations(associationTuples);
273
Vijay Khemkab38fd582020-07-23 13:21:23 -0700274 /* Start the timer for reading sensor data at regular interval */
275 readTimer.restart(std::chrono::milliseconds(sensorConfig.freq * 1000));
276}
277
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700278void HealthSensor::checkSensorThreshold(const double value)
279{
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300280 if (std::isfinite(sensorConfig.criticalHigh) &&
281 (value > sensorConfig.criticalHigh))
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700282 {
283 if (!CriticalInterface::criticalAlarmHigh())
284 {
285 CriticalInterface::criticalAlarmHigh(true);
286 if (sensorConfig.criticalLog)
Potin Lai156ecf32022-07-11 17:09:10 +0800287 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500288 error(
289 "ASSERT: sensor {SENSOR} is above the upper threshold critical high",
290 "SENSOR", sensorConfig.name);
Potin Lai156ecf32022-07-11 17:09:10 +0800291 startUnit(sensorConfig.criticalTgt);
292 }
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700293 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300294 return;
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700295 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300296
297 if (CriticalInterface::criticalAlarmHigh())
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700298 {
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300299 CriticalInterface::criticalAlarmHigh(false);
300 if (sensorConfig.criticalLog)
301 info(
302 "DEASSERT: sensor {SENSOR} is under the upper threshold critical high",
303 "SENSOR", sensorConfig.name);
304 }
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700305
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300306 if (std::isfinite(sensorConfig.warningHigh) &&
307 (value > sensorConfig.warningHigh))
308 {
309 if (!WarningInterface::warningAlarmHigh())
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700310 {
311 WarningInterface::warningAlarmHigh(true);
312 if (sensorConfig.warningLog)
Potin Lai156ecf32022-07-11 17:09:10 +0800313 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500314 error(
315 "ASSERT: sensor {SENSOR} is above the upper threshold warning high",
316 "SENSOR", sensorConfig.name);
Potin Lai156ecf32022-07-11 17:09:10 +0800317 startUnit(sensorConfig.warningTgt);
318 }
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700319 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300320 return;
321 }
322
323 if (WarningInterface::warningAlarmHigh())
324 {
325 WarningInterface::warningAlarmHigh(false);
326 if (sensorConfig.warningLog)
327 info(
328 "DEASSERT: sensor {SENSOR} is under the upper threshold warning high",
329 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700330 }
331}
332
Vijay Khemkab38fd582020-07-23 13:21:23 -0700333void HealthSensor::readHealthSensor()
334{
335 /* Read current sensor value */
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800336 double value;
337
338 if (sensorConfig.name.rfind(storage, 0) == 0)
339 {
340 value = readSensors.find(storage)->second(sensorConfig.path);
341 }
342 else if (sensorConfig.name.rfind(inode, 0) == 0)
343 {
344 value = readSensors.find(inode)->second(sensorConfig.path);
345 }
346 else
347 {
348 value = readSensors.find(sensorConfig.name)->second(sensorConfig.path);
349 }
350
Vijay Khemkab38fd582020-07-23 13:21:23 -0700351 if (value < 0)
352 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500353 error("Reading Sensor Utilization failed: {SENSOR}", "SENSOR",
354 sensorConfig.name);
Vijay Khemkab38fd582020-07-23 13:21:23 -0700355 return;
356 }
357
358 /* Remove first item from the queue */
Potin Laic82e6162022-08-02 10:22:56 +0000359 if (valQueue.size() >= sensorConfig.windowSize)
360 {
361 valQueue.pop_front();
362 }
Vijay Khemkab38fd582020-07-23 13:21:23 -0700363 /* Add new item at the back */
364 valQueue.push_back(value);
Potin Laic82e6162022-08-02 10:22:56 +0000365 /* Wait until the queue is filled with enough reference*/
366 if (valQueue.size() < sensorConfig.windowSize)
367 {
368 return;
369 }
Vijay Khemkab38fd582020-07-23 13:21:23 -0700370
371 /* Calculate average values for the given window size */
372 double avgValue = 0;
373 avgValue = accumulate(valQueue.begin(), valQueue.end(), avgValue);
374 avgValue = avgValue / sensorConfig.windowSize;
375
376 /* Set this new value to dbus */
377 setSensorValueToDbus(avgValue);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700378
379 /* Check the sensor threshold and log required message */
380 checkSensorThreshold(avgValue);
Vijay Khemka15537762020-07-22 11:44:56 -0700381}
382
Potin Lai156ecf32022-07-11 17:09:10 +0800383void HealthSensor::startUnit(const std::string& sysdUnit)
384{
385 if (sysdUnit.empty())
386 {
387 return;
388 }
389
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500390 sdbusplus::message_t msg = bus.new_method_call(
Potin Lai156ecf32022-07-11 17:09:10 +0800391 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
392 "org.freedesktop.systemd1.Manager", "StartUnit");
393 msg.append(sysdUnit, "replace");
394 bus.call_noreply(msg);
395}
396
Sui Chen036f1612021-07-22 01:31:49 -0700397void HealthMon::recreateSensors()
398{
399 PHOSPHOR_LOG2_USING;
400 healthSensors.clear();
401 std::vector<std::string> bmcIds = {};
402 if (FindSystemInventoryInObjectMapper(bus))
403 {
404 try
405 {
406 // Find all BMCs (DBus objects implementing the
407 // Inventory.Item.Bmc interface that may be created by
408 // configuring the Inventory Manager)
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500409 sdbusplus::message_t msg = bus.new_method_call(
Sui Chen036f1612021-07-22 01:31:49 -0700410 "xyz.openbmc_project.ObjectMapper",
411 "/xyz/openbmc_project/object_mapper",
412 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
413
414 // Search term
415 msg.append(InventoryPath);
416
417 // Limit the depth to 2. Example of "depth":
418 // /xyz/openbmc_project/inventory/system/chassis has a depth of
419 // 1 since it has 1 '/' after
420 // "/xyz/openbmc_project/inventory/system".
421 msg.append(2);
422
423 // Must have the Inventory.Item.Bmc interface
424 msg.append(std::vector<std::string>{
425 "xyz.openbmc_project.Inventory.Item.Bmc"});
426
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500427 sdbusplus::message_t reply = bus.call(msg, 0);
Sui Chen036f1612021-07-22 01:31:49 -0700428 reply.read(bmcIds);
429 info("BMC inventory found");
430 }
431 catch (std::exception& e)
432 {
433 error("Exception occurred while calling {PATH}: {ERROR}", "PATH",
434 InventoryPath, "ERROR", e);
435 }
436 }
437 else
438 {
439 error("Path {PATH} does not exist in ObjectMapper, cannot "
440 "create association",
441 "PATH", InventoryPath);
442 }
443 // Create health sensors
444 createHealthSensors(bmcIds);
445}
446
Vijay Khemka15537762020-07-22 11:44:56 -0700447void printConfig(HealthConfig& cfg)
448{
449 std::cout << "Name: " << cfg.name << "\n";
450 std::cout << "Freq: " << (int)cfg.freq << "\n";
451 std::cout << "Window Size: " << (int)cfg.windowSize << "\n";
452 std::cout << "Critical value: " << (int)cfg.criticalHigh << "\n";
453 std::cout << "warning value: " << (int)cfg.warningHigh << "\n";
454 std::cout << "Critical log: " << (int)cfg.criticalLog << "\n";
455 std::cout << "Warning log: " << (int)cfg.warningLog << "\n";
456 std::cout << "Critical Target: " << cfg.criticalTgt << "\n";
457 std::cout << "Warning Target: " << cfg.warningTgt << "\n\n";
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800458 std::cout << "Path : " << cfg.path << "\n\n";
Vijay Khemka15537762020-07-22 11:44:56 -0700459}
460
Vijay Khemkae2795302020-07-15 17:28:45 -0700461/* Create dbus utilization sensor object for each configured sensors */
Sui Chen670cc132021-04-13 09:27:22 -0700462void HealthMon::createHealthSensors(const std::vector<std::string>& chassisIds)
Vijay Khemkae2795302020-07-15 17:28:45 -0700463{
464 for (auto& cfg : sensorConfigs)
465 {
466 std::string objPath = std::string(HEALTH_SENSOR_PATH) + cfg.name;
Sui Chen670cc132021-04-13 09:27:22 -0700467 auto healthSensor = std::make_shared<HealthSensor>(bus, objPath.c_str(),
468 cfg, chassisIds);
Vijay Khemkae2795302020-07-15 17:28:45 -0700469 healthSensors.emplace(cfg.name, healthSensor);
470
Patrick Williams957e03c2021-09-02 16:38:42 -0500471 info("{SENSOR} Health Sensor created", "SENSOR", cfg.name);
Vijay Khemkae2795302020-07-15 17:28:45 -0700472
473 /* Set configured values of crtical and warning high to dbus */
474 healthSensor->setSensorThreshold(cfg.criticalHigh, cfg.warningHigh);
475 }
476}
477
478/** @brief Parsing Health config JSON file */
479Json HealthMon::parseConfigFile(std::string configFile)
480{
481 std::ifstream jsonFile(configFile);
482 if (!jsonFile.is_open())
483 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500484 error("config JSON file not found: {PATH}", "PATH", configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700485 }
486
487 auto data = Json::parse(jsonFile, nullptr, false);
488 if (data.is_discarded())
489 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500490 error("config readings JSON parser failure: {PATH}", "PATH",
491 configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700492 }
493
494 return data;
495}
496
Vijay Khemkae2795302020-07-15 17:28:45 -0700497void HealthMon::getConfigData(Json& data, HealthConfig& cfg)
498{
499
500 static const Json empty{};
501
Vijay Khemka15537762020-07-22 11:44:56 -0700502 /* Default frerquency of sensor polling is 1 second */
503 cfg.freq = data.value("Frequency", 1);
504
505 /* Default window size sensor queue is 1 */
506 cfg.windowSize = data.value("Window_size", 1);
507
Vijay Khemkae2795302020-07-15 17:28:45 -0700508 auto threshold = data.value("Threshold", empty);
509 if (!threshold.empty())
510 {
511 auto criticalData = threshold.value("Critical", empty);
512 if (!criticalData.empty())
513 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700514 cfg.criticalHigh =
515 criticalData.value("Value", defaultHighThreshold);
Vijay Khemkae2795302020-07-15 17:28:45 -0700516 cfg.criticalLog = criticalData.value("Log", true);
517 cfg.criticalTgt = criticalData.value("Target", "");
518 }
519 auto warningData = threshold.value("Warning", empty);
520 if (!warningData.empty())
521 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700522 cfg.warningHigh = warningData.value("Value", defaultHighThreshold);
523 cfg.warningLog = warningData.value("Log", false);
Vijay Khemkae2795302020-07-15 17:28:45 -0700524 cfg.warningTgt = warningData.value("Target", "");
525 }
526 }
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800527 cfg.path = data.value("Path", "");
Vijay Khemkae2795302020-07-15 17:28:45 -0700528}
529
Vijay Khemka15537762020-07-22 11:44:56 -0700530std::vector<HealthConfig> HealthMon::getHealthConfig()
Vijay Khemkae2795302020-07-15 17:28:45 -0700531{
532
533 std::vector<HealthConfig> cfgs;
534 HealthConfig cfg;
535 auto data = parseConfigFile(HEALTH_CONFIG_FILE);
536
537 // print values
538 if (DEBUG)
539 std::cout << "Config json data:\n" << data << "\n\n";
540
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800541 /* Get data items from config json data*/
Vijay Khemkae2795302020-07-15 17:28:45 -0700542 for (auto& j : data.items())
543 {
544 auto key = j.key();
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800545 /* key need match default value in map readSensors or match the key
546 * start with "Storage" or "Inode" */
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800547 bool isStorageOrInode =
548 (key.rfind(storage, 0) == 0 || key.rfind(inode, 0) == 0);
549 if (readSensors.find(key) != readSensors.end() || isStorageOrInode)
Vijay Khemkae2795302020-07-15 17:28:45 -0700550 {
551 HealthConfig cfg = HealthConfig();
552 cfg.name = j.key();
553 getConfigData(j.value(), cfg);
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800554 if (isStorageOrInode)
555 {
556 struct statvfs buffer
557 {};
558 int ret = statvfs(cfg.path.c_str(), &buffer);
559 if (ret != 0)
560 {
561 auto e = errno;
562 std::cerr << "Error from statvfs: " << strerror(e)
563 << ", name: " << cfg.name
564 << ", path: " << cfg.path
565 << ", please check your settings in config file."
566 << std::endl;
567 continue;
568 }
569 }
Vijay Khemkae2795302020-07-15 17:28:45 -0700570 cfgs.push_back(cfg);
571 if (DEBUG)
572 printConfig(cfg);
573 }
574 else
575 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500576 error("{SENSOR} Health Sensor not supported", "SENSOR", key);
Vijay Khemkae2795302020-07-15 17:28:45 -0700577 }
578 }
579 return cfgs;
580}
581
582} // namespace health
583} // namespace phosphor
584
585/**
586 * @brief Main
587 */
588int main()
589{
Sui Chen036f1612021-07-22 01:31:49 -0700590 // The io_context is needed for the timer
591 boost::asio::io_context io;
592
593 // DBus connection
594 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
595
596 conn->request_name(HEALTH_BUS_NAME);
597
Vijay Khemkae2795302020-07-15 17:28:45 -0700598 // Get a default event loop
599 auto event = sdeventplus::Event::get_default();
600
Vijay Khemkae2795302020-07-15 17:28:45 -0700601 // Create an health monitor object
Sui Chen036f1612021-07-22 01:31:49 -0700602 healthMon = std::make_shared<phosphor::health::HealthMon>(*conn);
Vijay Khemkae2795302020-07-15 17:28:45 -0700603
Yong Lif8d79732021-03-12 09:12:19 +0800604 // Add object manager through object_server
605 sdbusplus::asio::object_server objectServer(conn);
Vijay Khemka1d0d0122020-09-29 12:17:43 -0700606
Sui Chen036f1612021-07-22 01:31:49 -0700607 sdbusplus::asio::sd_event_wrapper sdEvents(io);
608
609 sensorRecreateTimer = std::make_shared<boost::asio::deadline_timer>(io);
610
611 // If the SystemInventory does not exist: wait for the InterfaceAdded signal
612 auto interfacesAddedSignalHandler =
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500613 std::make_unique<sdbusplus::bus::match_t>(
614 static_cast<sdbusplus::bus_t&>(*conn),
Sui Chen036f1612021-07-22 01:31:49 -0700615 sdbusplus::bus::match::rules::interfacesAdded(
616 phosphor::health::BMCActivationPath),
Patrick Williamsbbfe7182022-07-22 19:26:56 -0500617 [conn](sdbusplus::message_t& msg) {
Sui Chen036f1612021-07-22 01:31:49 -0700618 sdbusplus::message::object_path o;
619 msg.read(o);
Willy Tu7fc0aa12022-06-20 20:49:03 -0700620 if (!needUpdate && o.str == phosphor::health::BMCActivationPath)
Sui Chen036f1612021-07-22 01:31:49 -0700621 {
622 info("should recreate sensors now");
623 needUpdate = true;
624 }
625 });
626
627 // Start the timer
628 io.post([]() { sensorRecreateTimerCallback(sensorRecreateTimer); });
629
630 io.run();
Vijay Khemkae2795302020-07-15 17:28:45 -0700631
632 return 0;
633}