blob: 089b93952732399af566bc6312ee10073084aeb3 [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
Vijay Khemka15537762020-07-22 11:44:56 -0700296 setSensorValueToDbus(value);
Vijay Khemkab38fd582020-07-23 13:21:23 -0700297
Sui Chen670cc132021-04-13 09:27:22 -0700298 // Associate the sensor to chassis
299 std::vector<AssociationTuple> associationTuples;
300 for (const auto& chassisId : chassisIds)
301 {
302 associationTuples.push_back({"bmc", "all_sensors", chassisId});
303 }
304 AssociationDefinitionInterface::associations(associationTuples);
305
Vijay Khemkab38fd582020-07-23 13:21:23 -0700306 /* Start the timer for reading sensor data at regular interval */
307 readTimer.restart(std::chrono::milliseconds(sensorConfig.freq * 1000));
308}
309
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700310void HealthSensor::checkSensorThreshold(const double value)
311{
Vijay Khemka415dcd22020-09-21 15:58:21 -0700312 if (sensorConfig.criticalHigh && (value > sensorConfig.criticalHigh))
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700313 {
314 if (!CriticalInterface::criticalAlarmHigh())
315 {
316 CriticalInterface::criticalAlarmHigh(true);
317 if (sensorConfig.criticalLog)
Patrick Williams957e03c2021-09-02 16:38:42 -0500318 error(
319 "ASSERT: sensor {SENSOR} is above the upper threshold critical high",
320 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700321 }
322 }
323 else
324 {
325 if (CriticalInterface::criticalAlarmHigh())
326 {
327 CriticalInterface::criticalAlarmHigh(false);
328 if (sensorConfig.criticalLog)
Patrick Williams957e03c2021-09-02 16:38:42 -0500329 info(
330 "DEASSERT: sensor {SENSOR} is under the upper threshold critical high",
331 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700332 }
333
Vijay Khemka415dcd22020-09-21 15:58:21 -0700334 /* if warning high value is not set then return */
335 if (!sensorConfig.warningHigh)
336 return;
337
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700338 if ((value > sensorConfig.warningHigh) &&
339 (!WarningInterface::warningAlarmHigh()))
340 {
341 WarningInterface::warningAlarmHigh(true);
342 if (sensorConfig.warningLog)
Patrick Williams957e03c2021-09-02 16:38:42 -0500343 error(
344 "ASSERT: sensor {SENSOR} is above the upper threshold warning high",
345 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700346 }
347 else if ((value <= sensorConfig.warningHigh) &&
348 (WarningInterface::warningAlarmHigh()))
349 {
350 WarningInterface::warningAlarmHigh(false);
351 if (sensorConfig.warningLog)
Patrick Williams957e03c2021-09-02 16:38:42 -0500352 info(
353 "DEASSERT: sensor {SENSOR} is under the upper threshold warning high",
354 "SENSOR", sensorConfig.name);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700355 }
356 }
357}
358
Vijay Khemkab38fd582020-07-23 13:21:23 -0700359void HealthSensor::readHealthSensor()
360{
361 /* Read current sensor value */
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800362 double value;
363
364 if (sensorConfig.name.rfind(storage, 0) == 0)
365 {
366 value = readSensors.find(storage)->second(sensorConfig.path);
367 }
368 else if (sensorConfig.name.rfind(inode, 0) == 0)
369 {
370 value = readSensors.find(inode)->second(sensorConfig.path);
371 }
372 else
373 {
374 value = readSensors.find(sensorConfig.name)->second(sensorConfig.path);
375 }
376
Vijay Khemkab38fd582020-07-23 13:21:23 -0700377 if (value < 0)
378 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500379 error("Reading Sensor Utilization failed: {SENSOR}", "SENSOR",
380 sensorConfig.name);
Vijay Khemkab38fd582020-07-23 13:21:23 -0700381 return;
382 }
383
384 /* Remove first item from the queue */
385 valQueue.pop_front();
386 /* Add new item at the back */
387 valQueue.push_back(value);
388
389 /* Calculate average values for the given window size */
390 double avgValue = 0;
391 avgValue = accumulate(valQueue.begin(), valQueue.end(), avgValue);
392 avgValue = avgValue / sensorConfig.windowSize;
393
394 /* Set this new value to dbus */
395 setSensorValueToDbus(avgValue);
Vijay Khemkab7a7b8a2020-07-29 12:22:01 -0700396
397 /* Check the sensor threshold and log required message */
398 checkSensorThreshold(avgValue);
Vijay Khemka15537762020-07-22 11:44:56 -0700399}
400
Sui Chen036f1612021-07-22 01:31:49 -0700401void HealthMon::recreateSensors()
402{
403 PHOSPHOR_LOG2_USING;
404 healthSensors.clear();
405 std::vector<std::string> bmcIds = {};
406 if (FindSystemInventoryInObjectMapper(bus))
407 {
408 try
409 {
410 // Find all BMCs (DBus objects implementing the
411 // Inventory.Item.Bmc interface that may be created by
412 // configuring the Inventory Manager)
413 sdbusplus::message::message msg = bus.new_method_call(
414 "xyz.openbmc_project.ObjectMapper",
415 "/xyz/openbmc_project/object_mapper",
416 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths");
417
418 // Search term
419 msg.append(InventoryPath);
420
421 // Limit the depth to 2. Example of "depth":
422 // /xyz/openbmc_project/inventory/system/chassis has a depth of
423 // 1 since it has 1 '/' after
424 // "/xyz/openbmc_project/inventory/system".
425 msg.append(2);
426
427 // Must have the Inventory.Item.Bmc interface
428 msg.append(std::vector<std::string>{
429 "xyz.openbmc_project.Inventory.Item.Bmc"});
430
431 sdbusplus::message::message reply = bus.call(msg, 0);
432 reply.read(bmcIds);
433 info("BMC inventory found");
434 }
435 catch (std::exception& e)
436 {
437 error("Exception occurred while calling {PATH}: {ERROR}", "PATH",
438 InventoryPath, "ERROR", e);
439 }
440 }
441 else
442 {
443 error("Path {PATH} does not exist in ObjectMapper, cannot "
444 "create association",
445 "PATH", InventoryPath);
446 }
447 // Create health sensors
448 createHealthSensors(bmcIds);
449}
450
Vijay Khemka15537762020-07-22 11:44:56 -0700451void printConfig(HealthConfig& cfg)
452{
453 std::cout << "Name: " << cfg.name << "\n";
454 std::cout << "Freq: " << (int)cfg.freq << "\n";
455 std::cout << "Window Size: " << (int)cfg.windowSize << "\n";
456 std::cout << "Critical value: " << (int)cfg.criticalHigh << "\n";
457 std::cout << "warning value: " << (int)cfg.warningHigh << "\n";
458 std::cout << "Critical log: " << (int)cfg.criticalLog << "\n";
459 std::cout << "Warning log: " << (int)cfg.warningLog << "\n";
460 std::cout << "Critical Target: " << cfg.criticalTgt << "\n";
461 std::cout << "Warning Target: " << cfg.warningTgt << "\n\n";
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800462 std::cout << "Path : " << cfg.path << "\n\n";
Vijay Khemka15537762020-07-22 11:44:56 -0700463}
464
Vijay Khemkae2795302020-07-15 17:28:45 -0700465/* Create dbus utilization sensor object for each configured sensors */
Sui Chen670cc132021-04-13 09:27:22 -0700466void HealthMon::createHealthSensors(const std::vector<std::string>& chassisIds)
Vijay Khemkae2795302020-07-15 17:28:45 -0700467{
468 for (auto& cfg : sensorConfigs)
469 {
470 std::string objPath = std::string(HEALTH_SENSOR_PATH) + cfg.name;
Sui Chen670cc132021-04-13 09:27:22 -0700471 auto healthSensor = std::make_shared<HealthSensor>(bus, objPath.c_str(),
472 cfg, chassisIds);
Vijay Khemkae2795302020-07-15 17:28:45 -0700473 healthSensors.emplace(cfg.name, healthSensor);
474
Patrick Williams957e03c2021-09-02 16:38:42 -0500475 info("{SENSOR} Health Sensor created", "SENSOR", cfg.name);
Vijay Khemkae2795302020-07-15 17:28:45 -0700476
477 /* Set configured values of crtical and warning high to dbus */
478 healthSensor->setSensorThreshold(cfg.criticalHigh, cfg.warningHigh);
479 }
480}
481
482/** @brief Parsing Health config JSON file */
483Json HealthMon::parseConfigFile(std::string configFile)
484{
485 std::ifstream jsonFile(configFile);
486 if (!jsonFile.is_open())
487 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500488 error("config JSON file not found: {PATH}", "PATH", configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700489 }
490
491 auto data = Json::parse(jsonFile, nullptr, false);
492 if (data.is_discarded())
493 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500494 error("config readings JSON parser failure: {PATH}", "PATH",
495 configFile);
Vijay Khemkae2795302020-07-15 17:28:45 -0700496 }
497
498 return data;
499}
500
Vijay Khemkae2795302020-07-15 17:28:45 -0700501void HealthMon::getConfigData(Json& data, HealthConfig& cfg)
502{
503
504 static const Json empty{};
505
Vijay Khemka15537762020-07-22 11:44:56 -0700506 /* Default frerquency of sensor polling is 1 second */
507 cfg.freq = data.value("Frequency", 1);
508
509 /* Default window size sensor queue is 1 */
510 cfg.windowSize = data.value("Window_size", 1);
511
Vijay Khemkae2795302020-07-15 17:28:45 -0700512 auto threshold = data.value("Threshold", empty);
513 if (!threshold.empty())
514 {
515 auto criticalData = threshold.value("Critical", empty);
516 if (!criticalData.empty())
517 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700518 cfg.criticalHigh =
519 criticalData.value("Value", defaultHighThreshold);
Vijay Khemkae2795302020-07-15 17:28:45 -0700520 cfg.criticalLog = criticalData.value("Log", true);
521 cfg.criticalTgt = criticalData.value("Target", "");
522 }
523 auto warningData = threshold.value("Warning", empty);
524 if (!warningData.empty())
525 {
Vijay Khemka415dcd22020-09-21 15:58:21 -0700526 cfg.warningHigh = warningData.value("Value", defaultHighThreshold);
527 cfg.warningLog = warningData.value("Log", false);
Vijay Khemkae2795302020-07-15 17:28:45 -0700528 cfg.warningTgt = warningData.value("Target", "");
529 }
530 }
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800531 cfg.path = data.value("Path", "");
Vijay Khemkae2795302020-07-15 17:28:45 -0700532}
533
Vijay Khemka15537762020-07-22 11:44:56 -0700534std::vector<HealthConfig> HealthMon::getHealthConfig()
Vijay Khemkae2795302020-07-15 17:28:45 -0700535{
536
537 std::vector<HealthConfig> cfgs;
538 HealthConfig cfg;
539 auto data = parseConfigFile(HEALTH_CONFIG_FILE);
540
541 // print values
542 if (DEBUG)
543 std::cout << "Config json data:\n" << data << "\n\n";
544
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800545 /* Get data items from config json data*/
Vijay Khemkae2795302020-07-15 17:28:45 -0700546 for (auto& j : data.items())
547 {
548 auto key = j.key();
Bruceleequantatwaf9acbd2020-10-12 15:21:42 +0800549 /* key need match default value in map readSensors or match the key
550 * start with "Storage" or "Inode" */
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800551 bool isStorageOrInode =
552 (key.rfind(storage, 0) == 0 || key.rfind(inode, 0) == 0);
553 if (readSensors.find(key) != readSensors.end() || isStorageOrInode)
Vijay Khemkae2795302020-07-15 17:28:45 -0700554 {
555 HealthConfig cfg = HealthConfig();
556 cfg.name = j.key();
557 getConfigData(j.value(), cfg);
Bruceleequantatw2b231e82020-11-23 13:23:45 +0800558 if (isStorageOrInode)
559 {
560 struct statvfs buffer
561 {};
562 int ret = statvfs(cfg.path.c_str(), &buffer);
563 if (ret != 0)
564 {
565 auto e = errno;
566 std::cerr << "Error from statvfs: " << strerror(e)
567 << ", name: " << cfg.name
568 << ", path: " << cfg.path
569 << ", please check your settings in config file."
570 << std::endl;
571 continue;
572 }
573 }
Vijay Khemkae2795302020-07-15 17:28:45 -0700574 cfgs.push_back(cfg);
575 if (DEBUG)
576 printConfig(cfg);
577 }
578 else
579 {
Patrick Williams957e03c2021-09-02 16:38:42 -0500580 error("{SENSOR} Health Sensor not supported", "SENSOR", key);
Vijay Khemkae2795302020-07-15 17:28:45 -0700581 }
582 }
583 return cfgs;
584}
585
586} // namespace health
587} // namespace phosphor
588
589/**
590 * @brief Main
591 */
592int main()
593{
Sui Chen036f1612021-07-22 01:31:49 -0700594 // The io_context is needed for the timer
595 boost::asio::io_context io;
596
597 // DBus connection
598 auto conn = std::make_shared<sdbusplus::asio::connection>(io);
599
600 conn->request_name(HEALTH_BUS_NAME);
601
Vijay Khemkae2795302020-07-15 17:28:45 -0700602 // Get a default event loop
603 auto event = sdeventplus::Event::get_default();
604
Vijay Khemkae2795302020-07-15 17:28:45 -0700605 // Create an health monitor object
Sui Chen036f1612021-07-22 01:31:49 -0700606 healthMon = std::make_shared<phosphor::health::HealthMon>(*conn);
Vijay Khemkae2795302020-07-15 17:28:45 -0700607
Vijay Khemka1d0d0122020-09-29 12:17:43 -0700608 // Add object manager to sensor node
Sui Chen036f1612021-07-22 01:31:49 -0700609 sdbusplus::server::manager::manager objManager(*conn, SENSOR_OBJPATH);
Vijay Khemka1d0d0122020-09-29 12:17:43 -0700610
Sui Chen036f1612021-07-22 01:31:49 -0700611 sdbusplus::asio::sd_event_wrapper sdEvents(io);
612
613 sensorRecreateTimer = std::make_shared<boost::asio::deadline_timer>(io);
614
615 // If the SystemInventory does not exist: wait for the InterfaceAdded signal
616 auto interfacesAddedSignalHandler =
617 std::make_unique<sdbusplus::bus::match::match>(
618 static_cast<sdbusplus::bus::bus&>(*conn),
619 sdbusplus::bus::match::rules::interfacesAdded(
620 phosphor::health::BMCActivationPath),
621 [conn](sdbusplus::message::message& msg) {
622 sdbusplus::message::object_path o;
623 msg.read(o);
624 if (o.str == phosphor::health::BMCActivationPath)
625 {
626 info("should recreate sensors now");
627 needUpdate = true;
628 }
629 });
630
631 // Start the timer
632 io.post([]() { sensorRecreateTimerCallback(sensorRecreateTimer); });
633
634 io.run();
Vijay Khemkae2795302020-07-15 17:28:45 -0700635
636 return 0;
637}