Add Redfish debug route and bulk clear action for sensor value overrides - Exposes GET /redfish/tlbmc/Debug/SensorValueOverrides to view active sensor value overrides formatted and grouped by board config key. - Exposes POST /redfish/tlbmc/Debug/SensorValueOverrides/Actions/SensorValueOverrides.ClearOverrides action to clear all active sensor value overrides across all sensors. - Gates ClearOverrides action using IsSensorOverrideEnabled() to ensure safety on prod images. - Registers authorization pattern in private_pattern_to_entity_array.h. Google-Bug-Id:550410302 PiperOrigin-RevId: 979537721 Change-Id: I82583f58015a25d8bba224ec71ea3841d2d30e1b
diff --git a/tlbmc/redfish/routes/debug.cc b/tlbmc/redfish/routes/debug.cc index 76cd5c6..6598cba 100644 --- a/tlbmc/redfish/routes/debug.cc +++ b/tlbmc/redfish/routes/debug.cc
@@ -5,6 +5,7 @@ #include <cstddef> #include <functional> #include <memory> +#include <optional> #include <string> #include <string_view> #include <utility> @@ -12,6 +13,7 @@ #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" +#include "absl/flags/flag.h" #include "absl/functional/bind_front.h" #include "absl/log/log.h" #include "absl/strings/str_cat.h" @@ -23,6 +25,7 @@ #include "tlbmc/redfish/app.h" #include "tlbmc/redfish/request.h" #include "tlbmc/redfish/response.h" +#include "tlbmc/redfish/routes/sensor.h" #include "tlbmc/sensors/sensor.h" #include "tlbmc/sensors/shared_mem_based_sensor.h" #include "tlbmc/store/store.h" @@ -34,7 +37,8 @@ namespace { constexpr auto kResources = std::to_array<std::string_view>( - {"App", "Config", "Scheduler", "Store", "HftService", "FruCollector"}); + {"App", "Config", "Scheduler", "Store", "HftService", "FruCollector", + "SensorValueOverrides"}); void HandleSharedMemorySensorsResource(const RedfishApp& app, const RedfishRequest& req, @@ -225,6 +229,96 @@ resp.SetKeyInJsonBody("/SmbiosFruTable", smbios_fru_table_json); } +void HandleSensorValueOverridesResource(const RedfishApp& app, + const RedfishRequest& req, + RedfishResponse& resp) { + DLOG(INFO) << "HandleSensorValueOverridesResource"; + resp.SetKeyInJsonBody("/@odata.id", + "/redfish/tlbmc/Debug/SensorValueOverrides"); + resp.SetKeyInJsonBody("/@odata.type", + "#TlbmcDebugSensorValueOverrides.v1_0_0." + "TlbmcDebugSensorValueOverrides"); + resp.SetKeyInJsonBody("/Name", "SensorValueOverrides"); + resp.SetKeyInJsonBody( + "/Description", + "Detailed view and control of active tlBMC sensor value overrides."); + + nlohmann::json action_target; + action_target["target"] = + "/redfish/tlbmc/Debug/SensorValueOverrides/Actions/" + "SensorValueOverrides.ClearOverrides"; + resp.SetKeyInJsonBody("/Actions/#SensorValueOverrides.ClearOverrides", + std::move(action_target)); + + const Store* store = app.GetStore(); + if (store == nullptr) { + resp.SetToInternalError("Store is null"); + return; + } + + std::vector<std::shared_ptr<const Sensor>> all_sensors = + store->GetAllSensors(); + + nlohmann::json::object_t overrides_by_board; + for (const auto& sensor : all_sensors) { + if (!sensor->IsOverridden()) { + continue; + } + std::string key = sensor->GetKey(); + std::string board_key = sensor->GetBoardConfigKey(); + + std::optional<SensorValue> val_opt = sensor->GetOverrideValue(); + if (!val_opt.has_value()) { + continue; + } + + nlohmann::json info; + if (val_opt->has_reading()) { + info["Reading"] = val_opt->reading(); + } else if (val_opt->has_count()) { + info["Reading"] = val_opt->count(); + } + info["Status"] = "STATUS_READY"; + overrides_by_board[board_key][key] = std::move(info); + } + + resp.SetKeyInJsonBody("/SensorValueOverrides", overrides_by_board); +} + +void HandleClearAllSensorOverridesAction(const RedfishApp& app, + const RedfishRequest& req, + RedfishResponse& resp) { + DLOG(INFO) << "HandleClearAllSensorOverridesAction"; + if (!absl::GetFlag(FLAGS_enable_tlbmc_sensor_override)) { + resp.SetToForbidden( + "Sensor error injection and software overrides are disabled on " + "production images. Use a dev-signed image or enable " + "--enable_tlbmc_sensor_override."); + return; + } + + Store* store = app.GetStore(); + if (store == nullptr) { + resp.SetToInternalError("Store is null"); + return; + } + + absl::Status status = store->ClearAllSensorOverrides(); + if (!status.ok()) { + resp.SetToAbslStatus(status); + return; + } + + nlohmann::json success = { + {{"@odata.type", "#Message.v1_1_1.Message"}, + {"Message", "All sensor overrides successfully cleared."}, + {"MessageArgs", nlohmann::json::array_t()}, + {"MessageId", "Base.1.13.0.Success"}, + {"MessageSeverity", "OK"}, + {"Resolution", "None"}}}; + resp.SetKeyInJsonBody("/@Message.ExtendedInfo", success); +} + } // namespace void RegisterRoutes(RedfishApp& app) { @@ -259,6 +353,16 @@ TLBMC_ROUTE(app, "/redfish/tlbmc/Debug/Store/SharedMemorySensors/") .methods(boost::beast::http::verb::get)( absl::bind_front(HandleSharedMemorySensorsResource, std::cref(app))); + + TLBMC_ROUTE(app, "/redfish/tlbmc/Debug/SensorValueOverrides/") + .methods(boost::beast::http::verb::get)( + absl::bind_front(HandleSensorValueOverridesResource, std::cref(app))); + + TLBMC_ROUTE(app, + "/redfish/tlbmc/Debug/SensorValueOverrides/Actions/" + "SensorValueOverrides.ClearOverrides/") + .methods(boost::beast::http::verb::post)(absl::bind_front( + HandleClearAllSensorOverridesAction, std::cref(app))); } } // namespace milotic_tlbmc::debug