Add support for owning Redfish SensorCollection.

This change introduces a new configuration option within the `RedfishRoute` expose type in the entity config JSON. When `OwnsSensorsCollection` is set to true for a given config key, tlBMC will own the `/redfish/v1/Chassis/<chassis_id>/Sensors` Redfish resource. This allows tlBMC to provide a complete SensorCollection for chassis where it is the only source of sensor data.

In e2e test, the Diorite config is updated to utilize this new feature.

Tested: see unit tests
PiperOrigin-RevId: 822749267
Change-Id: I57894e6ab4d109cee4c05b3a3731d16fad252ce7
diff --git a/tlbmc/configs/entity_config.cc b/tlbmc/configs/entity_config.cc
index 0e39251..1956ee9 100644
--- a/tlbmc/configs/entity_config.cc
+++ b/tlbmc/configs/entity_config.cc
@@ -184,4 +184,9 @@
       "{\"Warning\": \"EmptyEntityConfigImpl used.\"}");
 }
 
+bool EmptyEntityConfigImpl::IsConfigKeyOwningAllSensors(
+    absl::string_view config_key) const {
+  return false;
+}
+
 }  // namespace milotic_tlbmc
diff --git a/tlbmc/configs/entity_config.h b/tlbmc/configs/entity_config.h
index d4601e7..46aad0f 100644
--- a/tlbmc/configs/entity_config.h
+++ b/tlbmc/configs/entity_config.h
@@ -79,6 +79,8 @@
       absl::string_view fru_key) const = 0;
   virtual absl::StatusOr<const Fru*> GetFru(absl::string_view key) const = 0;
   virtual absl::StatusOr<const FruTable*> GetAllFrus() const = 0;
+  virtual bool IsConfigKeyOwningAllSensors(
+      absl::string_view config_key) const = 0;
   virtual void UpdateFruAndTopology(const RawFruTable& fru_table,
                                     const RawFru& raw_fru) = 0;
   virtual void SetSmartRouter(::crow::RouterInterface* smart_router) = 0;
@@ -127,6 +129,7 @@
       absl::string_view fru_key) const override;
   absl::StatusOr<const Fru*> GetFru(absl::string_view key) const override;
   absl::StatusOr<const FruTable*> GetAllFrus() const override;
+  bool IsConfigKeyOwningAllSensors(absl::string_view config_key) const override;
   void UpdateFruAndTopology(const RawFruTable& fru_table,
                             const RawFru& raw_fru) override;
   void SetSmartRouter(::crow::RouterInterface* smart_router) override;
diff --git a/tlbmc/configs/entity_config_json_impl.cc b/tlbmc/configs/entity_config_json_impl.cc
index d299cc7..f6f84b5 100644
--- a/tlbmc/configs/entity_config_json_impl.cc
+++ b/tlbmc/configs/entity_config_json_impl.cc
@@ -1025,6 +1025,10 @@
   return it->second;
 }
 
