xref: /openbmc/bmcweb/features/redfish/lib/manager_diagnostic_data.hpp (revision e610b3168321eee167271e4532c37fe1ed9c6f56)
1a51fc2d2SSui Chen #pragma once
2a51fc2d2SSui Chen 
33ccb3adbSEd Tanous #include "app.hpp"
43ccb3adbSEd Tanous #include "async_resp.hpp"
53ccb3adbSEd Tanous #include "http_request.hpp"
63ccb3adbSEd Tanous #include "privileges.hpp"
73ccb3adbSEd Tanous #include "query.hpp"
83ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
93ccb3adbSEd Tanous #include "routing.hpp"
103ccb3adbSEd Tanous 
11*e610b316SJagpal Singh Gill #include <boost/system/error_code.hpp>
12*e610b316SJagpal Singh Gill #include <boost/system/linux_error.hpp>
13a51fc2d2SSui Chen #include <nlohmann/json.hpp>
145ace29d2SEd Tanous #include <sdbusplus/asio/property.hpp>
15a51fc2d2SSui Chen 
16*e610b316SJagpal Singh Gill #include <functional>
17*e610b316SJagpal Singh Gill #include <limits>
18*e610b316SJagpal Singh Gill #include <memory>
19a51fc2d2SSui Chen #include <string>
20a51fc2d2SSui Chen 
21a51fc2d2SSui Chen namespace redfish
22a51fc2d2SSui Chen {
23a51fc2d2SSui Chen 
24*e610b316SJagpal Singh Gill static constexpr auto healthMonitorServiceName =
25*e610b316SJagpal Singh Gill     "xyz.openbmc_project.HealthMon";
26*e610b316SJagpal Singh Gill static constexpr auto valueInterface = "xyz.openbmc_project.Metric.Value";
27*e610b316SJagpal Singh Gill static constexpr auto valueProperty = "Value";
28*e610b316SJagpal Singh Gill 
29*e610b316SJagpal Singh Gill inline bool checkErrors(
30*e610b316SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
31*e610b316SJagpal Singh Gill     const boost::system::error_code& ec,
32*e610b316SJagpal Singh Gill     const std::source_location src = std::source_location::current())
33*e610b316SJagpal Singh Gill {
34*e610b316SJagpal Singh Gill     if (ec.value() == boost::asio::error::basic_errors::host_unreachable)
35*e610b316SJagpal Singh Gill     {
36*e610b316SJagpal Singh Gill         BMCWEB_LOG_WARNING("Failed to find server, Dbus error {}", ec);
37*e610b316SJagpal Singh Gill         return true;
38*e610b316SJagpal Singh Gill     }
39*e610b316SJagpal Singh Gill     if (ec.value() == boost::system::linux_error::bad_request_descriptor)
40*e610b316SJagpal Singh Gill     {
41*e610b316SJagpal Singh Gill         BMCWEB_LOG_WARNING("Invalid Path, Dbus error {}", ec);
42*e610b316SJagpal Singh Gill         return true;
43*e610b316SJagpal Singh Gill     }
44*e610b316SJagpal Singh Gill     if (ec)
45*e610b316SJagpal Singh Gill     {
46*e610b316SJagpal Singh Gill         BMCWEB_LOG_ERROR("{} failed, error {}", src.function_name(), ec);
47*e610b316SJagpal Singh Gill         messages::internalError(asyncResp->res);
48*e610b316SJagpal Singh Gill         return true;
49*e610b316SJagpal Singh Gill     }
50*e610b316SJagpal Singh Gill     return false;
51*e610b316SJagpal Singh Gill }
52*e610b316SJagpal Singh Gill 
53*e610b316SJagpal Singh Gill inline void
54*e610b316SJagpal Singh Gill     setBytesProperty(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
55*e610b316SJagpal Singh Gill                      const nlohmann::json::json_pointer& jPtr,
56*e610b316SJagpal Singh Gill                      const boost::system::error_code& ec, double bytes)
57*e610b316SJagpal Singh Gill {
58*e610b316SJagpal Singh Gill     if (checkErrors(asyncResp, ec))
59*e610b316SJagpal Singh Gill     {
60*e610b316SJagpal Singh Gill         return;
61*e610b316SJagpal Singh Gill     }
62*e610b316SJagpal Singh Gill     if (!std::isfinite(bytes))
63*e610b316SJagpal Singh Gill     {
64*e610b316SJagpal Singh Gill         BMCWEB_LOG_WARNING("Property read for {} was not finite",
65*e610b316SJagpal Singh Gill                            jPtr.to_string());
66*e610b316SJagpal Singh Gill         asyncResp->res.jsonValue[jPtr] = nullptr;
67*e610b316SJagpal Singh Gill         return;
68*e610b316SJagpal Singh Gill     }
69*e610b316SJagpal Singh Gill     // If the param is in Kib, make it Kib.  Redfish uses this as a naming
70*e610b316SJagpal Singh Gill     // DBus represents as bytes
71*e610b316SJagpal Singh Gill     if (std::string_view(jPtr.back()).ends_with("KiB"))
72*e610b316SJagpal Singh Gill     {
73*e610b316SJagpal Singh Gill         bytes /= 1024.0;
74*e610b316SJagpal Singh Gill     }
75*e610b316SJagpal Singh Gill 
76*e610b316SJagpal Singh Gill     asyncResp->res.jsonValue[jPtr] = static_cast<int64_t>(bytes);
77*e610b316SJagpal Singh Gill }
78*e610b316SJagpal Singh Gill 
79*e610b316SJagpal Singh Gill inline void managerGetStorageStatistics(
80*e610b316SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
81*e610b316SJagpal Singh Gill {
82*e610b316SJagpal Singh Gill     constexpr auto freeStorageObjPath =
83*e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/storage/rw";
84*e610b316SJagpal Singh Gill 
85*e610b316SJagpal Singh Gill     sdbusplus::asio::getProperty<double>(
86*e610b316SJagpal Singh Gill         *crow::connections::systemBus, healthMonitorServiceName,
87*e610b316SJagpal Singh Gill         freeStorageObjPath, valueInterface, valueProperty,
88*e610b316SJagpal Singh Gill         std::bind_front(setBytesProperty, asyncResp,
89*e610b316SJagpal Singh Gill                         nlohmann::json::json_pointer("/FreeStorageSpaceKiB")));
90*e610b316SJagpal Singh Gill }
91*e610b316SJagpal Singh Gill 
92*e610b316SJagpal Singh Gill inline void
93*e610b316SJagpal Singh Gill     setPercentProperty(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
94*e610b316SJagpal Singh Gill                        const nlohmann::json::json_pointer& jPtr,
95*e610b316SJagpal Singh Gill                        const boost::system::error_code& ec, double userCPU)
96*e610b316SJagpal Singh Gill {
97*e610b316SJagpal Singh Gill     if (checkErrors(asyncResp, ec))
98*e610b316SJagpal Singh Gill     {
99*e610b316SJagpal Singh Gill         return;
100*e610b316SJagpal Singh Gill     }
101*e610b316SJagpal Singh Gill     if (!std::isfinite(userCPU))
102*e610b316SJagpal Singh Gill     {
103*e610b316SJagpal Singh Gill         asyncResp->res.jsonValue[jPtr] = nullptr;
104*e610b316SJagpal Singh Gill         return;
105*e610b316SJagpal Singh Gill     }
106*e610b316SJagpal Singh Gill 
107*e610b316SJagpal Singh Gill     static constexpr double roundFactor = 10000; // 4 decimal places
108*e610b316SJagpal Singh Gill     asyncResp->res.jsonValue[jPtr] = std::round(userCPU * roundFactor) /
109*e610b316SJagpal Singh Gill                                      roundFactor;
110*e610b316SJagpal Singh Gill }
111*e610b316SJagpal Singh Gill 
112*e610b316SJagpal Singh Gill inline void managerGetProcessorStatistics(
113*e610b316SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
114*e610b316SJagpal Singh Gill {
115*e610b316SJagpal Singh Gill     constexpr auto kernelCPUObjPath =
116*e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/cpu/kernel";
117*e610b316SJagpal Singh Gill     constexpr auto userCPUObjPath = "/xyz/openbmc_project/metric/bmc/cpu/user";
118*e610b316SJagpal Singh Gill 
119*e610b316SJagpal Singh Gill     using json_pointer = nlohmann::json::json_pointer;
120*e610b316SJagpal Singh Gill     sdbusplus::asio::getProperty<double>(
121*e610b316SJagpal Singh Gill         *crow::connections::systemBus, healthMonitorServiceName,
122*e610b316SJagpal Singh Gill         kernelCPUObjPath, valueInterface, valueProperty,
123*e610b316SJagpal Singh Gill         std::bind_front(setPercentProperty, asyncResp,
124*e610b316SJagpal Singh Gill                         json_pointer("/ProcessorStatistics/KernelPercent")));
125*e610b316SJagpal Singh Gill 
126*e610b316SJagpal Singh Gill     sdbusplus::asio::getProperty<double>(
127*e610b316SJagpal Singh Gill         *crow::connections::systemBus, healthMonitorServiceName, userCPUObjPath,
128*e610b316SJagpal Singh Gill         valueInterface, valueProperty,
129*e610b316SJagpal Singh Gill         std::bind_front(setPercentProperty, asyncResp,
130*e610b316SJagpal Singh Gill                         json_pointer("/ProcessorStatistics/UserPercent")));
131*e610b316SJagpal Singh Gill }
132*e610b316SJagpal Singh Gill 
133*e610b316SJagpal Singh Gill inline void managerGetMemoryStatistics(
134*e610b316SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
135*e610b316SJagpal Singh Gill {
136*e610b316SJagpal Singh Gill     using json_pointer = nlohmann::json::json_pointer;
137*e610b316SJagpal Singh Gill     constexpr auto availableMemoryObjPath =
138*e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/memory/available";
139*e610b316SJagpal Singh Gill     sdbusplus::asio::getProperty<double>(
140*e610b316SJagpal Singh Gill         *crow::connections::systemBus, healthMonitorServiceName,
141*e610b316SJagpal Singh Gill         availableMemoryObjPath, valueInterface, valueProperty,
142*e610b316SJagpal Singh Gill         std::bind_front(setBytesProperty, asyncResp,
143*e610b316SJagpal Singh Gill                         json_pointer("/MemoryStatistics/AvailableBytes")));
144*e610b316SJagpal Singh Gill 
145*e610b316SJagpal Singh Gill     constexpr auto bufferedAndCachedMemoryObjPath =
146*e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/memory/buffered_and_cached";
147*e610b316SJagpal Singh Gill     sdbusplus::asio::getProperty<double>(
148*e610b316SJagpal Singh Gill         *crow::connections::systemBus, healthMonitorServiceName,
149*e610b316SJagpal Singh Gill         bufferedAndCachedMemoryObjPath, valueInterface, valueProperty,
150*e610b316SJagpal Singh Gill         std::bind_front(
151*e610b316SJagpal Singh Gill             setBytesProperty, asyncResp,
152*e610b316SJagpal Singh Gill             json_pointer("/MemoryStatistics/BuffersAndCacheBytes")));
153*e610b316SJagpal Singh Gill 
154*e610b316SJagpal Singh Gill     constexpr auto freeMemoryObjPath =
155*e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/memory/free";
156*e610b316SJagpal Singh Gill     sdbusplus::asio::getProperty<double>(
157*e610b316SJagpal Singh Gill         *crow::connections::systemBus, healthMonitorServiceName,
158*e610b316SJagpal Singh Gill         freeMemoryObjPath, valueInterface, valueProperty,
159*e610b316SJagpal Singh Gill         std::bind_front(setBytesProperty, asyncResp,
160*e610b316SJagpal Singh Gill                         json_pointer("/MemoryStatistics/FreeBytes")));
161*e610b316SJagpal Singh Gill 
162*e610b316SJagpal Singh Gill     constexpr auto sharedMemoryObjPath =
163*e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/memory/shared";
164*e610b316SJagpal Singh Gill     sdbusplus::asio::getProperty<double>(
165*e610b316SJagpal Singh Gill         *crow::connections::systemBus, healthMonitorServiceName,
166*e610b316SJagpal Singh Gill         sharedMemoryObjPath, valueInterface, valueProperty,
167*e610b316SJagpal Singh Gill         std::bind_front(setBytesProperty, asyncResp,
168*e610b316SJagpal Singh Gill                         json_pointer("/MemoryStatistics/SharedBytes")));
169*e610b316SJagpal Singh Gill 
170*e610b316SJagpal Singh Gill     constexpr auto totalMemoryObjPath =
171*e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/memory/total";
172*e610b316SJagpal Singh Gill     sdbusplus::asio::getProperty<double>(
173*e610b316SJagpal Singh Gill         *crow::connections::systemBus, healthMonitorServiceName,
174*e610b316SJagpal Singh Gill         totalMemoryObjPath, valueInterface, valueProperty,
175*e610b316SJagpal Singh Gill         std::bind_front(setBytesProperty, asyncResp,
176*e610b316SJagpal Singh Gill                         json_pointer("/MemoryStatistics/TotalBytes")));
177*e610b316SJagpal Singh Gill }
178*e610b316SJagpal Singh Gill 
179ac106bf6SEd Tanous inline void afterGetManagerStartTime(
180ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
181ac106bf6SEd Tanous     const boost::system::error_code& ec, uint64_t bmcwebResetTime)
1825ace29d2SEd Tanous {
1835ace29d2SEd Tanous     if (ec)
1845ace29d2SEd Tanous     {
1855ace29d2SEd Tanous         // Not all servers will be running in systemd, so ignore the error.
1865ace29d2SEd Tanous         return;
1875ace29d2SEd Tanous     }
1885ace29d2SEd Tanous     using std::chrono::steady_clock;
1895ace29d2SEd Tanous 
1905ace29d2SEd Tanous     std::chrono::duration<steady_clock::rep, std::micro> usReset{
1915ace29d2SEd Tanous         bmcwebResetTime};
1925ace29d2SEd Tanous     steady_clock::time_point resetTime{usReset};
1935ace29d2SEd Tanous 
1945ace29d2SEd Tanous     steady_clock::time_point now = steady_clock::now();
1955ace29d2SEd Tanous 
1965ace29d2SEd Tanous     steady_clock::duration runTime = now - resetTime;
1975ace29d2SEd Tanous 
1985ace29d2SEd Tanous     if (runTime < steady_clock::duration::zero())
1995ace29d2SEd Tanous     {
20062598e31SEd Tanous         BMCWEB_LOG_CRITICAL("Uptime was negative????");
201ac106bf6SEd Tanous         messages::internalError(asyncResp->res);
2025ace29d2SEd Tanous         return;
2035ace29d2SEd Tanous     }
2045ace29d2SEd Tanous 
2055ace29d2SEd Tanous     // Floor to the closest millisecond
2065ace29d2SEd Tanous     using Milli = std::chrono::duration<steady_clock::rep, std::milli>;
2075ace29d2SEd Tanous     Milli milli = std::chrono::floor<Milli>(runTime);
2085ace29d2SEd Tanous 
2095ace29d2SEd Tanous     using SecondsFloat = std::chrono::duration<double>;
2105ace29d2SEd Tanous     SecondsFloat sec = std::chrono::duration_cast<SecondsFloat>(milli);
2115ace29d2SEd Tanous 
212ac106bf6SEd Tanous     asyncResp->res.jsonValue["ServiceRootUptimeSeconds"] = sec.count();
2135ace29d2SEd Tanous }
2145ace29d2SEd Tanous 
215ac106bf6SEd Tanous inline void managerGetServiceRootUptime(
216ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2175ace29d2SEd Tanous {
2185ace29d2SEd Tanous     sdbusplus::asio::getProperty<uint64_t>(
2195ace29d2SEd Tanous         *crow::connections::systemBus, "org.freedesktop.systemd1",
2205ace29d2SEd Tanous         "/org/freedesktop/systemd1/unit/bmcweb_2eservice",
2215ace29d2SEd Tanous         "org.freedesktop.systemd1.Unit", "ActiveEnterTimestampMonotonic",
222ac106bf6SEd Tanous         std::bind_front(afterGetManagerStartTime, asyncResp));
2235ace29d2SEd Tanous }
224a51fc2d2SSui Chen /**
225a51fc2d2SSui Chen  * handleManagerDiagnosticData supports ManagerDiagnosticData.
226a51fc2d2SSui Chen  * It retrieves BMC health information from various DBus resources and returns
227a51fc2d2SSui Chen  * the information through the response.
228a51fc2d2SSui Chen  */
229a51fc2d2SSui Chen inline void handleManagerDiagnosticDataGet(
230a51fc2d2SSui Chen     crow::App& app, const crow::Request& req,
231a51fc2d2SSui Chen     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
232a51fc2d2SSui Chen {
233a51fc2d2SSui Chen     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
234a51fc2d2SSui Chen     {
235a51fc2d2SSui Chen         return;
236a51fc2d2SSui Chen     }
237a51fc2d2SSui Chen     asyncResp->res.jsonValue["@odata.type"] =
2385ace29d2SEd Tanous         "#ManagerDiagnosticData.v1_2_0.ManagerDiagnosticData";
239a51fc2d2SSui Chen     asyncResp->res.jsonValue["@odata.id"] =
240a51fc2d2SSui Chen         "/redfish/v1/Managers/bmc/ManagerDiagnosticData";
241a51fc2d2SSui Chen     asyncResp->res.jsonValue["Id"] = "ManagerDiagnosticData";
242a51fc2d2SSui Chen     asyncResp->res.jsonValue["Name"] = "Manager Diagnostic Data";
2435ace29d2SEd Tanous 
2445ace29d2SEd Tanous     managerGetServiceRootUptime(asyncResp);
245*e610b316SJagpal Singh Gill     managerGetProcessorStatistics(asyncResp);
246*e610b316SJagpal Singh Gill     managerGetMemoryStatistics(asyncResp);
247*e610b316SJagpal Singh Gill     managerGetStorageStatistics(asyncResp);
248a51fc2d2SSui Chen }
249a51fc2d2SSui Chen 
250a51fc2d2SSui Chen inline void requestRoutesManagerDiagnosticData(App& app)
251a51fc2d2SSui Chen {
252a51fc2d2SSui Chen     BMCWEB_ROUTE(app, "/redfish/v1/Managers/bmc/ManagerDiagnosticData")
253a51fc2d2SSui Chen         .privileges(redfish::privileges::getManagerDiagnosticData)
254a51fc2d2SSui Chen         .methods(boost::beast::http::verb::get)(
255a51fc2d2SSui Chen             std::bind_front(handleManagerDiagnosticDataGet, std::ref(app)));
256a51fc2d2SSui Chen }
257a51fc2d2SSui Chen 
258a51fc2d2SSui Chen } // namespace redfish
259