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