| // gpowerd is the safe power local agent for BMC. |
| // It implements the SafePowerLocalAgent service, and is responsible for |
| // actuating power cycles on the machine. |
| |
| #include <csignal> |
| #include <memory> |
| #include <string> |
| #include <utility> |
| |
| #include "action_context.h" |
| #include "bmc/auth.h" |
| #include "bmc/daemon_context_bmc.h" |
| #include "bmc/machine_configs/setup_configs.h" |
| #include "bmc/state_monitor_bmc.h" |
| #include "safepower_agent_config.pb.h" |
| #include "safepower_agent.h" |
| #include "state_updater.h" |
| #include "absl/flags/flag.h" |
| #include "one/public_offline_node_entities.h" |
| #include "absl/flags/parse.h" |
| #include "absl/log/globals.h" |
| #include "absl/log/log.h" |
| #include "absl/status/status.h" |
| #include "grpc/grpc.h" |
| #include "grpc/support/time.h" |
| #include "grpcpp/ext/proto_server_reflection_plugin.h" |
| #include "grpcpp/security/authorization_policy_provider.h" |
| #include "grpcpp/security/server_credentials.h" |
| #include "grpcpp/server.h" |
| #include "grpcpp/server_builder.h" |
| #include "bmc/status_macros.h" |
| |
| using grpc::Server; |
| using grpc::ServerBuilder; |
| using safepower_agent::DaemonContextBMC; |
| using safepower_agent::SafepowerLocalAgentImpl; |
| using safepower_agent::StateUpdater; |
| |
| using ::grpc::experimental::AuthorizationPolicyProviderInterface; |
| |
| const char* address = "[::]:20120"; |
| |
| // The built-in log flags are not being pulled into this code because the cmake |
| // build does not include the flags library for logging, so a local flag was |
| // setup to mitigate this. |
| |
| // Global log verbosity level. Default is 0. |
| ABSL_FLAG(int, v, 0, "Global log verbosity level").OnUpdate([] { |
| absl::SetGlobalVLogLevel(absl::GetFlag(FLAGS_v)); |
| }); |
| void SetupChannelParams(ServerBuilder& builder) |
| { |
| DaemonContextBMC& daemon_context = DaemonContextBMC::Get(); |
| |
| auto grpc_config = daemon_context.config().grpc_config(); |
| builder.AddChannelArgument( |
| GRPC_ARG_KEEPALIVE_TIME_MS, grpc_config.keepalive_time_ms()); |
| |
| builder.AddChannelArgument( |
| GRPC_ARG_KEEPALIVE_TIMEOUT_MS, grpc_config.keepalive_timeout_ms()); |
| builder.AddChannelArgument( |
| GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, |
| grpc_config.keepalive_permit_without_calls()); |
| builder.AddChannelArgument( |
| GRPC_ARG_HTTP2_MAX_PINGS_WITHOUT_DATA, |
| grpc_config.max_pings_without_data()); |
| builder.AddChannelArgument( |
| GRPC_ARG_HTTP2_MIN_RECV_PING_INTERVAL_WITHOUT_DATA_MS, |
| grpc_config.min_recv_ping_interval_without_data_ms()); |
| builder.AddChannelArgument( |
| GRPC_ARG_HTTP2_MAX_PING_STRIKES, |
| grpc_config.max_ping_strikes()); |
| } |
| |
| absl::Status main_gpowerd() { |
| DaemonContextBMC daemon_context; |
| safepower_agent_proto::SystemState initialState; |
| auto state_updater = |
| std::make_shared<StateUpdater<safepower_agent_proto::SystemState>>( |
| std::move(initialState)); |
| auto global_state_updater = |
| std::make_shared<StateUpdater<safepower_agent_proto::SystemState>>(); |
| auto action_context_manager = |
| std::make_unique<safepower_agent::ActionContextManager>( |
| state_updater, global_state_updater); |
| |
| auto state_monitor = |
| std::make_shared<safepower_agent::StateMonitorBMC>(state_updater); |
| |
| // TODO: b/447628549 - gpowerd should work without offline node entities |
| auto offline_node_entities = |
| production_msv::node_entities::ReadOfflineNodeEntityInformation(); |
| if (!offline_node_entities.ok()) { |
| LOG(DFATAL) << "Failed to read offline node entities: " |
| << offline_node_entities.status(); |
| } else { |
| LOG(INFO) << "offline_node_entities: " << offline_node_entities; |
| daemon_context.set_offline_node_entities(*std::move(offline_node_entities)); |
| } |
| |
| RETURN_IF_ERROR( |
| setup_configs::SetupConfigs(*state_monitor, *action_context_manager)); |
| |
| if (absl::Status status = action_context_manager->LoadSavedActions(); |
| !status.ok()) { |
| LOG(ERROR) << "Failed to load saved actions: " << status; |
| RETURN_IF_ERROR( |
| daemon_context.persistent_storage_manager().InitializeSavedActions()); |
| LOG(INFO) << "Empty saved actions initialized"; |
| } else { |
| LOG(INFO) << "Saved actions loaded"; |
| } |
| SafepowerLocalAgentImpl safePowerService(std::move(state_updater), |
| std::move(global_state_updater), |
| std::move(action_context_manager)); |
| ServerBuilder builder; |
| SetupChannelParams(builder); |
| std::shared_ptr<grpc::ServerCredentials> creds = nullptr; |
| #ifdef INSECURE_MODE |
| creds = grpc::InsecureServerCredentials(); // NOLINT if the image is |
| // build in insecure mode, build the grpc server with |
| // insecure credentials |
| LOG(WARNING) << "Using insecure credentials"; |
| #else |
| LOG(INFO) << "Using secure credentials"; |
| |
| ASSIGN_OR_RETURN(creds, auth::GetCredsInfo()); |
| |
| LOG(INFO) << "Credentials loaded"; |
| ASSIGN_OR_RETURN(std::shared_ptr<AuthorizationPolicyProviderInterface> policy, |
| auth::GetAuthPolicy()); |
| LOG(INFO) << "authorization policy loaded"; |
| builder.experimental().SetAuthorizationPolicyProvider(policy); |
| #endif // INSECURE_MODE |
| |
| LOG(INFO) << "using address " << address; |
| builder.AddListeningPort(address, creds); |
| |
| /* Listen on the given address with an authentication mechanism. */ |
| builder.RegisterService(&safePowerService); |
| grpc::reflection::InitProtoReflectionServerBuilderPlugin(); |
| |
| std::unique_ptr<Server> server(builder.BuildAndStart()); |
| if (server == nullptr) { |
| // TODO Add logic to restarting safePowerService, while running events |
| // in the scheduler. (Possibly schedule a retry.) |
| LOG(ERROR) << "grpc server failed to start, exiting gPowerD"; |
| return absl::InternalError("grpc server failed to start, exiting gPowerD"); |
| } |
| |
| // register SIGTERM handler before starting io loop |
| std::signal(SIGTERM, [](int) { |
| LOG(INFO) << "Received SIGTERM, starting shutting down gracefully"; |
| |
| absl::Status status = DaemonContextBMC::Get().scheduler().Shutdown(); |
| if (!status.ok()) { |
| LOG(ERROR) << "SIGTERM, shutting down error : " << status; |
| } |
| }); |
| |
| LOG(INFO) << "gPowerD started"; |
| DaemonContextBMC::Get().get_io_context().run(); |
| LOG(INFO) << "event loop returned"; |
| if (server) { |
| server->Shutdown(gpr_now(GPR_CLOCK_MONOTONIC)); |
| } |
| LOG(INFO) << "gPowerD stopped; grpc server shutdown"; |
| return absl::OkStatus(); |
| } |
| |
| int main(int argc, char** argv) { |
| absl::ParseCommandLine(argc, argv); |
| absl::Status status = main_gpowerd(); |
| if (!status.ok()) { |
| LOG(ERROR) << "gpowerd exited with status: " << status; |
| return 1; |
| } |
| LOG(INFO) << "gpowerd exited with status: 0 "; |
| return 0; |
| } |