Refactor init/recovery to use kms URI

So far the masterSecret was sent to the initial bootstrapper
on init/recovery. With this commit this information is encoded
in the kmsURI that is sent during init.
For recover, the communication with the recoveryserver is
changed. Before a streaming gRPC call was used to
exchanges UUID for measurementSecret and state disk key.
Now a standard gRPC is made that includes the same kmsURI &
storageURI that are sent during init.
This commit is contained in:
Otto Bittner 2023-01-16 11:19:03 +01:00
parent 0e71322e2e
commit 9a1f52e94e
35 changed files with 466 additions and 623 deletions

View file

@ -34,6 +34,7 @@ import (
qemucloud "github.com/edgelesssys/constellation/v2/internal/cloud/qemu"
"github.com/edgelesssys/constellation/v2/internal/constants"
"github.com/edgelesssys/constellation/v2/internal/grpc/dialer"
kmssetup "github.com/edgelesssys/constellation/v2/internal/kms/setup"
"github.com/edgelesssys/constellation/v2/internal/logger"
"github.com/edgelesssys/constellation/v2/internal/role"
tpmClient "github.com/google/go-tpm-tools/client"
@ -151,7 +152,7 @@ func main() {
// set up recovery server if control-plane node
var recoveryServer setup.RecoveryServer
if self.Role == role.ControlPlane {
recoveryServer = recoveryserver.New(issuer, log.Named("recoveryServer"))
recoveryServer = recoveryserver.New(issuer, kmssetup.KMS, log.Named("recoveryServer"))
} else {
recoveryServer = recoveryserver.NewStub(log.Named("recoveryServer"))
}

View file

@ -13,8 +13,10 @@ import (
"github.com/edgelesssys/constellation/v2/disk-mapper/recoverproto"
"github.com/edgelesssys/constellation/v2/internal/atls"
"github.com/edgelesssys/constellation/v2/internal/crypto"
"github.com/edgelesssys/constellation/v2/internal/grpc/atlscredentials"
"github.com/edgelesssys/constellation/v2/internal/grpc/grpclog"
"github.com/edgelesssys/constellation/v2/internal/kms/kms"
"github.com/edgelesssys/constellation/v2/internal/logger"
"go.uber.org/zap"
"google.golang.org/grpc"
@ -22,6 +24,8 @@ import (
"google.golang.org/grpc/status"
)
type kmsFactory func(ctx context.Context, storageURI string, kmsURI string) (kms.CloudKMS, error)
// RecoveryServer is a gRPC server that can be used by an admin to recover a restarting node.
type RecoveryServer struct {
mux sync.Mutex
@ -30,6 +34,7 @@ type RecoveryServer struct {
stateDiskKey []byte
measurementSecret []byte
grpcServer server
factory kmsFactory
log *logger.Logger
@ -37,9 +42,10 @@ type RecoveryServer struct {
}
// New returns a new RecoveryServer.
func New(issuer atls.Issuer, log *logger.Logger) *RecoveryServer {
func New(issuer atls.Issuer, factory kmsFactory, log *logger.Logger) *RecoveryServer {
server := &RecoveryServer{
log: log,
log: log,
factory: factory,
}
grpcServer := grpc.NewServer(
@ -87,47 +93,32 @@ func (s *RecoveryServer) Serve(ctx context.Context, listener net.Listener, diskU
}
// Recover is a bidirectional streaming RPC that is used to send recovery keys to a restarting node.
func (s *RecoveryServer) Recover(stream recoverproto.API_RecoverServer) error {
func (s *RecoveryServer) Recover(ctx context.Context, req *recoverproto.RecoverMessage) (*recoverproto.RecoverResponse, error) {
s.mux.Lock()
defer s.mux.Unlock()
log := s.log.With(zap.String("peer", grpclog.PeerAddrFromContext(stream.Context())))
log := s.log.With(zap.String("peer", grpclog.PeerAddrFromContext(ctx)))
log.Infof("Received recover call")
msg, err := stream.Recv()
cloudKms, err := s.factory(ctx, req.StorageUri, req.KmsUri)
if err != nil {
return status.Error(codes.Internal, "failed to receive message")
return nil, status.Errorf(codes.Internal, "creating kms client: %s", err)
}
measurementSecret, ok := msg.GetRequest().(*recoverproto.RecoverMessage_MeasurementSecret)
if !ok {
log.Errorf("Received invalid first message: not a measurement secret")
return status.Error(codes.InvalidArgument, "first message is not a measurement secret")
}
if err := stream.Send(&recoverproto.RecoverResponse{DiskUuid: s.diskUUID}); err != nil {
log.With(zap.Error(err)).Errorf("Failed to send disk UUID")
return status.Error(codes.Internal, "failed to send response")
}
msg, err = stream.Recv()
measurementSecret, err := cloudKms.GetDEK(ctx, crypto.DEKPrefix+crypto.MeasurementSecretKeyID, crypto.DerivedKeyLengthDefault)
if err != nil {
log.With(zap.Error(err)).Errorf("Failed to receive disk key")
return status.Error(codes.Internal, "failed to receive message")
return nil, status.Errorf(codes.Internal, "requesting measurementSecret: %s", err)
}
stateDiskKey, ok := msg.GetRequest().(*recoverproto.RecoverMessage_StateDiskKey)
if !ok {
log.Errorf("Received invalid second message: not a state disk key")
return status.Error(codes.InvalidArgument, "second message is not a state disk key")
stateDiskKey, err := cloudKms.GetDEK(ctx, crypto.DEKPrefix+s.diskUUID, crypto.StateDiskKeyLength)
if err != nil {
return nil, status.Errorf(codes.Internal, "requesting stateDiskKey: %s", err)
}
s.stateDiskKey = stateDiskKey.StateDiskKey
s.measurementSecret = measurementSecret.MeasurementSecret
s.stateDiskKey = stateDiskKey
s.measurementSecret = measurementSecret
log.Infof("Received state disk key and measurement secret, shutting down server")
go s.grpcServer.GracefulStop()
return nil
return &recoverproto.RecoverResponse{}, nil
}
// StubServer implements the RecoveryServer interface but does not actually start a server.

View file

@ -8,7 +8,7 @@ package recoveryserver
import (
"context"
"io"
"errors"
"sync"
"testing"
"time"
@ -17,6 +17,7 @@ import (
"github.com/edgelesssys/constellation/v2/internal/atls"
"github.com/edgelesssys/constellation/v2/internal/grpc/dialer"
"github.com/edgelesssys/constellation/v2/internal/grpc/testdialer"
"github.com/edgelesssys/constellation/v2/internal/kms/kms"
"github.com/edgelesssys/constellation/v2/internal/logger"
"github.com/edgelesssys/constellation/v2/internal/oid"
"github.com/stretchr/testify/assert"
@ -25,14 +26,17 @@ import (
)
func TestMain(m *testing.M) {
goleak.VerifyTestMain(m)
goleak.VerifyTestMain(m,
// https://github.com/census-instrumentation/opencensus-go/issues/1262
goleak.IgnoreTopFunction("go.opencensus.io/stats/view.(*worker).start"),
)
}
func TestServe(t *testing.T) {
assert := assert.New(t)
log := logger.NewTest(t)
uuid := "uuid"
server := New(atls.NewFakeIssuer(oid.Dummy{}), log)
server := New(atls.NewFakeIssuer(oid.Dummy{}), newStubKMS(nil, nil), log)
dialer := testdialer.NewBufconnDialer()
listener := dialer.GetListener("192.0.2.1:1234")
ctx, cancel := context.WithCancel(context.Background())
@ -49,7 +53,7 @@ func TestServe(t *testing.T) {
cancel()
wg.Wait()
server = New(atls.NewFakeIssuer(oid.Dummy{}), log)
server = New(atls.NewFakeIssuer(oid.Dummy{}), newStubKMS(nil, nil), log)
dialer = testdialer.NewBufconnDialer()
listener = dialer.GetListener("192.0.2.1:1234")
@ -71,59 +75,26 @@ func TestServe(t *testing.T) {
func TestRecover(t *testing.T) {
testCases := map[string]struct {
initialMsg message
keyMsg message
kmsURI string
storageURI string
factory kmsFactory
wantErr bool
}{
"success": {
initialMsg: message{
recoverMsg: &recoverproto.RecoverMessage{
Request: &recoverproto.RecoverMessage_MeasurementSecret{
MeasurementSecret: []byte("measurementSecret"),
},
},
},
keyMsg: message{
recoverMsg: &recoverproto.RecoverMessage{
Request: &recoverproto.RecoverMessage_StateDiskKey{
StateDiskKey: []byte("diskKey"),
},
},
},
// base64 encoded: key=masterkey&salt=somesalt
kmsURI: "kms://cluster-kms?key=bWFzdGVya2V5&salt=c29tZXNhbHQ=",
storageURI: "storage://no-store",
factory: newStubKMS(nil, nil),
},
"first message is not a measurement secret": {
initialMsg: message{
recoverMsg: &recoverproto.RecoverMessage{
Request: &recoverproto.RecoverMessage_StateDiskKey{
StateDiskKey: []byte("diskKey"),
},
},
wantErr: true,
},
keyMsg: message{
recoverMsg: &recoverproto.RecoverMessage{
Request: &recoverproto.RecoverMessage_StateDiskKey{
StateDiskKey: []byte("diskKey"),
},
},
},
"kms init fails": {
factory: newStubKMS(errors.New("setup failed"), nil),
wantErr: true,
},
"second message is not a state disk key": {
initialMsg: message{
recoverMsg: &recoverproto.RecoverMessage{
Request: &recoverproto.RecoverMessage_MeasurementSecret{
MeasurementSecret: []byte("measurementSecret"),
},
},
},
keyMsg: message{
recoverMsg: &recoverproto.RecoverMessage{
Request: &recoverproto.RecoverMessage_MeasurementSecret{
MeasurementSecret: []byte("measurementSecret"),
},
},
wantErr: true,
},
"GetDEK fails": {
kmsURI: "kms://cluster-kms?key=bWFzdGVya2V5&salt=c29tZXNhbHQ=",
storageURI: "storage://no-store",
factory: newStubKMS(nil, errors.New("GetDEK failed")),
wantErr: true,
},
}
@ -134,7 +105,7 @@ func TestRecover(t *testing.T) {
ctx := context.Background()
serverUUID := "uuid"
server := New(atls.NewFakeIssuer(oid.Dummy{}), logger.NewTest(t))
server := New(atls.NewFakeIssuer(oid.Dummy{}), tc.factory, logger.NewTest(t))
netDialer := testdialer.NewBufconnDialer()
listener := netDialer.GetListener("192.0.2.1:1234")
@ -154,41 +125,46 @@ func TestRecover(t *testing.T) {
conn, err := dialer.New(nil, nil, netDialer).Dial(ctx, "192.0.2.1:1234")
require.NoError(err)
defer conn.Close()
client, err := recoverproto.NewAPIClient(conn).Recover(ctx)
require.NoError(err)
// Send initial message
err = client.Send(tc.initialMsg.recoverMsg)
require.NoError(err)
req := recoverproto.RecoverMessage{
KmsUri: tc.kmsURI,
StorageUri: tc.storageURI,
}
_, err = recoverproto.NewAPIClient(conn).Recover(ctx, &req)
// Receive uuid
uuid, err := client.Recv()
if tc.initialMsg.wantErr {
if tc.wantErr {
assert.Error(err)
return
}
assert.Equal(serverUUID, uuid.DiskUuid)
// Send key message
err = client.Send(tc.keyMsg.recoverMsg)
require.NoError(err)
_, err = client.Recv()
if tc.keyMsg.wantErr {
assert.Error(err)
return
}
assert.ErrorIs(io.EOF, err)
wg.Wait()
assert.NoError(serveErr)
assert.Equal(tc.initialMsg.recoverMsg.GetMeasurementSecret(), measurementSecret)
assert.Equal(tc.keyMsg.recoverMsg.GetStateDiskKey(), diskKey)
require.NoError(serveErr)
assert.NoError(err)
assert.NotNil(measurementSecret)
assert.NotNil(diskKey)
})
}
}
type message struct {
recoverMsg *recoverproto.RecoverMessage
wantErr bool
func newStubKMS(setupErr, getDEKErr error) kmsFactory {
return func(ctx context.Context, storageURI string, kmsURI string) (kms.CloudKMS, error) {
if setupErr != nil {
return nil, setupErr
}
return &stubKMS{getDEKErr: getDEKErr}, nil
}
}
type stubKMS struct {
getDEKErr error
}
func (s *stubKMS) CreateKEK(ctx context.Context, keyID string, kek []byte) error {
return nil
}
func (s *stubKMS) GetDEK(ctx context.Context, dekID string, dekSize int) ([]byte, error) {
if s.getDEKErr != nil {
return nil, s.getDEKErr
}
return []byte("someDEK"), nil
}

View file

@ -25,11 +25,10 @@ type RecoverMessage struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
// Types that are assignable to Request:
//
// *RecoverMessage_StateDiskKey
// *RecoverMessage_MeasurementSecret
Request isRecoverMessage_Request `protobuf_oneof:"request"`
// bytes state_disk_key = 1; removed
// bytes measurement_secret = 2; removed
KmsUri string `protobuf:"bytes,3,opt,name=kms_uri,json=kmsUri,proto3" json:"kms_uri,omitempty"`
StorageUri string `protobuf:"bytes,4,opt,name=storage_uri,json=storageUri,proto3" json:"storage_uri,omitempty"`
}
func (x *RecoverMessage) Reset() {
@ -64,49 +63,24 @@ func (*RecoverMessage) Descriptor() ([]byte, []int) {
return file_recover_proto_rawDescGZIP(), []int{0}
}
func (m *RecoverMessage) GetRequest() isRecoverMessage_Request {
if m != nil {
return m.Request
func (x *RecoverMessage) GetKmsUri() string {
if x != nil {
return x.KmsUri
}
return nil
return ""
}
func (x *RecoverMessage) GetStateDiskKey() []byte {
if x, ok := x.GetRequest().(*RecoverMessage_StateDiskKey); ok {
return x.StateDiskKey
func (x *RecoverMessage) GetStorageUri() string {
if x != nil {
return x.StorageUri
}
return nil
return ""
}
func (x *RecoverMessage) GetMeasurementSecret() []byte {
if x, ok := x.GetRequest().(*RecoverMessage_MeasurementSecret); ok {
return x.MeasurementSecret
}
return nil
}
type isRecoverMessage_Request interface {
isRecoverMessage_Request()
}
type RecoverMessage_StateDiskKey struct {
StateDiskKey []byte `protobuf:"bytes,1,opt,name=state_disk_key,json=stateDiskKey,proto3,oneof"`
}
type RecoverMessage_MeasurementSecret struct {
MeasurementSecret []byte `protobuf:"bytes,2,opt,name=measurement_secret,json=measurementSecret,proto3,oneof"`
}
func (*RecoverMessage_StateDiskKey) isRecoverMessage_Request() {}
func (*RecoverMessage_MeasurementSecret) isRecoverMessage_Request() {}
type RecoverResponse struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
DiskUuid string `protobuf:"bytes,1,opt,name=disk_uuid,json=diskUuid,proto3" json:"disk_uuid,omitempty"`
}
func (x *RecoverResponse) Reset() {
@ -141,39 +115,27 @@ func (*RecoverResponse) Descriptor() ([]byte, []int) {
return file_recover_proto_rawDescGZIP(), []int{1}
}
func (x *RecoverResponse) GetDiskUuid() string {
if x != nil {
return x.DiskUuid
}
return ""
}
var File_recover_proto protoreflect.FileDescriptor
var file_recover_proto_rawDesc = []byte{
0x0a, 0x0d, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12,
0x0c, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x74, 0x0a,
0x0c, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x4a, 0x0a,
0x0e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12,
0x26, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x6b, 0x65,
0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0c, 0x73, 0x74, 0x61, 0x74, 0x65,
0x44, 0x69, 0x73, 0x6b, 0x4b, 0x65, 0x79, 0x12, 0x2f, 0x0a, 0x12, 0x6d, 0x65, 0x61, 0x73, 0x75,
0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x72, 0x65, 0x74, 0x18, 0x02, 0x20,
0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x11, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65,
0x6e, 0x74, 0x53, 0x65, 0x63, 0x72, 0x65, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x72, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x22, 0x2e, 0x0a, 0x0f, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x64, 0x69, 0x73, 0x6b, 0x5f, 0x75,
0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x64, 0x69, 0x73, 0x6b, 0x55,
0x75, 0x69, 0x64, 0x32, 0x53, 0x0a, 0x03, 0x41, 0x50, 0x49, 0x12, 0x4c, 0x0a, 0x07, 0x52, 0x65,
0x63, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73,
0x61, 0x67, 0x65, 0x1a, 0x1d, 0x2e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x00, 0x28, 0x01, 0x30, 0x01, 0x42, 0x42, 0x5a, 0x40, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x64, 0x67, 0x65, 0x6c, 0x65, 0x73, 0x73, 0x73,
0x79, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x65, 0x6c, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x2f, 0x76, 0x32, 0x2f, 0x64, 0x69, 0x73, 0x6b, 0x2d, 0x6d, 0x61, 0x70, 0x70, 0x65, 0x72, 0x2f,
0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
0x17, 0x0a, 0x07, 0x6b, 0x6d, 0x73, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x6b, 0x6d, 0x73, 0x55, 0x72, 0x69, 0x12, 0x1f, 0x0a, 0x0b, 0x73, 0x74, 0x6f, 0x72,
0x61, 0x67, 0x65, 0x5f, 0x75, 0x72, 0x69, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x73,
0x74, 0x6f, 0x72, 0x61, 0x67, 0x65, 0x55, 0x72, 0x69, 0x22, 0x11, 0x0a, 0x0f, 0x52, 0x65, 0x63,
0x6f, 0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x32, 0x4f, 0x0a, 0x03,
0x41, 0x50, 0x49, 0x12, 0x48, 0x0a, 0x07, 0x52, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x12, 0x1c,
0x2e, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65,
0x63, 0x6f, 0x76, 0x65, 0x72, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x1d, 0x2e, 0x72,
0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x52, 0x65, 0x63, 0x6f,
0x76, 0x65, 0x72, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x42, 0x5a,
0x40, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x65, 0x64, 0x67, 0x65,
0x6c, 0x65, 0x73, 0x73, 0x73, 0x79, 0x73, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x65, 0x6c, 0x6c,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x76, 0x32, 0x2f, 0x64, 0x69, 0x73, 0x6b, 0x2d, 0x6d, 0x61,
0x70, 0x70, 0x65, 0x72, 0x2f, 0x72, 0x65, 0x63, 0x6f, 0x76, 0x65, 0x72, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@ -234,10 +196,6 @@ func file_recover_proto_init() {
}
}
}
file_recover_proto_msgTypes[0].OneofWrappers = []interface{}{
(*RecoverMessage_StateDiskKey)(nil),
(*RecoverMessage_MeasurementSecret)(nil),
}
type x struct{}
out := protoimpl.TypeBuilder{
File: protoimpl.DescBuilder{

View file

@ -5,16 +5,19 @@ package recoverproto;
option go_package = "github.com/edgelesssys/constellation/v2/disk-mapper/recoverproto";
service API {
rpc Recover(stream RecoverMessage) returns (stream RecoverResponse) {}
// Recover sends the necessary information to the recoveryserver to start recovering the cluster.
rpc Recover(RecoverMessage) returns (RecoverResponse) {}
}
message RecoverMessage {
oneof request {
bytes state_disk_key = 1;
bytes measurement_secret = 2;
}
// bytes state_disk_key = 1; removed
// bytes measurement_secret = 2; removed
// kms_uri is the URI of the KMS the recoveryserver should use to decrypt DEKs.
string kms_uri = 3;
// storage_uri is the URI of the storage location the recoveryserver should use to fetch DEKs.
string storage_uri = 4;
}
message RecoverResponse {
string disk_uuid = 1;
// string disk_uuid = 1; removed
}

View file

@ -22,7 +22,7 @@ const _ = grpc.SupportPackageIsVersion7
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type APIClient interface {
Recover(ctx context.Context, opts ...grpc.CallOption) (API_RecoverClient, error)
Recover(ctx context.Context, in *RecoverMessage, opts ...grpc.CallOption) (*RecoverResponse, error)
}
type aPIClient struct {
@ -33,42 +33,20 @@ func NewAPIClient(cc grpc.ClientConnInterface) APIClient {
return &aPIClient{cc}
}
func (c *aPIClient) Recover(ctx context.Context, opts ...grpc.CallOption) (API_RecoverClient, error) {
stream, err := c.cc.NewStream(ctx, &API_ServiceDesc.Streams[0], "/recoverproto.API/Recover", opts...)
func (c *aPIClient) Recover(ctx context.Context, in *RecoverMessage, opts ...grpc.CallOption) (*RecoverResponse, error) {
out := new(RecoverResponse)
err := c.cc.Invoke(ctx, "/recoverproto.API/Recover", in, out, opts...)
if err != nil {
return nil, err
}
x := &aPIRecoverClient{stream}
return x, nil
}
type API_RecoverClient interface {
Send(*RecoverMessage) error
Recv() (*RecoverResponse, error)
grpc.ClientStream
}
type aPIRecoverClient struct {
grpc.ClientStream
}
func (x *aPIRecoverClient) Send(m *RecoverMessage) error {
return x.ClientStream.SendMsg(m)
}
func (x *aPIRecoverClient) Recv() (*RecoverResponse, error) {
m := new(RecoverResponse)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
}
return m, nil
return out, nil
}
// APIServer is the server API for API service.
// All implementations must embed UnimplementedAPIServer
// for forward compatibility
type APIServer interface {
Recover(API_RecoverServer) error
Recover(context.Context, *RecoverMessage) (*RecoverResponse, error)
mustEmbedUnimplementedAPIServer()
}
@ -76,8 +54,8 @@ type APIServer interface {
type UnimplementedAPIServer struct {
}
func (UnimplementedAPIServer) Recover(API_RecoverServer) error {
return status.Errorf(codes.Unimplemented, "method Recover not implemented")
func (UnimplementedAPIServer) Recover(context.Context, *RecoverMessage) (*RecoverResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method Recover not implemented")
}
func (UnimplementedAPIServer) mustEmbedUnimplementedAPIServer() {}
@ -92,30 +70,22 @@ func RegisterAPIServer(s grpc.ServiceRegistrar, srv APIServer) {
s.RegisterService(&API_ServiceDesc, srv)
}
func _API_Recover_Handler(srv interface{}, stream grpc.ServerStream) error {
return srv.(APIServer).Recover(&aPIRecoverServer{stream})
}
type API_RecoverServer interface {
Send(*RecoverResponse) error
Recv() (*RecoverMessage, error)
grpc.ServerStream
}
type aPIRecoverServer struct {
grpc.ServerStream
}
func (x *aPIRecoverServer) Send(m *RecoverResponse) error {
return x.ServerStream.SendMsg(m)
}
func (x *aPIRecoverServer) Recv() (*RecoverMessage, error) {
m := new(RecoverMessage)
if err := x.ServerStream.RecvMsg(m); err != nil {
func _API_Recover_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RecoverMessage)
if err := dec(in); err != nil {
return nil, err
}
return m, nil
if interceptor == nil {
return srv.(APIServer).Recover(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/recoverproto.API/Recover",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(APIServer).Recover(ctx, req.(*RecoverMessage))
}
return interceptor(ctx, in, info, handler)
}
// API_ServiceDesc is the grpc.ServiceDesc for API service.
@ -124,14 +94,12 @@ func (x *aPIRecoverServer) Recv() (*RecoverMessage, error) {
var API_ServiceDesc = grpc.ServiceDesc{
ServiceName: "recoverproto.API",
HandlerType: (*APIServer)(nil),
Methods: []grpc.MethodDesc{},
Streams: []grpc.StreamDesc{
Methods: []grpc.MethodDesc{
{
StreamName: "Recover",
Handler: _API_Recover_Handler,
ServerStreams: true,
ClientStreams: true,
MethodName: "Recover",
Handler: _API_Recover_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "recover.proto",
}