blob: 9024048d0ce60cd1758dd92b3870aa223b652621 [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);
246 WarningInterface::warningHigh(warningHigh);
247}
248
Vijay Khemka15537762020-07-22 11:44:56 -0700249void HealthSensor::setSensorValueToDbus(const double value)
Vijay Khemkae2795302020-07-15 17:28:45 -0700250{
251 ValueIface::value(value);
252}
253
Sui Chen670cc132021-04-13 09:27:22 -0700254void HealthSensor::initHealthSensor(const std::vector<std::string>& chassisIds)
Vijay Khemka15537762020-07-22 11:44:56 -0700255{
Patrick Williams957e03c2021-09-02 16:38:42 -0500256 info("{SENSOR} Health Sensor initialized", "SENSOR", sensorConfig.name);
Vijay Khemka15537762020-07-22 11:44:56 -0700257
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800258 /* Look for sensor read functions and Read Sensor values */
259 double value;
260 std::map<std::string,
261 std::function<double(std::string path)>>::const_iterator it;
262 it = readSensors.find(sensorConfig.name);
263
264 if (sensorConfig.name.rfind(storage, 0) == 0)
265 {
266 it = readSensors.find(storage);
267 }
268 else if (sensorConfig.name.rfind(inode, 0) == 0)
269 {
270 it = readSensors.find(inode);
271 }
272 else if (it == readSensors.end())
Vijay Khemka15537762020-07-22 11:44:56 -0700273 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500274 error("Sensor read function not available");
Vijay Khemka15537762020-07-22 11:44:56 -0700275 return;
276 }
277
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800278 value = it->second(sensorConfig.path);
Vijay Khemka15537762020-07-22 11:44:56 -0700279
280 if (value < 0)
281 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500282 error("Reading Sensor Utilization failed: {SENSOR}", "SENSOR",
283 sensorConfig.name);
Vijay Khemka15537762020-07-22 11:44:56 -0700284 return;
285 }
286
Vijay Khemka08797702020-09-21 14:53:57 -0700287 /* Initialize value queue with initial sensor reading */
Vijay Khemka15537762020-07-22 11:44:56 -0700288 for (int i = 0; i < sensorConfig.windowSize; i++)
289 {
290 valQueue.push_back(value);
291 }
Vijay Khemka08797702020-09-21 14:53:57 -0700292
293 /* Initialize unit value (Percent) for utilization sensor */
294 ValueIface::unit(ValueIface::Unit::Percent);
295
Konstantin Aladyshev9d29b372021-12-21 15:45:02 +0300296 ValueIface::maxValue(100);
297 ValueIface::minValue(0);
298
Vijay Khemka15537762020-07-22 11:44:56 -0700299 setSensorValueToDbus(value);
Vijay Khemkab38fd582020-07-23 13:21:23 -0700300
Sui Chen670cc132021-04-13 09:27:22 -0700301 // Associate the sensor to chassis
302 std::vector<AssociationTuple> associationTuples;
303 for (const auto& chassisId : chassisIds)
304 {
305 associationTuples.push_back({"bmc", "all_sensors", chassisId});
306 }
307 AssociationDefinitionInterface::associations(associationTuples);
308
Vijay Khemkab38fd582020-07-23 13:21:23 -0700309 /* Start the timer for reading sensor data at regular interval */
310 readTimer.restart(std::chrono::milliseconds(sensorConfig.freq * 1000));
311}
312
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700313void HealthSensor::checkSensorThreshold(const double value)
314{
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300315 if (std::isfinite(sensorConfig.criticalHigh) &&
316 (value > sensorConfig.criticalHigh))
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700317 {
318 if (!CriticalInterface::criticalAlarmHigh())
319 {
320 CriticalInterface::criticalAlarmHigh(true);
321 if (sensorConfig.criticalLog)
Patrick Williams957e03c2021-09-02 16:38:42 -0500322 error(
323 "ASSERT: sensor {SENSOR} is above the upper threshold critical high",
324 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700325 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300326 return;
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700327 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300328
329 if (CriticalInterface::criticalAlarmHigh())
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700330 {
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300331 CriticalInterface::criticalAlarmHigh(false);
332 if (sensorConfig.criticalLog)
333 info(
334 "DEASSERT: sensor {SENSOR} is under the upper threshold critical high",
335 "SENSOR", sensorConfig.name);
336 }
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700337
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300338 if (std::isfinite(sensorConfig.warningHigh) &&
339 (value > sensorConfig.warningHigh))
340 {
341 if (!WarningInterface::warningAlarmHigh())
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700342 {
343 WarningInterface::warningAlarmHigh(true);
344 if (sensorConfig.warningLog)
Patrick Williams957e03c2021-09-02 16:38:42 -0500345 error(
346 "ASSERT: sensor {SENSOR} is above the upper threshold warning high",
347 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700348 }
Konstantin Aladysheva6cd7042021-12-21 15:36:01 +0300349 return;
350 }
351
352 if (WarningInterface::warningAlarmHigh())
353 {
354 WarningInterface::warningAlarmHigh(false);
355 if (sensorConfig.warningLog)
356 info(
357 "DEASSERT: sensor {SENSOR} is under the upper threshold warning high",
358 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700359 }
360}
361
Vijay Khemkab38fd582020-07-23 13:21:23 -0700362void HealthSensor::readHealthSensor()
363{
364 /* Read current sensor value */
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800365 double value;
366
367 if (sensorConfig.name.rfind(storage, 0) == 0)
368 {
369 value = readSensors.find(storage)->second(sensorConfig.path);
370 }
371 else if (sensorConfig.name.rfind(inode, 0) == 0)
372 {
373 value = readSensors.find(inode)->second(sensorConfig.path);
374 }
375 else
376 {
377 value = readSensors.find(sensorConfig.name)->second(sensorConfig.path);
378 }
379
Vijay Khemkab38fd582020-07-23 13:21:23 -0700380 if (value < 0)
381 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500382 error("Reading Sensor Utilization failed: {SENSOR}", "SENSOR",
383 sensorConfig.name);
Vijay Khemkab38fd582020-07-23 13:21:23 -0700384 return;
385 }
386
387 /* Remove first item from the queue */
388 valQueue.pop_front();
389 /* Add new item at the back */
390 valQueue.push_back(value);
391
392 /* Calculate average values for the given window size */
393 double avgValue = 0;
394 avgValue = accumulate(valQueue.begin(), valQueue.end(), avgValue);
395 avgValue = avgValue / sensorConfig.windowSize;
396
397 /* Set this new value to dbus */
398 setSensorValueToDbus(avgValue);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700399
400 /* Check the sensor threshold and log required message */
401 checkSensorThreshold(avgValue);
Vijay Khemka15537762020-07-22 11:44:56 -0700402}
403
Sui Chen036f1612021-07-22 01:31:49 -0700404void HealthMon::recreateSensors()
405{
406 PHOSPHOR_LOG2_USING;
407 healthSensors.clear();
408 std::vector<std::string> bmcIds = {};
409 if (FindSystemInventoryInObjectMapper(bus))
410 {
411 try
412 {
413 // Find all BMCs (DBus objects implementing the
414 // Inventory.Item.Bmc interface that may be created by
415 // configuring the Inventory Manager)
416 sdbusplus::message::message msg = bus.new_method_call(
417 "xyz.openbmc_project.ObjectMapper",
418 "/xyz/openbmc_project/object_mapper",
419 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
420
421 // Search term
422 msg.append(InventoryPath);
423
424 // Limit the depth to 2. Example of "depth":
425 // /xyz/openbmc_project/inventory/system/chassis has a depth of
426 // 1 since it has 1 '/' after
427 // "/xyz/openbmc_project/inventory/system".
428 msg.append(2);
429
430 // Must have the Inventory.Item.Bmc interface
431 msg.append(std::vector<std::string>{
432 "xyz.openbmc_project.Inventory.Item.Bmc"});
433
434 sdbusplus::message::message reply = bus.call(msg, 0);
435 reply.read(bmcIds);
436 info("BMC inventory found");
437 }
438 catch (std::exception& e)
439 {
440 error("Exception occurred while calling {PATH}: {ERROR}", "PATH",
441 InventoryPath, "ERROR", e);
442 }
443 }
444 else
445 {
446 error("Path {PATH} does not exist in ObjectMapper, cannot "
447 "create association",
448 "PATH", InventoryPath);
449 }
450 // Create health sensors
451 createHealthSensors(bmcIds);
452}
453
Vijay Khemka15537762020-07-22 11:44:56 -0700454void printConfig(HealthConfig& cfg)
455{
456 std::cout << "Name: " << cfg.name << "\n";
457 std::cout << "Freq: " << (int)cfg.freq << "\n";
458 std::cout << "Window Size: " << (int)cfg.windowSize << "\n";
459 std::cout << "Critical value: " << (int)cfg.criticalHigh << "\n";
460 std::cout << "warning value: " << (int)cfg.warningHigh << "\n";
461 std::cout << "Critical log: " << (int)cfg.criticalLog << "\n";
462 std::cout << "Warning log: " << (int)cfg.warningLog << "\n";
463 std::cout << "Critical Target: " << cfg.criticalTgt << "\n";
464 std::cout << "Warning Target: " << cfg.warningTgt << "\n\n";
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800465 std::cout << "Path : " << cfg.path << "\n\n";
Vijay Khemka15537762020-07-22 11:44:56 -0700466}
467
Vijay Khemkae2795302020-07-15 17:28:45 -0700468/* Create dbus utilization sensor object for each configured sensors */
Sui Chen670cc132021-04-13 09:27:22 -0700469void HealthMon::createHealthSensors(const std::vector<std::string>& chassisIds)
Vijay Khemkae2795302020-07-15 17:28:45 -0700470{
471 for (auto& cfg : sensorConfigs)
472 {
473 std::string objPath = std::string(HEALTH_SENSOR_PATH) + cfg.name;
Sui Chen670cc132021-04-13 09:27:22 -0700474 auto healthSensor = std::make_shared<HealthSensor>(bus, objPath.c_str(),
475 cfg, chassisIds);
Vijay Khemkae2795302020-07-15 17:28:45 -0700476 healthSensors.emplace(cfg.name, healthSensor);
477
Patrick Williams957e03c2021-09-02 16:38:42 -0500478 info("{SENSOR} Health Sensor created", "SENSOR", cfg.name);
Vijay Khemkae2795302020-07-15 17:28:45 -0700479
480 /* Set configured values of crtical and warning high to dbus */
481 healthSensor->setSensorThreshold(cfg.criticalHigh, cfg.warningHigh);
482 }
483}
484
485/** @brief Parsing Health config JSON file */
486Json HealthMon::parseConfigFile(std::string configFile)
487{
488 std::ifstream jsonFile(configFile);
489 if (!jsonFile.is_open())
490 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500491 error("config JSON file not found: {PATH}", "PATH", configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700492 }
493
494 auto data = Json::parse(jsonFile, nullptr, false);
495 if (data.is_discarded())
496 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500497 error("config readings JSON parser failure: {PATH}", "PATH",
498 configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700499 }
500
501 return data;
502}
503
Vijay Khemkae2795302020-07-15 17:28:45 -0700504void HealthMon::getConfigData(Json& data, HealthConfig& cfg)
505{
506
507 static const Json empty{};
508
Vijay Khemka15537762020-07-22 11:44:56 -0700509 /* Default frerquency of sensor polling is 1 second */
510 cfg.freq = data.value("Frequency", 1);
511
512 /* Default window size sensor queue is 1 */
513 cfg.windowSize = data.value("Window_size", 1);
514
Vijay Khemkae2795302020-07-15 17:28:45 -0700515 auto threshold = data.value("Threshold", empty);
516 if (!threshold.empty())
517 {
518 auto criticalData = threshold.value("Critical", empty);
519 if (!criticalData.empty())
520 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700521 cfg.criticalHigh =
522 criticalData.value("Value", defaultHighThreshold);
Vijay Khemkae2795302020-07-15 17:28:45 -0700523 cfg.criticalLog = criticalData.value("Log", true);
524 cfg.criticalTgt = criticalData.value("Target", "");
525 }
526 auto warningData = threshold.value("Warning", empty);
527 if (!warningData.empty())
528 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700529 cfg.warningHigh = warningData.value("Value", defaultHighThreshold);
530 cfg.warningLog = warningData.value("Log", false);
Vijay Khemkae2795302020-07-15 17:28:45 -0700531 cfg.warningTgt = warningData.value("Target", "");
532 }
533 }
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800534 cfg.path = data.value("Path", "");
Vijay Khemkae2795302020-07-15 17:28:45 -0700535}
536
Vijay Khemka15537762020-07-22 11:44:56 -0700537std::vector<HealthConfig> HealthMon::getHealthConfig()
Vijay Khemkae2795302020-07-15 17:28:45 -0700538{
539
540 std::vector<HealthConfig> cfgs;
541 HealthConfig cfg;
542 auto data = parseConfigFile(HEALTH_CONFIG_FILE);
543
544 // print values
545 if (DEBUG)
546 std::cout << "Config json data:\n" << data << "\n\n";
547
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800548 /* Get data items from config json data*/
Vijay Khemkae2795302020-07-15 17:28:45 -0700549 for (auto& j : data.items())
550 {
551 auto key = j.key();
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800552 /* key need match default value in map readSensors or match the key
553 * start with "Storage" or "Inode" */
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800554 bool isStorageOrInode =
555 (key.rfind(storage, 0) == 0 || key.rfind(inode, 0) == 0);
556 if (readSensors.find(key) != readSensors.end() || isStorageOrInode)
Vijay Khemkae2795302020-07-15 17:28:45 -0700557 {
558 HealthConfig cfg = HealthConfig();
559 cfg.name = j.key();
560 getConfigData(j.value(), cfg);
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800561 if (isStorageOrInode)
562 {
563 struct statvfs buffer
564 {};
565 int ret = statvfs(cfg.path.c_str(), &buffer);
566 if (ret != 0)
567 {
568 auto e = errno;
569 std::cerr << "Error from statvfs: " << strerror(e)
570 << ", name: " << cfg.name
571 << ", path: " << cfg.path
572 << ", please check your settings in config file."
573 << std::endl;
574 continue;
575 }
576 }
Vijay Khemkae2795302020-07-15 17:28:45 -0700577 cfgs.push_back(cfg);
578 if (DEBUG)
579 printConfig(cfg);
580 }
581 else
582 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500583 error("{SENSOR} Health Sensor not supported", "SENSOR", key);
Vijay Khemkae2795302020-07-15 17:28:45 -0700584 }
585 }
586 return cfgs;
587}
588
589} // namespace health
590} // namespace phosphor
591
592/**
593 * @brief Main
594 */
595int main()
596{
Sui Chen036f1612021-07-22 01:31:49 -0700597 // The io_context is needed for the timer
598 boost::asio::io_context io;
599
600 // DBus connection
601 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
602
603 conn->request_name(HEALTH_BUS_NAME);
604
Vijay Khemkae2795302020-07-15 17:28:45 -0700605 // Get a default event loop
606 auto event = sdeventplus::Event::get_default();
607
Vijay Khemkae2795302020-07-15 17:28:45 -0700608 // Create an health monitor object
Sui Chen036f1612021-07-22 01:31:49 -0700609 healthMon = std::make_shared<phosphor::health::HealthMon>(*conn);
Vijay Khemkae2795302020-07-15 17:28:45 -0700610
Vijay Khemka1d0d0122020-09-29 12:17:43 -0700611 // Add object manager to sensor node
Sui Chen036f1612021-07-22 01:31:49 -0700612 sdbusplus::server::manager::manager objManager(*conn, SENSOR_OBJPATH);
Vijay Khemka1d0d0122020-09-29 12:17:43 -0700613
Sui Chen036f1612021-07-22 01:31:49 -0700614 sdbusplus::asio::sd_event_wrapper sdEvents(io);
615
616 sensorRecreateTimer = std::make_shared<boost::asio::deadline_timer>(io);
617
618 // If the SystemInventory does not exist: wait for the InterfaceAdded signal
619 auto interfacesAddedSignalHandler =
620 std::make_unique<sdbusplus::bus::match::match>(
621 static_cast<sdbusplus::bus::bus&>(*conn),
622 sdbusplus::bus::match::rules::interfacesAdded(
623 phosphor::health::BMCActivationPath),
624 [conn](sdbusplus::message::message& msg) {
625 sdbusplus::message::object_path o;
626 msg.read(o);
627 if (o.str == phosphor::health::BMCActivationPath)
628 {
629 info("should recreate sensors now");
630 needUpdate = true;
631 }
632 });
633
634 // Start the timer
635 io.post([]() { sensorRecreateTimerCallback(sensorRecreateTimer); });
636
637 io.run();
Vijay Khemkae2795302020-07-15 17:28:45 -0700638
639 return 0;
640}