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