| #include "tlbmc/store/store_impl.h" |
| |
| #include <sys/sysinfo.h> |
| |
| #include <cstddef> |
| #include <cstdint> |
| #include <filesystem> // NOLINT |
| #include <memory> |
| #include <optional> |
| #include <ostream> |
| #include <string> |
| #include <system_error> // NOLINT |
| #include <utility> |
| #include <vector> |
| |
| #include "owner_certificate/owner_verification_cert_configuration.pb.h" |
| #include "bus_topology.pb.h" |
| #include "absl/container/flat_hash_map.h" |
| #include "absl/functional/any_invocable.h" |
| #include "absl/log/log.h" |
| #include "absl/memory/memory.h" |
| #include "absl/status/status.h" |
| #include "absl/status/statusor.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/strings/substitute.h" |
| #include "absl/time/clock.h" |
| #include "absl/time/time.h" |
| #include "g3/macros.h" |
| #include "thread/thread.h" |
| #include "time/clock.h" |
| #include <nlohmann/json.hpp> |
| #include "central_config.pb.h" |
| #include "tlbmc/central_config/config.h" |
| #include "tlbmc/collector/bulk_sensor_collector_base.h" |
| #include "tlbmc/collector/collector.h" |
| #include "tlbmc/collector/fru_collector.h" |
| #include "tlbmc/collector/gpio_collector.h" |
| #include "tlbmc/collector/led_collector.h" |
| #include "tlbmc/collector/metric_collector.h" |
| #include "tlbmc/collector/monitoring_change_base.h" |
| #include "tlbmc/collector/pcie_collector.h" |
| #include "tlbmc/collector/power_control_collector.h" |
| #include "tlbmc/collector/power_fault_log_collector.h" |
| #include "tlbmc/collector/sel_collector.h" |
| #include "tlbmc/collector/sensor_collector.h" |
| #include "tlbmc/collector/sensor_collector_aggregator.h" |
| #include "tlbmc/collector/thermal_collector.h" |
| #include "ad_hoc_fru_config.pb.h" |
| #include "tlbmc/configs/entity_config.h" |
| #include "gpio_config.pb.h" |
| #include "power_control.pb.h" |
| #include "software_metrics_config.pb.h" |
| #include "thermal_config.pb.h" |
| #include "topology_config.pb.h" |
| #include "tlbmc/credentials/credential_manager.h" |
| #include "tlbmc/hal/fru_scanner.h" |
| #include "tlbmc/hal/peci/peci_access_impl.h" |
| #include "tlbmc/hal/peci/peci_access_interface.h" |
| #include "tlbmc/hal/system_registry.h" |
| #include "tlbmc/host_state/power_control.h" |
| #include "fru.pb.h" |
| #include "power_fault_log_entry.pb.h" |
| #include "tlbmc/resource/reset_type.h" |
| #include "resource.pb.h" |
| #include "sensor.pb.h" |
| #include "software_metrics.pb.h" |
| #include "tlbmc/scheduler/scheduler.h" |
| #include "tlbmc/sensors/sensor.h" |
| #include "tlbmc/store/store.h" |
| #include "tlbmc/thermal/controller/dff_controller.h" |
| #include "tlbmc/thermal/controller/eat_controller.h" |
| #include "tlbmc/thermal/controller/fan_pid_controller.h" |
| #include "tlbmc/thermal/controller/pid_controller.h" |
| #include "tlbmc/thermal/controller/stepwise_controller.h" |
| #include "tlbmc/thermal/zone_manager.h" |
| #include "tlbmc/trace/tracer.h" |
| #include "tlbmc/true_hitless_metrics.pb.h" |
| #include "router_interface.h" |
| |
| namespace milotic_tlbmc { |
| |
| using ::crow::RouterInterface; |
| |
| namespace { |
| |
| constexpr int kDefaultPeriodicDumpIntervalMs = 1000 * 60 * 60; // 1 hour |
| |
| } // namespace |
| |
| absl::Status StoreImpl::ConfigureDeterministicCollection( |
| const Collector::Config& config) const { |
| return all_collectors_.fru_collector->ConfigureDeterministicCollection( |
| config); |
| } |
| |
| std::unique_ptr<MonitoringChangeBase> StoreImpl::CreateMonitoringChange() { |
| return all_collectors_.sensor_collector_aggregator->CreateMonitoringChange(); |
| } |
| |
| PowerControlCollector* StoreImpl::GetPowerControlCollector() const { |
| return all_collectors_.power_control_collector.get(); |
| } |
| |
| FruCollector* StoreImpl::GetFruCollector() const { |
| return all_collectors_.fru_collector.get(); |
| } |
| |
| GpioCollector* StoreImpl::GetGpioCollector() const { |
| return all_collectors_.gpio_collector.get(); |
| } |
| |
| LedCollector* StoreImpl::GetLedCollector() const { |
| return all_collectors_.led_collector.get(); |
| } |
| |
| PcieCollector* StoreImpl::GetPcieCollector() const { |
| return all_collectors_.pcie_collector.get(); |
| } |
| |
| std::vector<std::shared_ptr<const Sensor>> StoreImpl::GetAllSensors() const { |
| return all_collectors_.sensor_collector_aggregator->GetAllSensors(); |
| } |
| std::vector<std::string> StoreImpl::GetAllSharedMemorySensorKeys() const { |
| return all_collectors_.sensor_collector_aggregator |
| ->GetAllSharedMemorySensorKeys(); |
| } |
| |
| 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_aggregator->GetSensorBySensorKey( |
| sensor_key); |
| } |
| |
| std::vector<std::string> StoreImpl::GetAllSensorKeysByConfigKey( |
| const std::string& board_config_key) const { |
| return all_collectors_.sensor_collector_aggregator |
| ->GetAllSensorKeysByConfigKey(board_config_key); |
| } |
| |
| std::shared_ptr<const Sensor> StoreImpl::GetSensorByConfigKeyAndSensorKey( |
| const std::string& board_config_key, const std::string& sensor_key) const { |
| return all_collectors_.sensor_collector_aggregator |
| ->GetSensorByConfigKeyAndSensorKey(board_config_key, sensor_key); |
| } |
| |
| absl::Status StoreImpl::WriteToSensor(const std::string& sensor_key, |
| const SensorValue& value) { |
| return all_collectors_.sensor_collector_aggregator->WriteToSensor(sensor_key, |
| value); |
| } |
| |
| absl::Status StoreImpl::SetSensorOverride(const std::string& sensor_key, |
| const SensorValue& value) { |
| if (all_collectors_.sensor_collector_aggregator == nullptr) { |
| return absl::InternalError( |
| "Sensor collector aggregator is not initialized"); |
| } |
| return all_collectors_.sensor_collector_aggregator->SetSensorOverride( |
| sensor_key, value); |
| } |
| |
| absl::Status StoreImpl::ClearSensorOverride(const std::string& sensor_key) { |
| if (all_collectors_.sensor_collector_aggregator == nullptr) { |
| return absl::InternalError( |
| "Sensor collector aggregator is not initialized"); |
| } |
| return all_collectors_.sensor_collector_aggregator->ClearSensorOverride( |
| sensor_key); |
| } |
| |
| absl::Status StoreImpl::ClearAllSensorOverrides() { |
| if (all_collectors_.sensor_collector_aggregator == nullptr) { |
| return absl::InternalError( |
| "Sensor collector aggregator is not initialized"); |
| } |
| return all_collectors_.sensor_collector_aggregator->ClearAllSensorOverrides(); |
| } |
| |
| std::vector<std::string> StoreImpl::GetOverriddenSensorKeys() const { |
| if (all_collectors_.sensor_collector_aggregator == nullptr) { |
| return {}; |
| } |
| return all_collectors_.sensor_collector_aggregator->GetOverriddenSensorKeys(); |
| } |
| |
| absl::StatusOr<bool> StoreImpl::IsSensorOverridden( |
| const std::string& sensor_key) const { |
| if (all_collectors_.sensor_collector_aggregator == nullptr) { |
| return false; |
| } |
| return all_collectors_.sensor_collector_aggregator->IsSensorOverridden( |
| sensor_key); |
| } |
| |
| absl::StatusOr<const std::string&> StoreImpl::GetDevpathFromSensor( |
| std::shared_ptr<const Sensor> sensor) const { |
| // Get devpath for the sensor. |
| // 1. Check if the sensor has valid GetDevpath method. If so, return the |
| // devpath. If not, go to the step 2. |
| // 2. Get the related item key from static attributes. |
| // 3. Get topology node from related item key. |
| // 4. Get devpath from topology node. |
| |
| absl::StatusOr<const std::string&> devpath = sensor->GetDevpath(); |
| if (devpath.ok() && !devpath.value().empty()) { |
| return devpath; |
| } |
| |
| const SensorAttributesStatic& static_attributes = |
| sensor->GetSensorAttributesStatic(); |
| absl::string_view related_item_key = static_attributes.related_item().id(); |
| // For fans, there may be several sensors with same related item id, we must |
| // get the true related item key from the parent board. |
| if (static_attributes.related_item().type() == RESOURCE_TYPE_FAN) { |
| ECCLESIA_ASSIGN_OR_RETURN( |
| const TopologyConfigNode* parent_board, |
| GetFruTopology( |
| static_attributes.entity_common_config().board_config_key())); |
| // The fan id should always be present in the parent board's children |
| // fans map. |
| auto fan_it = parent_board->children_fans().find(related_item_key); |
| if (fan_it == parent_board->children_fans().end()) { |
| return absl::NotFoundError(absl::Substitute( |
| "Fan $0 not found in parent board $1", related_item_key, |
| parent_board->fru_info().fru_key())); |
| } |
| related_item_key = fan_it->second; |
| } else if (static_attributes.related_item().type() == |
| RESOURCE_TYPE_PROCESSOR) { |
| ECCLESIA_ASSIGN_OR_RETURN( |
| const TopologyConfigNode* parent_board, |
| GetFruTopology( |
| static_attributes.entity_common_config().board_config_key())); |
| // related_item.id is the topology processor key (physical id). |
| auto processor_it = |
| parent_board->children_processors().find(related_item_key); |
| if (processor_it == parent_board->children_processors().end()) { |
| return absl::NotFoundError(absl::Substitute( |
| "Processor $0 not found in parent board $1", related_item_key, |
| parent_board->fru_info().fru_key())); |
| } |
| related_item_key = processor_it->second; |
| } else if (static_attributes.related_item().type() == RESOURCE_TYPE_DIMM) { |
| ECCLESIA_ASSIGN_OR_RETURN( |
| const TopologyConfigNode* parent_board, |
| GetFruTopology( |
| static_attributes.entity_common_config().board_config_key())); |
| // The dimm id should always be present in the parent board's children |
| // fans map. |
| auto dimm_it = parent_board->children_dimms().find(related_item_key); |
| if (dimm_it == parent_board->children_dimms().end()) { |
| return absl::NotFoundError(absl::Substitute( |
| "DIMM $0 not found in parent board $1", related_item_key, |
| parent_board->fru_info().fru_key())); |
| } |
| related_item_key = dimm_it->second; |
| } |
| ECCLESIA_ASSIGN_OR_RETURN(const TopologyConfigNode* topology_node, |
| GetFruTopology(related_item_key)); |
| |
| return topology_node->location_context().devpath(); |
| } |
| |
| void StoreImpl::InitializeSensorDevpaths() const { |
| if (!all_collectors_.sensor_collector_aggregator) { |
| return; |
| } |
| |
| std::vector<std::shared_ptr<const Sensor>> sensors = |
| all_collectors_.sensor_collector_aggregator->GetAllSensors(); |
| for (const std::shared_ptr<const Sensor>& sensor : sensors) { |
| absl::StatusOr<const std::string&> devpath = GetDevpathFromSensor(sensor); |
| if (!devpath.ok()) { |
| LOG(WARNING) << "Failed to get devpath for sensor " << sensor->GetKey() |
| << ": " << devpath.status(); |
| continue; |
| } |
| absl::Status status = |
| all_collectors_.sensor_collector_aggregator->SetDevpathForSensor( |
| sensor->GetKey(), devpath.value()); |
| if (!status.ok()) { |
| LOG(WARNING) << "Failed to set devpath for sensor " << sensor->GetKey() |
| << ": " << status; |
| } |
| } |
| } |
| |
| absl::StatusOr<const Fru*> StoreImpl::GetFru(absl::string_view key) const { |
| return entity_config_->GetFru(key); |
| } |
| |
| absl::StatusOr<const FruTable*> StoreImpl::GetAllFrus() const { |
| return entity_config_->GetAllFrus(); |
| } |
| |
| SoftwareMetricsValue StoreImpl::GetMetricValues() const { |
| return all_collectors_.metric_collector->GetMetricValues(); |
| } |
| |
| SocketStatStates StoreImpl::GetMetricSocketStatValues() const { |
| return all_collectors_.metric_collector->GetSocketStatMetricsValues(); |
| } |
| |
| NetFilterStates StoreImpl::GetMetricNetFilterValues() const { |
| return all_collectors_.metric_collector->GetNetFilterValues(); |
| } |
| |
| TrueHitlessMetrics StoreImpl::GetTrueHitlessMetrics() const { |
| return all_collectors_.metric_collector->GetTrueHitlessMetrics(); |
| } |
| |
| absl::StatusOr<std::vector<const thermal::ZoneManager*>> |
| StoreImpl::GetAllThermalZones() const { |
| return all_collectors_.thermal_collector->GetAllThermalZones(); |
| } |
| |
| absl::StatusOr<std::vector<const thermal::PidController*>> |
| StoreImpl::GetAllPidControllers() const { |
| return all_collectors_.thermal_collector->GetAllPidControllers(); |
| } |
| |
| absl::StatusOr<std::vector<const thermal::StepwiseController*>> |
| StoreImpl::GetAllStepwiseControllers() const { |
| return all_collectors_.thermal_collector->GetAllStepwiseControllers(); |
| } |
| |
| absl::StatusOr<std::vector<const thermal::FanPidController*>> |
| StoreImpl::GetAllFanPidControllers() const { |
| return all_collectors_.thermal_collector->GetAllFanPidControllers(); |
| } |
| |
| absl::StatusOr<std::vector<const thermal::EatController*>> |
| StoreImpl::GetAllEatControllers() const { |
| return all_collectors_.thermal_collector->GetAllEatControllers(); |
| } |
| |
| absl::StatusOr<std::vector<const thermal::DffController*>> |
| StoreImpl::GetAllDffControllers() const { |
| return all_collectors_.thermal_collector->GetAllDffControllers(); |
| } |
| |
| std::string StoreImpl::GetBmcUuid() const { |
| return all_collectors_.metric_collector->GetBmcUuid(); |
| } |
| |
| std::string StoreImpl::GetBmcFirmwareVersion() const { |
| return all_collectors_.metric_collector->GetBmcFirmwareVersion(); |
| } |
| |
| std::string StoreImpl::GetBmcFirmwareVersionId() const { |
| return all_collectors_.metric_collector->GetBmcFirmwareVersionId(); |
| } |
| |
| absl::Status StoreImpl::SetGpio(absl::string_view gpio_name, bool value) { |
| return all_collectors_.gpio_collector->SetGpio(gpio_name, value); |
| } |
| |
| absl::Status StoreImpl::SetGpioActive(absl::string_view gpio_name) { |
| return all_collectors_.gpio_collector->SetActive(gpio_name); |
| } |
| |
| absl::Status StoreImpl::SetGpioActiveForDuration(absl::string_view gpio_name, |
| absl::Duration duration) { |
| return all_collectors_.gpio_collector->SetActiveForDuration(gpio_name, |
| duration); |
| } |
| |
| absl::StatusOr<bool> StoreImpl::GetGpio(absl::string_view gpio_name) { |
| return all_collectors_.gpio_collector->GetValue(gpio_name); |
| } |
| |
| absl::Status StoreImpl::SendSystemResetRequest(absl::string_view system_id, |
| ResetType reset_type, |
| absl::Duration delay) { |
| LOG(INFO) << "SendSystemResetRequest: " << system_id << " " << reset_type |
| << " " << delay; |
| if (all_collectors_.power_control_collector == nullptr) { |
| return absl::NotFoundError( |
| absl::Substitute("System $0 not found", system_id)); |
| } |
| return all_collectors_.power_control_collector->SendSystemResetRequest( |
| system_id, reset_type, delay); |
| } |
| |
| absl::StatusOr<std::vector<ResetType>> |
| StoreImpl::GetSupportedCustomChassisResetTypes( |
| absl::string_view chassis_id) const { |
| ECCLESIA_ASSIGN_OR_RETURN(std::string fru_key, |
| entity_config_->GetFruKeyByConfigKey(chassis_id)); |
| ECCLESIA_ASSIGN_OR_RETURN(const Fru* fru, entity_config_->GetFru(fru_key)); |
| if (fru == nullptr) { |
| return absl::NotFoundError( |
| absl::StrCat("Fru not found for chassis: ", chassis_id)); |
| } |
| |
| std::vector<ResetType> supported_types; |
| const auto& chassis_reset = |
| fru->attributes().chassis_properties().chassis_reset(); |
| if (!chassis_reset.enabled()) { |
| return supported_types; |
| } |
| |
| supported_types.reserve(chassis_reset.actions_size()); |
| for (const auto& action : chassis_reset.actions()) { |
| supported_types.push_back(action.type()); |
| } |
| return supported_types; |
| } |
| |
| absl::StatusOr<bool> StoreImpl::SupportsCustomChassisReset( |
| absl::string_view chassis_id) const { |
| ECCLESIA_ASSIGN_OR_RETURN(std::string fru_key, |
| entity_config_->GetFruKeyByConfigKey(chassis_id)); |
| ECCLESIA_ASSIGN_OR_RETURN(const Fru* fru, entity_config_->GetFru(fru_key)); |
| if (fru == nullptr) { |
| return absl::NotFoundError( |
| absl::StrCat("Fru not found for chassis: ", chassis_id)); |
| } |
| return fru->attributes().chassis_properties().chassis_reset().enabled(); |
| } |
| |
| absl::Status StoreImpl::ExecuteCustomChassisReset(absl::string_view chassis_id, |
| ResetType reset_type) { |
| ECCLESIA_ASSIGN_OR_RETURN(std::string fru_key, |
| entity_config_->GetFruKeyByConfigKey(chassis_id)); |
| ECCLESIA_ASSIGN_OR_RETURN(const Fru* fru, entity_config_->GetFru(fru_key)); |
| if (fru == nullptr) { |
| return absl::NotFoundError( |
| absl::StrCat("Fru not found for chassis: ", chassis_id)); |
| } |
| |
| const auto& chassis_reset = |
| fru->attributes().chassis_properties().chassis_reset(); |
| if (!chassis_reset.enabled()) { |
| return absl::FailedPreconditionError(absl::StrCat( |
| "Custom chassis reset is not enabled for chassis: ", chassis_id)); |
| } |
| |
| absl::string_view gpio_name; |
| for (const auto& action : chassis_reset.actions()) { |
| if (action.type() == reset_type) { |
| gpio_name = action.gpio(); |
| break; |
| } |
| } |
| |
| if (gpio_name.empty()) { |
| absl::StatusOr<absl::string_view> reset_type_string = |
| GetResetTypeString(reset_type); |
| return absl::NotFoundError(absl::Substitute( |
| "No custom reset action found for chassis $0 and reset type $1", |
| chassis_id, |
| reset_type_string.value_or(reset_type_string.status().message()))); |
| } |
| |
| ECCLESIA_ASSIGN_OR_RETURN( |
| bool current_value, all_collectors_.gpio_collector->GetValue(gpio_name)); |
| |
| ECCLESIA_RETURN_IF_ERROR( |
| all_collectors_.gpio_collector->SetGpio(gpio_name, !current_value)); |
| |
| return all_collectors_.gpio_collector->SetGpio(gpio_name, current_value); |
| } |
| |
| absl::StatusOr<PsiMetrics> StoreImpl::GetPsiMetrics() const { |
| return all_collectors_.metric_collector->GetPsiMetrics(); |
| } |
| |
| absl::StatusOr<std::vector<std::string>> StoreImpl::GetAvailableServices() |
| const { |
| return all_collectors_.metric_collector->GetAvailableServices(); |
| } |
| |
| absl::StatusOr<PsiMetrics> StoreImpl::GetPsiMetricsForService( |
| const std::string& service_name) const { |
| return all_collectors_.metric_collector->GetPsiMetricsForService( |
| service_name); |
| } |
| |
| nlohmann::json StoreImpl::ToJson() const { |
| nlohmann::json json; |
| all_collectors_.sensor_collector_aggregator->ToJson(json); |
| json["Fru"] = all_collectors_.fru_collector->ToJson(); |
| json["Metric"] = all_collectors_.metric_collector->ToJson(); |
| json["Gpio"] = all_collectors_.gpio_collector->ToJson(); |
| json["Led"] = all_collectors_.led_collector->ToJson(); |
| json["Fan"] = all_collectors_.thermal_collector->ToJson(); |
| json["PowerFaultLog"] = all_collectors_.power_fault_log_collector->ToJson(); |
| json["Sel"] = all_collectors_.sel_collector->ToJson(); |
| json["Pcie"] = all_collectors_.pcie_collector->ToJson(); |
| json["EntityConfig"] = entity_config_->ToJson(); |
| json["PowerState"] = all_collectors_.power_control_collector->ToJson(); |
| return json; |
| } |
| |
| nlohmann::json StoreImpl::GetSchedulerStats() const { |
| nlohmann::json json; |
| json["SensorCollector"] = |
| all_collectors_.sensor_collector->GetSchedulerStats(); |
| json["FruCollector"] = all_collectors_.fru_collector->GetSchedulerStats(); |
| json["MetricCollector"] = |
| all_collectors_.metric_collector->GetSchedulerStats(); |
| json["GpioCollector"] = all_collectors_.gpio_collector->GetSchedulerStats(); |
| json["LedCollector"] = all_collectors_.led_collector->GetSchedulerStats(); |
| json["Fan"] = all_collectors_.thermal_collector->GetSchedulerStats(); |
| json["PowerFaultLogCollector"] = |
| all_collectors_.power_fault_log_collector->GetSchedulerStats(); |
| json["SelCollector"] = all_collectors_.sel_collector->GetSchedulerStats(); |
| json["PcieCollector"] = all_collectors_.pcie_collector->GetSchedulerStats(); |
| json["PowerControlCollector"] = |
| all_collectors_.power_control_collector->GetSchedulerStats(); |
| json["Store"] = task_scheduler_->ToJson(); |
| return json; |
| } |
| |
| Store::Metrics StoreImpl::GetMetrics() const { return metrics_; } |
| |
| absl::StatusOr<const TopologyConfigNode*> StoreImpl::GetFruTopology( |
| absl::string_view config_key) const { |
| return entity_config_->GetFruTopologyByConfig(config_key); |
| } |
| |
| absl::StatusOr<const TopologyConfig*> StoreImpl::GetTopologyConfig() const { |
| return entity_config_->GetTopologyConfig(); |
| } |
| |
| absl::StatusOr<std::vector<std::string>> StoreImpl::GetAllConfigKeys() const { |
| return entity_config_->GetAllConfigKeys(); |
| } |
| |
| absl::StatusOr<std::string> StoreImpl::GetConfigKeyByFruKey( |
| absl::string_view fru_key) const { |
| return entity_config_->GetConfigKeyByFruKey(fru_key); |
| } |
| |
| absl::StatusOr<std::string> StoreImpl::GetFruKeyByConfigKey( |
| absl::string_view config_key) const { |
| return entity_config_->GetFruKeyByConfigKey(config_key); |
| } |
| |
| absl::StatusOr<std::vector<std::pair<std::string, std::string>>> |
| StoreImpl::GetFanInfoByConfigKey(absl::string_view config_name) const { |
| return entity_config_->GetFanInfoByConfigKey(config_name); |
| } |
| |
| absl::StatusOr<std::string> StoreImpl::GenerateCsr( |
| const CredentialManager::CsrParams& csr_params) const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Trust Bundle Install Module is not enabled"); |
| } |
| return credential_manager_->GenerateCsr(csr_params); |
| } |
| |
| absl::Status StoreImpl::InstallServerCert( |
| const std::string& certificate) const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Trust Bundle Install Module is not enabled"); |
| } |
| return credential_manager_->InstallServerCert(certificate); |
| } |
| |
| absl::Status StoreImpl::InstallTrustBundle(const std::string& trust_bundle, |
| const std::string& signature) const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Trust Bundle Install Module is not enabled"); |
| } |
| return credential_manager_->InstallTrustBundle(trust_bundle, signature); |
| } |
| |
| absl::Status StoreImpl::InstallOsVerificationCertificate( |
| const std::string& cert_string) const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Trust Bundle Install Module is not enabled"); |
| } |
| return credential_manager_->InstallOsVerificationCertificate(cert_string); |
| } |
| |
| absl::Status StoreImpl::InstallSerialConsoleTrustedUserCAKeys( |
| const std::string& trusted_user_ca_keys, |
| const std::string& signature) const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Trust Bundle Install Module is not enabled"); |
| } |
| return credential_manager_->InstallSerialConsoleTrustedUserCAKeys( |
| trusted_user_ca_keys, signature); |
| } |
| |
| absl::Status StoreImpl::InstallSyslogCert(const std::string& cert_string, |
| const std::string& target_ip, |
| int64_t target_port, |
| SyslogProtocol protocol, |
| SyslogTlsMode tls_mode) const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Trust Bundle Install Module is not enabled"); |
| } |
| return credential_manager_->InstallSyslogCert( |
| cert_string, target_ip, target_port, protocol, tls_mode); |
| } |
| |
| bool StoreImpl::IsFirmwareUpdateable() const { |
| if (credential_manager_ == nullptr) { |
| return true; |
| } |
| return credential_manager_->IsFirmwareUpdateable(); |
| } |
| |
| absl::StatusOr<std::optional<std::string>> StoreImpl::GetOwnerVerificationCert() |
| const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Credential manager is null"); |
| } |
| return credential_manager_->GetOwnerVerificationCert(); |
| } |
| |
| absl::StatusOr< |
| std::optional<owner_certificate::OwnerVerificationCertConfiguration>> |
| StoreImpl::GetOwnerVerificationCertConfiguration() const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Credential manager is null"); |
| } |
| return credential_manager_->GetOwnerVerificationCertConfiguration(); |
| } |
| |
| absl::StatusOr<std::optional<std::string>> |
| StoreImpl::GetBmcSshTrustedUserCAKeysSignature() const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Credential manager is null"); |
| } |
| return credential_manager_->GetBmcSshTrustedUserCAKeysSignature(); |
| } |
| |
| absl::StatusOr<std::optional<std::string>> StoreImpl::GetTrustBundle() const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Credential manager is null"); |
| } |
| return credential_manager_->GetTrustBundle(); |
| } |
| |
| absl::StatusOr<std::optional<std::string>> StoreImpl::GetTrustBundleSignature() |
| const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Credential manager is null"); |
| } |
| return credential_manager_->GetTrustBundleSignature(); |
| } |
| |
| absl::StatusOr<std::optional<std::string>> StoreImpl::GetServerCert() const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Credential manager is null"); |
| } |
| return credential_manager_->GetServerCert(); |
| } |
| |
| absl::StatusOr<std::optional<std::string>> StoreImpl::GetOsVerificationCert() |
| const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Credential manager is null"); |
| } |
| return credential_manager_->GetOsVerificationCert(); |
| } |
| |
| absl::StatusOr<std::optional<std::string>> |
| StoreImpl::GetSerialConsoleTrustedUserCAKeys() const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Credential manager is null"); |
| } |
| return credential_manager_->GetSerialConsoleTrustedUserCAKeys(); |
| } |
| |
| absl::StatusOr<std::optional<std::string>> |
| StoreImpl::GetSerialConsoleDetatchedSignature() const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Credential manager is null"); |
| } |
| return credential_manager_->GetSerialConsoleDetatchedSignature(); |
| } |
| |
| absl::StatusOr<std::optional<SyslogTargetConfig>> |
| StoreImpl::GetSyslogClientConf() const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Credential manager is null"); |
| } |
| return credential_manager_->GetSyslogClientConf(); |
| } |
| |
| absl::StatusOr<std::optional<std::string>> StoreImpl::GetSyslogRootCert() |
| const { |
| if (credential_manager_ == nullptr) { |
| return absl::InternalError("Credential manager is null"); |
| } |
| return credential_manager_->GetSyslogRootCert(); |
| } |
| |
| absl::Time StoreImpl::GetCurrentTime() const { return absl::Now(); } |
| |
| absl::Time StoreImpl::GetLastResetTime() const { |
| struct sysinfo info; |
| if (sysinfo(&info) != 0) { |
| return absl::UnixEpoch(); |
| } |
| |
| return absl::Now() - absl::Seconds(info.uptime); |
| } |
| |
| absl::StatusOr<std::string> StoreImpl::GetHotswapGpioName() { |
| if (!GetTlbmcConfig() |
| .gpio_collector_module() |
| .power_control_sub_module() |
| .enabled()) { |
| return absl::InternalError("Power control module is not enabled."); |
| } |
| if (GetTlbmcConfig() |
| .gpio_collector_module() |
| .power_control_sub_module() |
| .power_control_type() != PowerControlType::POWER_CONTROL_TYPE_GPIO) { |
| return absl::InternalError("Power control type is not GPIO."); |
| } |
| if (!options_.proto_parser->GetPowerControlConfigs().has_hotswap_pin_name()) { |
| return absl::InternalError("Hotswap pin name is not set."); |
| } |
| return options_.proto_parser->GetPowerControlConfigs().hotswap_pin_name(); |
| } |
| |
| absl::StatusOr<std::unique_ptr<StoreImpl>> StoreImpl::Create( |
| Options&& options) { |
| Metrics metrics_at_bootup; |
| absl::Time create_start_time = absl::Now(); |
| if (options.fru_scanners.empty()) { |
| return absl::InvalidArgumentError("FruScanners is empty"); |
| } |
| if (options.i2c_sysfs == nullptr) { |
| return absl::InvalidArgumentError("I2cSysfs is null"); |
| } |
| if (options.i3c_sysfs == nullptr) { |
| return absl::InvalidArgumentError("I3cSysfs is null"); |
| } |
| if (options.peci_sysfs == nullptr) { |
| return absl::InvalidArgumentError("PeciSysfs is null"); |
| } |
| |
| if (options.proto_parser == nullptr) { |
| return absl::InvalidArgumentError("Proto config parser is null"); |
| } |
| options.proto_parser->LoadProtoConfigs(); |
| |
| absl::Time parse_configs_start_time = absl::Now(); |
| Tracer::GetInstance().AddOneOffDatapoint("Tlbmc-Parse-Configs-Begin", |
| parse_configs_start_time); |
| |
| ECCLESIA_RETURN_IF_ERROR(options.entity_config_reader->LoadEntityConfig( |
| options.config_location, options.offline_node_entities_path)); |
| |
| std::vector<AdHocFruConfig> ad_hoc_fru_scanning_configs = |
| FruCollector::Options::ParseAdHocFruConfigs( |
| options.entity_config_reader->GetConfig()); |
| |
| absl::Time parse_configs_end_time = absl::Now(); |
| metrics_at_bootup.config_parse_duration = |
| parse_configs_end_time - parse_configs_start_time; |
| Tracer::GetInstance().AddOneOffDatapoint("Tlbmc-Parse-Configs-End", |
| parse_configs_end_time); |
| |
| size_t ad_hoc_fru_count = ad_hoc_fru_scanning_configs.size(); |
| |
| absl::flat_hash_map<AdHocScannerType, FruScanner*> fru_scanners_raw; |
| for (const auto& [type, scanner] : options.fru_scanners) { |
| fru_scanners_raw[type] = scanner.get(); |
| } |
| |
| absl::flat_hash_map< |
| uhmm::BmcMonitoredComponentsResponse::MonitoredComponent::ProbePath, |
| FruScanner*> |
| deterministic_fru_scanners_raw; |
| for (const auto& [probe_path, scanner] : options.deterministic_fru_scanners) { |
| deterministic_fru_scanners_raw[probe_path] = scanner.get(); |
| } |
| |
| const auto power_control_configs = |
| options.proto_parser->GetPowerControlConfigs(); |
| |
| std::vector<RelatedStateConfig> host_power_related_state_configs; |
| std::vector<RelatedStateConfig> os_state_related_state_configs; |
| |
| for (const auto& power_control_config : |
| power_control_configs.power_control_configs()) { |
| if (power_control_config.has_host_power_related_state_config()) { |
| LOG(INFO) << "Host power related state config: " |
| << power_control_config.host_power_related_state_config(); |
| host_power_related_state_configs.push_back( |
| power_control_config.host_power_related_state_config()); |
| } |
| if (power_control_config.has_os_state_related_state_config()) { |
| os_state_related_state_configs.push_back( |
| power_control_config.os_state_related_state_config()); |
| } |
| } |
| |
| FruCollector::Options fru_collector_options = { |
| .fru_scanners = std::move(fru_scanners_raw), |
| .ad_hoc_fru_scanning_configs = std::move(ad_hoc_fru_scanning_configs), |
| .enable_deterministic_fru_scanning = options.enable_deterministic_bmc, |
| .strict_part_info_check = |
| GetTlbmcConfig().fru_collector_module().strict_part_info_check(), |
| .deterministic_fru_scanners = std::move(deterministic_fru_scanners_raw), |
| .enable_deterministic_periodic_fru_scanning = |
| options.enable_deterministic_periodic_fru_scanning, |
| .periodic_deterministic_fru_scan_interval_ms = |
| options.periodic_deterministic_fru_scan_interval_ms, |
| .host_power_related_state_configs = |
| std::move(host_power_related_state_configs), |
| .os_state_related_state_configs = |
| std::move(os_state_related_state_configs), |
| .smbios_inventory = options.smbios_inventory, |
| .smbios_single_host_file_path = options.smbios_single_host_file_path, |
| .smbios_multihost_host_file_path_prefix = |
| options.smbios_multihost_host_file_path_prefix, |
| .smbios_single_host_status_file_path = |
| options.smbios_single_host_status_file_path, |
| .smbios_multihost_host_status_file_path_prefix = |
| options.smbios_multihost_host_status_file_path_prefix, |
| .expected_smbios_components = |
| std::move(options.expected_smbios_components), |
| }; |
| |
| if (!options.cached_fru_table_path.empty()) { |
| fru_collector_options.cached_fru_table_path = options.cached_fru_table_path; |
| } |
| |
| AllCollectors all_collectors = { |
| .sensor_collector_aggregator = nullptr, |
| .sensor_collector = EmptySensorCollector::Create(), |
| .bulk_sensor_collector = nullptr, |
| .fru_collector = EmptyFruCollector::Create(), |
| .metric_collector = EmptyMetricCollector::Create(), |
| .gpio_collector = EmptyGpioCollector::Create(), |
| .power_control_collector = EmptyPowerControlCollector::Create(), |
| .led_collector = EmptyLedCollector::Create(), |
| .power_fault_log_collector = EmptyPowerFaultLogCollector::Create(), |
| .sel_collector = EmptySelCollector::Create(), |
| .pcie_collector = EmptyPcieCollector::Create(), |
| .thermal_collector = EmptyThermalCollector::Create(), |
| }; |
| std::shared_ptr<EntityConfig> entity_config_shared = |
| EmptyEntityConfigImpl::Create(); |
| |
| if (options.gpio_collector != nullptr) { |
| all_collectors.gpio_collector = std::move(options.gpio_collector); |
| } |
| |
| // Initialize power control collector before FruCollector and SensorCollector |
| // to make sure some sensors in FruCollector and SensorCollector can register |
| // power control callbacks. |
| if (GetTlbmcConfig() |
| .gpio_collector_module() |
| .power_control_sub_module() |
| .enabled() || |
| options.proto_parser->GetPowerControlConfigs().has_hotswap_pin_name()) { |
| absl::StatusOr<std::unique_ptr<PowerControlCollector>> collector = |
| options.collector_factory->CreatePowerControlCollector({ |
| .power_control_configs = |
| options.proto_parser->GetPowerControlConfigs(), |
| .gpio_collector = all_collectors.gpio_collector.get(), |
| .root_path = options.root_path, |
| }); |
| if (!collector.ok()) { |
| LOG(ERROR) << "Failed to create PowerControlCollector: " |
| << collector.status(); |
| return collector.status(); |
| } |
| all_collectors.power_control_collector = *std::move(collector); |
| } |
| |
| if (GetTlbmcConfig().led_collector_module().enabled()) { |
| ECCLESIA_ASSIGN_OR_RETURN( |
| std::unique_ptr<LedCollector> led_collector, |
| options.collector_factory->CreateLedCollector({ |
| .led_configs = options.proto_parser->GetLedConfigs(), |
| .led_sysfs = *options.led_sysfs, |
| .power_control_collector = |
| all_collectors.power_control_collector.get(), |
| .gpio_collector = all_collectors.gpio_collector.get(), |
| })); |
| all_collectors.led_collector = std::move(led_collector); |
| } |
| |
| if (GetTlbmcConfig().fru_collector_module().enabled()) { |
| absl::Time fru_scan_start_time = absl::Now(); |
| Tracer::GetInstance().AddOneOffDatapoint("Tlbmc-Scan-FRUs-Begin", |
| fru_scan_start_time); |
| |
| ECCLESIA_ASSIGN_OR_RETURN( |
| std::unique_ptr<FruCollector> fru_collector, |
| options.collector_factory->CreateFruCollector(fru_collector_options)); |
| |
| const RawFruTable fru_table = fru_collector->GetCopyOfCurrentScannedFrus(); |
| absl::Time fru_scan_end_time = absl::Now(); |
| metrics_at_bootup.fru_scan_and_collector_create_duration = |
| fru_scan_end_time - fru_scan_start_time; |
| Tracer::GetInstance().AddOneOffDatapoint("Tlbmc-Scan-FRUs-End", |
| fru_scan_end_time); |
| |
| // Load Configs |
| absl::Time load_configs_start_time = absl::Now(); |
| Tracer::GetInstance().AddOneOffDatapoint("Tlbmc-Load-Configs-Begin", |
| load_configs_start_time); |
| |
| absl::StatusOr<std::unique_ptr<EntityConfig>> entity_config = |
| options.entity_config_reader->CreateEntityConfig( |
| fru_table, ad_hoc_fru_count, options.enable_deterministic_bmc, |
| all_collectors.gpio_collector.get(), |
| options.enable_hft_test_sensor); |
| if (!entity_config.ok()) { |
| LOG(ERROR) << "Failed to create entity config: " |
| << entity_config.status(); |
| LOG(ERROR) << "The cached FRU table will be deleted."; |
| // If Store is bad, then cache may be bad too. Let cache reload on next |
| // boot. |
| std::error_code ec; |
| if (!std::filesystem::remove(fru_collector_options.cached_fru_table_path, |
| ec) && |
| ec) { |
| LOG(WARNING) << "Failed to remove cached FRU table: " << ec.message(); |
| } |
| return entity_config.status(); |
| } |
| |
| absl::Time load_configs_end_time = absl::Now(); |
| metrics_at_bootup.topology_config_load_duration = |
| load_configs_end_time - load_configs_start_time; |
| Tracer::GetInstance().AddOneOffDatapoint("Tlbmc-Load-Configs-End", |
| load_configs_end_time); |
| |
| // EntityConfig must be shared as it is used by the FruCollector. |
| entity_config_shared = absl::ShareUniquePtr(std::move(*entity_config)); |
| |
| fru_collector->SetEntityConfig(entity_config_shared); |
| |
| all_collectors.fru_collector = std::move(fru_collector); |
| |
| if (GetTlbmcConfig().sensor_collector_module().enabled()) { |
| // Now create all the collectors one by one. |
| absl::Time sensor_collector_create_start_time = absl::Now(); |
| Tracer::GetInstance().AddOneOffDatapoint( |
| "Tlbmc-Create-SensorCollector-Begin", |
| sensor_collector_create_start_time); |
| |
| ECCLESIA_ASSIGN_OR_RETURN(SensorCollector::SensorConfigs sensor_configs, |
| entity_config_shared->GetAllSensorConfigs()); |
| |
| std::unique_ptr<PeciAccessInterface> peci_access = |
| std::make_unique<PeciAccessImpl>(); |
| |
| SensorCollector::Params sensor_collector_params = { |
| .sensor_configs = std::move(sensor_configs), |
| .iio_sysfs = *options.iio_sysfs, |
| .i2c_sysfs = *options.i2c_sysfs, |
| .i3c_sysfs = *options.i3c_sysfs, |
| .peci_sysfs = *options.peci_sysfs, |
| .peci_access = *options.peci_access, |
| .override_sensor_sampling_interval_ms = |
| options.override_sensor_sampling_interval_ms, |
| .gpio_collector = all_collectors.gpio_collector.get(), |
| .enable_threshold_monitoring = GetTlbmcConfig() |
| .sensor_collector_module() |
| .enable_threshold_monitoring(), |
| .power_control_collector = |
| all_collectors.power_control_collector.get(), |
| }; |
| |
| if (options.nic_accessor_factory) { |
| sensor_collector_params.nic_accessor_factory = |
| std::move(options.nic_accessor_factory); |
| } |
| |
| absl::StatusOr<std::unique_ptr<SensorCollector>> sensor_collector = |
| options.collector_factory->CreateSensorCollector( |
| sensor_collector_params); |
| if (!sensor_collector.ok()) { |
| LOG(ERROR) << "Failed to create sensor collector: " |
| << sensor_collector.status(); |
| LOG(ERROR) << "The cached FRU table will be deleted."; |
| // If Store is bad, then cache may be bad too. Let cache reload on next |
| // boot. |
| std::error_code ec; |
| if (!std::filesystem::remove( |
| fru_collector_options.cached_fru_table_path, ec) && |
| ec) { |
| LOG(WARNING) << "Failed to remove cached FRU table: " << ec.message(); |
| } |
| return sensor_collector.status(); |
| } |
| |
| absl::Time sensor_collector_create_end_time = absl::Now(); |
| metrics_at_bootup.sensor_collector_create_duration = |
| sensor_collector_create_end_time - sensor_collector_create_start_time; |
| Tracer::GetInstance().AddOneOffDatapoint( |
| "Tlbmc-Create-SensorCollector-End", sensor_collector_create_end_time); |
| all_collectors.sensor_collector = std::move(*sensor_collector); |
| } |
| |
| if (GetTlbmcConfig().pcie_collector_module().enabled()) { |
| absl::StatusOr<std::unique_ptr<PcieCollector>> pcie_collector = |
| options.collector_factory->CreatePcieCollector({ |
| .pcie_configs = options.proto_parser->GetPcieConfigs(), |
| .gpio_collector = all_collectors.gpio_collector.get(), |
| }); |
| if (!pcie_collector.ok()) { |
| LOG(ERROR) << "Failed to create PCIe collector: " |
| << pcie_collector.status(); |
| return pcie_collector.status(); |
| } |
| all_collectors.pcie_collector = std::move(*pcie_collector); |
| } |
| } |
| absl::StatusOr<std::shared_ptr<BulkSensorCollectorBase>> |
| bulk_sensor_collector_or = CreateBulkSensorCollector( |
| *entity_config_shared, ecclesia::GetDefaultThreadFactory(), |
| ecclesia::Clock::RealClock()); |
| if (!bulk_sensor_collector_or.ok()) { |
| LOG(ERROR) << "Failed to create bulk sensor collector: " |
| << bulk_sensor_collector_or.status(); |
| return bulk_sensor_collector_or.status(); |
| } |
| all_collectors.bulk_sensor_collector = std::move(*bulk_sensor_collector_or); |
| // Uses either EmptySensorCollector or SensorCollector from above. |
| all_collectors.sensor_collector_aggregator = |
| std::make_unique<SensorCollectorAggregator>( |
| all_collectors.sensor_collector.get(), |
| all_collectors.bulk_sensor_collector.get()); |
| |
| if (GetTlbmcConfig().sensor_collector_module().enabled()) { |
| entity_config_shared->SetSensorCollectorAggregator( |
| all_collectors.sensor_collector_aggregator.get()); |
| } |
| |
| if (all_collectors.power_control_collector != nullptr) { |
| for (const auto& [host_id, power_control_ptr] : |
| all_collectors.power_control_collector->GetAllPowerControls()) { |
| if (power_control_ptr == nullptr) { |
| continue; |
| } |
| power_control_ptr->RegisterHostPowerOnToOffCallback( |
| [&resource_state_managers = |
| all_collectors.fru_collector->GetResourceStateManagers(), |
| host_id]([[maybe_unused]] bool setup_run) { |
| auto it = resource_state_managers.find(RELATED_STATE_HOST_POWER); |
| if (it == resource_state_managers.end()) { |
| LOG(WARNING) |
| |
| << "No resource state managers found for host power."; |
| return; |
| } |
| for (const auto& [state, resource_state_manager] : |
| resource_state_managers) { |
| resource_state_manager->HandleStateOnToOff(host_id); |
| } |
| }); |
| power_control_ptr->RegisterHostPowerOffToOnCallback( |
| [&resource_state_managers = |
| all_collectors.fru_collector->GetResourceStateManagers(), |
| host_id]([[maybe_unused]] bool setup_run) { |
| auto it = resource_state_managers.find(RELATED_STATE_HOST_POWER); |
| if (it == resource_state_managers.end()) { |
| LOG(WARNING) |
| |
| << "No resource state managers found for host power."; |
| return; |
| } |
| for (const auto& [state, resource_state_manager] : |
| resource_state_managers) { |
| resource_state_manager->HandleStateOffToOn(host_id); |
| } |
| }); |
| power_control_ptr->RegisterHostPowerOffToOnCallback( |
| [sensor_collector = all_collectors.sensor_collector.get()]( |
| bool setup_run) { sensor_collector->TriggerPeciScan(); }); |
| |
| power_control_ptr->RegisterHostOSInactiveToStandbyCallback( |
| [fru_collector_ptr = all_collectors.fru_collector.get(), |
| host_id = host_id](bool setup_run) { |
| LOG(INFO) << "Registering HostOSInactiveToStandbyCallback with " |
| "setup_run: " |
| << setup_run << " for host_id: " << host_id; |
| fru_collector_ptr->HandleHostOsInactiveToStandby(host_id, |
| setup_run); |
| }); |
| power_control_ptr->RegisterHostOSStandbyToInactiveCallback( |
| [fru_collector_ptr = all_collectors.fru_collector.get(), |
| host_id = host_id](bool setup_run) { |
| LOG(INFO) << "Registering HostOSStandbyToInactiveCallback with " |
| "setup_run: " |
| << setup_run << " for host_id: " << host_id; |
| fru_collector_ptr->HandleHostOsStandbyToInactive(host_id, |
| setup_run); |
| }); |
| |
| // Start the power control. This is not a blocking call. |
| power_control_ptr->Start(); |
| } |
| } |
| |
| if (GetTlbmcConfig().metric_collector_module().enabled()) { |
| absl::StatusOr<std::unique_ptr<MetricCollector>> metric_collector; |
| MetricCollector::Params params = { |
| .metric_configs = options.proto_parser->GetSoftwareMetricsConfig(), |
| .root_path = options.root_path, |
| .psi_base_path = |
| (std::filesystem::path(options.root_path) / "sys/fs/cgroup") |
| .string()}; |
| |
| if (options.executor_command_map.empty()) { |
| metric_collector = |
| options.collector_factory->CreateMetricCollector(params); |
| } else { |
| params.executor_command_map = options.executor_command_map; |
| metric_collector = MetricCollector::CreateForUnitTest(params); |
| } |
| if (!metric_collector.ok()) { |
| LOG(ERROR) << "Failed to create metric collector: " |
| << metric_collector.status(); |
| return metric_collector.status(); |
| } |
| all_collectors.metric_collector = std::move(*metric_collector); |
| } |
| |
| if (GetTlbmcConfig() |
| .sensor_collector_module() |
| .thermal_control_sub_module() |
| .enabled()) { |
| absl::StatusOr<std::unique_ptr<ThermalCollector>> thermal_collector; |
| ThermalConfigs thermal_configs = options.proto_parser->GetThermalConfigs(); |
| ThermalCollector::Params params = { |
| .zone_manager_configs = thermal_configs.zones(), |
| .first_order_adrc_controller_configs = |
| thermal_configs.first_order_adrc_controllers(), |
| .second_order_adrc_controller_configs = |
| thermal_configs.second_order_adrc_controllers(), |
| .dff_controller_configs = thermal_configs.dff_controllers(), |
| .pid_controller_configs = thermal_configs.pid_controllers(), |
| .stepwise_controller_configs = thermal_configs.stepwise_controllers(), |
| .fan_pid_controller_configs = thermal_configs.fan_pid_controllers(), |
| .failsafe_logger_config = thermal_configs.failsafe_logger_config(), |
| .tuning_enabled = thermal_configs.tuning_enabled(), |
| }; |
| |
| thermal_collector = options.collector_factory->CreateThermalCollector( |
| params, &*all_collectors.sensor_collector_aggregator, |
| all_collectors.fru_collector.get(), entity_config_shared.get()); |
| if (!thermal_collector.ok()) { |
| LOG(ERROR) << "Failed to create thermal collector: " |
| << thermal_collector.status(); |
| return thermal_collector.status(); |
| } |
| all_collectors.thermal_collector = std::move(*thermal_collector); |
| } |
| |
| if (all_collectors.sensor_collector != nullptr && |
| all_collectors.thermal_collector != nullptr) { |
| all_collectors.sensor_collector->SetManualPwmCallback( |
| [thermal_collector = all_collectors.thermal_collector.get()]( |
| absl::string_view fan_name, double pwm) { |
| thermal_collector->SetManualPwm(fan_name, pwm); |
| }); |
| } |
| |
| if (GetTlbmcConfig().power_fault_log_collector_module().enabled()) { |
| // The PowerFaultLogCollector is responsible for loading its own config. |
| PowerFaultLogCollector::Params params; |
| params.config = options.proto_parser->GetPowerFaultLogConfig(); |
| absl::StatusOr<std::unique_ptr<PowerFaultLogCollector>> |
| power_fault_log_collector = |
| options.collector_factory->CreatePowerFaultLogCollector(params); |
| if (!power_fault_log_collector.ok()) { |
| LOG(ERROR) << "Failed to create PowerFaultLogCollector: " |
| << power_fault_log_collector.status(); |
| return power_fault_log_collector.status(); |
| } |
| if (absl::Status status = (*power_fault_log_collector)->StartCollection(); |
| !status.ok()) { |
| LOG(ERROR) << "Failed to start PowerFaultLogCollector: " << status; |
| return status; |
| } |
| all_collectors.power_fault_log_collector = |
| std::move(*power_fault_log_collector); |
| |
| // Register power fault detector callbacks with GPIO collector. |
| absl::flat_hash_map<std::string, absl::AnyInvocable<void(GpioEventType)>> |
| gpio_monitor_callback_bundle = all_collectors.power_fault_log_collector |
| ->GetGpioMonitorCallbackBundle(); |
| for (auto& [gpio_name, callback] : gpio_monitor_callback_bundle) { |
| if (absl::Status status = all_collectors.gpio_collector->RegisterCallback( |
| gpio_name, std::move(callback)); |
| !status.ok()) { |
| LOG(ERROR) |
| << "Failed to register power fault detector callback for GPIO " |
| << gpio_name << ": " << status; |
| return status; |
| } |
| } |
| |
| // Register PrePowerCycle callback with power_control_collector to disable |
| // power fault detection prior to AC cycles. |
| auto* raw_collector = all_collectors.power_fault_log_collector.get(); |
| if (all_collectors.power_control_collector != nullptr) { |
| all_collectors.power_control_collector->RegisterPrePowerCycleCallback( |
| [raw_collector]() { raw_collector->DisableFaultDetection(); }); |
| } |
| } |
| |
| if (GetTlbmcConfig().sel_collector_module().enabled()) { |
| // The SelCollector is responsible for loading its own config. |
| SelCollector::Params params; |
| params.config = options.proto_parser->GetSelConfig(); |
| absl::StatusOr<std::unique_ptr<SelCollector>> sel_collector = |
| options.collector_factory->CreateSelCollector(params); |
| if (!sel_collector.ok()) { |
| LOG(ERROR) << "Failed to create SelCollector: " << sel_collector.status(); |
| return sel_collector.status(); |
| } |
| ECCLESIA_RETURN_IF_ERROR((*sel_collector)->StartDefaultSubscriber()); |
| all_collectors.sel_collector = std::move(*sel_collector); |
| } |
| |
| // Create the store |
| int periodic_dump_interval_ms = |
| options.override_store_snapshot_interval_ms.value_or( |
| kDefaultPeriodicDumpIntervalMs); |
| metrics_at_bootup.time_to_ready = absl::Now() - create_start_time; |
| |
| // Trigger AdHocFruScanning after every collector has been initialized to |
| // prevent race conditions |
| all_collectors.fru_collector->SetUpAdHocFruScanning(); |
| |
| std::shared_ptr<CredentialManager> credential_manager = |
| options.credential_manager; |
| if (credential_manager == nullptr && |
| GetTlbmcConfig().trust_bundle_install_module().enabled()) { |
| return absl::InvalidArgumentError( |
| "CredentialManager cannot be null when trust bundle install module is " |
| "enabled."); |
| } |
| std::unique_ptr<StoreImpl> store = absl::WrapUnique( |
| new StoreImpl(std::move(options), std::move(all_collectors), |
| std::move(entity_config_shared), |
| absl::Milliseconds(periodic_dump_interval_ms), |
| std::move(credential_manager), metrics_at_bootup, |
| options.system_registry)); |
| store->InitializeSensorDevpaths(); |
| return store; |
| } |
| |
| void StoreImpl::SetSmartRouter(RouterInterface* smart_router) { |
| entity_config_->SetSmartRouter(smart_router); |
| } |
| |
| StoreImpl::StoreImpl(Options&& options, AllCollectors all_collectors, |
| std::shared_ptr<EntityConfig> entity_config, |
| absl::Duration store_snapshot_interval, |
| std::shared_ptr<CredentialManager> credential_manager, |
| Metrics metrics_at_bootup, |
| std::shared_ptr<SystemRegistry> system_registry) |
| : credential_manager_(std::move(credential_manager)), |
| options_(std::move(options)), |
| all_collectors_(std::move(all_collectors)), |
| entity_config_(std::move(entity_config)), |
| task_scheduler_(std::make_unique<TaskScheduler>()), |
| system_registry_(std::move(system_registry)), |
| metrics_(metrics_at_bootup) { |
| task_scheduler_->RunAndScheduleAsync( |
| [this](absl::AnyInvocable<void()> done) { |
| // Dump the store snapshot. |
| LOG(WARNING) << "=== Store snapshot ==="; |
| LOG(WARNING) << ToJson().dump(); |
| LOG(WARNING) << "=== END ==="; |
| |
| // Dump the collector scheduler stats. |
| LOG(WARNING) << "=== Collector Scheduler stats ==="; |
| LOG(WARNING) << GetSchedulerStats().dump(); |
| LOG(WARNING) << "=== END ==="; |
| |
| // Dump the central config. |
| LOG(WARNING) << "=== Central Config ==="; |
| LOG(WARNING) << GetTlbmcConfig(); |
| LOG(WARNING) << "=== END ==="; |
| done(); |
| }, |
| store_snapshot_interval); |
| } |
| |
| // Since the task scheduler is a member variable, we need to stop it before |
| // destructing since the store is running an async task that is accessing the |
| // task scheduler. |
| StoreImpl::~StoreImpl() { |
| if (all_collectors_.sensor_collector != nullptr) { |
| all_collectors_.sensor_collector->SetManualPwmCallback(std::nullopt); |
| } |
| if (all_collectors_.sel_collector != nullptr) { |
| all_collectors_.sel_collector->Stop(); |
| } |
| if (task_scheduler_ != nullptr) { |
| task_scheduler_->Stop(); |
| } |
| // Collectors with background threads or dependencies on sensor collectors |
| // and GPIO/state managers MUST be destroyed/stopped first. |
| all_collectors_.led_collector.reset(); |
| all_collectors_.power_control_collector.reset(); |
| all_collectors_.pcie_collector.reset(); |
| all_collectors_.thermal_collector.reset(); |
| all_collectors_.fru_collector.reset(); |
| all_collectors_.metric_collector.reset(); |
| all_collectors_.power_fault_log_collector.reset(); |
| all_collectors_.sel_collector.reset(); |
| all_collectors_.gpio_collector.reset(); |
| if (entity_config_ != nullptr) { |
| entity_config_->SetSensorCollectorAggregator(nullptr); |
| } |
| all_collectors_.sensor_collector_aggregator.reset(); |
| all_collectors_.bulk_sensor_collector.reset(); |
| all_collectors_.sensor_collector.reset(); |
| } |
| |
| void StoreImpl::StartSensorCollection() const { |
| if (all_collectors_.sensor_collector_aggregator != nullptr) { |
| all_collectors_.sensor_collector_aggregator->StartSensorCollection(); |
| } |
| } |
| |
| void StoreImpl::StartThermalCollection() const { |
| if (all_collectors_.thermal_collector != nullptr) { |
| all_collectors_.thermal_collector->StartCollection(); |
| } |
| } |
| |
| void StoreImpl::SetManualMode(bool enable_manual_mode) { |
| if (all_collectors_.thermal_collector != nullptr) { |
| all_collectors_.thermal_collector->SetManualMode(enable_manual_mode); |
| } |
| } |
| |
| void StoreImpl::SetManualPwm(absl::string_view fan_name, double pwm) { |
| if (all_collectors_.thermal_collector != nullptr) { |
| all_collectors_.thermal_collector->SetManualPwm(fan_name, pwm); |
| } |
| } |
| |
| PowerFaultLogEntries StoreImpl::GetPowerFaultLogEntries() const { |
| return all_collectors_.power_fault_log_collector->GetCollectedEntries(); |
| } |
| |
| absl::StatusOr<std::string> StoreImpl::GetPowerFaultLogFileContent( |
| absl::string_view folder_name, absl::string_view file_name) const { |
| return all_collectors_.power_fault_log_collector->GetLogFileContent( |
| folder_name, file_name); |
| } |
| |
| absl::Status StoreImpl::SetPidControllerCoefficients( |
| absl::string_view controller_id, |
| const thermal::PidController::PidControllerCoefficients& coefficients, |
| absl::Duration timeout) { |
| absl::Status status = |
| all_collectors_.thermal_collector->RequestPidControllerCoefficientsTuning( |
| controller_id, coefficients); |
| |
| if (!status.ok()) { |
| return status; |
| } |
| |
| absl::Time start_time = absl::Now(); |
| while (all_collectors_.thermal_collector->HasPendingTuningRequest( |
| controller_id) && |
| absl::Now() - start_time < timeout) { |
| absl::SleepFor(absl::Milliseconds(100)); |
| } |
| |
| return all_collectors_.thermal_collector->HasPendingTuningRequest( |
| controller_id) |
| ? absl::DeadlineExceededError(absl::StrCat( |
| "Timeout ", timeout, |
| " exceeded and tuning request is still pending.")) |
| : absl::OkStatus(); |
| } |
| |
| absl::Status StoreImpl::SetFanPidControllerCoefficients( |
| absl::string_view controller_id, |
| const thermal::FanPidController::FanPidControllerCoefficients& coefficients, |
| absl::Duration timeout) { |
| absl::Status status = all_collectors_.thermal_collector |
| ->RequestFanPidControllerCoefficientsTuning( |
| controller_id, coefficients); |
| |
| if (!status.ok()) { |
| return status; |
| } |
| |
| absl::Time start_time = absl::Now(); |
| while (all_collectors_.thermal_collector->HasPendingTuningRequest( |
| controller_id) && |
| absl::Now() - start_time < timeout) { |
| absl::SleepFor(absl::Milliseconds(100)); |
| } |
| |
| return all_collectors_.thermal_collector->HasPendingTuningRequest( |
| controller_id) |
| ? absl::DeadlineExceededError(absl::StrCat( |
| "Timeout ", timeout, |
| " exceeded and tuning request is still pending.")) |
| : absl::OkStatus(); |
| } |
| |
| std::vector<nlohmann::json> StoreImpl::GetSelEntriesForward( |
| uint64_t start_id, size_t max_count) const { |
| return all_collectors_.sel_collector->GetSelEntriesForward(start_id, |
| max_count); |
| } |
| |
| std::vector<nlohmann::json> StoreImpl::GetSelEntriesBackward( |
| uint64_t start_id, size_t max_count) const { |
| return all_collectors_.sel_collector->GetSelEntriesBackward(start_id, |
| max_count); |
| } |
| |
| std::vector<nlohmann::json> StoreImpl::GetLatestSelEntries( |
| size_t max_count) const { |
| return all_collectors_.sel_collector->GetLatestSelEntries(max_count); |
| } |
| |
| void StoreImpl::DumpSelEntriesRaw(uint64_t start_id, std::ostream& os) const { |
| if (all_collectors_.sel_collector != nullptr) { |
| all_collectors_.sel_collector->DumpSelEntriesRaw(start_id, os); |
| } |
| } |
| |
| } // namespace milotic_tlbmc |