blob: 90919d076d2caf8899e14f442e10542d42f5fa9d [file] [log] [blame]
#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