From f053279c4e596b40c91f989d4ca45cc31599d70c Mon Sep 17 00:00:00 2001 From: Riddhi Shah Date: Sun, 27 Mar 2022 16:29:30 +0530 Subject: [PATCH 1/3] [OSS] Supported dataplane features gRPC endpoint Adds a new gRPC service and endpoint to return the list of supported consul dataplane features. The Consul Dataplane will use this API to customize its interaction with that particular server. --- agent/consul/server.go | 7 +- .../services/connectca/watch_roots_test.go | 7 +- .../dataplane/get_supported_features.go | 45 ++ .../dataplane/get_supported_features_test.go | 82 ++++ .../services/dataplane/mock_ACLResolver.go | 38 ++ .../grpc/public/services/dataplane/server.go | 33 ++ .../public/services/dataplane/server_test.go | 40 ++ .../acl_test.go => testutils/acl.go} | 9 +- .../pbdataplane/dataplane.pb.binary.go | 38 ++ proto-public/pbdataplane/dataplane.pb.go | 448 ++++++++++++++++++ proto-public/pbdataplane/dataplane.proto | 32 ++ 11 files changed, 769 insertions(+), 10 deletions(-) create mode 100644 agent/grpc/public/services/dataplane/get_supported_features.go create mode 100644 agent/grpc/public/services/dataplane/get_supported_features_test.go create mode 100644 agent/grpc/public/services/dataplane/mock_ACLResolver.go create mode 100644 agent/grpc/public/services/dataplane/server.go create mode 100644 agent/grpc/public/services/dataplane/server_test.go rename agent/grpc/public/{services/connectca/acl_test.go => testutils/acl.go} (69%) create mode 100644 proto-public/pbdataplane/dataplane.pb.binary.go create mode 100644 proto-public/pbdataplane/dataplane.pb.go create mode 100644 proto-public/pbdataplane/dataplane.proto diff --git a/agent/consul/server.go b/agent/consul/server.go index ccfa3044a..2b40a615e 100644 --- a/agent/consul/server.go +++ b/agent/consul/server.go @@ -44,6 +44,7 @@ import ( agentgrpc "github.com/hashicorp/consul/agent/grpc/private" "github.com/hashicorp/consul/agent/grpc/private/services/subscribe" "github.com/hashicorp/consul/agent/grpc/public/services/connectca" + "github.com/hashicorp/consul/agent/grpc/public/services/dataplane" "github.com/hashicorp/consul/agent/metadata" "github.com/hashicorp/consul/agent/pool" "github.com/hashicorp/consul/agent/router" @@ -633,12 +634,16 @@ func NewServer(config *Config, flat Deps, publicGRPCServer *grpc.Server) (*Serve // since it can fire events when leadership is obtained. go s.monitorLeadership() - // Initialize public gRPC server. + // Initialize public gRPC server - register services on public gRPC server. connectca.NewServer(connectca.Config{ GetStore: func() connectca.StateStore { return s.FSM().State() }, Logger: logger.Named("grpc-api.connect-ca"), ACLResolver: plainACLResolver{s.ACLResolver}, }).Register(s.publicGRPCServer) + dataplane.NewServer(dataplane.Config{ + Logger: logger.Named("grpc-api.dataplane"), + ACLResolver: plainACLResolver{s.ACLResolver}, + }).Register(s.publicGRPCServer) // Start listening for RPC requests. go func() { diff --git a/agent/grpc/public/services/connectca/watch_roots_test.go b/agent/grpc/public/services/connectca/watch_roots_test.go index efd022d90..d650a4d13 100644 --- a/agent/grpc/public/services/connectca/watch_roots_test.go +++ b/agent/grpc/public/services/connectca/watch_roots_test.go @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/grpc/public" + "github.com/hashicorp/consul/agent/grpc/public/testutils" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/proto-public/pbconnectca" ) @@ -39,7 +40,7 @@ func TestWatchRoots_Success(t *testing.T) { // Mock the ACL Resolver to return an authorizer with `service:write`. aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). - Return(testAuthorizer(t), nil) + Return(testutils.TestAuthorizer(t), nil) ctx := public.ContextWithToken(context.Background(), testACLToken) @@ -121,7 +122,7 @@ func TestWatchRoots_ACLTokenInvalidated(t *testing.T) { // first two times it is called (initial connect and first re-auth). aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). - Return(testAuthorizer(t), nil).Twice() + Return(testutils.TestAuthorizer(t), nil).Twice() ctx := public.ContextWithToken(context.Background(), testACLToken) @@ -187,7 +188,7 @@ func TestWatchRoots_StateStoreAbandoned(t *testing.T) { // Mock the ACL Resolver to return an authorizer with `service:write`. aclResolver := &MockACLResolver{} aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). - Return(testAuthorizer(t), nil) + Return(testutils.TestAuthorizer(t), nil) ctx := public.ContextWithToken(context.Background(), testACLToken) diff --git a/agent/grpc/public/services/dataplane/get_supported_features.go b/agent/grpc/public/services/dataplane/get_supported_features.go new file mode 100644 index 000000000..672e48f66 --- /dev/null +++ b/agent/grpc/public/services/dataplane/get_supported_features.go @@ -0,0 +1,45 @@ +package dataplane + +import ( + "context" + + acl "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/agent/grpc/public" + structs "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/proto-public/pbdataplane" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func (d *Server) SupportedDataplaneFeatures(ctx context.Context, req *pbdataplane.SupportedDataplaneFeaturesRequest) (*pbdataplane.SupportedDataplaneFeaturesResponse, error) { + d.Logger.Trace("Received request for supported dataplane features") + + // Require the given ACL token to have `service:write` on any service + token := public.TokenFromContext(ctx) + var authzContext acl.AuthorizerContext + entMeta := structs.WildcardEnterpriseMetaInPartition(structs.WildcardSpecifier) + authz, err := d.ACLResolver.ResolveTokenAndDefaultMeta(token, entMeta, &authzContext) + if err != nil { + return nil, status.Error(codes.Unauthenticated, err.Error()) + } + if err := authz.ToAllowAuthorizer().ServiceWriteAnyAllowed(&authzContext); err != nil { + return nil, status.Error(codes.PermissionDenied, err.Error()) + } + + supportedFeatures := []*pbdataplane.DataplaneFeatureSupport{ + { + FeatureName: pbdataplane.DataplaneFeatures_WATCH_SERVERS, + Supported: true, + }, + { + FeatureName: pbdataplane.DataplaneFeatures_EDGE_CERTIFICATE_MANAGEMENT, + Supported: true, + }, + { + FeatureName: pbdataplane.DataplaneFeatures_ENVOY_BOOTSTRAP_CONFIGURATION, + Supported: true, + }, + } + + return &pbdataplane.SupportedDataplaneFeaturesResponse{SupportedDataplaneFeatures: supportedFeatures}, nil +} diff --git a/agent/grpc/public/services/dataplane/get_supported_features_test.go b/agent/grpc/public/services/dataplane/get_supported_features_test.go new file mode 100644 index 000000000..2b3c5e76d --- /dev/null +++ b/agent/grpc/public/services/dataplane/get_supported_features_test.go @@ -0,0 +1,82 @@ +package dataplane + +import ( + "context" + "testing" + + "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/agent/grpc/public" + "github.com/hashicorp/consul/agent/grpc/public/testutils" + "github.com/hashicorp/consul/proto-public/pbdataplane" + "github.com/hashicorp/go-hclog" + mock "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +const testACLToken = "acl-token" + +func TestSupportedDataplaneFeatures_Success(t *testing.T) { + // Mock the ACL Resolver to return an authorizer with `service:write`. + aclResolver := &MockACLResolver{} + aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). + Return(testutils.TestAuthorizer(t), nil) + ctx := public.ContextWithToken(context.Background(), testACLToken) + server := NewServer(Config{ + Logger: hclog.NewNullLogger(), + ACLResolver: aclResolver, + }) + + client := testClient(t, server) + resp, err := client.SupportedDataplaneFeatures(ctx, &pbdataplane.SupportedDataplaneFeaturesRequest{}) + require.NoError(t, err) + require.Equal(t, 3, len(resp.SupportedDataplaneFeatures)) + + for _, feature := range resp.SupportedDataplaneFeatures { + switch feature.GetFeatureName() { + case pbdataplane.DataplaneFeatures_EDGE_CERTIFICATE_MANAGEMENT: + require.True(t, feature.GetSupported()) + case pbdataplane.DataplaneFeatures_WATCH_SERVERS: + require.True(t, feature.GetSupported()) + case pbdataplane.DataplaneFeatures_ENVOY_BOOTSTRAP_CONFIGURATION: + require.True(t, feature.GetSupported()) + default: + require.False(t, feature.GetSupported()) + } + } +} + +func TestSupportedDataplaneFeatures_Unauthenticated(t *testing.T) { + // Mock the ACL resolver to return ErrNotFound. + aclResolver := &MockACLResolver{} + aclResolver.On("ResolveTokenAndDefaultMeta", mock.Anything, mock.Anything, mock.Anything). + Return(nil, acl.ErrNotFound) + ctx := public.ContextWithToken(context.Background(), testACLToken) + server := NewServer(Config{ + Logger: hclog.NewNullLogger(), + ACLResolver: aclResolver, + }) + client := testClient(t, server) + resp, err := client.SupportedDataplaneFeatures(ctx, &pbdataplane.SupportedDataplaneFeaturesRequest{}) + require.Error(t, err) + require.Equal(t, codes.Unauthenticated.String(), status.Code(err).String()) + require.Nil(t, resp) +} + +func TestSupportedDataplaneFeatures_PermissionDenied(t *testing.T) { + // Mock the ACL resolver to return ErrNotFound. + aclResolver := &MockACLResolver{} + aclResolver.On("ResolveTokenAndDefaultMeta", testACLToken, mock.Anything, mock.Anything). + Return(acl.DenyAll(), nil) + ctx := public.ContextWithToken(context.Background(), testACLToken) + server := NewServer(Config{ + Logger: hclog.NewNullLogger(), + ACLResolver: aclResolver, + }) + client := testClient(t, server) + resp, err := client.SupportedDataplaneFeatures(ctx, &pbdataplane.SupportedDataplaneFeaturesRequest{}) + require.Error(t, err) + require.Equal(t, codes.PermissionDenied.String(), status.Code(err).String()) + require.Nil(t, resp) +} diff --git a/agent/grpc/public/services/dataplane/mock_ACLResolver.go b/agent/grpc/public/services/dataplane/mock_ACLResolver.go new file mode 100644 index 000000000..364e17e66 --- /dev/null +++ b/agent/grpc/public/services/dataplane/mock_ACLResolver.go @@ -0,0 +1,38 @@ +// Code generated by mockery v1.0.0. DO NOT EDIT. + +package dataplane + +import ( + acl "github.com/hashicorp/consul/acl" + mock "github.com/stretchr/testify/mock" + + structs "github.com/hashicorp/consul/agent/structs" +) + +// MockACLResolver is an autogenerated mock type for the ACLResolver type +type MockACLResolver struct { + mock.Mock +} + +// ResolveTokenAndDefaultMeta provides a mock function with given fields: _a0, _a1, _a2 +func (_m *MockACLResolver) ResolveTokenAndDefaultMeta(_a0 string, _a1 *structs.EnterpriseMeta, _a2 *acl.AuthorizerContext) (acl.Authorizer, error) { + ret := _m.Called(_a0, _a1, _a2) + + var r0 acl.Authorizer + if rf, ok := ret.Get(0).(func(string, *structs.EnterpriseMeta, *acl.AuthorizerContext) acl.Authorizer); ok { + r0 = rf(_a0, _a1, _a2) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(acl.Authorizer) + } + } + + var r1 error + if rf, ok := ret.Get(1).(func(string, *structs.EnterpriseMeta, *acl.AuthorizerContext) error); ok { + r1 = rf(_a0, _a1, _a2) + } else { + r1 = ret.Error(1) + } + + return r0, r1 +} diff --git a/agent/grpc/public/services/dataplane/server.go b/agent/grpc/public/services/dataplane/server.go new file mode 100644 index 000000000..90a050e22 --- /dev/null +++ b/agent/grpc/public/services/dataplane/server.go @@ -0,0 +1,33 @@ +package dataplane + +import ( + "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/proto-public/pbdataplane" + "github.com/hashicorp/go-hclog" + "google.golang.org/grpc" +) + +type Server struct { + Config +} + +type Config struct { + Logger hclog.Logger + ACLResolver ACLResolver +} + +//go:generate mockery -name ACLResolver -inpkg +type ACLResolver interface { + ResolveTokenAndDefaultMeta(string, *structs.EnterpriseMeta, *acl.AuthorizerContext) (acl.Authorizer, error) +} + +func NewServer(cfg Config) *Server { + return &Server{cfg} +} + +var _ pbdataplane.DataplaneServiceServer = (*Server)(nil) + +func (s *Server) Register(grpcServer *grpc.Server) { + pbdataplane.RegisterDataplaneServiceServer(grpcServer, s) +} diff --git a/agent/grpc/public/services/dataplane/server_test.go b/agent/grpc/public/services/dataplane/server_test.go new file mode 100644 index 000000000..5a9186c5a --- /dev/null +++ b/agent/grpc/public/services/dataplane/server_test.go @@ -0,0 +1,40 @@ +package dataplane + +import ( + "context" + "net" + "testing" + + "github.com/hashicorp/consul/proto-public/pbdataplane" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" +) + +func testClient(t *testing.T, server *Server) pbdataplane.DataplaneServiceClient { + t.Helper() + + addr := RunTestServer(t, server) + + conn, err := grpc.DialContext(context.Background(), addr.String(), grpc.WithInsecure()) + require.NoError(t, err) + t.Cleanup(func() { + require.NoError(t, conn.Close()) + }) + + return pbdataplane.NewDataplaneServiceClient(conn) +} + +func RunTestServer(t *testing.T, server *Server) net.Addr { + t.Helper() + + lis, err := net.Listen("tcp", "127.0.0.1:0") + require.NoError(t, err) + + grpcServer := grpc.NewServer() + server.Register(grpcServer) + + go grpcServer.Serve(lis) + t.Cleanup(grpcServer.Stop) + + return lis.Addr() +} diff --git a/agent/grpc/public/services/connectca/acl_test.go b/agent/grpc/public/testutils/acl.go similarity index 69% rename from agent/grpc/public/services/connectca/acl_test.go rename to agent/grpc/public/testutils/acl.go index bac0e342e..0c640d266 100644 --- a/agent/grpc/public/services/connectca/acl_test.go +++ b/agent/grpc/public/testutils/acl.go @@ -1,16 +1,13 @@ -package connectca +package testutils import ( "testing" - "github.com/stretchr/testify/require" - "github.com/hashicorp/consul/acl" + "github.com/stretchr/testify/require" ) -// testAuthorizer returns an ACL policy authorizer with `service:write` on an -// arbitrary service. -func testAuthorizer(t *testing.T) acl.Authorizer { +func TestAuthorizer(t *testing.T) acl.Authorizer { t.Helper() policy, err := acl.NewPolicyFromSource(` diff --git a/proto-public/pbdataplane/dataplane.pb.binary.go b/proto-public/pbdataplane/dataplane.pb.binary.go new file mode 100644 index 000000000..aae9be911 --- /dev/null +++ b/proto-public/pbdataplane/dataplane.pb.binary.go @@ -0,0 +1,38 @@ +// Code generated by protoc-gen-go-binary. DO NOT EDIT. +// source: proto-public/pbdataplane/dataplane.proto + +package pbdataplane + +import ( + "github.com/golang/protobuf/proto" +) + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *SupportedDataplaneFeaturesRequest) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *SupportedDataplaneFeaturesRequest) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *DataplaneFeatureSupport) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *DataplaneFeatureSupport) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *SupportedDataplaneFeaturesResponse) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *SupportedDataplaneFeaturesResponse) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} diff --git a/proto-public/pbdataplane/dataplane.pb.go b/proto-public/pbdataplane/dataplane.pb.go new file mode 100644 index 000000000..c5e48a241 --- /dev/null +++ b/proto-public/pbdataplane/dataplane.pb.go @@ -0,0 +1,448 @@ +// Package dataplane provides a service on Consul servers for the Consul Dataplane + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.23.0 +// protoc v3.15.8 +// source: proto-public/pbdataplane/dataplane.proto + +package pbdataplane + +import ( + context "context" + proto "github.com/golang/protobuf/proto" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type DataplaneFeatures int32 + +const ( + DataplaneFeatures_UNKNOWN DataplaneFeatures = 0 + DataplaneFeatures_WATCH_SERVERS DataplaneFeatures = 1 + DataplaneFeatures_EDGE_CERTIFICATE_MANAGEMENT DataplaneFeatures = 2 + DataplaneFeatures_ENVOY_BOOTSTRAP_CONFIGURATION DataplaneFeatures = 3 +) + +// Enum value maps for DataplaneFeatures. +var ( + DataplaneFeatures_name = map[int32]string{ + 0: "UNKNOWN", + 1: "WATCH_SERVERS", + 2: "EDGE_CERTIFICATE_MANAGEMENT", + 3: "ENVOY_BOOTSTRAP_CONFIGURATION", + } + DataplaneFeatures_value = map[string]int32{ + "UNKNOWN": 0, + "WATCH_SERVERS": 1, + "EDGE_CERTIFICATE_MANAGEMENT": 2, + "ENVOY_BOOTSTRAP_CONFIGURATION": 3, + } +) + +func (x DataplaneFeatures) Enum() *DataplaneFeatures { + p := new(DataplaneFeatures) + *p = x + return p +} + +func (x DataplaneFeatures) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (DataplaneFeatures) Descriptor() protoreflect.EnumDescriptor { + return file_proto_public_pbdataplane_dataplane_proto_enumTypes[0].Descriptor() +} + +func (DataplaneFeatures) Type() protoreflect.EnumType { + return &file_proto_public_pbdataplane_dataplane_proto_enumTypes[0] +} + +func (x DataplaneFeatures) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use DataplaneFeatures.Descriptor instead. +func (DataplaneFeatures) EnumDescriptor() ([]byte, []int) { + return file_proto_public_pbdataplane_dataplane_proto_rawDescGZIP(), []int{0} +} + +type SupportedDataplaneFeaturesRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *SupportedDataplaneFeaturesRequest) Reset() { + *x = SupportedDataplaneFeaturesRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_public_pbdataplane_dataplane_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SupportedDataplaneFeaturesRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SupportedDataplaneFeaturesRequest) ProtoMessage() {} + +func (x *SupportedDataplaneFeaturesRequest) ProtoReflect() protoreflect.Message { + mi := &file_proto_public_pbdataplane_dataplane_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SupportedDataplaneFeaturesRequest.ProtoReflect.Descriptor instead. +func (*SupportedDataplaneFeaturesRequest) Descriptor() ([]byte, []int) { + return file_proto_public_pbdataplane_dataplane_proto_rawDescGZIP(), []int{0} +} + +type DataplaneFeatureSupport struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + FeatureName DataplaneFeatures `protobuf:"varint,1,opt,name=feature_name,json=featureName,proto3,enum=dataplane.DataplaneFeatures" json:"feature_name,omitempty"` + Supported bool `protobuf:"varint,2,opt,name=supported,proto3" json:"supported,omitempty"` +} + +func (x *DataplaneFeatureSupport) Reset() { + *x = DataplaneFeatureSupport{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_public_pbdataplane_dataplane_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *DataplaneFeatureSupport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*DataplaneFeatureSupport) ProtoMessage() {} + +func (x *DataplaneFeatureSupport) ProtoReflect() protoreflect.Message { + mi := &file_proto_public_pbdataplane_dataplane_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use DataplaneFeatureSupport.ProtoReflect.Descriptor instead. +func (*DataplaneFeatureSupport) Descriptor() ([]byte, []int) { + return file_proto_public_pbdataplane_dataplane_proto_rawDescGZIP(), []int{1} +} + +func (x *DataplaneFeatureSupport) GetFeatureName() DataplaneFeatures { + if x != nil { + return x.FeatureName + } + return DataplaneFeatures_UNKNOWN +} + +func (x *DataplaneFeatureSupport) GetSupported() bool { + if x != nil { + return x.Supported + } + return false +} + +type SupportedDataplaneFeaturesResponse struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + SupportedDataplaneFeatures []*DataplaneFeatureSupport `protobuf:"bytes,1,rep,name=supported_dataplane_features,json=supportedDataplaneFeatures,proto3" json:"supported_dataplane_features,omitempty"` +} + +func (x *SupportedDataplaneFeaturesResponse) Reset() { + *x = SupportedDataplaneFeaturesResponse{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_public_pbdataplane_dataplane_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *SupportedDataplaneFeaturesResponse) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*SupportedDataplaneFeaturesResponse) ProtoMessage() {} + +func (x *SupportedDataplaneFeaturesResponse) ProtoReflect() protoreflect.Message { + mi := &file_proto_public_pbdataplane_dataplane_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use SupportedDataplaneFeaturesResponse.ProtoReflect.Descriptor instead. +func (*SupportedDataplaneFeaturesResponse) Descriptor() ([]byte, []int) { + return file_proto_public_pbdataplane_dataplane_proto_rawDescGZIP(), []int{2} +} + +func (x *SupportedDataplaneFeaturesResponse) GetSupportedDataplaneFeatures() []*DataplaneFeatureSupport { + if x != nil { + return x.SupportedDataplaneFeatures + } + return nil +} + +var File_proto_public_pbdataplane_dataplane_proto protoreflect.FileDescriptor + +var file_proto_public_pbdataplane_dataplane_proto_rawDesc = []byte{ + 0x0a, 0x28, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, + 0x62, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2f, 0x64, 0x61, 0x74, 0x61, 0x70, + 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x64, 0x61, 0x74, 0x61, + 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x22, 0x23, 0x0a, 0x21, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x78, 0x0a, 0x17, 0x44, 0x61, + 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3f, 0x0a, 0x0c, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x64, 0x61, + 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, + 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x52, 0x0b, 0x66, 0x65, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x75, 0x70, 0x70, 0x6f, + 0x72, 0x74, 0x65, 0x64, 0x22, 0x8a, 0x01, 0x0a, 0x22, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, + 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, + 0x72, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x64, 0x0a, 0x1c, 0x73, + 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, + 0x6e, 0x65, 0x5f, 0x66, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x22, 0x2e, 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x44, 0x61, + 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x53, 0x75, + 0x70, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x1a, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, + 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, + 0x73, 0x2a, 0x77, 0x0a, 0x11, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, + 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x57, 0x41, 0x54, 0x43, 0x48, 0x5f, 0x53, 0x45, 0x52, + 0x56, 0x45, 0x52, 0x53, 0x10, 0x01, 0x12, 0x1f, 0x0a, 0x1b, 0x45, 0x44, 0x47, 0x45, 0x5f, 0x43, + 0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x5f, 0x4d, 0x41, 0x4e, 0x41, 0x47, + 0x45, 0x4d, 0x45, 0x4e, 0x54, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x45, 0x4e, 0x56, 0x4f, 0x59, + 0x5f, 0x42, 0x4f, 0x4f, 0x54, 0x53, 0x54, 0x52, 0x41, 0x50, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, + 0x47, 0x55, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x03, 0x32, 0x8f, 0x01, 0x0a, 0x10, 0x44, + 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, + 0x7b, 0x0a, 0x1a, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, + 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, 0x65, 0x73, 0x12, 0x2c, 0x2e, + 0x64, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, + 0x75, 0x72, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2d, 0x2e, 0x64, 0x61, + 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x2e, 0x53, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x65, + 0x64, 0x44, 0x61, 0x74, 0x61, 0x70, 0x6c, 0x61, 0x6e, 0x65, 0x46, 0x65, 0x61, 0x74, 0x75, 0x72, + 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x42, 0x36, 0x5a, 0x34, + 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x64, 0x61, 0x74, 0x61, 0x70, + 0x6c, 0x61, 0x6e, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_proto_public_pbdataplane_dataplane_proto_rawDescOnce sync.Once + file_proto_public_pbdataplane_dataplane_proto_rawDescData = file_proto_public_pbdataplane_dataplane_proto_rawDesc +) + +func file_proto_public_pbdataplane_dataplane_proto_rawDescGZIP() []byte { + file_proto_public_pbdataplane_dataplane_proto_rawDescOnce.Do(func() { + file_proto_public_pbdataplane_dataplane_proto_rawDescData = protoimpl.X.CompressGZIP(file_proto_public_pbdataplane_dataplane_proto_rawDescData) + }) + return file_proto_public_pbdataplane_dataplane_proto_rawDescData +} + +var file_proto_public_pbdataplane_dataplane_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_proto_public_pbdataplane_dataplane_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_proto_public_pbdataplane_dataplane_proto_goTypes = []interface{}{ + (DataplaneFeatures)(0), // 0: dataplane.DataplaneFeatures + (*SupportedDataplaneFeaturesRequest)(nil), // 1: dataplane.SupportedDataplaneFeaturesRequest + (*DataplaneFeatureSupport)(nil), // 2: dataplane.DataplaneFeatureSupport + (*SupportedDataplaneFeaturesResponse)(nil), // 3: dataplane.SupportedDataplaneFeaturesResponse +} +var file_proto_public_pbdataplane_dataplane_proto_depIdxs = []int32{ + 0, // 0: dataplane.DataplaneFeatureSupport.feature_name:type_name -> dataplane.DataplaneFeatures + 2, // 1: dataplane.SupportedDataplaneFeaturesResponse.supported_dataplane_features:type_name -> dataplane.DataplaneFeatureSupport + 1, // 2: dataplane.DataplaneService.SupportedDataplaneFeatures:input_type -> dataplane.SupportedDataplaneFeaturesRequest + 3, // 3: dataplane.DataplaneService.SupportedDataplaneFeatures:output_type -> dataplane.SupportedDataplaneFeaturesResponse + 3, // [3:4] is the sub-list for method output_type + 2, // [2:3] is the sub-list for method input_type + 2, // [2:2] is the sub-list for extension type_name + 2, // [2:2] is the sub-list for extension extendee + 0, // [0:2] is the sub-list for field type_name +} + +func init() { file_proto_public_pbdataplane_dataplane_proto_init() } +func file_proto_public_pbdataplane_dataplane_proto_init() { + if File_proto_public_pbdataplane_dataplane_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_proto_public_pbdataplane_dataplane_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SupportedDataplaneFeaturesRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_public_pbdataplane_dataplane_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DataplaneFeatureSupport); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_proto_public_pbdataplane_dataplane_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*SupportedDataplaneFeaturesResponse); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_proto_public_pbdataplane_dataplane_proto_rawDesc, + NumEnums: 1, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_proto_public_pbdataplane_dataplane_proto_goTypes, + DependencyIndexes: file_proto_public_pbdataplane_dataplane_proto_depIdxs, + EnumInfos: file_proto_public_pbdataplane_dataplane_proto_enumTypes, + MessageInfos: file_proto_public_pbdataplane_dataplane_proto_msgTypes, + }.Build() + File_proto_public_pbdataplane_dataplane_proto = out.File + file_proto_public_pbdataplane_dataplane_proto_rawDesc = nil + file_proto_public_pbdataplane_dataplane_proto_goTypes = nil + file_proto_public_pbdataplane_dataplane_proto_depIdxs = nil +} + +// Reference imports to suppress errors if they are not otherwise used. +var _ context.Context +var _ grpc.ClientConnInterface + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +const _ = grpc.SupportPackageIsVersion6 + +// DataplaneServiceClient is the client API for DataplaneService service. +// +// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream. +type DataplaneServiceClient interface { + SupportedDataplaneFeatures(ctx context.Context, in *SupportedDataplaneFeaturesRequest, opts ...grpc.CallOption) (*SupportedDataplaneFeaturesResponse, error) +} + +type dataplaneServiceClient struct { + cc grpc.ClientConnInterface +} + +func NewDataplaneServiceClient(cc grpc.ClientConnInterface) DataplaneServiceClient { + return &dataplaneServiceClient{cc} +} + +func (c *dataplaneServiceClient) SupportedDataplaneFeatures(ctx context.Context, in *SupportedDataplaneFeaturesRequest, opts ...grpc.CallOption) (*SupportedDataplaneFeaturesResponse, error) { + out := new(SupportedDataplaneFeaturesResponse) + err := c.cc.Invoke(ctx, "/dataplane.DataplaneService/SupportedDataplaneFeatures", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// DataplaneServiceServer is the server API for DataplaneService service. +type DataplaneServiceServer interface { + SupportedDataplaneFeatures(context.Context, *SupportedDataplaneFeaturesRequest) (*SupportedDataplaneFeaturesResponse, error) +} + +// UnimplementedDataplaneServiceServer can be embedded to have forward compatible implementations. +type UnimplementedDataplaneServiceServer struct { +} + +func (*UnimplementedDataplaneServiceServer) SupportedDataplaneFeatures(context.Context, *SupportedDataplaneFeaturesRequest) (*SupportedDataplaneFeaturesResponse, error) { + return nil, status.Errorf(codes.Unimplemented, "method SupportedDataplaneFeatures not implemented") +} + +func RegisterDataplaneServiceServer(s *grpc.Server, srv DataplaneServiceServer) { + s.RegisterService(&_DataplaneService_serviceDesc, srv) +} + +func _DataplaneService_SupportedDataplaneFeatures_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(SupportedDataplaneFeaturesRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(DataplaneServiceServer).SupportedDataplaneFeatures(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/dataplane.DataplaneService/SupportedDataplaneFeatures", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(DataplaneServiceServer).SupportedDataplaneFeatures(ctx, req.(*SupportedDataplaneFeaturesRequest)) + } + return interceptor(ctx, in, info, handler) +} + +var _DataplaneService_serviceDesc = grpc.ServiceDesc{ + ServiceName: "dataplane.DataplaneService", + HandlerType: (*DataplaneServiceServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "SupportedDataplaneFeatures", + Handler: _DataplaneService_SupportedDataplaneFeatures_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "proto-public/pbdataplane/dataplane.proto", +} diff --git a/proto-public/pbdataplane/dataplane.proto b/proto-public/pbdataplane/dataplane.proto new file mode 100644 index 000000000..17789fc55 --- /dev/null +++ b/proto-public/pbdataplane/dataplane.proto @@ -0,0 +1,32 @@ +// Package dataplane provides a service on Consul servers for the Consul Dataplane + +syntax = "proto3"; + +package dataplane; + +option go_package = "github.com/hashicorp/consul/proto-public/pbdataplane"; + + +message SupportedDataplaneFeaturesRequest {} + +enum DataplaneFeatures { + UNKNOWN = 0; + WATCH_SERVERS = 1; + EDGE_CERTIFICATE_MANAGEMENT = 2; + ENVOY_BOOTSTRAP_CONFIGURATION = 3; +} + + +message DataplaneFeatureSupport { + DataplaneFeatures feature_name = 1; + bool supported = 2; +} + +message SupportedDataplaneFeaturesResponse { + repeated DataplaneFeatureSupport supported_dataplane_features = 1; +} + + +service DataplaneService { + rpc SupportedDataplaneFeatures(SupportedDataplaneFeaturesRequest) returns (SupportedDataplaneFeaturesResponse) {}; +} \ No newline at end of file From e7dfc7288496646e22a514937760c0e1a62542db Mon Sep 17 00:00:00 2001 From: Riddhi Shah Date: Tue, 5 Apr 2022 07:44:26 -0700 Subject: [PATCH 2/3] Add changelog --- .changelog/12695.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/12695.txt diff --git a/.changelog/12695.txt b/.changelog/12695.txt new file mode 100644 index 000000000..e9eb3aef0 --- /dev/null +++ b/.changelog/12695.txt @@ -0,0 +1,3 @@ +```release-note:feature +New gRPC service and endpoint to return the list of supported consul dataplane features +``` \ No newline at end of file From 76cfe558669fdb42f930454b1da9a819f907b10d Mon Sep 17 00:00:00 2001 From: Riddhi Shah Date: Tue, 5 Apr 2022 09:08:37 -0700 Subject: [PATCH 3/3] Update .changelog/12695.txt Co-authored-by: Matt Keeler --- .changelog/12695.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/12695.txt b/.changelog/12695.txt index e9eb3aef0..9baaa3dcb 100644 --- a/.changelog/12695.txt +++ b/.changelog/12695.txt @@ -1,3 +1,3 @@ ```release-note:feature -New gRPC service and endpoint to return the list of supported consul dataplane features +grpc: New gRPC service and endpoint to return the list of supported consul dataplane features ``` \ No newline at end of file