diff --git a/Dockerfile b/Dockerfile index 68eb7acdce..a214f43677 100644 --- a/Dockerfile +++ b/Dockerfile @@ -74,22 +74,23 @@ WORKDIR /src FROM build AS generate-build # Common needs to be at or near the top to satisfy the subsequent imports +COPY ./api/vendor/ /api/vendor/ COPY ./api/common/common.proto /api/common/common.proto -RUN protoc -I/api --go_out=plugins=grpc,paths=source_relative:/api common/common.proto +RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api common/common.proto COPY ./api/health/health.proto /api/health/health.proto -RUN protoc -I/api --go_out=plugins=grpc,paths=source_relative:/api health/health.proto +RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api health/health.proto COPY ./api/security/security.proto /api/security/security.proto -RUN protoc -I/api --go_out=plugins=grpc,paths=source_relative:/api security/security.proto +RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api security/security.proto COPY ./api/storage/storage.proto /api/storage/storage.proto -RUN protoc -I/api --go_out=plugins=grpc,paths=source_relative:/api storage/storage.proto +RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api storage/storage.proto COPY ./api/machine/machine.proto /api/machine/machine.proto -RUN protoc -I/api --go_out=plugins=grpc,paths=source_relative:/api machine/machine.proto +RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api machine/machine.proto COPY ./api/time/time.proto /api/time/time.proto -RUN protoc -I/api --go_out=plugins=grpc,paths=source_relative:/api time/time.proto +RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api time/time.proto COPY ./api/network/network.proto /api/network/network.proto -RUN protoc -I/api --go_out=plugins=grpc,paths=source_relative:/api network/network.proto +RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api network/network.proto COPY ./api/cluster/cluster.proto /api/cluster/cluster.proto -RUN protoc -I/api --go_out=plugins=grpc,paths=source_relative:/api cluster/cluster.proto +RUN protoc -I/api -I/api/vendor/ --go_out=plugins=grpc,paths=source_relative:/api cluster/cluster.proto # Gofumports generated files to adjust import order RUN gofumports -w -local github.com/talos-systems/talos /api/ @@ -646,8 +647,10 @@ RUN protoc \ -I/protos/security \ -I/protos/storage \ -I/protos/time \ + -I/protos/vendor \ --doc_opt=/tmp/markdown.tmpl,api.md \ --doc_out=/tmp \ + /protos/common/*.proto \ /protos/health/*.proto \ /protos/machine/*.proto \ /protos/network/*.proto \ diff --git a/api/common/common.proto b/api/common/common.proto index 875c8d6a1c..e129a63c97 100644 --- a/api/common/common.proto +++ b/api/common/common.proto @@ -5,6 +5,7 @@ package common; option go_package = "github.com/talos-systems/talos/pkg/machinery/api/common"; import "google/protobuf/any.proto"; +import "google/rpc/status.proto"; enum Code { FATAL = 0; @@ -24,6 +25,8 @@ message Metadata { // error is set if request failed to the upstream (rest of response is // undefined) string error = 2; + // error as gRPC Status + google.rpc.Status status = 3; } message Data { diff --git a/api/vendor/google/rpc/status.proto b/api/vendor/google/rpc/status.proto new file mode 100644 index 0000000000..3b1f7a932f --- /dev/null +++ b/api/vendor/google/rpc/status.proto @@ -0,0 +1,47 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +syntax = "proto3"; + +package google.rpc; + +import "google/protobuf/any.proto"; + +option cc_enable_arenas = true; +option go_package = "google.golang.org/genproto/googleapis/rpc/status;status"; +option java_multiple_files = true; +option java_outer_classname = "StatusProto"; +option java_package = "com.google.rpc"; +option objc_class_prefix = "RPC"; + +// The `Status` type defines a logical error model that is suitable for +// different programming environments, including REST APIs and RPC APIs. It is +// used by [gRPC](https://github.com/grpc). Each `Status` message contains +// three pieces of data: error code, error message, and error details. +// +// You can find out more about this error model and how to work with it in the +// [API Design Guide](https://cloud.google.com/apis/design/errors). +message Status { + // The status code, which should be an enum value of [google.rpc.Code][google.rpc.Code]. + int32 code = 1; + + // A developer-facing error message, which should be in English. Any + // user-facing error message should be localized and sent in the + // [google.rpc.Status.details][google.rpc.Status.details] field, or localized by the client. + string message = 2; + + // A list of messages that carry the error details. There is a common set of + // message types for APIs to use. + repeated google.protobuf.Any details = 3; +} diff --git a/internal/app/apid/pkg/backend/apid.go b/internal/app/apid/pkg/backend/apid.go index 1b2a2dd480..840489613c 100644 --- a/internal/app/apid/pkg/backend/apid.go +++ b/internal/app/apid/pkg/backend/apid.go @@ -14,6 +14,7 @@ import ( "google.golang.org/grpc" "google.golang.org/grpc/credentials" "google.golang.org/grpc/metadata" + "google.golang.org/grpc/status" "google.golang.org/protobuf/encoding/protowire" "google.golang.org/protobuf/proto" @@ -199,6 +200,7 @@ func (a *APID) BuildError(streaming bool, err error) ([]byte, error) { Metadata: &common.Metadata{ Hostname: a.target, Error: err.Error(), + Status: status.Convert(err).Proto(), }, } diff --git a/pkg/machinery/api/common/common.pb.go b/pkg/machinery/api/common/common.pb.go index 2374a6ded2..c674599ba7 100644 --- a/pkg/machinery/api/common/common.pb.go +++ b/pkg/machinery/api/common/common.pb.go @@ -12,6 +12,7 @@ import ( proto "github.com/golang/protobuf/proto" any "github.com/golang/protobuf/ptypes/any" + status "google.golang.org/genproto/googleapis/rpc/status" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" ) @@ -193,6 +194,8 @@ type Metadata struct { // error is set if request failed to the upstream (rest of response is // undefined) Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + // error as gRPC Status + Status *status.Status `protobuf:"bytes,3,opt,name=status,proto3" json:"status,omitempty"` } func (x *Metadata) Reset() { @@ -241,6 +244,13 @@ func (x *Metadata) GetError() string { return "" } +func (x *Metadata) GetStatus() *status.Status { + if x != nil { + return x.Status + } + return nil +} + type Data struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -443,43 +453,47 @@ var file_common_common_proto_rawDesc = []byte{ 0x0a, 0x13, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x1a, 0x19, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x61, - 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x73, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, - 0x72, 0x12, 0x20, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, - 0x0c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, - 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, - 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, - 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, - 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x3c, 0x0a, - 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, - 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, - 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x4a, 0x0a, 0x04, 0x44, - 0x61, 0x74, 0x61, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x38, 0x0a, 0x0c, 0x44, 0x61, 0x74, 0x61, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, - 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x73, 0x22, 0x35, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, - 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, - 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, - 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3a, 0x0a, 0x0d, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x08, 0x6d, 0x65, 0x73, - 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0d, 0x2e, 0x63, 0x6f, - 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x73, - 0x61, 0x67, 0x65, 0x73, 0x2a, 0x1d, 0x0a, 0x04, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x09, 0x0a, 0x05, - 0x46, 0x41, 0x54, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4c, 0x4f, 0x43, 0x4b, 0x45, - 0x44, 0x10, 0x01, 0x2a, 0x2a, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, 0x61, 0x69, 0x6e, 0x65, 0x72, - 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x4f, 0x4e, 0x54, 0x41, 0x49, - 0x4e, 0x45, 0x52, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x43, 0x52, 0x49, 0x10, 0x01, 0x42, - 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x74, 0x61, - 0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, 0x2f, 0x74, 0x61, 0x6c, 0x6f, - 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, 0x6e, 0x65, 0x72, 0x79, 0x2f, - 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x6e, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x22, 0x73, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x20, 0x0a, 0x04, 0x63, 0x6f, + 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0c, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, + 0x6e, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x2e, 0x0a, 0x07, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x41, 0x6e, 0x79, 0x52, 0x07, 0x64, + 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x68, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x12, 0x2a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x72, 0x70, + 0x63, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, + 0x22, 0x4a, 0x0a, 0x04, 0x44, 0x61, 0x74, 0x61, 0x12, 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, + 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x62, 0x79, 0x74, 0x65, 0x73, 0x22, 0x38, 0x0a, 0x0c, + 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x08, + 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x0c, + 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x22, 0x35, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, + 0x2c, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3a, 0x0a, + 0x0d, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, + 0x0a, 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x0d, 0x2e, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x52, + 0x08, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x73, 0x2a, 0x1d, 0x0a, 0x04, 0x43, 0x6f, 0x64, + 0x65, 0x12, 0x09, 0x0a, 0x05, 0x46, 0x41, 0x54, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, + 0x4c, 0x4f, 0x43, 0x4b, 0x45, 0x44, 0x10, 0x01, 0x2a, 0x2a, 0x0a, 0x0f, 0x43, 0x6f, 0x6e, 0x74, + 0x61, 0x69, 0x6e, 0x65, 0x72, 0x44, 0x72, 0x69, 0x76, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x0a, 0x43, + 0x4f, 0x4e, 0x54, 0x41, 0x49, 0x4e, 0x45, 0x52, 0x44, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x43, + 0x52, 0x49, 0x10, 0x01, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, + 0x6f, 0x6d, 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2d, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x73, + 0x2f, 0x74, 0x61, 0x6c, 0x6f, 0x73, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x6d, 0x61, 0x63, 0x68, 0x69, + 0x6e, 0x65, 0x72, 0x79, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -507,21 +521,23 @@ var ( (*Empty)(nil), // 6: common.Empty (*EmptyResponse)(nil), // 7: common.EmptyResponse (*any.Any)(nil), // 8: google.protobuf.Any + (*status.Status)(nil), // 9: google.rpc.Status } ) var file_common_common_proto_depIdxs = []int32{ 0, // 0: common.Error.code:type_name -> common.Code 8, // 1: common.Error.details:type_name -> google.protobuf.Any - 3, // 2: common.Data.metadata:type_name -> common.Metadata - 4, // 3: common.DataResponse.messages:type_name -> common.Data - 3, // 4: common.Empty.metadata:type_name -> common.Metadata - 6, // 5: common.EmptyResponse.messages:type_name -> common.Empty - 6, // [6:6] is the sub-list for method output_type - 6, // [6:6] is the sub-list for method input_type - 6, // [6:6] is the sub-list for extension type_name - 6, // [6:6] is the sub-list for extension extendee - 0, // [0:6] is the sub-list for field type_name + 9, // 2: common.Metadata.status:type_name -> google.rpc.Status + 3, // 3: common.Data.metadata:type_name -> common.Metadata + 4, // 4: common.DataResponse.messages:type_name -> common.Data + 3, // 5: common.Empty.metadata:type_name -> common.Metadata + 6, // 6: common.EmptyResponse.messages:type_name -> common.Empty + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name } func init() { file_common_common_proto_init() } diff --git a/pkg/machinery/client/reply.go b/pkg/machinery/client/reply.go index 73c2669c23..335add9c6a 100644 --- a/pkg/machinery/client/reply.go +++ b/pkg/machinery/client/reply.go @@ -5,22 +5,30 @@ package client import ( + "errors" "fmt" "reflect" "github.com/hashicorp/go-multierror" + rpcstatus "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc/status" ) // NodeError is RPC error from some node. type NodeError struct { Node string - Err string + Err error } func (ne *NodeError) Error() string { return fmt.Sprintf("%s: %s", ne.Node, ne.Err) } +// Unwrap implements errors.Unwrap interface. +func (ne *NodeError) Unwrap() error { + return ne.Err +} + // FilterMessages removes error Messagess from resp and builds multierror. // //nolint: gocyclo @@ -102,6 +110,26 @@ func FilterMessages(resp interface{}, err error) (interface{}, error) { continue } + rpcError := errors.New(errorField.String()) + + statusField := metadata.FieldByName("Status") + if !statusField.IsValid() { + panic("metadata.Status field missing") + } + + if statusField.Kind() != reflect.Ptr { + panic("metadata.Status should be pointer") + } + + if !statusField.IsZero() { + statusValue, ok := statusField.Interface().(*rpcstatus.Status) + if !ok { + panic("metadata.Status should be of type *status.Status") + } + + rpcError = status.FromProto(statusValue).Err() + } + hostnameField := metadata.FieldByName("Hostname") if !hostnameField.IsValid() { panic("metadata.Hostname field missing") @@ -114,7 +142,7 @@ func FilterMessages(resp interface{}, err error) (interface{}, error) { // extract error nodeError := &NodeError{ Node: hostnameField.String(), - Err: errorField.String(), + Err: rpcError, } multiErr = multierror.Append(multiErr, nodeError) diff --git a/pkg/machinery/client/reply_test.go b/pkg/machinery/client/reply_test.go index 0a1d486fef..49557d3d1a 100644 --- a/pkg/machinery/client/reply_test.go +++ b/pkg/machinery/client/reply_test.go @@ -9,6 +9,8 @@ import ( "testing" "github.com/stretchr/testify/assert" + "google.golang.org/genproto/googleapis/rpc/status" + "google.golang.org/grpc/codes" "github.com/talos-systems/talos/pkg/machinery/api/common" "github.com/talos-systems/talos/pkg/machinery/client" @@ -93,3 +95,34 @@ func TestFilterMessagesOnlyErrors(t *testing.T) { assert.EqualError(t, err, "2 errors occurred:\n\t* host2: something wrong\n\t* host4: even more wrong\n\n") assert.Nil(t, filtered) } + +func TestFilterMessagesGRPCStatus(t *testing.T) { + reply := &common.DataResponse{ + Messages: []*common.Data{ + { + Metadata: &common.Metadata{ + Hostname: "host2", + Error: "should be ignored", + Status: &status.Status{ + Code: int32(codes.Aborted), + Message: "something aborted", + }, + }, + }, + { + Metadata: &common.Metadata{ + Hostname: "host4", + Error: "should be ignored", + Status: &status.Status{ + Code: int32(codes.Unknown), + Message: "something went wrong", + }, + }, + }, + }, + } + + filtered, err := client.FilterMessages(reply, nil) + assert.EqualError(t, err, "2 errors occurred:\n\t* host2: rpc error: code = Aborted desc = something aborted\n\t* host4: rpc error: code = Unknown desc = something went wrong\n\n") + assert.Nil(t, filtered) +} diff --git a/pkg/machinery/go.mod b/pkg/machinery/go.mod index d028786754..576b2e608f 100644 --- a/pkg/machinery/go.mod +++ b/pkg/machinery/go.mod @@ -21,6 +21,7 @@ require ( golang.org/x/net v0.0.0-20200707034311-ab3426394381 // indirect golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 // indirect golang.org/x/text v0.3.3 // indirect + google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 google.golang.org/grpc v1.29.0 google.golang.org/protobuf v1.25.0 gopkg.in/yaml.v2 v2.2.8 // indirect diff --git a/prototool.yaml b/prototool.yaml index 9366fd67be..5242d425a3 100644 --- a/prototool.yaml +++ b/prototool.yaml @@ -15,8 +15,8 @@ protoc: # Additional paths to include with -I to protoc. # By default, the directory of the config file is included, # or the current directory if there is no config file. - #includes: - # - ../../vendor/github.com/grpc-ecosystem/grpc-gateway/third_party/googleapis + includes: + - vendor/ # If not set, compile will fail if there are unused imports. # Setting this will ignore unused imports. #allow_unused_imports: true diff --git a/website/content/docs/v0.8/Reference/api.md b/website/content/docs/v0.8/Reference/api.md index 3b4f6495d9..2003386acd 100644 --- a/website/content/docs/v0.8/Reference/api.md +++ b/website/content/docs/v0.8/Reference/api.md @@ -5,6 +5,17 @@ description: Talos gRPC API reference. ## Table of Contents +- [common/common.proto](#common/common.proto) + - [Data](#common.Data) + - [DataResponse](#common.DataResponse) + - [Empty](#common.Empty) + - [EmptyResponse](#common.EmptyResponse) + - [Error](#common.Error) + - [Metadata](#common.Metadata) + + - [Code](#common.Code) + - [ContainerDriver](#common.ContainerDriver) + - [health/health.proto](#health/health.proto) - [HealthCheck](#health.HealthCheck) - [HealthCheckResponse](#health.HealthCheckResponse) @@ -188,6 +199,141 @@ description: Talos gRPC API reference. + +

