| #include "tlbmc/redfish/app.h" |
| |
| #include <array> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <thread> // NOLINT |
| #include <utility> |
| #include <vector> |
| |
| #include "absl/container/flat_hash_set.h" |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/strings/match.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/str_join.h" |
| #include "tlbmc/hal/shared_mem/server.h" |
| #include "tlbmc/pacemaker/pacemaker.h" |
| #include "tlbmc/redfish/request.h" |
| #include "tlbmc/redfish/response.h" |
| #include "tlbmc/store/store.h" |
| #include "redfish-core/include/error_messages.hpp" |
| #include "dbus_utility.hpp" // NOLINT |
| #include "async_resp.hpp" // NOLINT |
| #include "http_request.hpp" // NOLINT |
| #include "router_interface.h" |
| |
| namespace milotic_tlbmc { |
| |
| using ::crow::RouterInterface; |
| |
| RedfishApp::RedfishApp(std::unique_ptr<milotic_tlbmc::Store> store) |
| : store_(std::move(store)), |
| thread_pool_(std::thread::hardware_concurrency()) { |
| } |
| |
| void RedfishApp::HandleInternal(const RedfishRequest& req, |
| RedfishResponse& resp) const { |
| if (store_ == nullptr) { |
| resp.SetToAbslStatus(absl::InternalError("Store is nullptr")); |
| resp.End(); |
| return; |
| } |
| |
| router_.Handle(req, resp); |
| } |
| |
| RedfishApp::RedfishApp(std::unique_ptr<milotic_tlbmc::Pacemaker> pacemaker) |
| : thread_pool_(std::thread::hardware_concurrency()), |
| pacemaker_(std::move(pacemaker)) { |
| } |
| |
| void RedfishApp::Handle(RedfishRequest&& req, RedfishResponse&& resp) const { |
| boost::asio::post(thread_pool_, [this, req(std::move(req)), |
| resp(std::move(resp))]() mutable { |
| HandleInternal(req, resp); |
| }); |
| } |
| |
| void RedfishApp::HandleFromCrowRequest( |
| const ::crow::Request& req, |
| const std::shared_ptr<bmcweb::AsyncResp>& async_resp) const { |
| absl::StatusOr<RedfishRequest> redfish_req = |
| RedfishRequest::Create(req.request()); |
| if (!redfish_req.ok()) { |
| LOG(WARNING) << "Failed to create redfish request: " |
| << redfish_req.status(); |
| redfish::messages::internalError(async_resp->res); |
| return; |
| } |
| |
| redfish_req->SetWithTrustBundle(req.with_trust_bundle); |
| redfish_req->SetFromGrpc(req.fromGrpc); |
| redfish_req->SetPeerAuthenticated(req.peer_authenticated); |
| redfish_req->SetPeerPrivileges(req.peer_privileges); |
| |
| RedfishResponse redfish_resp; |
| redfish_resp.SetAsyncResp(async_resp); |
| |
| HandleInternal(*redfish_req, redfish_resp); |
| } |
| |
| void RedfishApp::Validate() { router_.Validate(); } |
| |
| std::vector<std::string_view> RedfishApp::GetRegisteredRoutes() const { |
| return router_.GetRegisteredRoutes(); |
| } |
| |
| absl::flat_hash_set<std::string> RedfishApp::GetSupportedUrls() const { |
| std::vector<std::string_view> routes = GetRegisteredRoutes(); |
| absl::flat_hash_set<std::string_view> routes_set(routes.begin(), |
| routes.end()); |
| absl::flat_hash_set<std::string> supported_urls; |
| |
| // Service |
| if (routes_set.contains("/redfish/")) { |
| supported_urls.insert("/redfish"); |
| } |
| // Service root |
| if (routes_set.contains("/redfish/v1/")) { |
| supported_urls.insert("/redfish/v1"); |
| } |
| // Chassis collection |
| if (routes_set.contains("/redfish/v1/Chassis/")) { |
| supported_urls.insert("/redfish/v1/Chassis"); |
| } |
| // Individual chassis |
| std::vector<std::string> chassis_ids; |
| |
| if (absl::StatusOr<std::vector<std::string>> configs = |
| store_->GetAllConfigNames(); |
| configs.ok()) { |
| for (const std::string& config : *configs) { |
| chassis_ids.push_back(config); |
| } |
| } |
| if (routes_set.contains("/redfish/v1/Chassis/<str>/")) { |
| for (const std::string& chassis_id : chassis_ids) { |
| supported_urls.insert(absl::StrCat("/redfish/v1/Chassis/", chassis_id)); |
| } |
| } |
| // Sensor Collections |
| if (routes_set.contains("/redfish/v1/Chassis/<str>/Sensors/")) { |
| for (const std::string& chassis_id : chassis_ids) { |
| supported_urls.insert( |
| absl::StrCat("/redfish/v1/Chassis/", chassis_id, "/Sensors")); |
| } |
| } |
| // Individual sensors |
| if (routes_set.contains("/redfish/v1/Chassis/<str>/Sensors/<str>/")) { |
| for (const std::string& chassis_id : chassis_ids) { |
| for (const auto& sensor_key : |
| store_->GetAllSensorKeysByConfigName(chassis_id)) { |
| supported_urls.insert(absl::StrCat("/redfish/v1/Chassis/", chassis_id, |
| "/Sensors/", sensor_key)); |
| } |
| } |
| } |
| |
| constexpr std::array<std::string_view, 9> kTlbmcUrls = { |
| "/redfish/tlbmc/", |
| "/redfish/tlbmc/AllChassis/", |
| "/redfish/tlbmc/AllSensors/", |
| "/redfish/tlbmc/AllSensorsHistory/", |
| "/redfish/tlbmc/Debug/", |
| "/redfish/tlbmc/Debug/App/", |
| "/redfish/tlbmc/Debug/Store/", |
| "/redfish/tlbmc/Debug/Scheduler/", |
| "/redfish/tlbmc/Metrics/", |
| }; |
| for (const auto& url : kTlbmcUrls) { |
| if (routes_set.contains(url)) { |
| // Get rid of trailing slash. |
| supported_urls.insert(std::string(url.substr(0, url.size() - 1))); |
| } |
| } |
| |
| return supported_urls; |
| } |
| |
| absl::flat_hash_set<std::string> RedfishApp::GetOwnedUrls() const { |
| std::vector<std::string_view> routes = GetRegisteredRoutes(); |
| absl::flat_hash_set<std::string> owned_urls; |
| |
| // Individual chassis |
| std::vector<std::string> chassis_ids; |
| if (absl::StatusOr<std::vector<std::string>> configs = |
| store_->GetAllConfigNames(); |
| configs.ok()) { |
| for (const std::string& config : *configs) { |
| chassis_ids.push_back(config); |
| } |
| } |
| |
| for (const std::string_view& route : routes) { |
| // The tlbmc redfish subtree /redfish/tlbmc/ is owned by tlbmc. |
| if (absl::StartsWith(route, "/redfish/tlbmc/")) { |
| // Rules ALWAYS have a trailing slash, but we don't want that for the |
| // owned urls. |
| // https://source.corp.google.com/piper///depot/google3/third_party/milotic/external/cc/tlbmc/redfish/routing.h;rcl=731047512;l=271 |
| owned_urls.insert(std::string(route.substr(0, route.size() - 1))); |
| continue; |
| } |
| |
| // Own the chassis corresponding to the configs in the store. |
| if (route == "/redfish/v1/Chassis/<str>/") { |
| for (const std::string& chassis_id : chassis_ids) { |
| owned_urls.insert(absl::StrCat("/redfish/v1/Chassis/", chassis_id)); |
| } |
| continue; |
| } |
| |
| // Own the sensors corresponding to the configs in the store. |
| if (route == "/redfish/v1/Chassis/<str>/Sensors/<str>/") { |
| for (const std::string& chassis_id : chassis_ids) { |
| for (const auto& sensor_key : |
| store_->GetAllSensorKeysByConfigName(chassis_id)) { |
| owned_urls.insert(absl::StrCat("/redfish/v1/Chassis/", chassis_id, |
| "/Sensors/", sensor_key)); |
| } |
| } |
| continue; |
| } |
| } |
| return owned_urls; |
| } |
| |
| void RedfishApp::SetSmartRouter(RouterInterface* smart_router) { |
| router_.SetSmartRouter(smart_router); |
| store_->SetSmartRouter(smart_router); |
| } |
| |
| void RedfishApp::DebugPrint() const { |
| LOG(INFO) << "tlBMC Supported URLs: " |
| << absl::StrJoin(GetSupportedUrls(), ","); |
| LOG(INFO) << "tlBMC Owned URLs: " << absl::StrJoin(GetOwnedUrls(), ","); |
| } |
| |
| } // namespace milotic_tlbmc |