| #include "bmc/state_monitor_bmc.h" |
| |
| #include <cstdint> |
| #include <memory> |
| #include <string> |
| |
| #include "bmc/daemon_context_bmc.h" |
| #include "bmc/redfish.h" |
| #include "safepower_agent.pb.h" |
| #include "safepower_agent_config.pb.h" |
| #include "state_updater.h" |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "absl/strings/str_cat.h" |
| #include "absl/strings/str_format.h" |
| #include "absl/strings/string_view.h" |
| #include "absl/time/time.h" |
| #include "nlohmann/json.hpp" |
| #include "nlohmann/json_fwd.hpp" |
| |
| namespace safepower_agent { |
| |
| using safepower_agent_config::GpowerdConfig; |
| using safepower_agent_config::StateGatheringInfo; |
| |
| StateMonitorBMC::StateMonitorBMC( |
| std::shared_ptr<StateUpdater<safepower_agent_proto::SystemState>> reactor) |
| : reactor_(reactor) {} |
| |
| absl::Status StateMonitorBMC::BuildFromConfig(const GpowerdConfig& config) { |
| for (auto& resource_to_monitor : config.state_monitor_config()) { |
| if (resource_to_monitor.state_gathering_info().info_case() == |
| StateGatheringInfo::kRedfish) { |
| std::string state_name = resource_to_monitor.state_name(); |
| std::string uri = |
| resource_to_monitor.state_gathering_info().redfish().uri(); |
| std::string json_key = |
| resource_to_monitor.state_gathering_info().redfish().json_key(); |
| std::string node_entity_tag = |
| resource_to_monitor.system_component().node_entity_tag(); |
| std::string component_name = |
| resource_to_monitor.system_component().name(); |
| uint64_t collection_interval_ms = |
| resource_to_monitor.state_gathering_info().collection_interval_ms(); |
| auto prototype = resource_to_monitor.state_gathering_info().prototype(); |
| if (prototype.has_power_state() && |
| (prototype.power_state().has_state())) { |
| // create bmcweb state monitor for power state |
| if (!CreateRedfishUpdatePowerState(state_name, uri, json_key, |
| collection_interval_ms, |
| node_entity_tag, component_name) |
| .ok()) { |
| LOG(ERROR) << "failed to create bmcweb state monitor for: " |
| << state_name; |
| return absl::InvalidArgumentError( |
| "failed to create bmcweb state monitor for: " + state_name); |
| } |
| } else { |
| LOG(ERROR) << "update function is not supported TODO b/372971177"; |
| return absl::UnimplementedError("update function is not supported "); |
| } |
| } else if (resource_to_monitor.state_gathering_info().info_case() == |
| StateGatheringInfo::kDbus) { |
| (void)CreateDbusStateMonitor("", "", "", "", "", 1000); |
| } else { |
| LOG(ERROR) << "state monitor type is not supported; " |
| << resource_to_monitor.state_gathering_info().info_case(); |
| return absl::InvalidArgumentError( |
| absl::StrCat("state monitor type is not supported: ", |
| resource_to_monitor.state_gathering_info().info_case())); |
| } |
| } |
| return absl::OkStatus(); |
| } |
| |
| absl::Status StateMonitorBMC::CreateRedfishUpdatePowerState( |
| std::string state_name, std::string uri, std::string json_key, |
| int collection_interval_ms, std::string node_entity_tag, |
| std::string component_name) { |
| LOG(INFO) << "creating bmcweb state monitor for:" << state_name; |
| LOG(INFO) << "uri: " << uri; |
| LOG(INFO) << "json_key: " << json_key; |
| LOG(INFO) << "collection_interval_ms: " << collection_interval_ms; |
| |
| return DaemonContextBMC::Get().scheduler().PeriodicCall( |
| [state_name, uri, json_key, this, node_entity_tag, component_name] { |
| Redfish::Get(uri, [state_name, uri, json_key, this, node_entity_tag, |
| component_name](absl::StatusOr<nlohmann::json> js) { |
| if (!js.ok()) { |
| LOG(ERROR) << "Failed to get " << uri |
| << " from BMC: " << js.status(); |
| return; |
| } |
| |
| auto js_value = js->find(json_key); |
| std::string state_str = js_value != js->end() ? *js_value : ""; |
| safepower_agent_proto::PowerStateSpecifier temp_power_state = |
| ConvertStatePowerStringToEnum(state_str); |
| const safepower_agent_proto::SystemState current_state = |
| this->reactor_->state(); |
| |
| safepower_agent_proto::PowerStateSpecifier last_ps = |
| safepower_agent_proto::POWER_STATE_UNSPECIFIED; |
| auto node_it = current_state.node_state().find(node_entity_tag); |
| if (node_it != current_state.node_state().end()) { |
| auto component_it = |
| node_it->second.component_state().find(component_name); |
| if (component_it != node_it->second.component_state().end()) { |
| last_ps = component_it->second.power_state().state(); |
| } |
| } |
| if (last_ps == temp_power_state) return; |
| absl::string_view last_ps_str = PowerStateSpecifier_Name(last_ps); |
| absl::string_view temp_ps_str = |
| PowerStateSpecifier_Name(temp_power_state); |
| LOG(INFO) << absl::StrFormat( |
| "state changed from: %d (%s) to: %d (%s)", last_ps, last_ps_str, |
| temp_power_state, temp_ps_str); |
| |
| // add new state power state to a new system proto |
| safepower_agent_proto::SystemState new_state; |
| safepower_agent_proto::PowerState ps; |
| ps.set_state(temp_power_state); |
| |
| safepower_agent_proto::ComponentState cs; |
| *(cs.mutable_power_state()) = ps; |
| |
| safepower_agent_proto::NodeState ns; |
| ns.mutable_component_state()->insert({component_name, cs}); |
| new_state.mutable_node_state()->insert({node_entity_tag, ns}); |
| |
| reactor_->UpdateState(new_state); |
| }); |
| }, |
| absl::Milliseconds(collection_interval_ms), state_name); |
| } |
| |
| safepower_agent_proto::PowerStateSpecifier |
| StateMonitorBMC::ConvertStatePowerStringToEnum(absl::string_view state_str) { |
| if (state_str == "On") { |
| return safepower_agent_proto::POWER_STATE_ON; |
| } else if (state_str == "Off") { |
| return safepower_agent_proto::POWER_STATE_OFF; |
| } else if (state_str == "Paused") { // not in bmcweb |
| return safepower_agent_proto::POWER_STATE_PAUSED; |
| } else if (state_str == "PoweringOn") { |
| return safepower_agent_proto::POWER_STATE_POWERING_ON; |
| } else if (state_str == "PoweringOff") { |
| return safepower_agent_proto::POWER_STATE_POWERING_OFF; |
| } else { |
| LOG(ERROR) << "failed to map power state string to enum: " << state_str; |
| return safepower_agent_proto::POWER_STATE_UNSPECIFIED; |
| } |
| } |
| |
| absl::Status StateMonitorBMC::CreateDbusStateMonitor( |
| std::string state_name, std::string dbus_path, std::string dbus_method, |
| std::string dbus_interface, std::string dbus_value, |
| int collection_interval_ms) { |
| LOG(INFO) << "creating dbus state monitor for:" << state_name; |
| LOG(INFO) << "dbus_path: " << dbus_path; |
| LOG(INFO) << "dbus_method: " << dbus_method; |
| LOG(INFO) << "dbus_interface: " << dbus_interface; |
| LOG(INFO) << "dbus_value: " << dbus_value; |
| LOG(INFO) << "collection_interval_ms: " << collection_interval_ms; |
| return absl::UnimplementedError("CreateDbusStateMonitor is not implemented"); |
| } |
| |
| } // namespace safepower_agent |