blob: 76cd5c672e2ff69a3ed5e0f75f6fda12adb3c80e [file]
#include "tlbmc/redfish/routes/debug.h"
#include <algorithm>
#include <array>
#include <cstddef>
#include <functional>
#include <memory>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/functional/bind_front.h"
#include "absl/log/log.h"
#include "absl/strings/str_cat.h"
#include <nlohmann/json.hpp>
#include <nlohmann/json_fwd.hpp>
#include "tlbmc/central_config/config.h"
#include "tlbmc/collector/fru_collector.h"
#include "tlbmc/hft/manager_debug_json.h"
#include "tlbmc/redfish/app.h"
#include "tlbmc/redfish/request.h"
#include "tlbmc/redfish/response.h"
#include "tlbmc/sensors/sensor.h"
#include "tlbmc/sensors/shared_mem_based_sensor.h"
#include "tlbmc/store/store.h"
#include "google/protobuf/json/json.h"
#include "google/protobuf/util/json_util.h"
namespace milotic_tlbmc::debug {
namespace {
constexpr auto kResources = std::to_array<std::string_view>(
{"App", "Config", "Scheduler", "Store", "HftService", "FruCollector"});
void HandleSharedMemorySensorsResource(const RedfishApp& app,
const RedfishRequest& req,
RedfishResponse& resp) {
DLOG(INFO) << "HandleSharedMemorySensorsResource";
resp.SetKeyInJsonBody("/@odata.id",
"/redfish/tlbmc/Debug/Store/SharedMemorySensors");
resp.SetKeyInJsonBody("/@odata.type",
"#TlbmcDebugStoreSharedMemorySensors.v1_0_0."
"TlbmcDebugStoreSharedMemorySensors");
resp.SetKeyInJsonBody("/Name", "SharedMemorySensors");
resp.SetKeyInJsonBody("/Description",
"Detailed view of tlBMC SharedMemorySensors.");
const Store& store = *app.GetStore();
std::vector<std::shared_ptr<const Sensor>> sensors = store.GetAllSensors();
nlohmann::json::object_t response;
for (const auto& sensor : sensors) {
if (!SharedMemBasedSensor::IsSharedMemSensorKey(sensor->GetKey())) {
continue;
}
std::string key = sensor->GetKey();
std::string board_config_key = sensor->GetBoardConfigKey();
absl::StatusOr<nlohmann::json> sensor_json = sensor->ToJson();
if (!sensor_json.ok()) {
LOG(ERROR) << "Failed to get sensor data for " << key << ": "
<< sensor_json.status();
continue;
}
response[board_config_key][key] = *std::move(sensor_json);
}
resp.SetKeyInJsonBody("/SharedMemorySensors", response);
}
void HandleDebugStoreResource(const RedfishApp& app, const RedfishRequest& req,
RedfishResponse& resp) {
DLOG(INFO) << "HandleDebugStoreResource";
resp.SetKeyInJsonBody("/@odata.id", "/redfish/tlbmc/Debug/Store");
resp.SetKeyInJsonBody("/@odata.type",
"#TlbmcDebugStore.v1_0_0.TlbmcDebugStore");
resp.SetKeyInJsonBody("/Name", "tlbmc");
resp.SetKeyInJsonBody("/Description", "Detailed view of tlBMC store.");
const Store& store = *app.GetStore();
nlohmann::json store_json = store.ToJson();
resp.SetKeyInJsonBody("/Store", store_json);
}
void HandleDebugResource(const RedfishApp& app, const RedfishRequest& req,
RedfishResponse& resp) {
DLOG(INFO) << "HandleDebugResource";
resp.SetKeyInJsonBody("/@odata.id", "/redfish/tlbmc/Debug");
resp.SetKeyInJsonBody("/@odata.type",
"#TlBMCDebugEndpoint.v1_0_0.TlBMCDebugEndpoint");
resp.SetKeyInJsonBody("/Name", "tlbmc");
resp.SetKeyInJsonBody("/Description", "Gets tlBMC debug views.");
for (const auto& resource : kResources) {
nlohmann::json::object_t resource_json;
resource_json["@odata.id"] =
absl::StrCat("/redfish/tlbmc/Debug/", resource);
resp.SetKeyInJsonBody(absl::StrCat("/", resource), resource_json);
}
}
void HandleSchedulerResource(const RedfishApp& app, const RedfishRequest& req,
RedfishResponse& resp) {
DLOG(INFO) << "HandleSchedulerResource";
resp.SetKeyInJsonBody("/@odata.id", "/redfish/tlbmc/Debug/Scheduler");
resp.SetKeyInJsonBody("/@odata.type",
"#TlbmcDebugScheduler.v1_0_0.TlbmcDebugScheduler");
resp.SetKeyInJsonBody("/Name", "Scheduler");
resp.SetKeyInJsonBody("/Description", "Detailed view of tlBMC scheduler.");
resp.SetKeyInJsonBody("/SchedulerStats", app.GetStore()->GetSchedulerStats());
}
void HandleAppResource(const RedfishApp& app, const RedfishRequest& req,
RedfishResponse& resp) {
DLOG(INFO) << "HandleDebugAppResource";
resp.SetKeyInJsonBody("/@odata.id", "/redfish/tlbmc/Debug/App");
resp.SetKeyInJsonBody("/@odata.type", "#TlbmcDebugApp.v1_0_0.TlbmcDebugApp");
resp.SetKeyInJsonBody("/Name", "App Debug");
resp.SetKeyInJsonBody("/Description", "Detailed view of tlBMC app.");
auto sort_urls = [](const absl::flat_hash_map<std::string, size_t>& urls) {
std::vector<std::string> urls_vector;
for (const auto& [url, _] : urls) {
urls_vector.push_back(url);
}
std::sort(urls_vector.begin(), urls_vector.end());
return urls_vector;
};
// We dont want to change the underlying api as that would cause performance
// issues elsewhere. The performance of this debug endpoint is not that
// important and we can spend some time sorting here.
resp.SetKeyInJsonBody("/OwnedUrls", sort_urls(app.GetOwnedUrls()));
auto sort_subtrees = [](const absl::flat_hash_set<std::string>& subtrees) {
std::vector<std::string> subtrees_vector(subtrees.begin(), subtrees.end());
std::sort(subtrees_vector.begin(), subtrees_vector.end());
return subtrees_vector;
};
resp.SetKeyInJsonBody("/OwnedSubtrees",
sort_subtrees(app.GetOwnedSubtrees()));
}
void HandleConfigResource(const RedfishApp& app, const RedfishRequest& req,
RedfishResponse& resp) {
DLOG(INFO) << "HandleConfigResource";
resp.SetKeyInJsonBody("/@odata.id", "/redfish/tlbmc/Debug/Config");
resp.SetKeyInJsonBody("/@odata.type",
"#TlbmcDebugConfig.v1_0_0.TlbmcDebugConfig");
resp.SetKeyInJsonBody("/Name", "Config");
resp.SetKeyInJsonBody("/Description", "Detailed view of tlBMC config.");
resp.SetKeyInJsonBody("/Config", GetTlbmcConfigAsJson());
}
void HandleHftServiceResource(const RedfishApp& app, const RedfishRequest& req,
RedfishResponse& resp) {
DLOG(INFO) << "HandleHftServiceResource";
resp.SetKeyInJsonBody("/@odata.id", "/redfish/tlbmc/Debug/HftService");
resp.SetKeyInJsonBody("/@odata.type",
"#TlbmcDebugHftService.v1_0_0.TlbmcDebugHftService");
resp.SetKeyInJsonBody("/Name", "HftService");
resp.SetKeyInJsonBody("/Description", "Detailed view of HftService.");
const auto* hft_service = app.GetHftService();
if (hft_service != nullptr) {
resp.SetKeyInJsonBody("/HftService",
milotic_hft::HftServiceDebugJson(*hft_service));
} else {
resp.SetKeyInJsonBody("/HftService", "HFT Service not enabled");
}
}
void HandleFruCollectorResource(const RedfishApp& app,
const RedfishRequest& req,
RedfishResponse& resp) {
DLOG(INFO) << "HandleFruCollectorResource";
resp.SetKeyInJsonBody("/@odata.id", "/redfish/tlbmc/Debug/FruCollector");
resp.SetKeyInJsonBody(
"/@odata.type", "#TlbmcDebugFruCollector.v1_0_0.TlbmcDebugFruCollector");
resp.SetKeyInJsonBody("/Name", "FruCollector");
resp.SetKeyInJsonBody("/Description",
"Detailed view of FruCollector tables.");
const Store& store = *app.GetStore();
resp.SetKeyInJsonBody("/IsDeterministicBmcEnabled",
store.IsDeterministicBmcEnabled());
FruCollector* fru_collector = store.GetFruCollector();
if (fru_collector == nullptr) {
resp.SetKeyInJsonBody("/Error", "FruCollector is null");
return;
}
resp.SetKeyInJsonBody("/IsDeterministicPeriodicFruScanningEnabled",
store.IsDeterministicPeriodicFruScanningEnabled());
nlohmann::json deterministic_fru_table_json;
nlohmann::json smbios_fru_table_json;
std::string json_string;
::google::protobuf::util::JsonPrintOptions opts;
opts.preserve_proto_field_names = true;
auto deterministic_table = fru_collector->GetCopyOfDeterministicFruTable();
if (::google::protobuf::json::MessageToJsonString(deterministic_table, &json_string,
opts)
.ok()) {
deterministic_fru_table_json =
nlohmann::json::parse(json_string, nullptr, false);
} else {
deterministic_fru_table_json = "Failed to convert to JSON";
}
json_string.clear();
auto smbios_table = fru_collector->GetCopyOfSmbiosFruTable();
if (::google::protobuf::json::MessageToJsonString(smbios_table, &json_string, opts)
.ok()) {
smbios_fru_table_json = nlohmann::json::parse(json_string, nullptr, false);
} else {
smbios_fru_table_json = "Failed to convert to JSON";
}
resp.SetKeyInJsonBody("/DeterministicFruTable", deterministic_fru_table_json);
resp.SetKeyInJsonBody("/SmbiosFruTable", smbios_fru_table_json);
}
} // namespace
void RegisterRoutes(RedfishApp& app) {
TLBMC_ROUTE(app, "/redfish/tlbmc/Debug/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleDebugResource, std::cref(app)));
TLBMC_ROUTE(app, "/redfish/tlbmc/Debug/App/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleAppResource, std::cref(app)));
TLBMC_ROUTE(app, "/redfish/tlbmc/Debug/Config/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleConfigResource, std::cref(app)));
TLBMC_ROUTE(app, "/redfish/tlbmc/Debug/Store/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleDebugStoreResource, std::cref(app)));
TLBMC_ROUTE(app, "/redfish/tlbmc/Debug/Scheduler/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleSchedulerResource, std::cref(app)));
TLBMC_ROUTE(app, "/redfish/tlbmc/Debug/HftService/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleHftServiceResource, std::cref(app)));
TLBMC_ROUTE(app, "/redfish/tlbmc/Debug/FruCollector/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleFruCollectorResource, std::cref(app)));
TLBMC_ROUTE(app, "/redfish/tlbmc/Debug/Store/SharedMemorySensors/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleSharedMemorySensorsResource, std::cref(app)));
}
} // namespace milotic_tlbmc::debug