blob: 7dd67d02c7a6757e2e2f7115729ad6e088cc53b6 [file] [log] [blame]
#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_