+bool EntityConfigJsonImpl::IsRedfishRouteConfig(std::string_view type) {
+  return type == "RedfishRoute";
+}
+
 FanTachType EntityConfigJsonImpl::IsFanTach(std::string_view type) {
   const auto* it = std::lower_bound(
       kSupportedFanTachTypes.begin(), kSupportedFanTachTypes.end(),
@@ -1036,6 +1040,12 @@
   return it->second;
 }
 
+bool EntityConfigJsonImpl::IsConfigKeyOwningAllSensors(
+    absl::string_view config_key) const {
+  return data_store_.immutable_data.redfish_route_configs
+      .configs_owning_sensors_collection.contains(config_key);
+}
+
 SharedMemSensorType EntityConfigJsonImpl::IsSharedMemSensor(
     std::string_view type) {
   const auto* it =
@@ -1199,6 +1209,16 @@
     data.nic_telemetry_configs.push_back(std::move(nic_telemetry_config));
   }
 
+  if (IsRedfishRouteConfig(*type)) {
+    tlbmc_supported = true;
+    const bool* owns_sensor_collection =
+        GetValueAsBool(element, "OwnsSensorsCollection");
+    if (owns_sensor_collection != nullptr && *owns_sensor_collection) {
+      data.redfish_route_configs.configs_owning_sensors_collection.insert(
+          std::string(config_name_with_index));
+    }
+  }
+
   if (!tlbmc_supported) {
     return absl::InvalidArgumentError(absl::StrCat(
         "Invalid config: Config is TlbmcOwned but does not match any supported "
diff --git a/tlbmc/configs/entity_config_json_impl.h b/tlbmc/configs/entity_config_json_impl.h
index 37658af..bbd5303 100644
--- a/tlbmc/configs/entity_config_json_impl.h
+++ b/tlbmc/configs/entity_config_json_impl.h
@@ -89,6 +89,10 @@
   std::vector<FruKey> fru_keys;
 };
 
+struct RedfishRouteConfigs {
+  absl::flat_hash_set<std::string> configs_owning_sensors_collection;
+};
+
 struct EntityConfigJsonImplImmutableData {
   std::vector<HwmonTempSensorConfig> hwmon_temp_sensor_configs;
   std::vector<PsuSensorConfig> psu_sensor_configs;
@@ -99,6 +103,7 @@
   std::vector<IntelCpuSensorConfig> intel_cpu_sensor_configs;
   std::vector<VirtualSensorConfig> virtual_sensor_configs;
   std::vector<NicTelemetryConfig> nic_telemetry_configs;
+  RedfishRouteConfigs redfish_route_configs;
 };
 
 struct EntityConfigJsonImplMutableData {
@@ -219,6 +224,8 @@
 
   absl::StatusOr<const Fru*> GetFru(absl::string_view key) const override;
 
+  bool IsConfigKeyOwningAllSensors(absl::string_view config_key) const override;
+
   absl::StatusOr<const FruTable*> GetAllFrus() const override;
 
   void UpdateFruAndTopology(const RawFruTable& fru_table,
@@ -274,6 +281,8 @@
 
   static bool IsDimm(std::string_view type);
 
+  static bool IsRedfishRouteConfig(std::string_view type);
+
   // Parses the Hwmon common config from the JSON config.
   static absl::StatusOr<HalCommonConfig> ParseHalCommonConfig(
       const nlohmann::json& config);
diff --git a/tlbmc/redfish/app.cc b/tlbmc/redfish/app.cc
index afc572c..11c0560 100644
--- a/tlbmc/redfish/app.cc
+++ b/tlbmc/redfish/app.cc
@@ -187,6 +187,19 @@
       continue;
     }
 
+    // Own the sensors collection corresponding to the configs in the store.
+    if (route == "/redfish/v1/Chassis/<str>/Sensors/") {
+      for (const std::string& chassis_id : chassis_ids) {
+        if (store_->IsConfigKeyOwningAllSensors(chassis_id)) {
+          owned_urls.insert(
+              std::make_pair(absl::StrCat("/redfish/v1/Chassis/", chassis_id,
+                                          "/Sensors"),
+                             methods_fields));
+        }
+      }
+      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) {
diff --git a/tlbmc/store/store.h b/tlbmc/store/store.h
index 285e91d..0dbcff1 100644
--- a/tlbmc/store/store.h
+++ b/tlbmc/store/store.h
@@ -93,6 +93,10 @@
   virtual absl::StatusOr<const TopologyConfig*> GetTopologyConfig() const = 0;
   // Returns all the config keys.
   virtual absl::StatusOr<std::vector<std::string>> GetAllConfigKeys() const = 0;
+  // Returns true if tlBMC for the given config key owns all the sensors.
+  // In this case, tlBMC will own the SensorCollection.
+  virtual bool IsConfigKeyOwningAllSensors(
+      absl::string_view config_key) const = 0;
   // Returns the config key of the given FRU key.
   virtual absl::StatusOr<std::string> GetConfigKeyByFruKey(
       absl::string_view fru_key) const = 0;
diff --git a/tlbmc/store/store_impl.cc b/tlbmc/store/store_impl.cc
index df6bcec..f28df97 100644
--- a/tlbmc/store/store_impl.cc
+++ b/tlbmc/store/store_impl.cc
@@ -65,6 +65,11 @@
   return all_collectors_.sensor_collector->GetAllSensors();
 }
 
+bool StoreImpl::IsConfigKeyOwningAllSensors(
+    absl::string_view config_key) const {
+  return entity_config_->IsConfigKeyOwningAllSensors(config_key);
+}
+
 std::shared_ptr<const Sensor> StoreImpl::GetSensorBySensorKey(
     const std::string& sensor_key) const {
   return all_collectors_.sensor_collector->GetSensorBySensorKey(sensor_key);
diff --git a/tlbmc/store/store_impl.h b/tlbmc/store/store_impl.h
index 51dc285..42559b8 100644
--- a/tlbmc/store/store_impl.h
+++ b/tlbmc/store/store_impl.h
@@ -138,9 +138,7 @@
 
   absl::StatusOr<const FruTable*> GetAllFrus() const override;
 
-  // TODO(rahulkpr): Add APIs that can be used to model Redfish resource based
-  // on data from the store. For example, find devpath for a given fru or sensor
-  // key, find parent of a given fru or sensor key, etc.
+  bool IsConfigKeyOwningAllSensors(absl::string_view config_key) const override;
 
   nlohmann::json ToJson() const override;