| #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 |