xref: /openbmc/bmcweb/features/redfish/lib/manager_diagnostic_data.hpp (revision 504af5a0568171b72caf13234cc81380b261fa21)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3a51fc2d2SSui Chen #pragma once
4a51fc2d2SSui Chen 
5d7857201SEd Tanous #include "bmcweb_config.h"
6d7857201SEd Tanous 
73ccb3adbSEd Tanous #include "app.hpp"
83ccb3adbSEd Tanous #include "async_resp.hpp"
9deae6a78SEd Tanous #include "dbus_utility.hpp"
10d7857201SEd Tanous #include "error_messages.hpp"
113ccb3adbSEd Tanous #include "http_request.hpp"
12d7857201SEd Tanous #include "logging.hpp"
133ccb3adbSEd Tanous #include "query.hpp"
143ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
153ccb3adbSEd Tanous 
16d7857201SEd Tanous #include <boost/asio/error.hpp>
17d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
18e610b316SJagpal Singh Gill #include <boost/system/error_code.hpp>
19e610b316SJagpal Singh Gill #include <boost/system/linux_error.hpp>
20253f11b8SEd Tanous #include <boost/url/format.hpp>
21a51fc2d2SSui Chen #include <nlohmann/json.hpp>
22a51fc2d2SSui Chen 
23d7857201SEd Tanous #include <chrono>
24d7857201SEd Tanous #include <cmath>
25d7857201SEd Tanous #include <cstdint>
26e610b316SJagpal Singh Gill #include <functional>
27e610b316SJagpal Singh Gill #include <memory>
28d7857201SEd Tanous #include <ratio>
29d7857201SEd Tanous #include <source_location>
30a51fc2d2SSui Chen #include <string>
31a51fc2d2SSui Chen 
32a51fc2d2SSui Chen namespace redfish
33a51fc2d2SSui Chen {
34a51fc2d2SSui Chen 
35e610b316SJagpal Singh Gill static constexpr auto healthMonitorServiceName =
36e610b316SJagpal Singh Gill     "xyz.openbmc_project.HealthMon";
37e610b316SJagpal Singh Gill static constexpr auto valueInterface = "xyz.openbmc_project.Metric.Value";
38e610b316SJagpal Singh Gill static constexpr auto valueProperty = "Value";
39e610b316SJagpal Singh Gill 
40e610b316SJagpal Singh Gill inline bool checkErrors(
41e610b316SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
42e610b316SJagpal Singh Gill     const boost::system::error_code& ec,
43e610b316SJagpal Singh Gill     const std::source_location src = std::source_location::current())
44e610b316SJagpal Singh Gill {
45e610b316SJagpal Singh Gill     if (ec.value() == boost::asio::error::basic_errors::host_unreachable)
46e610b316SJagpal Singh Gill     {
47e610b316SJagpal Singh Gill         BMCWEB_LOG_WARNING("Failed to find server, Dbus error {}", ec);
48e610b316SJagpal Singh Gill         return true;
49e610b316SJagpal Singh Gill     }
50e610b316SJagpal Singh Gill     if (ec.value() == boost::system::linux_error::bad_request_descriptor)
51e610b316SJagpal Singh Gill     {
52e610b316SJagpal Singh Gill         BMCWEB_LOG_WARNING("Invalid Path, Dbus error {}", ec);
53e610b316SJagpal Singh Gill         return true;
54e610b316SJagpal Singh Gill     }
55e610b316SJagpal Singh Gill     if (ec)
56e610b316SJagpal Singh Gill     {
57e610b316SJagpal Singh Gill         BMCWEB_LOG_ERROR("{} failed, error {}", src.function_name(), ec);
58e610b316SJagpal Singh Gill         messages::internalError(asyncResp->res);
59e610b316SJagpal Singh Gill         return true;
60e610b316SJagpal Singh Gill     }
61e610b316SJagpal Singh Gill     return false;
62e610b316SJagpal Singh Gill }
63e610b316SJagpal Singh Gill 
64*504af5a0SPatrick Williams inline void setBytesProperty(
65*504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
66e610b316SJagpal Singh Gill     const nlohmann::json::json_pointer& jPtr,
67e610b316SJagpal Singh Gill     const boost::system::error_code& ec, double bytes)
68e610b316SJagpal Singh Gill {
69e610b316SJagpal Singh Gill     if (checkErrors(asyncResp, ec))
70e610b316SJagpal Singh Gill     {
71e610b316SJagpal Singh Gill         return;
72e610b316SJagpal Singh Gill     }
73e610b316SJagpal Singh Gill     if (!std::isfinite(bytes))
74e610b316SJagpal Singh Gill     {
75e610b316SJagpal Singh Gill         BMCWEB_LOG_WARNING("Property read for {} was not finite",
76e610b316SJagpal Singh Gill                            jPtr.to_string());
77e610b316SJagpal Singh Gill         asyncResp->res.jsonValue[jPtr] = nullptr;
78e610b316SJagpal Singh Gill         return;
79e610b316SJagpal Singh Gill     }
80e610b316SJagpal Singh Gill     // If the param is in Kib, make it Kib.  Redfish uses this as a naming
81e610b316SJagpal Singh Gill     // DBus represents as bytes
82e610b316SJagpal Singh Gill     if (std::string_view(jPtr.back()).ends_with("KiB"))
83e610b316SJagpal Singh Gill     {
84e610b316SJagpal Singh Gill         bytes /= 1024.0;
85e610b316SJagpal Singh Gill     }
86e610b316SJagpal Singh Gill 
87e610b316SJagpal Singh Gill     asyncResp->res.jsonValue[jPtr] = static_cast<int64_t>(bytes);
88e610b316SJagpal Singh Gill }
89e610b316SJagpal Singh Gill 
90e610b316SJagpal Singh Gill inline void managerGetStorageStatistics(
91e610b316SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
92e610b316SJagpal Singh Gill {
93e610b316SJagpal Singh Gill     constexpr auto freeStorageObjPath =
94e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/storage/rw";
95e610b316SJagpal Singh Gill 
96deae6a78SEd Tanous     dbus::utility::getProperty<double>(
97deae6a78SEd Tanous         healthMonitorServiceName, freeStorageObjPath, valueInterface,
98deae6a78SEd Tanous         valueProperty,
99e610b316SJagpal Singh Gill         std::bind_front(setBytesProperty, asyncResp,
100e610b316SJagpal Singh Gill                         nlohmann::json::json_pointer("/FreeStorageSpaceKiB")));
101e610b316SJagpal Singh Gill }
102e610b316SJagpal Singh Gill 
103*504af5a0SPatrick Williams inline void setPercentProperty(
104*504af5a0SPatrick Williams     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
105e610b316SJagpal Singh Gill     const nlohmann::json::json_pointer& jPtr,
106e610b316SJagpal Singh Gill     const boost::system::error_code& ec, double userCPU)
107e610b316SJagpal Singh Gill {
108e610b316SJagpal Singh Gill     if (checkErrors(asyncResp, ec))
109e610b316SJagpal Singh Gill     {
110e610b316SJagpal Singh Gill         return;
111e610b316SJagpal Singh Gill     }
112e610b316SJagpal Singh Gill     if (!std::isfinite(userCPU))
113e610b316SJagpal Singh Gill     {
114e610b316SJagpal Singh Gill         asyncResp->res.jsonValue[jPtr] = nullptr;
115e610b316SJagpal Singh Gill         return;
116e610b316SJagpal Singh Gill     }
117e610b316SJagpal Singh Gill 
118e610b316SJagpal Singh Gill     static constexpr double roundFactor = 10000; // 4 decimal places
119bd79bce8SPatrick Williams     asyncResp->res.jsonValue[jPtr] =
120bd79bce8SPatrick Williams         std::round(userCPU * roundFactor) / roundFactor;
121e610b316SJagpal Singh Gill }
122e610b316SJagpal Singh Gill 
123e610b316SJagpal Singh Gill inline void managerGetProcessorStatistics(
124e610b316SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
125e610b316SJagpal Singh Gill {
126e610b316SJagpal Singh Gill     constexpr auto kernelCPUObjPath =
127e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/cpu/kernel";
128e610b316SJagpal Singh Gill     constexpr auto userCPUObjPath = "/xyz/openbmc_project/metric/bmc/cpu/user";
129e610b316SJagpal Singh Gill 
130e610b316SJagpal Singh Gill     using json_pointer = nlohmann::json::json_pointer;
131deae6a78SEd Tanous     dbus::utility::getProperty<double>(
132deae6a78SEd Tanous         healthMonitorServiceName, kernelCPUObjPath, valueInterface,
133deae6a78SEd Tanous         valueProperty,
134e610b316SJagpal Singh Gill         std::bind_front(setPercentProperty, asyncResp,
135e610b316SJagpal Singh Gill                         json_pointer("/ProcessorStatistics/KernelPercent")));
136e610b316SJagpal Singh Gill 
137deae6a78SEd Tanous     dbus::utility::getProperty<double>(
138deae6a78SEd Tanous         healthMonitorServiceName, userCPUObjPath, valueInterface, valueProperty,
139e610b316SJagpal Singh Gill         std::bind_front(setPercentProperty, asyncResp,
140e610b316SJagpal Singh Gill                         json_pointer("/ProcessorStatistics/UserPercent")));
141e610b316SJagpal Singh Gill }
142e610b316SJagpal Singh Gill 
143e610b316SJagpal Singh Gill inline void managerGetMemoryStatistics(
144e610b316SJagpal Singh Gill     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
145e610b316SJagpal Singh Gill {
146e610b316SJagpal Singh Gill     using json_pointer = nlohmann::json::json_pointer;
147e610b316SJagpal Singh Gill     constexpr auto availableMemoryObjPath =
148e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/memory/available";
149deae6a78SEd Tanous     dbus::utility::getProperty<double>(
150deae6a78SEd Tanous         healthMonitorServiceName, availableMemoryObjPath, valueInterface,
151deae6a78SEd Tanous         valueProperty,
152e610b316SJagpal Singh Gill         std::bind_front(setBytesProperty, asyncResp,
153e610b316SJagpal Singh Gill                         json_pointer("/MemoryStatistics/AvailableBytes")));
154e610b316SJagpal Singh Gill 
155e610b316SJagpal Singh Gill     constexpr auto bufferedAndCachedMemoryObjPath =
156e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/memory/buffered_and_cached";
157deae6a78SEd Tanous     dbus::utility::getProperty<double>(
158deae6a78SEd Tanous         healthMonitorServiceName, bufferedAndCachedMemoryObjPath,
159deae6a78SEd Tanous         valueInterface, valueProperty,
160e610b316SJagpal Singh Gill         std::bind_front(
161e610b316SJagpal Singh Gill             setBytesProperty, asyncResp,
162e610b316SJagpal Singh Gill             json_pointer("/MemoryStatistics/BuffersAndCacheBytes")));
163e610b316SJagpal Singh Gill 
164e610b316SJagpal Singh Gill     constexpr auto freeMemoryObjPath =
165e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/memory/free";
166deae6a78SEd Tanous     dbus::utility::getProperty<double>(
167deae6a78SEd Tanous         healthMonitorServiceName, freeMemoryObjPath, valueInterface,
168deae6a78SEd Tanous         valueProperty,
169e610b316SJagpal Singh Gill         std::bind_front(setBytesProperty, asyncResp,
170e610b316SJagpal Singh Gill                         json_pointer("/MemoryStatistics/FreeBytes")));
171e610b316SJagpal Singh Gill 
172e610b316SJagpal Singh Gill     constexpr auto sharedMemoryObjPath =
173e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/memory/shared";
174deae6a78SEd Tanous     dbus::utility::getProperty<double>(
175deae6a78SEd Tanous         healthMonitorServiceName, sharedMemoryObjPath, valueInterface,
176deae6a78SEd Tanous         valueProperty,
177e610b316SJagpal Singh Gill         std::bind_front(setBytesProperty, asyncResp,
178e610b316SJagpal Singh Gill                         json_pointer("/MemoryStatistics/SharedBytes")));
179e610b316SJagpal Singh Gill 
180e610b316SJagpal Singh Gill     constexpr auto totalMemoryObjPath =
181e610b316SJagpal Singh Gill         "/xyz/openbmc_project/metric/bmc/memory/total";
182deae6a78SEd Tanous     dbus::utility::getProperty<double>(
183deae6a78SEd Tanous         healthMonitorServiceName, totalMemoryObjPath, valueInterface,
184deae6a78SEd Tanous         valueProperty,
185e610b316SJagpal Singh Gill         std::bind_front(setBytesProperty, asyncResp,
186e610b316SJagpal Singh Gill                         json_pointer("/MemoryStatistics/TotalBytes")));
187e610b316SJagpal Singh Gill }
188e610b316SJagpal Singh Gill 
189ac106bf6SEd Tanous inline void afterGetManagerStartTime(
190ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
191ac106bf6SEd Tanous     const boost::system::error_code& ec, uint64_t bmcwebResetTime)
1925ace29d2SEd Tanous {
1935ace29d2SEd Tanous     if (ec)
1945ace29d2SEd Tanous     {
1955ace29d2SEd Tanous         // Not all servers will be running in systemd, so ignore the error.
1965ace29d2SEd Tanous         return;
1975ace29d2SEd Tanous     }
1985ace29d2SEd Tanous     using std::chrono::steady_clock;
1995ace29d2SEd Tanous 
2005ace29d2SEd Tanous     std::chrono::duration<steady_clock::rep, std::micro> usReset{
2015ace29d2SEd Tanous         bmcwebResetTime};
2025ace29d2SEd Tanous     steady_clock::time_point resetTime{usReset};
2035ace29d2SEd Tanous 
2045ace29d2SEd Tanous     steady_clock::time_point now = steady_clock::now();
2055ace29d2SEd Tanous 
2065ace29d2SEd Tanous     steady_clock::duration runTime = now - resetTime;
2075ace29d2SEd Tanous 
2085ace29d2SEd Tanous     if (runTime < steady_clock::duration::zero())
2095ace29d2SEd Tanous     {
21062598e31SEd Tanous         BMCWEB_LOG_CRITICAL("Uptime was negative????");
211ac106bf6SEd Tanous         messages::internalError(asyncResp->res);
2125ace29d2SEd Tanous         return;
2135ace29d2SEd Tanous     }
2145ace29d2SEd Tanous 
2155ace29d2SEd Tanous     // Floor to the closest millisecond
2165ace29d2SEd Tanous     using Milli = std::chrono::duration<steady_clock::rep, std::milli>;
2175ace29d2SEd Tanous     Milli milli = std::chrono::floor<Milli>(runTime);
2185ace29d2SEd Tanous 
2195ace29d2SEd Tanous     using SecondsFloat = std::chrono::duration<double>;
2205ace29d2SEd Tanous     SecondsFloat sec = std::chrono::duration_cast<SecondsFloat>(milli);
2215ace29d2SEd Tanous 
222ac106bf6SEd Tanous     asyncResp->res.jsonValue["ServiceRootUptimeSeconds"] = sec.count();
2235ace29d2SEd Tanous }
2245ace29d2SEd Tanous 
225ac106bf6SEd Tanous inline void managerGetServiceRootUptime(
226ac106bf6SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
2275ace29d2SEd Tanous {
228deae6a78SEd Tanous     dbus::utility::getProperty<uint64_t>(
229deae6a78SEd Tanous         "org.freedesktop.systemd1",
2305ace29d2SEd Tanous         "/org/freedesktop/systemd1/unit/bmcweb_2eservice",
2315ace29d2SEd Tanous         "org.freedesktop.systemd1.Unit", "ActiveEnterTimestampMonotonic",
232ac106bf6SEd Tanous         std::bind_front(afterGetManagerStartTime, asyncResp));
2335ace29d2SEd Tanous }
234a51fc2d2SSui Chen /**
235a51fc2d2SSui Chen  * handleManagerDiagnosticData supports ManagerDiagnosticData.
236a51fc2d2SSui Chen  * It retrieves BMC health information from various DBus resources and returns
237a51fc2d2SSui Chen  * the information through the response.
238a51fc2d2SSui Chen  */
239a51fc2d2SSui Chen inline void handleManagerDiagnosticDataGet(
240a51fc2d2SSui Chen     crow::App& app, const crow::Request& req,
241253f11b8SEd Tanous     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
242253f11b8SEd Tanous     const std::string& managerId)
243a51fc2d2SSui Chen {
244a51fc2d2SSui Chen     if (!redfish::setUpRedfishRoute(app, req, asyncResp))
245a51fc2d2SSui Chen     {
246a51fc2d2SSui Chen         return;
247a51fc2d2SSui Chen     }
248253f11b8SEd Tanous 
249253f11b8SEd Tanous     if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME)
250253f11b8SEd Tanous     {
251253f11b8SEd Tanous         messages::resourceNotFound(asyncResp->res, "Manager", managerId);
252253f11b8SEd Tanous         return;
253253f11b8SEd Tanous     }
254253f11b8SEd Tanous 
255a51fc2d2SSui Chen     asyncResp->res.jsonValue["@odata.type"] =
2565ace29d2SEd Tanous         "#ManagerDiagnosticData.v1_2_0.ManagerDiagnosticData";
257a51fc2d2SSui Chen     asyncResp->res.jsonValue["@odata.id"] =
258253f11b8SEd Tanous         boost::urls::format("/redfish/v1/Managers/{}/ManagerDiagnosticData",
259253f11b8SEd Tanous                             BMCWEB_REDFISH_MANAGER_URI_NAME);
260a51fc2d2SSui Chen     asyncResp->res.jsonValue["Id"] = "ManagerDiagnosticData";
261a51fc2d2SSui Chen     asyncResp->res.jsonValue["Name"] = "Manager Diagnostic Data";
2625ace29d2SEd Tanous 
2635ace29d2SEd Tanous     managerGetServiceRootUptime(asyncResp);
264e610b316SJagpal Singh Gill     managerGetProcessorStatistics(asyncResp);
265e610b316SJagpal Singh Gill     managerGetMemoryStatistics(asyncResp);
266e610b316SJagpal Singh Gill     managerGetStorageStatistics(asyncResp);
267a51fc2d2SSui Chen }
268a51fc2d2SSui Chen 
269a51fc2d2SSui Chen inline void requestRoutesManagerDiagnosticData(App& app)
270a51fc2d2SSui Chen {
271253f11b8SEd Tanous     BMCWEB_ROUTE(app, "/redfish/v1/Managers/<str>/ManagerDiagnosticData")
272a51fc2d2SSui Chen         .privileges(redfish::privileges::getManagerDiagnosticData)
273a51fc2d2SSui Chen         .methods(boost::beast::http::verb::get)(
274a51fc2d2SSui Chen             std::bind_front(handleManagerDiagnosticDataGet, std::ref(app)));
275a51fc2d2SSui Chen }
276a51fc2d2SSui Chen 
277a51fc2d2SSui Chen } // namespace redfish
278