Top

+ +## common/common.proto + + + + + +### Data + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| metadata | [Metadata](#common.Metadata) | | | +| bytes | [bytes](#bytes) | | | + + + + + + + + +### DataResponse + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| messages | [Data](#common.Data) | repeated | | + + + + + + + + +### Empty + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| metadata | [Metadata](#common.Metadata) | | | + + + + + + + + +### EmptyResponse + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| messages | [Empty](#common.Empty) | repeated | | + + + + + + + + +### Error + + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| code | [Code](#common.Code) | | | +| message | [string](#string) | | | +| details | [google.protobuf.Any](#google.protobuf.Any) | repeated | | + + + + + + + + +### Metadata +Common metadata message nested in all reply message types + + +| Field | Type | Label | Description | +| ----- | ---- | ----- | ----------- | +| hostname | [string](#string) | | hostname of the server response comes from (injected by proxy) | +| error | [string](#string) | | error is set if request failed to the upstream (rest of response is undefined) | +| status | [google.rpc.Status](#google.rpc.Status) | | error as gRPC Status | + + + + + + + + + + +### Code + + +| Name | Number | Description | +| ---- | ------ | ----------- | +| FATAL | 0 | | +| LOCKED | 1 | | + + + + + +### ContainerDriver + + +| Name | Number | Description | +| ---- | ------ | ----------- | +| CONTAINERD | 0 | | +| CRI | 1 | | + + + + + + + + + +

Top