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