| #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 |