blob: aa2f4112e114aefaf00e150b20ae97b0d8917f59 [file] [log] [blame] [edit]
#include "boottime_callback.h"
#include <cstdint>
#include <memory>
#include <string>
#include <tuple>
#include <utility>
#include <vector>
#include "boottime.grpc.pb.h"
#include "absl/log/log.h"
#include "absl/status/status.h"
#include "absl/time/time.h"
#include "boottime_api/boottime_api_common.h"
#include "boottime_api/node_config.h"
#include "boottime_api/resource.h"
#include "grpcpp/server_context.h"
#include "grpcpp/support/server_callback.h"
#include "grpcpp/support/status.h"
namespace blobs {
namespace btm = boot_time_monitor;
grpc::Status BootTimeServiceImpl::ToGrpcStatus(absl::Status s) {
if (s.ok()) {
return grpc::Status::OK;
}
// The grpc & absl code have 1:1 mapping from 0 (OK) to 15 (DATA_LOSS).
grpc::StatusCode code = static_cast<grpc::StatusCode>(s.code());
if (code > grpc::StatusCode::DATA_LOSS) {
code = grpc::StatusCode::UNKNOWN;
}
return grpc::Status(static_cast<grpc::StatusCode>(s.code()),
std::string(s.message()));
}
absl::Status BootTimeServiceImpl::RegisterSelfToApi() {
if (base_path_.empty()) {
// Using default FileResource path
return boottime_api_.RegisterNode(node_config_);
} else {
// Using custom base path
auto resource = std::make_unique<btm::resource::FileResource>(
node_config_.node_name,
base_path_ + std::string(btm::def::kDataDir));
return boottime_api_.RegisterNode(node_config_, std::move(resource));
}
}
BootTimeServiceImpl::BootTimeServiceImpl(int instance)
: phosphor::boottime::grpc_gen::BootTimeService::CallbackService(),
instance_number_(instance),
base_path_(),
node_config_("host" + std::to_string(instance),
std::string(btm::kBootTimeTagHost)) {
RegisterSelfToApi().IgnoreError();
}
BootTimeServiceImpl::BootTimeServiceImpl(int instance,
const std::string& basePath)
: phosphor::boottime::grpc_gen::BootTimeService::CallbackService(),
instance_number_(instance),
base_path_(basePath),
node_config_("host" + std::to_string(instance),
std::string(btm::kBootTimeTagHost)),
boottime_api_(basePath + std::string(btm::def::kLockFile),
absl::Seconds(5)) {
auto resource = std::make_unique<btm::resource::FileResource>(
node_config_.node_name,
basePath + std::string(btm::def::kDataDir));
RegisterSelfToApi().IgnoreError();
}
grpc::ServerUnaryReactor* BootTimeServiceImpl::SetCheckpoint(
[[maybe_unused]] grpc::CallbackServerContext* context,
const phosphor::boottime::SetCheckpointRequest* request,
[[maybe_unused]] phosphor::boottime::SetCheckpointResponse* response) {
LOG(INFO) << "SetCheckpoint[" << instance_number_
<< "]: name=" << request->name()
<< ", timestamp=" << request->timestamp_ms()
<< ", duration=" << request->duration_ms();
grpc::ServerUnaryReactor* reactor = context->DefaultReactor();
// Check request content
// Note that timestamp or duration is optional and can be 0
if (request->name().empty() || request->name().length() > 1024) {
reactor->Finish(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
"Invalid name length"));
return reactor;
}
absl::Status ret = boottime_api_.SetNodeCheckpoint(
node_config_, request->name(), request->timestamp_ms(),
request->duration_ms());
if (ret.code() == absl::StatusCode::kNotFound) {
// Retry node register if the node is not found.
LOG(ERROR) << "Node not found. Retrying node registration.";
if (!(ret = RegisterSelfToApi()).ok()) {
reactor->Finish(ToGrpcStatus(ret));
return reactor;
}
ret = boottime_api_.SetNodeCheckpoint(node_config_, request->name(),
request->timestamp_ms(),
request->duration_ms());
}
reactor->Finish(ToGrpcStatus(ret));
return reactor;
}
grpc::ServerUnaryReactor* BootTimeServiceImpl::RebootComplete(
[[maybe_unused]] grpc::CallbackServerContext* context,
[[maybe_unused]] const phosphor::boottime::RebootCompleteRequest* request,
[[maybe_unused]] phosphor::boottime::RebootCompleteResponse* response) {
LOG(INFO) << "RebootComplete[" << instance_number_ << "]";
grpc::ServerUnaryReactor* reactor = context->DefaultReactor();
absl::Status ret = boottime_api_.NotifyNodeComplete(node_config_);
if (ret.code() == absl::StatusCode::kNotFound) {
// Retry node register if the node is not found.
LOG(ERROR) << "Node not found. Retrying node registration.";
if (!(ret = RegisterSelfToApi()).ok()) {
reactor->Finish(ToGrpcStatus(ret));
return reactor;
}
ret = boottime_api_.NotifyNodeComplete(node_config_);
}
reactor->Finish(ToGrpcStatus(ret));
return reactor;
}
grpc::ServerUnaryReactor* BootTimeServiceImpl::SetDuration(
[[maybe_unused]] grpc::CallbackServerContext* context,
const phosphor::boottime::SetDurationRequest* request,
[[maybe_unused]] phosphor::boottime::SetDurationResponse* response) {
LOG(INFO) << "SetDuration[" << instance_number_
<< "]: name=" << request->name()
<< ", duration=" << request->duration_ms();
grpc::ServerUnaryReactor* reactor = context->DefaultReactor();
// Check request content
if (request->name().empty() || request->name().length() > 1024) {
reactor->Finish(grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
"Invalid name length"));
return reactor;
}
absl::Status ret = boottime_api_.SetNodeDuration(
node_config_, request->name(), request->duration_ms());
if (ret.code() == absl::StatusCode::kNotFound) {
// Retry node register if the node is not found.
LOG(ERROR) << "Node not found. Retrying node registration.";
if (!(ret = RegisterSelfToApi()).ok()) {
reactor->Finish(ToGrpcStatus(ret));
return reactor;
}
ret = boottime_api_.SetNodeDuration(node_config_, request->name(),
request->duration_ms());
}
reactor->Finish(ToGrpcStatus(ret));
return reactor;
}
grpc::ServerUnaryReactor* BootTimeServiceImpl::GetBootTime(
[[maybe_unused]] grpc::CallbackServerContext* context,
[[maybe_unused]] const phosphor::boottime::GetBootTimeRequest* request,
phosphor::boottime::GetBootTimeResponse* response) {
LOG(INFO) << "GetBootTime[" << instance_number_ << "]";
grpc::ServerUnaryReactor* reactor = context->DefaultReactor();
std::vector<std::tuple<std::string, int64_t, int64_t>> checkpoints =
boottime_api_.GetNodeCheckpointList(node_config_);
for (const auto& [name, wall_time_ms, mono_time_ms] : checkpoints) {
auto* rbf = response->add_reboot_flow();
rbf->set_stage(name);
rbf->set_timestamp_wall_ms(wall_time_ms);
rbf->set_timestamp_mono_ms(mono_time_ms);
}
std::vector<std::tuple<std::string, int64_t>> durations =
boottime_api_.GetNodeAdditionalDurations(node_config_);
for (const auto& [name, duration_ms] : durations) {
auto* d = response->add_durations();
d->set_name(name);
d->set_duration_ms(duration_ms);
}
response->mutable_stat()->set_is_rebooting(
boottime_api_.IsNodeRebooting(node_config_));
reactor->Finish(grpc::Status::OK);
return reactor;
}
} // namespace blobs