| #include "absl/strings/match.h" |
| #include "managed_store_http.hpp" |
| |
| #include <malloc.h> |
| |
| #include "logging.hpp" |
| #include "managed_store.hpp" |
| #include "managed_store_clock.hpp" |
| #include "managed_store_types.hpp" |
| #include "query.hpp" |
| |
| #include <nlohmann/json.hpp> |
| |
| #include <algorithm> |
| #include <charconv> |
| #include <string_view> |
| |
| #ifdef UNIT_TEST_BUILD |
| #include "test/g3/mock_managed_store.hpp" // NOLINT |
| #endif |
| |
| namespace managedStore |
| { |
| |
| void ManagedObjectStoreHttp::requestRoutesManagedStoreDebug( |
| const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| // playing with the header: |
| auto maxAgeSec = 0; |
| const auto maxAgeSecStr = |
| req.getHeaderValue(bmcweb::BMCWEB_HINT_MAX_AGE_SEC); |
| if (!maxAgeSecStr.empty()) |
| { |
| std::from_chars(maxAgeSecStr.data(), |
| maxAgeSecStr.data() + maxAgeSecStr.size(), maxAgeSec); |
| } |
| |
| BMCWEB_LOG_STATEFUL_DEBUG |
| << "=> /debug/managed_store: target: " << req.target() |
| << " method: " << req.method() << " body: " << req.body() |
| << " maxAgeSecStr: " << maxAgeSecStr << " maxAgeSec: " << maxAgeSec; |
| |
| // ManagedObjectStore instance: |
| auto *store = managedStore::GetManagedObjectStore(); |
| if (store == nullptr) |
| { |
| asyncResp->res.jsonValue["err"] = "managed object store is null"; |
| BMCWEB_LOG_STATEFUL_ERROR << "=> ERROR: " |
| << asyncResp->res.jsonValue.dump(); |
| return; |
| } |
| |
| // config: |
| asyncResp->res.jsonValue["config"] = store->getConfig().toJson(); |
| |
| // objects: |
| asyncResp->res.jsonValue["managed_objects_metrics"] = |
| store->GetManagedObjectsMetrics(managedStore::clockNow()); |
| |
| // serialized size: |
| asyncResp->res.jsonValue["snapshot_size_in_bytes"] = |
| store->GetSnapshotSizeInBytes(); |
| |
| // Export pq entries: |
| store->GetPriorityQueueSize([asyncResp](size_t size) { |
| asyncResp->res.jsonValue["managed_objects_pq_size"] = size; |
| }); |
| store->GetPriorityQueueMetrics([asyncResp](const nlohmann::json& metrics) { |
| asyncResp->res.jsonValue["managed_objects_pq_entries"] = metrics; |
| }); |
| |
| // ManagedStore counters from managedStoreTracker |
| const ManagedStoreTracker& storeTracker = store->getStoreTracker(); |
| asyncResp->res.jsonValue["tracker"] = storeTracker.toJson(); |
| |
| // always keep this one as the last item: |
| asyncResp->res.jsonValue["ok"] = true; |
| } |
| |
| void ManagedObjectStoreHttp::requestRoutesManagedStorePostFlush( |
| const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| BMCWEB_LOG_STATEFUL_DEBUG |
| << "=> /debug/managed_store: target: " << req.target() |
| << " method: " << req.method() << " body: " << req.body(); |
| |
| // ManagedObjectStore instance: |
| auto *store = managedStore::GetManagedObjectStore(); |
| if (store == nullptr) |
| { |
| asyncResp->res.jsonValue["err"] = "managed object store is null"; |
| BMCWEB_LOG_STATEFUL_ERROR << "=> ERROR: " |
| << asyncResp->res.jsonValue.dump(); |
| return; |
| } |
| |
| asyncResp->res.jsonValue["config"] = store->getConfig().toJson(); |
| store->clearAllObjects(); |
| asyncResp->res.jsonValue["managed_objects_metrics"] = |
| store->GetManagedObjectsMetrics(managedStore::clockNow()); |
| store->GetPriorityQueueSize([asyncResp](size_t size) { |
| asyncResp->res.jsonValue["managed_objects_pq_size"] = size; |
| }); |
| |
| // always keep this one as the last item: |
| asyncResp->res.jsonValue["ok"] = true; |
| } |
| |
| void ManagedObjectStoreHttp::requestRoutesSubscriptionsDebug( |
| const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| BMCWEB_LOG_STATEFUL_DEBUG |
| << "=> /debug/subscriptions: target: " << req.target() |
| << " method: " << req.method() << " body: " << req.body(); |
| |
| // ManagedObjectStore instance: |
| auto *store = managedStore::GetManagedObjectStore(); |
| if (store == nullptr) |
| { |
| asyncResp->res.jsonValue["err"] = "managed object store is null"; |
| BMCWEB_LOG_STATEFUL_ERROR << "=> ERROR: " |
| << asyncResp->res.jsonValue.dump(); |
| return; |
| } |
| |
| asyncResp->res.jsonValue["SubscriptionStore"] = |
| store->GetSubscriptionsToJSON(); |
| asyncResp->res.jsonValue["DBusMonitors"] = store->GetDBusMonitorsToJSON(); |
| } |
| |
| void ManagedObjectStoreHttp::requestRoutesEventStoreDebug( |
| const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| BMCWEB_LOG_STATEFUL_DEBUG |
| << "=> /debug/event_store: target: " << req.target() |
| << " method: " << req.method() << " body: " << req.body(); |
| |
| // ManagedObjectStore instance: |
| auto *store = managedStore::GetManagedObjectStore(); |
| if (store == nullptr) |
| { |
| asyncResp->res.jsonValue["err"] = "managed object store is null"; |
| BMCWEB_LOG_STATEFUL_ERROR << "=> ERROR: " |
| << asyncResp->res.jsonValue.dump(); |
| return; |
| } |
| |
| std::string_view target = req.target(); |
| auto startIndex = target.find('?'); |
| if (startIndex != std::string::npos) |
| { |
| // The query has query params |
| auto subIdIndex = target.find("subscription_id=", startIndex); |
| if (subIdIndex == std::string::npos || subIdIndex != startIndex + 1) |
| { |
| asyncResp->res.jsonValue["Error"] = |
| "Invalid query param. Only subscription_id param is supported."; |
| return; |
| } |
| auto len = strlen("subscription_id="); |
| std::string_view subscription_id = target.substr(subIdIndex + len); |
| if (subscription_id.empty() || absl::StrContains(subscription_id, '?')) |
| { |
| asyncResp->res.jsonValue["Error"] = |
| "Invalid query params. Only subscription_id param is supported."; |
| return; |
| } |
| BMCWEB_LOG_STATEFUL_DEBUG << "subscription_id = " << subscription_id; |
| size_t id = 0; |
| if (1 == sscanf(subscription_id.data(), "%zu", &id)) // NOLINT |
| { |
| asyncResp->res.jsonValue = |
| store->GetEventsBySubscriptionIdToJSON(id); |
| return; |
| } |
| asyncResp->res.jsonValue["Error"] = "Invalid subscription_id."; |
| return; |
| } |
| asyncResp->res.jsonValue = store->GetEventsToJSON(); |
| } |
| |
| void ManagedObjectStoreHttp::requestRoutesEventStoreFlush( |
| const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| BMCWEB_LOG_STATEFUL_DEBUG |
| << "=> /debug/event_store: target: " << req.target() |
| << " method: " << req.method() << " body: " << req.body(); |
| |
| // ManagedObjectStore instance: |
| auto *store = managedStore::GetManagedObjectStore(); |
| if (store == nullptr) |
| { |
| asyncResp->res.jsonValue["err"] = "managed object store is null"; |
| BMCWEB_LOG_STATEFUL_ERROR << "=> ERROR: " |
| << asyncResp->res.jsonValue.dump(); |
| return; |
| } |
| |
| store->ClearEventStore(); |
| asyncResp->res.jsonValue = store->GetEventsToJSON(); |
| } |
| |
| void ManagedObjectStoreHttp::requestGetGoogleManagedObjectStoreMetrics( |
| App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| if (!redfish::setUpRedfishRoute(app, req, asyncResp)) |
| { |
| return; |
| } |
| |
| asyncResp->res.jsonValue = |
| managedStore::GetManagedObjectStore()->GetManagedObjectsMetrics( |
| managedStore::clockNow()); |
| } |
| |
| void ManagedObjectStoreHttp::requestGetGoogleTimetrace( |
| App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| (void)app; |
| BMCWEB_LOG_STATEFUL_DEBUG |
| << "=> GoogleTimetrace:" << " method: " << req.method() |
| << " target: " << req.target() << " body: " << req.body(); |
| |
| // ManagedObjectStore instance: |
| auto *store = managedStore::GetManagedObjectStore(); |
| if (store == nullptr) |
| { |
| asyncResp->res.jsonValue["err"] = "managed object store is null"; |
| BMCWEB_LOG_STATEFUL_ERROR << "=> ERROR: " |
| << asyncResp->res.jsonValue.dump(); |
| return; |
| } |
| |
| nlohmann::json google; |
| google["@odata.id"] = |
| "/redfish/v1/Managers/bmc/ManagerDiagnosticData/Oem/Google/GoogleTimetrace"; |
| google["@odata.type"] = "#GoogleTimetrace.v1_0_0.GoogleTimetrace"; |
| |
| google["Actions"]["#GoogleTimetrace.Clear"] = { |
| {"target", |
| "/redfish/v1/Managers/bmc/ManagerDiagnosticData/Oem/Google/GoogleTimetrace/Actions/GoogleTimetrace.Clear"}}; |
| |
| // timeTrace |
| const auto& timeTrace = store->getTimeTrace(); |
| google["time_trace_size"] = timeTrace.size(); |
| google["timetrace"] = timeTrace; |
| |
| // always keep this one as the last item: |
| // final object: |
| asyncResp->res.jsonValue = google; |
| } |
| |
| void ManagedObjectStoreHttp::handleGoogleTimetraceClearPost( |
| App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| (void)app; |
| BMCWEB_LOG_STATEFUL_DEBUG |
| << "=> GoogleTimetraceClear:" << " method: " << req.method() |
| << " target: " << req.target() << " body: " << req.body(); |
| |
| // ManagedObjectStore instance: |
| auto *store = managedStore::GetManagedObjectStore(); |
| if (store == nullptr) |
| { |
| asyncResp->res.jsonValue["err"] = "managed object store is null"; |
| BMCWEB_LOG_STATEFUL_ERROR << "=> ERROR: " |
| << asyncResp->res.jsonValue.dump(); |
| return; |
| } |
| |
| store->clearTimeTrace(); |
| } |
| |
| void ManagedObjectStoreHttp::handleGoogleTakeSnapShot( |
| [[maybe_unused]] App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| BMCWEB_LOG_STATEFUL_DEBUG |
| << "=> GoogleTakeSnapShot:" << " method: " << req.method() |
| << " target: " << req.target() << " body: " << req.body(); |
| |
| auto *store = managedStore::GetManagedObjectStore(); |
| if (store == nullptr) |
| { |
| asyncResp->res.jsonValue["err"] = "managed object store is null"; |
| BMCWEB_LOG_STATEFUL_ERROR << "=> ERROR: " |
| << asyncResp->res.jsonValue.dump(); |
| return; |
| } |
| if (store->serialize()) |
| { |
| asyncResp->res.jsonValue["ok"] = true; |
| } |
| else |
| { |
| asyncResp->res.jsonValue["err"] = "Error making snapshot"; |
| BMCWEB_LOG_STATEFUL_ERROR << "=> ERROR: " |
| << asyncResp->res.jsonValue.dump(); |
| } |
| } |
| |
| void ManagedObjectStoreHttp::handleGoogleLoadSnapShot( |
| [[maybe_unused]] App& app, const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) |
| { |
| BMCWEB_LOG_STATEFUL_DEBUG |
| << "=> GoogleLoadSnapShot:" << " method: " << req.method() |
| << " target: " << req.target() << " body: " << req.body(); |
| |
| auto *store = managedStore::GetManagedObjectStore(); |
| if (store == nullptr) |
| { |
| asyncResp->res.jsonValue["err"] = "managed object store is null"; |
| BMCWEB_LOG_STATEFUL_ERROR << "=> ERROR: " |
| << asyncResp->res.jsonValue.dump(); |
| return; |
| } |
| if (store->deserialize()) |
| { |
| asyncResp->res.jsonValue["ok"] = true; |
| } |
| else |
| { |
| asyncResp->res.jsonValue["err"] = "Error loading snapshot"; |
| BMCWEB_LOG_STATEFUL_ERROR << "=> ERROR: " |
| << asyncResp->res.jsonValue.dump(); |
| } |
| } |
| |
| void requestRoutesManagedStore(App& app) |
| { |
| // a few exports for debugging: |
| BMCWEB_ROUTE(app, "/debug/malloc_stats") |
| .methods(boost::beast::http::verb::get)( |
| []([[maybe_unused]] const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| asyncResp->res.jsonValue["ok"] = true; |
| malloc_stats(); |
| }); |
| |
| // a few exports for debugging: |
| BMCWEB_ROUTE(app, "/debug/managed_store") |
| // .privileges(redfish::privileges::postManager) |
| .methods(boost::beast::http::verb::get)( |
| [](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| ManagedObjectStoreHttp::requestRoutesManagedStoreDebug(req, asyncResp); |
| }); |
| |
| // flush the managed objects: |
| BMCWEB_ROUTE(app, "/debug/managed_store/clear") |
| .methods(boost::beast::http::verb::post)( |
| [](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| ManagedObjectStoreHttp::requestRoutesManagedStorePostFlush(req, |
| asyncResp); |
| }); |
| |
| // debug subscriptions |
| BMCWEB_ROUTE(app, "/debug/subscriptions") |
| .methods(boost::beast::http::verb::get)( |
| [](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| ManagedObjectStoreHttp::requestRoutesSubscriptionsDebug(req, asyncResp); |
| }); |
| |
| // debug events |
| BMCWEB_ROUTE(app, "/debug/event_store") |
| .methods(boost::beast::http::verb::get)( |
| [](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| ManagedObjectStoreHttp::requestRoutesEventStoreDebug(req, asyncResp); |
| }); |
| |
| // flush the event store |
| BMCWEB_ROUTE(app, "/debug/event_store/clear") |
| .methods(boost::beast::http::verb::post)( |
| [](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| ManagedObjectStoreHttp::requestRoutesEventStoreFlush(req, asyncResp); |
| }); |
| |
| // GoogleManagedObjectStoreMetrics: |
| BMCWEB_ROUTE( |
| app, |
| "/redfish/v1/Managers/bmc/ManagerDiagnosticData/Oem/Google/GoogleManagedObjectStoreMetrics") |
| .methods(boost::beast::http::verb::get)( |
| [&app](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| ManagedObjectStoreHttp::requestGetGoogleManagedObjectStoreMetrics( |
| app, req, asyncResp); |
| }); |
| |
| // requests time trace |
| BMCWEB_ROUTE( |
| app, |
| "/redfish/v1/Managers/bmc/ManagerDiagnosticData/Oem/Google/GoogleTimetrace") |
| .methods(boost::beast::http::verb::get)( |
| [&app](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| ManagedObjectStoreHttp::requestGetGoogleTimetrace(app, req, asyncResp); |
| }); |
| |
| // Clear timetrace: |
| BMCWEB_ROUTE( |
| app, |
| "/redfish/v1/Managers/bmc/ManagerDiagnosticData/Oem/Google/GoogleTimetrace/Actions/GoogleTimetrace.Clear") |
| .methods(boost::beast::http::verb::post)( |
| [&app](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| ManagedObjectStoreHttp::handleGoogleTimetraceClearPost(app, req, |
| asyncResp); |
| }); |
| |
| // take snapshot |
| BMCWEB_ROUTE( |
| app, |
| "/redfish/v1/Managers/bmc/ManagerDiagnosticData/Oem/Google/GoogleSnapShot/Actions/GoogleTakeSnapShot") |
| .methods(boost::beast::http::verb::post)( |
| [&app](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| ManagedObjectStoreHttp::handleGoogleTakeSnapShot(app, req, asyncResp); |
| }); |
| |
| // load snapshot |
| BMCWEB_ROUTE( |
| app, |
| "/redfish/v1/Managers/bmc/ManagerDiagnosticData/Oem/Google/GoogleSnapShot/Actions/GoogleLoadSnapShot") |
| .methods(boost::beast::http::verb::post)( |
| [&app](const crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { |
| ManagedObjectStoreHttp::handleGoogleLoadSnapShot(app, req, asyncResp); |
| }); |
| } |
| |
| } // namespace managedStore |