blob: 8608735ffd46078133d2a66149a510ea1a2c49e3 [file]
#include "tlbmc/redfish/data/stable_id.h"
#include <algorithm>
#include <string>
#include <string_view>
#include <vector>
#include "absl/log/log.h"
#include "absl/strings/match.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_join.h"
#include "absl/strings/str_split.h"
#include <nlohmann/json.hpp>
#include "json_utils.h"
#include "topology_config.pb.h"
#include "stable_id.pb.h"
#include "resource.pb.h"
namespace milotic_tlbmc {
// Returns true if the Redfish location object matches the tlBMC StableId.
bool MatchStableId(const nlohmann::json& redfish_location,
const StableId& tlbmc_stable_id) {
// If the tlbmc_stable_id has no identifying fields set, it should not match
// any Redfish location.
if (!tlbmc_stable_id.has_service_label() &&
!tlbmc_stable_id.has_part_location_context() &&
!tlbmc_stable_id.has_location_type() &&
!tlbmc_stable_id.has_embedded_location_context() &&
!tlbmc_stable_id.has_machine_local_devpath()) {
return false;
}
const std::string* service_label = milotic::authz::GetValueAsString(
redfish_location, "/PartLocation/ServiceLabel"_json_pointer);
const std::string* part_location_context = milotic::authz::GetValueAsString(
redfish_location, "/PartLocationContext"_json_pointer);
const std::string* location_type = milotic::authz::GetValueAsString(
redfish_location, "/PartLocation/LocationType"_json_pointer);
const std::string* embedded_location_context =
milotic::authz::GetValueAsString(
redfish_location, "/Oem/Google/EmbeddedLocationContext"_json_pointer);
const std::string* machine_local_devpath = milotic::authz::GetValueAsString(
redfish_location, "/Oem/Google/Devpath"_json_pointer);
// If all fields are missing in the Redfish location, it should not match.
if (service_label == nullptr && part_location_context == nullptr &&
location_type == nullptr && embedded_location_context == nullptr &&
machine_local_devpath == nullptr) {
return false;
}
if (tlbmc_stable_id.has_service_label()) {
if (service_label == nullptr ||
tlbmc_stable_id.service_label() != *service_label) {
return false;
}
}
if (tlbmc_stable_id.has_part_location_context()) {
if (part_location_context == nullptr ||
tlbmc_stable_id.part_location_context() != *part_location_context) {
return false;
}
}
if (tlbmc_stable_id.has_location_type()) {
if (location_type == nullptr) {
return false;
}
PartLocationType type =
GetPartLocationTypeFromRedfishString(*location_type);
if (tlbmc_stable_id.location_type() != type) {
return false;
}
}
if (tlbmc_stable_id.has_embedded_location_context()) {
if (embedded_location_context == nullptr ||
tlbmc_stable_id.embedded_location_context() !=
*embedded_location_context) {
return false;
}
}
if (tlbmc_stable_id.has_machine_local_devpath()) {
if (machine_local_devpath == nullptr ||
tlbmc_stable_id.machine_local_devpath() != *machine_local_devpath) {
return false;
}
}
return true;
}
std::string GetNodeLocalDevpath(const std::string& devpath,
const std::string& root_chassis_location_code) {
// If the root chassis location code is empty, then the devpath is already
// machine local.
if (root_chassis_location_code.empty()) {
return devpath;
}
// The root chassis location code should ALWAYS be the prefix of the devpath.
// If it is not, then we have an error and return the empty string.
if (!absl::StrContains(devpath,
absl::StrCat("/", root_chassis_location_code))) {
LOG(ERROR) << "Root chassis location code " << root_chassis_location_code
<< " is not a prefix of the devpath " << devpath;
return "";
}
// If the beginning is not /phys, then replace the beginning devpath part with
// /phys.
return absl::StrCat("/phys",
// +1 here to include the first "/" in the devpath.
devpath.substr(root_chassis_location_code.size() + 1));
}
StableId GetStableId(const LocationContext& location_context,
const std::string& root_chassis_location_code) {
StableId stable_id;
std::string devpath = location_context.devpath();
stable_id.set_machine_local_devpath(
GetNodeLocalDevpath(devpath, root_chassis_location_code));
// Remove /phys from the devpath.
if (absl::StartsWith(devpath, "/phys")) {
devpath = devpath.substr(5);
}
// Find and remove the port label from the devpath.
std::string embedded_port_label;
auto find_device = devpath.find(":device:");
if (find_device != std::string::npos) {
embedded_port_label = devpath.substr(find_device + 8);
devpath = devpath.substr(0, find_device);
}
std::vector<std::string> devpath_parts =
absl::StrSplit(devpath, '/', absl::SkipEmpty());
if (devpath_parts.empty() && embedded_port_label.empty()) {
return stable_id;
}
if (!embedded_port_label.empty()) {
stable_id.set_service_label(embedded_port_label);
stable_id.set_part_location_context(
absl::StrJoin(devpath_parts.begin(), devpath_parts.end(), "/"));
} else {
stable_id.set_service_label(devpath_parts.back());
stable_id.set_part_location_context(
absl::StrJoin(devpath_parts.begin(), devpath_parts.end() - 1, "/"));
}
std::string embedded_location_context;
for (const auto& logical_identifier :
location_context.logical_identifiers()) {
absl::StrAppend(&embedded_location_context,
embedded_location_context.empty() ? "" : "/",
logical_identifier);
}
if (!embedded_location_context.empty()) {
stable_id.set_embedded_location_context(embedded_location_context);
}
if (location_context.has_location_type()) {
stable_id.set_location_type(location_context.location_type());
}
return stable_id;
}
StableId GetStableId(const TopologyConfigNode& topology_config_node) {
return GetStableId(topology_config_node.location_context(),
topology_config_node.root_chassis_location_code());
}
PartLocationType GetPartLocationTypeFromRedfishString(
const std::string& part_location_type) {
const auto* it = std::find_if(kPartLocationTypeStrings.begin(),
kPartLocationTypeStrings.end(),
[&part_location_type](const auto& pair) {
return pair.first == part_location_type;
});
if (it == kPartLocationTypeStrings.end()) {
return PART_LOCATION_TYPE_UNSPECIFIED;
}
return it->second;
}
std::string_view GetRedfishStringFromPartLocationType(
PartLocationType part_location_type) {
const auto* it = std::find_if(kPartLocationTypeStrings.begin(),
kPartLocationTypeStrings.end(),
[&part_location_type](const auto& pair) {
return pair.second == part_location_type;
});
if (it == kPartLocationTypeStrings.end()) {
return "";
}
return it->first;
}
} // namespace milotic_tlbmc