| #ifndef THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_CONFIG_ENTITY_CONFIG_JSON_IMPL_H_ |
| #define THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_CONFIG_ENTITY_CONFIG_JSON_IMPL_H_ |
| |
| #include <stdbool.h> |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <optional> |
| #include <tuple> |
| #include <utility> |
| |
| #include "absl/container/flat_hash_set.h" |
| #include "absl/strings/numbers.h" |
| #include "absl/strings/str_split.h" |
| #include "g3/macros.h" |
| #include "fan_tach_config.pb.h" |
| #include "tlbmc/rcu/simple_rcu.h" |
| #include "router_interface.h" |
| |
| #pragma GCC diagnostic push |
| #pragma GCC diagnostic warning "-Wconversion" |
| |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <vector> |
| |
| #include "absl/container/flat_hash_map.h" |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/types/span.h" |
| #include "nlohmann/json.hpp" |
| #include "tlbmc/configs/entity_config.h" |
| #include "fan_controller_config.pb.h" |
| #include "fan_pwm_config.pb.h" |
| #include "hwmon_temp_sensor_config.pb.h" |
| #include "psu_sensor_config.pb.h" |
| #include "reading_range_config.pb.h" |
| #include "reading_transform_config.pb.h" |
| #include "shared_mem_sensor_config.pb.h" |
| #include "threshold_config.pb.h" |
| #include "topology_config.pb.h" |
| #include "fru.pb.h" |
| #include "google/protobuf/json/json.h" |
| #include "google/protobuf/util/json_util.h" |
| |
| namespace milotic_tlbmc { |
| |
| struct FruKey { |
| size_t bus; |
| size_t address; |
| // key_str is the string representation of the unique identifier of the FRU. |
| // This is used to sort the FRU when bus and address are defined. |
| // key_str may be one of: |
| // 1. the name of the FRU if the ProbeV2 is TRUE, meaning that there is no |
| // bus or address associated with the FRU |
| // 2. the bus:address of the FRU, a scanned FRU matches and valid |
| // bus/address are assigned to this FRU |
| std::string key_str; |
| |
| explicit FruKey(const std::string& key) : bus(0), address(0), key_str(key) { |
| std::pair<absl::string_view, absl::string_view> key_split = |
| absl::StrSplit(key, ':'); |
| if (!absl::SimpleAtoi(key_split.first, &bus) || |
| (!absl::SimpleAtoi(key_split.second, &address) && |
| !absl::SimpleHexAtoi(key_split.second, &address))) { |
| LOG(INFO) << "Failed to parse bus and address from: " << key; |
| bus = 0; |
| address = 0; |
| } |
| } |
| |
| // In the case bus and address are undefined, order does not matter as this is |
| // a TRUE probe |
| bool operator<(const FruKey& other) const { |
| return std::tie(bus, address) < std::tie(other.bus, other.address); |
| } |
| |
| std::string ToString() const { return key_str; } |
| }; |
| |
| struct ProbedConfigData { |
| nlohmann::json config; |
| std::vector<FruKey> fru_keys; |
| }; |
| |
| struct EntityConfigJsonImplImmutableData { |
| std::vector<HwmonTempSensorConfig> hwmon_temp_sensor_configs; |
| std::vector<PsuSensorConfig> psu_sensor_configs; |
| std::vector<FanControllerConfig> fan_controller_configs; |
| std::vector<FanPwmConfig> fan_pwm_configs; |
| std::vector<FanTachConfig> fan_tach_configs; |
| std::vector<SharedMemSensorConfig> shared_mem_sensor_configs; |
| }; |
| |
| struct EntityConfigJsonImplMutableData { |
| absl::Status parsed_status; |
| TopologyConfig topology_config; |
| FruTable fru_table; |
| }; |
| |
| // This is just an aggregation of the immutable and mutable data. |
| // This is how the data will actually be stored within the EntityConfigJsonImpl |
| // class. |
| struct EntityConfigJsonImplData { |
| EntityConfigJsonImplImmutableData immutable_data; |
| EntityConfigJsonImplMutableData mutable_data; |
| size_t max_updates_to_mutable_data; |
| }; |
| |
| // This is how the data will actually be stored within the EntityConfigJsonImpl |
| // class. |
| struct EntityConfigJsonImplDataStore { |
| const EntityConfigJsonImplImmutableData immutable_data = {}; |
| SimpleRcu<EntityConfigJsonImplMutableData> mutable_data; |
| }; |
| class EntityConfigJsonImpl : public EntityConfig { |
| public: |
| enum class ReloadType : std::uint8_t { |
| kReloadAll = 0, |
| kReloadFruAndTopologyOnly, |
| }; |
| |
| // Creates an entity config from a directory of JSON files and a FRU table. |
| static absl::StatusOr<std::unique_ptr<EntityConfig>> Create( |
| std::vector<nlohmann::json>&& config_list, const RawFruTable& fru_table, |
| size_t ad_hoc_fru_count); |
| |
| static absl::StatusOr<std::vector<nlohmann::json>> |
| ParseJsonFilesIntoConfigList(absl::string_view config_location); |
| |
| absl::StatusOr<absl::Span<const HwmonTempSensorConfig>> |
| GetAllHwmonTempSensorConfigs() const override { |
| ECCLESIA_RETURN_IF_ERROR(GetParsedStatus()); |
| return data_store_.immutable_data.hwmon_temp_sensor_configs; |
| } |
| |
| absl::StatusOr<absl::Span<const PsuSensorConfig>> GetAllPsuSensorConfigs() |
| const override { |
| ECCLESIA_RETURN_IF_ERROR(GetParsedStatus()); |
| |
| return data_store_.immutable_data.psu_sensor_configs; |
| } |
| |
| absl::StatusOr<absl::Span<const FanControllerConfig>> |
| GetAllFanControllerConfigs() const override { |
| ECCLESIA_RETURN_IF_ERROR(GetParsedStatus()); |
| |
| return data_store_.immutable_data.fan_controller_configs; |
| } |
| |
| absl::StatusOr<absl::Span<const FanPwmConfig>> GetAllFanPwmConfigs() |
| const override { |
| ECCLESIA_RETURN_IF_ERROR(GetParsedStatus()); |
| |
| return data_store_.immutable_data.fan_pwm_configs; |
| } |
| |
| absl::StatusOr<absl::Span<const FanTachConfig>> GetAllFanTachConfigs() |
| const override { |
| ECCLESIA_RETURN_IF_ERROR(GetParsedStatus()); |
| |
| return data_store_.immutable_data.fan_tach_configs; |
| } |
| |
| absl::StatusOr<absl::Span<const SharedMemSensorConfig>> |
| GetAllSharedMemSensorConfigs() const override { |
| ECCLESIA_RETURN_IF_ERROR(GetParsedStatus()); |
| return data_store_.immutable_data.shared_mem_sensor_configs; |
| } |
| |
| absl::StatusOr<const TopologyConfigNode*> GetFruTopology( |
| absl::string_view fru_key) const override; |
| |
| absl::StatusOr<std::string> GetFruDevpath( |
| absl::string_view fru_key) const override; |
| |
| absl::StatusOr<const TopologyConfigNode*> GetFruTopologyByConfig( |
| absl::string_view config_name) const override; |
| |
| absl::StatusOr<const TopologyConfig*> GetTopologyConfig() const override; |
| |
| absl::StatusOr<std::vector<std::string>> GetAllConfigNames() const override; |
| |
| absl::StatusOr<std::string> GetConfigNameByFruKey( |
| absl::string_view fru_key) const override; |
| |
| absl::StatusOr<std::string> GetFruKeyByConfigName( |
| absl::string_view config_name) const override; |
| |
| absl::StatusOr<const Fru*> GetFru(absl::string_view key) const override; |
| |
| absl::StatusOr<const FruTable*> GetAllFrus() const override; |
| |
| void UpdateFruAndTopology(const RawFruTable& fru_table) override; |
| |
| nlohmann::json ToJson() const override; |
| |
| void SetSmartRouter(::crow::RouterInterface* smart_router) override; |
| |
| protected: |
| explicit EntityConfigJsonImpl(std::vector<nlohmann::json>&& config_list, |
| const RawFruTable& fru_table, |
| size_t ad_hoc_fru_count); |
| EntityConfigJsonImpl() = default; |
| |
| EntityConfigJsonImplData ReloadConfig(const RawFruTable& fru_table, |
| size_t ad_hoc_fru_count, |
| ReloadType reload_type); |
| |
| EntityConfigJsonImplImmutableData LoadMutableDataAndReturnImmutableData( |
| const RawFruTable& fru_table); |
| |
| static absl::Status ParseAndPopulateConfig( |
| EntityConfigJsonImplImmutableData& data, const nlohmann::json& element, |
| absl::string_view config_name_with_index, bool is_subfru); |
| |
| // Returns the type of the hardware monitor temperature sensor. If the type is |
| // not supported, returns HwmonTempSensorType::kUnknown. |
| static HwmonTempSensorType IsHwmonTempSensor(std::string_view type); |
| |
| // Returns the type of the PSU sensor. If the type is not supported, returns |
| // PsuSensorType::kUnknown. |
| static PsuSensorType IsPsuSensor(std::string_view type); |
| |
| static FanControllerType IsFanController(std::string_view type); |
| |
| static FanPwmType IsFanPwm(std::string_view type); |
| |
| static FanTachType IsFanTach(std::string_view type); |
| |
| static SharedMemSensorType IsSharedMemSensor(std::string_view type); |
| |
| // Parses the I2C common config from the JSON config. |
| static absl::StatusOr<I2cCommonConfig> ParseI2cCommonConfig( |
| const nlohmann::json& config); |
| |
| static absl::StatusOr<ThresholdType> ParseThresholdType( |
| std::string_view name); |
| |
| // Parses the threshold configs from the JSON config. |
| // If no label is specified, the empty string is used as the label. |
| static absl::StatusOr<absl::flat_hash_map<std::string, ThresholdConfigs>> |
| ParseThresholdConfigs(const nlohmann::json& config); |
| |
| static absl::StatusOr<absl::flat_hash_map<std::string, ThresholdConfigs>> |
| ParseThresholdConfigsForHwmonTemp(const nlohmann::json& config, |
| const std::vector<std::string>& labels); |
| |
| // Parses the labels from the JSON config. |
| static absl::StatusOr<std::vector<std::string>> ParseLabels( |
| const nlohmann::json& config); |
| |
| // Parses the reading range configs from the JSON config given labels. |
| static absl::flat_hash_map<std::string, ReadingRangeConfigs> |
| ParseReadingRangeConfigs(const nlohmann::json& config, |
| absl::Span<const std::string> labels); |
| |
| // Parses the reading range configs. |
| static ReadingRangeConfigs ParseReadingRangeConfigs( |
| const nlohmann::json& config, std::optional<double> default_min, |
| std::optional<double> default_max); |
| |
| // Parses the offset and scale from the JSON config given labels. |
| static absl::flat_hash_map<std::string, ReadingTransformConfig> |
| ParseReadingTransformConfigs(const nlohmann::json& config, |
| absl::Span<const std::string> labels); |
| |
| // Parses the label to name map from the JSON config given labels. |
| // ignore_zero_index_name is used to indicate that "Name" should not be |
| // considered a zero indexed name for a label. |
| // If true, ParseLabelToName will not attempt to find names with the |
| // Name$index schema and set name to empty string if not found. |
| static absl::StatusOr<absl::flat_hash_map<std::string, std::string>> |
| ParseLabelToName(const nlohmann::json& config, |
| absl::Span<const std::string> labels, |
| bool ignore_zero_index_name = false); |
| |
| static absl::StatusOr<HwmonTempSensorConfig> ParseHwmonTempSensorConfig( |
| HwmonTempSensorType type, const nlohmann::json& config); |
| |
| static absl::StatusOr<PsuSensorConfig> ParsePsuSensorConfig( |
| PsuSensorType type, const nlohmann::json& config); |
| |
| static absl::StatusOr<FanControllerConfig> ParseFanControllerConfig( |
| FanControllerType type, const nlohmann::json& config); |
| |
| static absl::StatusOr<FanPwmConfig> ParseFanPwmConfig( |
| FanPwmType type, const nlohmann::json& config); |
| |
| static absl::StatusOr<FanTachConfig> ParseFanTachConfig( |
| FanTachType type, const nlohmann::json& config); |
| |
| static absl::StatusOr<SharedMemSensorConfig> ParseSharedMemSensorConfig( |
| SharedMemSensorType type, const nlohmann::json& config); |
| |
| static absl::Status CreateAssociationsBetweenTopologyConfigNodes( |
| TopologyConfig& topology_config, FruTable& fru_table, |
| absl::flat_hash_set<absl::string_view> expected_nodes_traversed); |
| |
| absl::Status GetParsedStatus() const; |
| |
| private: |
| static EntityConfigJsonImplDataStore PackDataIntoStore( |
| EntityConfigJsonImplData&& data); |
| |
| template <typename ProtoT> |
| nlohmann::json ProtoToJson(const ProtoT& proto) const { |
| nlohmann::json response; |
| std::string json_string; |
| ::google::protobuf::util::JsonPrintOptions opts; |
| opts.preserve_proto_field_names = true; |
| if (!::google::protobuf::json::MessageToJsonString(proto, &json_string, opts).ok()) { |
| LOG(ERROR) << "Failed to convert FRU table to JSON"; |
| return response; |
| } |
| LOG(INFO) << "json_string: " << json_string; |
| return nlohmann::json::parse(json_string, nullptr, false); |
| } |
| |
| // These data members will only be changed by a single thread in a blocking |
| // manner, and will never change afterwards. |
| const std::vector<nlohmann::json> immutable_config_list_; |
| EntityConfigJsonImplDataStore data_store_; |
| |
| ::crow::RouterInterface* smart_router_ = nullptr; |
| }; |
| |
| } // namespace milotic_tlbmc |
| |
| #pragma GCC diagnostic pop |
| |
| #endif // THIRD_PARTY_MILOTIC_EXTERNAL_CC_TLBMC_CONFIG_ENTITY_CONFIG_JSON_IMPL_H_ |