blob: 33433abcc9366543ebfc8672bfb5d01e2720488a [file] [log] [blame]
// 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;
}