Refactor SubFru definition to be based on the ResourceType instead of "IsSubFru" field
It is incorrect to allow SubFrus to be defined as `RESOURCE_TYPE_BOARD`. A subfru should be defined as a logical or physical resource attached to a Fru but cannot be removed from the Fru and is not detectable on its own. This refactor will prevent SubFrus from being defined as `RESOURCE_TYPE_BOARD` and must be defined with `RESOURCE_TYPE_ASSEMBLY` instead.
Since these are subfru objects, they must be defined with `PART_LOCATION_TYPE_EMBEDDED`. This requirement is still enforced. Since these will now be populated under the Assembly collection which is not yet owned by tlBMC, configs with `RESOURCE_TYPE_ASSEMBLY` are no longer expected in the redfish response.
Follow up cl/758881979 will propagate sensors from children assemblies to the parent Fru as described in go/tlbmc-redfish-gf-tree-assimilation.
#tlbmc
PiperOrigin-RevId: 761720588
Change-Id: If006d6c88aac636a52ad23b1bcebbaee3e938710
diff --git a/tlbmc/configs/entity_config_json_impl.cc b/tlbmc/configs/entity_config_json_impl.cc
index c187523..dbdee5f 100644
--- a/tlbmc/configs/entity_config_json_impl.cc
+++ b/tlbmc/configs/entity_config_json_impl.cc
@@ -423,14 +423,6 @@
return find_key->get<nlohmann::json>();
}
-bool IsSubFru(const nlohmann::json& probe) {
- const bool* is_sub_fru = GetValueAsBool(probe, "IsSubFru");
- if (is_sub_fru == nullptr) {
- return false;
- }
- return *is_sub_fru;
-}
-
absl::StatusOr<std::string> ParseConfigName(const nlohmann::json& config) {
const std::string* name = GetValueAsString(config, "Name");
if (name == nullptr) {
@@ -939,8 +931,17 @@
// config.
for (const auto& [name, config_data] : *probed_config_map) {
// Check if config belongs to a sub FRU.
- // We have already checked that the config has a probe in `ProcessConfigs`.
- bool is_subfru = IsSubFru(config_data.config.at(kProbeKeyword));
+ // RESOURCE_TYPE_ASSEMBLY indicates a config that is a sub FRU.
+ absl::StatusOr<ResourceType> resource_type =
+ ParseResourceType(config_data.config);
+
+ if (!resource_type.ok()) {
+ mutable_data.parsed_status = resource_type.status();
+ return EntityConfigJsonImplData{
+ .immutable_data = std::move(immutable_data),
+ .mutable_data = std::move(mutable_data),
+ .max_updates_to_mutable_data = ad_hoc_fru_count};
+ }
// For each FRU, substitute config variables with FRU info and parse the
// config.
@@ -954,17 +955,20 @@
&config_name_with_index);
topology_config_node.set_name(config_name_with_index);
- const std::string fru_key = config_data.fru_keys[i].ToString();
+ std::string fru_key = config_data.fru_keys[i].ToString();
- absl::StatusOr<ResourceType> resource_type =
- ParseResourceType(config_data.config);
-
- if (!resource_type.ok()) {
- mutable_data.parsed_status = resource_type.status();
- return EntityConfigJsonImplData{
- .immutable_data = std::move(immutable_data),
- .mutable_data = std::move(mutable_data),
- .max_updates_to_mutable_data = ad_hoc_fru_count};
+ // In the case of a sub FRU, we create an entry in the FruTable keyed by
+ // the config name to have separate Fru data from the parent Fru.
+ if (*resource_type == RESOURCE_TYPE_ASSEMBLY) {
+ fru_key = config_name_with_index;
+ Fru sub_fru_info;
+ Attributes* attributes = sub_fru_info.mutable_attributes();
+ attributes->set_key(fru_key);
+ attributes->set_status(Status::STATUS_READY);
+ attributes->mutable_refresh_policy()->set_refresh_mode(
+ RefreshMode::REFRESH_MODE_ON_DEMAND);
+ mutable_data.fru_table.mutable_key_to_fru()->insert(
+ {fru_key, sub_fru_info});
}
// Get the FRU object from the fru_key. This is used to update the Fru
@@ -981,16 +985,6 @@
ParsePartLocationType(config_data.config, topology_config_node);
ParseRootChassisLocationCode(config_data.config, topology_config_node);
- if (is_subfru &&
- topology_config_node.location_context().location_type() !=
- PART_LOCATION_TYPE_EMBEDDED) {
- mutable_data.parsed_status = absl::InternalError(absl::StrCat(
- "Invalid config: Sub FRU ", topology_config_node.name(),
- " has part location type ",
- topology_config_node.location_context().location_type(),
- ". All sub FRUs should have part location type "
- "PART_LOCATION_TYPE_EMBEDDED."));
- }
absl::StatusOr<nlohmann::json> exposes =
GetObject(config_data.config, "Exposes");
@@ -1145,15 +1139,17 @@
}
topology_config_node.mutable_fru_info()->set_fru_key(fru_key);
- if (!is_subfru) {
- mutable_data.topology_config.mutable_fru_configs()->insert(
- {fru_key, config_name_with_index});
- } else {
+
+ mutable_data.topology_config.mutable_fru_configs()->insert(
+ {fru_key, config_name_with_index});
+ if (*resource_type == RESOURCE_TYPE_ASSEMBLY) {
topology_config_node.mutable_fru_info()->set_is_sub_fru(true);
- fru_key_to_sub_fru_config[fru_key].insert(config_name_with_index);
+ fru_key_to_sub_fru_config[config_data.fru_keys[i].ToString()].insert(
+ config_name_with_index);
}
- if (fru_info.attributes().resource_type() == RESOURCE_TYPE_CABLE) {
+ if (fru_info.attributes().resource_type() == RESOURCE_TYPE_CABLE ||
+ fru_info.attributes().resource_type() == RESOURCE_TYPE_ASSEMBLY) {
topology_config_node.set_not_owned_by_tlbmc(true);
}
@@ -1899,6 +1895,9 @@
downstream_node.set_parent_resource_id(current_node->name());
if (downstream_fru.attributes().resource_type() == RESOURCE_TYPE_BOARD) {
current_node->add_children_chassis_ids(downstream_node.name());
+ } else if (downstream_fru.attributes().resource_type() ==
+ RESOURCE_TYPE_ASSEMBLY) {
+ current_node->add_children_assembly_ids(downstream_node.name());
}
node_queue.push(&downstream_node);
}
diff --git a/tlbmc/redfish/data/stable_id.cc b/tlbmc/redfish/data/stable_id.cc
index 862c22a..36a6e61 100644
--- a/tlbmc/redfish/data/stable_id.cc
+++ b/tlbmc/redfish/data/stable_id.cc
@@ -61,9 +61,6 @@
if (location_context.has_location_type()) {
stable_id.set_location_type(location_context.location_type());
- if (stable_id.location_type() == PART_LOCATION_TYPE_EMBEDDED) {
- stable_id.set_service_label(topology_config_node.name());
- }
}
return stable_id;
diff --git a/tlbmc/resource.proto b/tlbmc/resource.proto
index 2356eb0..bcce08d 100644
--- a/tlbmc/resource.proto
+++ b/tlbmc/resource.proto
@@ -43,6 +43,7 @@
RESOURCE_TYPE_STORAGE = 4;
RESOURCE_TYPE_COMPUTER_SYSTEM = 5;
RESOURCE_TYPE_FAN = 6;
+ RESOURCE_TYPE_ASSEMBLY = 7;
}
// Type of the chassis, used when resource type is RESOURCE_TYPE_BOARD.
diff --git a/tlbmc/topology_config.proto b/tlbmc/topology_config.proto
index f446ce9..46af327 100644
--- a/tlbmc/topology_config.proto
+++ b/tlbmc/topology_config.proto
@@ -75,6 +75,7 @@
repeated string children_cable_ids = 11;
repeated string children_processor_ids = 12;
repeated string children_storage_ids = 13;
+ repeated string children_assembly_ids = 16;
// Whether the config in this node is supported by tlBMC query. If true, this
// node will not be returned in GetAllConfigNames() since this config is not
// supported by tlBMC at the moment.