blob: b66e04b49a2f80e1256c59dce66122490d486209 [file] [log] [blame]
#include "tlbmc/redfish/routes/cable.h"
#include <algorithm>
#include <functional>
#include <string>
#include <utility>
#include <vector>
#include "absl/functional/bind_front.h"
#include "absl/log/log.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "nlohmann/json.hpp"
#include "topology_config.pb.h"
#include "tlbmc/redfish/app.h"
#include "tlbmc/redfish/data/stable_id.h"
#include "stable_id.pb.h"
#include "tlbmc/redfish/request.h"
#include "tlbmc/redfish/response.h"
#include "tlbmc/redfish/url.h"
#include "fru.pb.h"
#include "resource.pb.h"
#include "tlbmc/store/store.h"
namespace milotic_tlbmc::cable {
void HandleCableCollection(const RedfishApp& app, const RedfishRequest& req,
RedfishResponse& resp) {
resp.SetKeyInJsonBody("/@odata.id", "/redfish/v1/Cables");
resp.SetKeyInJsonBody("/@odata.type", "#CableCollection.CableCollection");
resp.SetKeyInJsonBody("/Name", "Cable Collection");
const Store& store = *app.GetStore();
absl::StatusOr<std::vector<std::string>> config_keys =
store.GetAllConfigKeys();
if (!config_keys.ok()) {
resp.SetToAbslStatus(config_keys.status());
return;
}
std::vector<std::string> cable_names;
for (const std::string& name : *config_keys) {
absl::StatusOr<std::string> fru_key = store.GetFruKeyByConfigKey(name);
if (!fru_key.ok()) {
continue;
}
absl::StatusOr<const Fru*> fru = store.GetFru(*fru_key);
if (!fru.ok() ||
(*fru)->attributes().resource_type() != RESOURCE_TYPE_CABLE) {
continue;
}
cable_names.push_back(name);
}
std::sort(cable_names.begin(), cable_names.end());
nlohmann::json::array_t members;
for (const auto& name : cable_names) {
nlohmann::json::object_t member;
member["@odata.id"] = absl::StrCat("/redfish/v1/Cables/", name);
members.push_back(std::move(member));
}
resp.SetKeyInJsonBody("/Members", members);
resp.SetKeyInJsonBody("/Members@odata.count", members.size());
}
void HandleCable(const RedfishApp& app, const RedfishRequest& req,
RedfishResponse& resp, absl::string_view cable_id) {
const Store& store = *app.GetStore();
absl::StatusOr<std::string> fru_key = store.GetFruKeyByConfigKey(cable_id);
if (!fru_key.ok()) {
resp.SetToAbslStatus(fru_key.status());
return;
}
absl::StatusOr<const Fru*> fru = store.GetFru(*fru_key);
if (!fru.ok()) {
resp.SetToAbslStatus(fru.status());
return;
}
absl::StatusOr<const TopologyConfigNode*> topology_config_node =
store.GetFruTopology(cable_id);
if (!topology_config_node.ok()) {
resp.SetToAbslStatus(topology_config_node.status());
return;
}
FillResponseWithCableData(nlohmann::json::json_pointer(""), *fru,
*topology_config_node, resp);
}
void FillResponseWithCableData(
const nlohmann::json::json_pointer& cable_ptr, const Fru* cable_fru_ptr,
const TopologyConfigNode* topology_config_node_ptr, RedfishResponse& resp) {
const std::string& cable_name = topology_config_node_ptr->name();
if (cable_fru_ptr->attributes().status() != STATUS_READY) {
resp.SetToNotReady(
absl::StrFormat("Cable %s is not ready in tlBMC Store", cable_name));
return;
}
resp.SetKeyInJsonBody(cable_ptr / "@odata.id",
CreateUrl({"redfish", "v1", "Cables", cable_name}));
resp.SetKeyInJsonBody(cable_ptr / "@odata.type", "#Cable.v1_2_4.Cable");
resp.SetKeyInJsonBody(cable_ptr / "Id", cable_name);
resp.SetKeyInJsonBody(cable_ptr / "Name", cable_name);
nlohmann::json::array_t downstream_chassis;
for (const std::string& chassis_id :
topology_config_node_ptr->children_chassis_ids()) {
nlohmann::json::object_t downstream_chassis_obj;
downstream_chassis_obj["@odata.id"] =
CreateUrl({"redfish", "v1", "Chassis", chassis_id});
downstream_chassis.emplace_back(std::move(downstream_chassis_obj));
}
resp.SetKeyInJsonBody(cable_ptr / "Links" / "DownstreamChassis",
downstream_chassis);
resp.SetKeyInJsonBody(cable_ptr / "Links" / "DownstreamChassis@odata.count",
downstream_chassis.size());
nlohmann::json::array_t upstream_chassis;
for (const auto& chassis_id :
topology_config_node_ptr->parent_chassis_ids()) {
nlohmann::json::object_t upstream_chassis_obj;
upstream_chassis_obj["@odata.id"] =
CreateUrl({"redfish", "v1", "Chassis", chassis_id});
upstream_chassis.emplace_back(std::move(upstream_chassis_obj));
}
resp.SetKeyInJsonBody(cable_ptr / "Links" / "UpstreamChassis",
upstream_chassis);
resp.SetKeyInJsonBody(cable_ptr / "Links" / "UpstreamChassis@odata.count",
upstream_chassis.size());
StableId stable_id = GetStableId(*topology_config_node_ptr);
if (!stable_id.service_label().empty()) {
resp.SetKeyInJsonBody(
cable_ptr / "Location" / "PartLocation" / "ServiceLabel",
stable_id.service_label());
}
if (!stable_id.part_location_context().empty() &&
stable_id.part_location_context() != "phys") {
resp.SetKeyInJsonBody(cable_ptr / "Location" / "PartLocationContext",
stable_id.part_location_context());
}
if (stable_id.has_location_type()) {
absl::string_view location_type;
switch (stable_id.location_type()) {
case PART_LOCATION_TYPE_CONNECTOR:
location_type = "Connector";
break;
case PART_LOCATION_TYPE_BACKPLANE:
case PART_LOCATION_TYPE_BAY:
case PART_LOCATION_TYPE_EMBEDDED:
case PART_LOCATION_TYPE_SLOT:
case PART_LOCATION_TYPE_SOCKET:
default:
LOG(WARNING) << "Unsupported location type for cable: "
<< stable_id.location_type();
break;
}
if (!location_type.empty()) {
resp.SetKeyInJsonBody(
cable_ptr / "Location" / "PartLocation" / "LocationType",
location_type);
}
}
resp.SetKeyInJsonBody(cable_ptr / "Status" / "Health", "OK");
resp.SetKeyInJsonBody(cable_ptr / "Status" / "State", "Enabled");
}
void RegisterRoutes(RedfishApp& app) {
TLBMC_ROUTE(app, "/redfish/v1/Cables/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleCableCollection, std::cref(app)));
TLBMC_ROUTE(app, "/redfish/v1/Cables/<str>/")
.methods(boost::beast::http::verb::get)(
absl::bind_front(HandleCable, std::cref(app)));
}
} // namespace milotic_tlbmc::cable