blob: a25c0f3aad106a6085e10ec2d243722b4d904cae [file]
#include "bmc/state_monitor_bmc.h"
#include <safepower_agent_config.pb.h>
#include <any>
#include <filesystem> // NOLINT
#include <fstream>
#include <string>
#include <unordered_map>
#include <utility>
#include "nlohmann/json.hpp"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "safepower_agent.pb.h"
#include "state_updater.h"
#include "bmc/redfish.h"
#include "absl/base/log_severity.h"
#include "absl/log/log.h"
#include "bmc/daemon_context_bmc.h"
namespace safepower_agent {
using safepower_agent_config::SafePowerAgentConfig;
using safepower_agent_config::GpowerdConfig;
using safepower_agent_config::StateMonitorConfig;
using safepower_agent_config::StateGatheringInfo;
using safepower_agent_config::RedfishInfo;
using safepower_agent_config::DbusInfo;
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
("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