feat(3p/nix/daemon): catch-all explicit Error-Status conversion

We wrap every server-side proto handler with a macro that catches
exceptions and turns them into proper grpc error codes. For the
time being, most exceptions map to INTERNAL, the existing mapping.

Change-Id: Id6ed6a279b198ad185d32562f39000ccc15eadbf
Reviewed-on: https://cl.tvl.fyi/c/depot/+/1599
Tested-by: BuildkiteCI
Reviewed-by: glittershark <grfn@gws.fyi>
This commit is contained in:
Kane York 2020-08-03 08:18:56 -07:00 committed by kanepyork
parent ae31f51dc8
commit 2344f8e528
2 changed files with 381 additions and 201 deletions

View file

@ -3,6 +3,7 @@
#include <algorithm>
#include <memory>
#include <absl/status/status.h>
#include <absl/strings/str_cat.h>
#include <absl/strings/str_format.h>
#include <google/protobuf/empty.pb.h>
@ -52,14 +53,105 @@ T FillFrom(const U& src) {
return result;
}
constexpr absl::StatusCode GRPCStatusCodeToAbsl(grpc::StatusCode code) {
switch (code) {
case grpc::StatusCode::OK:
return absl::StatusCode::kOk;
case grpc::StatusCode::CANCELLED:
return absl::StatusCode::kCancelled;
case grpc::StatusCode::UNKNOWN:
return absl::StatusCode::kUnknown;
case grpc::StatusCode::INVALID_ARGUMENT:
return absl::StatusCode::kInvalidArgument;
case grpc::StatusCode::DEADLINE_EXCEEDED:
return absl::StatusCode::kDeadlineExceeded;
case grpc::StatusCode::NOT_FOUND:
return absl::StatusCode::kNotFound;
case grpc::StatusCode::ALREADY_EXISTS:
return absl::StatusCode::kAlreadyExists;
case grpc::StatusCode::PERMISSION_DENIED:
return absl::StatusCode::kPermissionDenied;
case grpc::StatusCode::UNAUTHENTICATED:
return absl::StatusCode::kUnauthenticated;
case grpc::StatusCode::RESOURCE_EXHAUSTED:
return absl::StatusCode::kResourceExhausted;
case grpc::StatusCode::FAILED_PRECONDITION:
return absl::StatusCode::kFailedPrecondition;
case grpc::StatusCode::ABORTED:
return absl::StatusCode::kAborted;
case grpc::StatusCode::OUT_OF_RANGE:
return absl::StatusCode::kOutOfRange;
case grpc::StatusCode::UNIMPLEMENTED:
return absl::StatusCode::kUnimplemented;
case grpc::StatusCode::INTERNAL:
return absl::StatusCode::kInternal;
case grpc::StatusCode::UNAVAILABLE:
return absl::StatusCode::kUnavailable;
case grpc::StatusCode::DATA_LOSS:
return absl::StatusCode::kDataLoss;
default:
return absl::StatusCode::kInternal;
}
}
constexpr absl::string_view GRPCStatusCodeDescription(grpc::StatusCode code) {
switch (code) {
case grpc::StatusCode::OK:
return "OK";
case grpc::StatusCode::CANCELLED:
return "CANCELLED";
case grpc::StatusCode::UNKNOWN:
return "UNKNOWN";
case grpc::StatusCode::INVALID_ARGUMENT:
return "INVALID_ARGUMENT";
case grpc::StatusCode::DEADLINE_EXCEEDED:
return "DEADLINE_EXCEEDED";
case grpc::StatusCode::NOT_FOUND:
return "NOT_FOUND";
case grpc::StatusCode::ALREADY_EXISTS:
return "ALREADY_EXISTS";
case grpc::StatusCode::PERMISSION_DENIED:
return "PERMISSION_DENIED";
case grpc::StatusCode::UNAUTHENTICATED:
return "UNAUTHENTICATED";
case grpc::StatusCode::RESOURCE_EXHAUSTED:
return "RESOURCE_EXHAUSTED";
case grpc::StatusCode::FAILED_PRECONDITION:
return "FAILED_PRECONDITION";
case grpc::StatusCode::ABORTED:
return "ABORTED";
case grpc::StatusCode::OUT_OF_RANGE:
return "OUT_OF_RANGE";
case grpc::StatusCode::UNIMPLEMENTED:
return "UNIMPLEMENTED";
case grpc::StatusCode::INTERNAL:
return "INTERNAL";
case grpc::StatusCode::UNAVAILABLE:
return "UNAVAILABLE";
case grpc::StatusCode::DATA_LOSS:
return "DATA_LOSS";
default:
return "<BAD ERROR CODE>";
};
}
// TODO(grfn): Obviously this should go away and be replaced by StatusOr... but
// that would require refactoring the entire store api, which we don't feel like
// doing right now. We should at some point though
void const RpcStore::SuccessOrThrow(const grpc::Status& status) const {
if (!status.ok()) {
throw Error(absl::StrFormat("Rpc call to %s failed (%d): %s ",
uri_.value_or("unknown URI"),
status.error_code(), status.error_message()));
auto uri = uri_.value_or("unknown URI");
switch (status.error_code()) {
case grpc::StatusCode::UNIMPLEMENTED:
throw Unsupported(
absl::StrFormat("operation is not supported by store at %s: %s",
uri, status.error_message()));
default:
throw Error(
absl::StrFormat("Rpc call to %s failed (%s): %s ", uri,
GRPCStatusCodeDescription(status.error_code()),
status.error_message()));
}
}
}