Add ACL enforcement to peering endpoints

This commit is contained in:
freddygv 2022-07-12 17:18:05 -06:00
parent b60ebc022e
commit 5bbc0cc615
27 changed files with 1300 additions and 918 deletions

View File

@ -335,6 +335,24 @@ func (a AllowAuthorizer) MeshWriteAllowed(ctx *AuthorizerContext) error {
return nil return nil
} }
// PeeringReadAllowed determines if the read-only Consul peering functions
// can be used.
func (a AllowAuthorizer) PeeringReadAllowed(ctx *AuthorizerContext) error {
if a.Authorizer.PeeringRead(ctx) != Allow {
return PermissionDeniedByACLUnnamed(a, ctx, ResourcePeering, AccessRead)
}
return nil
}
// PeeringWriteAllowed determines if the state-changing Consul peering
// functions can be used.
func (a AllowAuthorizer) PeeringWriteAllowed(ctx *AuthorizerContext) error {
if a.Authorizer.PeeringWrite(ctx) != Allow {
return PermissionDeniedByACLUnnamed(a, ctx, ResourcePeering, AccessWrite)
}
return nil
}
// NodeReadAllowed checks for permission to read (discover) a given node. // NodeReadAllowed checks for permission to read (discover) a given node.
func (a AllowAuthorizer) NodeReadAllowed(name string, ctx *AuthorizerContext) error { func (a AllowAuthorizer) NodeReadAllowed(name string, ctx *AuthorizerContext) error {
if a.Authorizer.NodeRead(name, ctx) != Allow { if a.Authorizer.NodeRead(name, ctx) != Allow {

View File

@ -3,16 +3,53 @@ package cachetype
import ( import (
"context" "context"
"fmt" "fmt"
"strconv"
"time"
"github.com/mitchellh/hashstructure"
"google.golang.org/grpc" "google.golang.org/grpc"
"github.com/hashicorp/consul/agent/cache" "github.com/hashicorp/consul/agent/cache"
external "github.com/hashicorp/consul/agent/grpc-external"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/proto/pbpeering" "github.com/hashicorp/consul/proto/pbpeering"
) )
// Recommended name for registration. // Recommended name for registration.
const TrustBundleReadName = "peer-trust-bundle" const TrustBundleReadName = "peer-trust-bundle"
type TrustBundleReadRequest struct {
Request *pbpeering.TrustBundleReadRequest
structs.QueryOptions
}
func (r *TrustBundleReadRequest) CacheInfo() cache.RequestInfo {
info := cache.RequestInfo{
Token: r.Token,
Datacenter: "",
MinIndex: 0,
Timeout: 0,
MustRevalidate: false,
// OPTIMIZE(peering): Cache.notifyPollingQuery polls at this interval. We need to revisit how that polling works.
// Using an exponential backoff when the result hasn't changed may be preferable.
MaxAge: 1 * time.Second,
}
v, err := hashstructure.Hash([]interface{}{
r.Request.Partition,
r.Request.Name,
}, nil)
if err == nil {
// If there is an error, we don't set the key. A blank key forces
// no cache for this request so the request is forwarded directly
// to the server.
info.Key = strconv.FormatUint(v, 10)
}
return info
}
// TrustBundle supports fetching discovering service instances via prepared // TrustBundle supports fetching discovering service instances via prepared
// queries. // queries.
type TrustBundle struct { type TrustBundle struct {
@ -33,14 +70,20 @@ func (t *TrustBundle) Fetch(_ cache.FetchOptions, req cache.Request) (cache.Fetc
// The request should be a TrustBundleReadRequest. // The request should be a TrustBundleReadRequest.
// We do not need to make a copy of this request type like in other cache types // We do not need to make a copy of this request type like in other cache types
// because the RequestInfo is synthetic. // because the RequestInfo is synthetic.
reqReal, ok := req.(*pbpeering.TrustBundleReadRequest) reqReal, ok := req.(*TrustBundleReadRequest)
if !ok { if !ok {
return result, fmt.Errorf( return result, fmt.Errorf(
"Internal cache failure: request wrong type: %T", req) "Internal cache failure: request wrong type: %T", req)
} }
// Always allow stale - there's no point in hitting leader if the request is
// going to be served from cache and end up arbitrarily stale anyway. This
// allows cached service-discover to automatically read scale across all
// servers too.
reqReal.QueryOptions.SetAllowStale(true)
// Fetch // Fetch
reply, err := t.Client.TrustBundleRead(context.Background(), reqReal) reply, err := t.Client.TrustBundleRead(external.ContextWithToken(context.Background(), reqReal.Token), reqReal.Request)
if err != nil { if err != nil {
return result, err return result, err
} }

View File

@ -33,8 +33,10 @@ func TestTrustBundle(t *testing.T) {
Return(resp, nil) Return(resp, nil)
// Fetch and assert against the result. // Fetch and assert against the result.
result, err := typ.Fetch(cache.FetchOptions{}, &pbpeering.TrustBundleReadRequest{ result, err := typ.Fetch(cache.FetchOptions{}, &TrustBundleReadRequest{
Name: "foo", Request: &pbpeering.TrustBundleReadRequest{
Name: "foo",
},
}) })
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, cache.FetchResult{ require.Equal(t, cache.FetchResult{
@ -82,7 +84,9 @@ func TestTrustBundle_MultipleUpdates(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
t.Cleanup(cancel) t.Cleanup(cancel)
err := c.Notify(ctx, TrustBundleReadName, &pbpeering.TrustBundleReadRequest{Name: "foo"}, "updates", ch) err := c.Notify(ctx, TrustBundleReadName, &TrustBundleReadRequest{
Request: &pbpeering.TrustBundleReadRequest{Name: "foo"},
}, "updates", ch)
require.NoError(t, err) require.NoError(t, err)
i := uint64(1) i := uint64(1)

View File

@ -3,16 +3,55 @@ package cachetype
import ( import (
"context" "context"
"fmt" "fmt"
"strconv"
"time"
"github.com/mitchellh/hashstructure"
"google.golang.org/grpc" "google.golang.org/grpc"
"github.com/hashicorp/consul/agent/cache" "github.com/hashicorp/consul/agent/cache"
external "github.com/hashicorp/consul/agent/grpc-external"
"github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/proto/pbpeering" "github.com/hashicorp/consul/proto/pbpeering"
) )
// Recommended name for registration. // Recommended name for registration.
const TrustBundleListName = "trust-bundles" const TrustBundleListName = "trust-bundles"
type TrustBundleListRequest struct {
Request *pbpeering.TrustBundleListByServiceRequest
structs.QueryOptions
}
func (r *TrustBundleListRequest) CacheInfo() cache.RequestInfo {
info := cache.RequestInfo{
Token: r.Token,
Datacenter: "",
MinIndex: 0,
Timeout: 0,
MustRevalidate: false,
// OPTIMIZE(peering): Cache.notifyPollingQuery polls at this interval. We need to revisit how that polling works.
// Using an exponential backoff when the result hasn't changed may be preferable.
MaxAge: 1 * time.Second,
}
v, err := hashstructure.Hash([]interface{}{
r.Request.Partition,
r.Request.Namespace,
r.Request.ServiceName,
r.Request.Kind,
}, nil)
if err == nil {
// If there is an error, we don't set the key. A blank key forces
// no cache for this request so the request is forwarded directly
// to the server.
info.Key = strconv.FormatUint(v, 10)
}
return info
}
// TrustBundles supports fetching discovering service instances via prepared // TrustBundles supports fetching discovering service instances via prepared
// queries. // queries.
type TrustBundles struct { type TrustBundles struct {
@ -30,17 +69,23 @@ type TrustBundleLister interface {
func (t *TrustBundles) Fetch(_ cache.FetchOptions, req cache.Request) (cache.FetchResult, error) { func (t *TrustBundles) Fetch(_ cache.FetchOptions, req cache.Request) (cache.FetchResult, error) {
var result cache.FetchResult var result cache.FetchResult
// The request should be a TrustBundleListByServiceRequest. // The request should be a TrustBundleListRequest.
// We do not need to make a copy of this request type like in other cache types // We do not need to make a copy of this request type like in other cache types
// because the RequestInfo is synthetic. // because the RequestInfo is synthetic.
reqReal, ok := req.(*pbpeering.TrustBundleListByServiceRequest) reqReal, ok := req.(*TrustBundleListRequest)
if !ok { if !ok {
return result, fmt.Errorf( return result, fmt.Errorf(
"Internal cache failure: request wrong type: %T", req) "Internal cache failure: request wrong type: %T", req)
} }
// Always allow stale - there's no point in hitting leader if the request is
// going to be served from cache and end up arbitrarily stale anyway. This
// allows cached service-discover to automatically read scale across all
// servers too.
reqReal.QueryOptions.SetAllowStale(true)
// Fetch // Fetch
reply, err := t.Client.TrustBundleListByService(context.Background(), reqReal) reply, err := t.Client.TrustBundleListByService(external.ContextWithToken(context.Background(), reqReal.Token), reqReal.Request)
if err != nil { if err != nil {
return result, err return result, err
} }

View File

@ -36,8 +36,10 @@ func TestTrustBundles(t *testing.T) {
Return(resp, nil) Return(resp, nil)
// Fetch and assert against the result. // Fetch and assert against the result.
result, err := typ.Fetch(cache.FetchOptions{}, &pbpeering.TrustBundleListByServiceRequest{ result, err := typ.Fetch(cache.FetchOptions{}, &TrustBundleListRequest{
ServiceName: "foo", Request: &pbpeering.TrustBundleListByServiceRequest{
ServiceName: "foo",
},
}) })
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, cache.FetchResult{ require.Equal(t, cache.FetchResult{
@ -85,7 +87,9 @@ func TestTrustBundles_MultipleUpdates(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
t.Cleanup(cancel) t.Cleanup(cancel)
err := c.Notify(ctx, TrustBundleListName, &pbpeering.TrustBundleListByServiceRequest{ServiceName: "foo"}, "updates", ch) err := c.Notify(ctx, TrustBundleListName, &TrustBundleListRequest{
Request: &pbpeering.TrustBundleListByServiceRequest{ServiceName: "foo"},
}, "updates", ch)
require.NoError(t, err) require.NoError(t, err)
i := uint64(1) i := uint64(1)

View File

@ -7,6 +7,8 @@ import (
"strconv" "strconv"
"sync" "sync"
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/acl/resolver"
"github.com/hashicorp/consul/agent/consul/stream" "github.com/hashicorp/consul/agent/consul/stream"
"github.com/hashicorp/consul/agent/grpc-external/services/peerstream" "github.com/hashicorp/consul/agent/grpc-external/services/peerstream"
"github.com/hashicorp/consul/agent/rpc/peering" "github.com/hashicorp/consul/agent/rpc/peering"
@ -160,3 +162,7 @@ func (b *PeeringBackend) CatalogDeregister(req *structs.DeregisterRequest) error
_, err := b.srv.leaderRaftApply("Catalog.Deregister", structs.DeregisterRequestType, req) _, err := b.srv.leaderRaftApply("Catalog.Deregister", structs.DeregisterRequestType, req)
return err return err
} }
func (b *PeeringBackend) ResolveTokenAndDefaultMeta(token string, entMeta *acl.EnterpriseMeta, authzCtx *acl.AuthorizerContext) (resolver.Result, error) {
return b.srv.ResolveTokenAndDefaultMeta(token, entMeta, authzCtx)
}

View File

@ -42,8 +42,7 @@ func TestPeeringBackend_RejectsPartition(t *testing.T) {
peeringClient := pbpeering.NewPeeringServiceClient(conn) peeringClient := pbpeering.NewPeeringServiceClient(conn)
req := pbpeering.GenerateTokenRequest{ req := pbpeering.GenerateTokenRequest{
Datacenter: "dc1", Partition: "test",
Partition: "test",
} }
_, err = peeringClient.GenerateToken(ctx, &req) _, err = peeringClient.GenerateToken(ctx, &req)
require.Error(t, err) require.Error(t, err)
@ -77,9 +76,8 @@ func TestPeeringBackend_IgnoresDefaultPartition(t *testing.T) {
peeringClient := pbpeering.NewPeeringServiceClient(conn) peeringClient := pbpeering.NewPeeringServiceClient(conn)
req := pbpeering.GenerateTokenRequest{ req := pbpeering.GenerateTokenRequest{
Datacenter: "dc1", PeerName: "my-peer",
PeerName: "my-peer", Partition: "DeFaUlT",
Partition: "DeFaUlT",
} }
_, err = peeringClient.GenerateToken(ctx, &req) _, err = peeringClient.GenerateToken(ctx, &req)
require.NoError(t, err) require.NoError(t, err)

View File

@ -15,43 +15,6 @@ import (
"github.com/hashicorp/consul/testrpc" "github.com/hashicorp/consul/testrpc"
) )
func TestPeeringBackend_DoesNotForwardToDifferentDC(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
t.Parallel()
_, s1 := testServerDC(t, "dc1")
_, s2 := testServerDC(t, "dc2")
joinWAN(t, s2, s1)
testrpc.WaitForLeader(t, s1.RPC, "dc1")
testrpc.WaitForLeader(t, s2.RPC, "dc2")
// make a grpc client to dial s2 directly
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
t.Cleanup(cancel)
conn, err := gogrpc.DialContext(ctx, s2.config.RPCAddr.String(),
gogrpc.WithContextDialer(newServerDialer(s2.config.RPCAddr.String())),
gogrpc.WithInsecure(),
gogrpc.WithBlock())
require.NoError(t, err)
t.Cleanup(func() { conn.Close() })
peeringClient := pbpeering.NewPeeringServiceClient(conn)
// GenerateToken request should fail against dc1, because we are dialing dc2. The GenerateToken request should never be forwarded across datacenters.
req := pbpeering.GenerateTokenRequest{
PeerName: "peer1-usw1",
Datacenter: "dc1",
}
_, err = peeringClient.GenerateToken(ctx, &req)
require.Error(t, err)
require.Contains(t, err.Error(), "requests to generate peering tokens cannot be forwarded to remote datacenters")
}
func TestPeeringBackend_ForwardToLeader(t *testing.T) { func TestPeeringBackend_ForwardToLeader(t *testing.T) {
t.Parallel() t.Parallel()
@ -86,8 +49,7 @@ func TestPeeringBackend_ForwardToLeader(t *testing.T) {
testutil.RunStep(t, "forward a write", func(t *testing.T) { testutil.RunStep(t, "forward a write", func(t *testing.T) {
// Do the grpc Write call to server2 // Do the grpc Write call to server2
req := pbpeering.GenerateTokenRequest{ req := pbpeering.GenerateTokenRequest{
Datacenter: "dc1", PeerName: "foo",
PeerName: "foo",
} }
_, err := peeringClient.GenerateToken(ctx, &req) _, err := peeringClient.GenerateToken(ctx, &req)
require.NoError(t, err) require.NoError(t, err)

View File

@ -6,6 +6,7 @@ import (
"strings" "strings"
"github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl"
external "github.com/hashicorp/consul/agent/grpc-external"
"github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib"
"github.com/hashicorp/consul/proto/pbpeering" "github.com/hashicorp/consul/proto/pbpeering"
@ -32,17 +33,20 @@ func (s *HTTPHandlers) PeeringEndpoint(resp http.ResponseWriter, req *http.Reque
// peeringRead fetches a peering that matches the name and partition. // peeringRead fetches a peering that matches the name and partition.
// This assumes that the name and partition parameters are valid // This assumes that the name and partition parameters are valid
func (s *HTTPHandlers) peeringRead(resp http.ResponseWriter, req *http.Request, name string) (interface{}, error) { func (s *HTTPHandlers) peeringRead(resp http.ResponseWriter, req *http.Request, name string) (interface{}, error) {
args := pbpeering.PeeringReadRequest{
Name: name,
Datacenter: s.agent.config.Datacenter,
}
var entMeta acl.EnterpriseMeta var entMeta acl.EnterpriseMeta
if err := s.parseEntMetaPartition(req, &entMeta); err != nil { if err := s.parseEntMetaPartition(req, &entMeta); err != nil {
return nil, err return nil, err
} }
args.Partition = entMeta.PartitionOrEmpty() args := pbpeering.PeeringReadRequest{
Name: name,
Partition: entMeta.PartitionOrEmpty(),
}
result, err := s.agent.rpcClientPeering.PeeringRead(req.Context(), &args) var token string
s.parseToken(req, &token)
ctx := external.ContextWithToken(req.Context(), token)
result, err := s.agent.rpcClientPeering.PeeringRead(ctx, &args)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -55,16 +59,19 @@ func (s *HTTPHandlers) peeringRead(resp http.ResponseWriter, req *http.Request,
// PeeringList fetches all peerings in the datacenter in OSS or in a given partition in Consul Enterprise. // PeeringList fetches all peerings in the datacenter in OSS or in a given partition in Consul Enterprise.
func (s *HTTPHandlers) PeeringList(resp http.ResponseWriter, req *http.Request) (interface{}, error) { func (s *HTTPHandlers) PeeringList(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
args := pbpeering.PeeringListRequest{
Datacenter: s.agent.config.Datacenter,
}
var entMeta acl.EnterpriseMeta var entMeta acl.EnterpriseMeta
if err := s.parseEntMetaPartition(req, &entMeta); err != nil { if err := s.parseEntMetaPartition(req, &entMeta); err != nil {
return nil, err return nil, err
} }
args.Partition = entMeta.PartitionOrEmpty() args := pbpeering.PeeringListRequest{
Partition: entMeta.PartitionOrEmpty(),
}
pbresp, err := s.agent.rpcClientPeering.PeeringList(req.Context(), &args) var token string
s.parseToken(req, &token)
ctx := external.ContextWithToken(req.Context(), token)
pbresp, err := s.agent.rpcClientPeering.PeeringList(ctx, &args)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -79,14 +86,12 @@ func (s *HTTPHandlers) PeeringGenerateToken(resp http.ResponseWriter, req *http.
return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "The peering arguments must be provided in the body"} return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "The peering arguments must be provided in the body"}
} }
apiRequest := &api.PeeringGenerateTokenRequest{ var apiRequest api.PeeringGenerateTokenRequest
Datacenter: s.agent.config.Datacenter, if err := lib.DecodeJSON(req.Body, &apiRequest); err != nil {
}
if err := lib.DecodeJSON(req.Body, apiRequest); err != nil {
return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Body decoding failed: %v", err)} return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Body decoding failed: %v", err)}
} }
args := pbpeering.NewGenerateTokenRequestFromAPI(apiRequest)
args := pbpeering.NewGenerateTokenRequestFromAPI(&apiRequest)
if args.PeerName == "" { if args.PeerName == "" {
return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "PeerName is required in the payload when generating a new peering token."} return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "PeerName is required in the payload when generating a new peering token."}
} }
@ -99,7 +104,11 @@ func (s *HTTPHandlers) PeeringGenerateToken(resp http.ResponseWriter, req *http.
args.Partition = entMeta.PartitionOrEmpty() args.Partition = entMeta.PartitionOrEmpty()
} }
out, err := s.agent.rpcClientPeering.GenerateToken(req.Context(), args) var token string
s.parseToken(req, &token)
ctx := external.ContextWithToken(req.Context(), token)
out, err := s.agent.rpcClientPeering.GenerateToken(ctx, args)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -114,18 +123,15 @@ func (s *HTTPHandlers) PeeringEstablish(resp http.ResponseWriter, req *http.Requ
return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "The peering arguments must be provided in the body"} return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "The peering arguments must be provided in the body"}
} }
apiRequest := &api.PeeringEstablishRequest{ var apiRequest api.PeeringEstablishRequest
Datacenter: s.agent.config.Datacenter, if err := lib.DecodeJSON(req.Body, &apiRequest); err != nil {
}
if err := lib.DecodeJSON(req.Body, apiRequest); err != nil {
return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Body decoding failed: %v", err)} return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: fmt.Sprintf("Body decoding failed: %v", err)}
} }
args := pbpeering.NewEstablishRequestFromAPI(apiRequest)
args := pbpeering.NewEstablishRequestFromAPI(&apiRequest)
if args.PeerName == "" { if args.PeerName == "" {
return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "PeerName is required in the payload when establishing a peering."} return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "PeerName is required in the payload when establishing a peering."}
} }
if args.PeeringToken == "" { if args.PeeringToken == "" {
return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "PeeringToken is required in the payload when establishing a peering."} return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "PeeringToken is required in the payload when establishing a peering."}
} }
@ -138,7 +144,11 @@ func (s *HTTPHandlers) PeeringEstablish(resp http.ResponseWriter, req *http.Requ
args.Partition = entMeta.PartitionOrEmpty() args.Partition = entMeta.PartitionOrEmpty()
} }
out, err := s.agent.rpcClientPeering.Establish(req.Context(), args) var token string
s.parseToken(req, &token)
ctx := external.ContextWithToken(req.Context(), token)
out, err := s.agent.rpcClientPeering.Establish(ctx, args)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -149,17 +159,20 @@ func (s *HTTPHandlers) PeeringEstablish(resp http.ResponseWriter, req *http.Requ
// peeringDelete initiates a deletion for a peering that matches the name and partition. // peeringDelete initiates a deletion for a peering that matches the name and partition.
// This assumes that the name and partition parameters are valid. // This assumes that the name and partition parameters are valid.
func (s *HTTPHandlers) peeringDelete(resp http.ResponseWriter, req *http.Request, name string) (interface{}, error) { func (s *HTTPHandlers) peeringDelete(resp http.ResponseWriter, req *http.Request, name string) (interface{}, error) {
args := pbpeering.PeeringDeleteRequest{
Name: name,
Datacenter: s.agent.config.Datacenter,
}
var entMeta acl.EnterpriseMeta var entMeta acl.EnterpriseMeta
if err := s.parseEntMetaPartition(req, &entMeta); err != nil { if err := s.parseEntMetaPartition(req, &entMeta); err != nil {
return nil, err return nil, err
} }
args.Partition = entMeta.PartitionOrEmpty() args := pbpeering.PeeringDeleteRequest{
Name: name,
Partition: entMeta.PartitionOrEmpty(),
}
_, err := s.agent.rpcClientPeering.PeeringDelete(req.Context(), &args) var token string
s.parseToken(req, &token)
ctx := external.ContextWithToken(req.Context(), token)
_, err := s.agent.rpcClientPeering.PeeringDelete(ctx, &args)
if err != nil { if err != nil {
return nil, err return nil, err
} }

View File

@ -3,6 +3,7 @@ package proxycfgglue
import ( import (
"context" "context"
"github.com/hashicorp/consul/proto/pbpeering"
"github.com/hashicorp/go-memdb" "github.com/hashicorp/go-memdb"
"github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl"
@ -14,7 +15,6 @@ import (
"github.com/hashicorp/consul/agent/consul/watch" "github.com/hashicorp/consul/agent/consul/watch"
"github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/proxycfg"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/proto/pbpeering"
) )
// Store is the state store interface required for server-local data sources. // Store is the state store interface required for server-local data sources.

View File

@ -19,7 +19,7 @@ import (
// CacheTrustBundle satisfies the proxycfg.TrustBundle interface by sourcing // CacheTrustBundle satisfies the proxycfg.TrustBundle interface by sourcing
// data from the agent cache. // data from the agent cache.
func CacheTrustBundle(c *cache.Cache) proxycfg.TrustBundle { func CacheTrustBundle(c *cache.Cache) proxycfg.TrustBundle {
return &cacheProxyDataSource[*pbpeering.TrustBundleReadRequest]{c, cachetype.TrustBundleReadName} return &cacheProxyDataSource[*cachetype.TrustBundleReadRequest]{c, cachetype.TrustBundleReadName}
} }
// ServerTrustBundle satisfies the proxycfg.TrustBundle interface by sourcing // ServerTrustBundle satisfies the proxycfg.TrustBundle interface by sourcing
@ -32,13 +32,13 @@ type serverTrustBundle struct {
deps ServerDataSourceDeps deps ServerDataSourceDeps
} }
func (s *serverTrustBundle) Notify(ctx context.Context, req *pbpeering.TrustBundleReadRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error { func (s *serverTrustBundle) Notify(ctx context.Context, req *cachetype.TrustBundleReadRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error {
// TODO(peering): ACL check. // TODO(peering): ACL check.
return watch.ServerLocalNotify(ctx, correlationID, s.deps.GetStore, return watch.ServerLocalNotify(ctx, correlationID, s.deps.GetStore,
func(ws memdb.WatchSet, store Store) (uint64, *pbpeering.TrustBundleReadResponse, error) { func(ws memdb.WatchSet, store Store) (uint64, *pbpeering.TrustBundleReadResponse, error) {
index, bundle, err := store.PeeringTrustBundleRead(ws, state.Query{ index, bundle, err := store.PeeringTrustBundleRead(ws, state.Query{
Value: req.Name, Value: req.Request.Name,
EnterpriseMeta: *structs.NodeEnterpriseMetaInPartition(req.Partition), EnterpriseMeta: *structs.NodeEnterpriseMetaInPartition(req.Request.Partition),
}) })
if err != nil { if err != nil {
return 0, nil, err return 0, nil, err
@ -55,7 +55,7 @@ func (s *serverTrustBundle) Notify(ctx context.Context, req *pbpeering.TrustBund
// CacheTrustBundleList satisfies the proxycfg.TrustBundleList interface by sourcing // CacheTrustBundleList satisfies the proxycfg.TrustBundleList interface by sourcing
// data from the agent cache. // data from the agent cache.
func CacheTrustBundleList(c *cache.Cache) proxycfg.TrustBundleList { func CacheTrustBundleList(c *cache.Cache) proxycfg.TrustBundleList {
return &cacheProxyDataSource[*pbpeering.TrustBundleListByServiceRequest]{c, cachetype.TrustBundleListName} return &cacheProxyDataSource[*cachetype.TrustBundleListRequest]{c, cachetype.TrustBundleListName}
} }
// ServerTrustBundleList satisfies the proxycfg.TrustBundle interface by // ServerTrustBundleList satisfies the proxycfg.TrustBundle interface by
@ -68,8 +68,8 @@ type serverTrustBundleList struct {
deps ServerDataSourceDeps deps ServerDataSourceDeps
} }
func (s *serverTrustBundleList) Notify(ctx context.Context, req *pbpeering.TrustBundleListByServiceRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error { func (s *serverTrustBundleList) Notify(ctx context.Context, req *cachetype.TrustBundleListRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error {
entMeta := acl.NewEnterpriseMetaWithPartition(req.Partition, req.Namespace) entMeta := acl.NewEnterpriseMetaWithPartition(req.Request.Partition, req.Request.Namespace)
// TODO(peering): ACL check. // TODO(peering): ACL check.
return watch.ServerLocalNotify(ctx, correlationID, s.deps.GetStore, return watch.ServerLocalNotify(ctx, correlationID, s.deps.GetStore,
@ -80,11 +80,11 @@ func (s *serverTrustBundleList) Notify(ctx context.Context, req *pbpeering.Trust
err error err error
) )
switch { switch {
case req.ServiceName != "": case req.Request.Kind == string(structs.ServiceKindMeshGateway):
index, bundles, err = store.TrustBundleListByService(ws, req.ServiceName, s.deps.Datacenter, entMeta)
case req.Kind == string(structs.ServiceKindMeshGateway):
index, bundles, err = store.PeeringTrustBundleList(ws, entMeta) index, bundles, err = store.PeeringTrustBundleList(ws, entMeta)
case req.Kind != "": case req.Request.ServiceName != "":
index, bundles, err = store.TrustBundleListByService(ws, req.Request.ServiceName, s.deps.Datacenter, entMeta)
case req.Request.Kind != "":
err = errors.New("kind must be mesh-gateway if set") err = errors.New("kind must be mesh-gateway if set")
default: default:
err = errors.New("one of service or kind is required") err = errors.New("one of service or kind is required")

View File

@ -4,6 +4,7 @@ import (
"context" "context"
"testing" "testing"
cachetype "github.com/hashicorp/consul/agent/cache-types"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
"github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/consul/state"
@ -32,8 +33,10 @@ func TestServerTrustBundle(t *testing.T) {
}) })
eventCh := make(chan proxycfg.UpdateEvent) eventCh := make(chan proxycfg.UpdateEvent)
err := dataSource.Notify(context.Background(), &pbpeering.TrustBundleReadRequest{ err := dataSource.Notify(context.Background(), &cachetype.TrustBundleReadRequest{
Name: peerName, Request: &pbpeering.TrustBundleReadRequest{
Name: peerName,
},
}, "", eventCh) }, "", eventCh)
require.NoError(t, err) require.NoError(t, err)
@ -96,9 +99,11 @@ func TestServerTrustBundleList(t *testing.T) {
}) })
eventCh := make(chan proxycfg.UpdateEvent) eventCh := make(chan proxycfg.UpdateEvent)
err := dataSource.Notify(context.Background(), &pbpeering.TrustBundleListByServiceRequest{ err := dataSource.Notify(context.Background(), &cachetype.TrustBundleListRequest{
ServiceName: serviceName, Request: &pbpeering.TrustBundleListByServiceRequest{
Partition: us, ServiceName: serviceName,
Partition: us,
},
}, "", eventCh) }, "", eventCh)
require.NoError(t, err) require.NoError(t, err)
@ -134,9 +139,11 @@ func TestServerTrustBundleList(t *testing.T) {
}) })
eventCh := make(chan proxycfg.UpdateEvent) eventCh := make(chan proxycfg.UpdateEvent)
err := dataSource.Notify(context.Background(), &pbpeering.TrustBundleListByServiceRequest{ err := dataSource.Notify(context.Background(), &cachetype.TrustBundleListRequest{
Kind: string(structs.ServiceKindMeshGateway), Request: &pbpeering.TrustBundleListByServiceRequest{
Partition: "default", Kind: string(structs.ServiceKindMeshGateway),
Partition: "default",
},
}, "", eventCh) }, "", eventCh)
require.NoError(t, err) require.NoError(t, err)

View File

@ -46,11 +46,13 @@ func (s *handlerConnectProxy) initialize(ctx context.Context) (ConfigSnapshot, e
return snap, err return snap, err
} }
err = s.dataSources.TrustBundleList.Notify(ctx, &pbpeering.TrustBundleListByServiceRequest{ err = s.dataSources.TrustBundleList.Notify(ctx, &cachetype.TrustBundleListRequest{
// TODO(peering): Pass ACL token Request: &pbpeering.TrustBundleListByServiceRequest{
ServiceName: s.proxyCfg.DestinationServiceName, ServiceName: s.proxyCfg.DestinationServiceName,
Namespace: s.proxyID.NamespaceOrDefault(), Namespace: s.proxyID.NamespaceOrDefault(),
Partition: s.proxyID.PartitionOrDefault(), Partition: s.proxyID.PartitionOrDefault(),
},
QueryOptions: structs.QueryOptions{Token: s.token},
}, peeringTrustBundlesWatchID, s.ch) }, peeringTrustBundlesWatchID, s.ch)
if err != nil { if err != nil {
return snap, err return snap, err
@ -226,9 +228,12 @@ func (s *handlerConnectProxy) initialize(ctx context.Context) (ConfigSnapshot, e
// Check whether a watch for this peer exists to avoid duplicates. // Check whether a watch for this peer exists to avoid duplicates.
if ok := snap.ConnectProxy.UpstreamPeerTrustBundles.IsWatched(uid.Peer); !ok { if ok := snap.ConnectProxy.UpstreamPeerTrustBundles.IsWatched(uid.Peer); !ok {
peerCtx, cancel := context.WithCancel(ctx) peerCtx, cancel := context.WithCancel(ctx)
if err := s.dataSources.TrustBundle.Notify(peerCtx, &pbpeering.TrustBundleReadRequest{ if err := s.dataSources.TrustBundle.Notify(peerCtx, &cachetype.TrustBundleReadRequest{
Name: uid.Peer, Request: &pbpeering.TrustBundleReadRequest{
Partition: uid.PartitionOrDefault(), Name: uid.Peer,
Partition: uid.PartitionOrDefault(),
},
QueryOptions: structs.QueryOptions{Token: s.token},
}, peerTrustBundleIDPrefix+uid.Peer, s.ch); err != nil { }, peerTrustBundleIDPrefix+uid.Peer, s.ch); err != nil {
cancel() cancel()
return snap, fmt.Errorf("error while watching trust bundle for peer %q: %w", uid.Peer, err) return snap, fmt.Errorf("error while watching trust bundle for peer %q: %w", uid.Peer, err)
@ -344,9 +349,12 @@ func (s *handlerConnectProxy) handleUpdate(ctx context.Context, u UpdateEvent, s
// Check whether a watch for this peer exists to avoid duplicates. // Check whether a watch for this peer exists to avoid duplicates.
if ok := snap.ConnectProxy.UpstreamPeerTrustBundles.IsWatched(uid.Peer); !ok { if ok := snap.ConnectProxy.UpstreamPeerTrustBundles.IsWatched(uid.Peer); !ok {
peerCtx, cancel := context.WithCancel(ctx) peerCtx, cancel := context.WithCancel(ctx)
if err := s.dataSources.TrustBundle.Notify(peerCtx, &pbpeering.TrustBundleReadRequest{ if err := s.dataSources.TrustBundle.Notify(peerCtx, &cachetype.TrustBundleReadRequest{
Name: uid.Peer, Request: &pbpeering.TrustBundleReadRequest{
Partition: uid.PartitionOrDefault(), Name: uid.Peer,
Partition: uid.PartitionOrDefault(),
},
QueryOptions: structs.QueryOptions{Token: s.token},
}, peerTrustBundleIDPrefix+uid.Peer, s.ch); err != nil { }, peerTrustBundleIDPrefix+uid.Peer, s.ch); err != nil {
cancel() cancel()
return fmt.Errorf("error while watching trust bundle for peer %q: %w", uid.Peer, err) return fmt.Errorf("error while watching trust bundle for peer %q: %w", uid.Peer, err)

View File

@ -5,7 +5,6 @@ import (
cachetype "github.com/hashicorp/consul/agent/cache-types" cachetype "github.com/hashicorp/consul/agent/cache-types"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/proto/pbpeering"
) )
// UpdateEvent contains new data for a resource we are subscribed to (e.g. an // UpdateEvent contains new data for a resource we are subscribed to (e.g. an
@ -220,13 +219,13 @@ type ServiceList interface {
// TrustBundle is the interface used to consume updates about a single // TrustBundle is the interface used to consume updates about a single
// peer's trust bundle. // peer's trust bundle.
type TrustBundle interface { type TrustBundle interface {
Notify(ctx context.Context, req *pbpeering.TrustBundleReadRequest, correlationID string, ch chan<- UpdateEvent) error Notify(ctx context.Context, req *cachetype.TrustBundleReadRequest, correlationID string, ch chan<- UpdateEvent) error
} }
// TrustBundleList is the interface used to consume updates about trust bundles // TrustBundleList is the interface used to consume updates about trust bundles
// for peered clusters that the given proxy is exported to. // for peered clusters that the given proxy is exported to.
type TrustBundleList interface { type TrustBundleList interface {
Notify(ctx context.Context, req *pbpeering.TrustBundleListByServiceRequest, correlationID string, ch chan<- UpdateEvent) error Notify(ctx context.Context, req *cachetype.TrustBundleListRequest, correlationID string, ch chan<- UpdateEvent) error
} }
// ExportedPeeredServices is the interface used to consume updates about the // ExportedPeeredServices is the interface used to consume updates about the

View File

@ -32,11 +32,14 @@ func (s *handlerMeshGateway) initialize(ctx context.Context) (ConfigSnapshot, er
} }
// Watch for all peer trust bundles we may need. // Watch for all peer trust bundles we may need.
err = s.dataSources.TrustBundleList.Notify(ctx, &pbpeering.TrustBundleListByServiceRequest{ err = s.dataSources.TrustBundleList.Notify(ctx, &cachetype.TrustBundleListRequest{
// TODO(peering): Pass ACL token Request: &pbpeering.TrustBundleListByServiceRequest{
Kind: string(structs.ServiceKindMeshGateway), Kind: string(structs.ServiceKindMeshGateway),
Namespace: s.proxyID.NamespaceOrDefault(), ServiceName: s.service,
Partition: s.proxyID.PartitionOrDefault(), Namespace: s.proxyID.NamespaceOrDefault(),
Partition: s.proxyID.PartitionOrDefault(),
},
QueryOptions: structs.QueryOptions{Token: s.token},
}, peeringTrustBundlesWatchID, s.ch) }, peeringTrustBundlesWatchID, s.ch)
if err != nil { if err != nil {
return snap, err return snap, err

View File

@ -137,8 +137,8 @@ func recordWatches(sc *stateConfig) *watchRecorder {
PreparedQuery: typedWatchRecorder[*structs.PreparedQueryExecuteRequest]{wr}, PreparedQuery: typedWatchRecorder[*structs.PreparedQueryExecuteRequest]{wr},
ResolvedServiceConfig: typedWatchRecorder[*structs.ServiceConfigRequest]{wr}, ResolvedServiceConfig: typedWatchRecorder[*structs.ServiceConfigRequest]{wr},
ServiceList: typedWatchRecorder[*structs.DCSpecificRequest]{wr}, ServiceList: typedWatchRecorder[*structs.DCSpecificRequest]{wr},
TrustBundle: typedWatchRecorder[*pbpeering.TrustBundleReadRequest]{wr}, TrustBundle: typedWatchRecorder[*cachetype.TrustBundleReadRequest]{wr},
TrustBundleList: typedWatchRecorder[*pbpeering.TrustBundleListByServiceRequest]{wr}, TrustBundleList: typedWatchRecorder[*cachetype.TrustBundleListRequest]{wr},
ExportedPeeredServices: typedWatchRecorder[*structs.DCSpecificRequest]{wr}, ExportedPeeredServices: typedWatchRecorder[*structs.DCSpecificRequest]{wr},
} }
recordWatchesEnterprise(sc, wr) recordWatchesEnterprise(sc, wr)
@ -203,9 +203,9 @@ func verifyDatacentersWatch(t testing.TB, request any) {
func genVerifyTrustBundleReadWatch(peer string) verifyWatchRequest { func genVerifyTrustBundleReadWatch(peer string) verifyWatchRequest {
return func(t testing.TB, request any) { return func(t testing.TB, request any) {
reqReal, ok := request.(*pbpeering.TrustBundleReadRequest) reqReal, ok := request.(*cachetype.TrustBundleReadRequest)
require.True(t, ok) require.True(t, ok)
require.Equal(t, peer, reqReal.Name) require.Equal(t, peer, reqReal.Request.Name)
} }
} }
@ -225,19 +225,19 @@ func genVerifyLeafWatch(expectedService string, expectedDatacenter string) verif
func genVerifyTrustBundleListWatch(service string) verifyWatchRequest { func genVerifyTrustBundleListWatch(service string) verifyWatchRequest {
return func(t testing.TB, request any) { return func(t testing.TB, request any) {
reqReal, ok := request.(*pbpeering.TrustBundleListByServiceRequest) reqReal, ok := request.(*cachetype.TrustBundleListRequest)
require.True(t, ok) require.True(t, ok)
require.Equal(t, service, reqReal.ServiceName) require.Equal(t, service, reqReal.Request.ServiceName)
} }
} }
func genVerifyTrustBundleListWatchForMeshGateway(partition string) verifyWatchRequest { func genVerifyTrustBundleListWatchForMeshGateway(partition string) verifyWatchRequest {
return func(t testing.TB, request any) { return func(t testing.TB, request any) {
reqReal, ok := request.(*pbpeering.TrustBundleListByServiceRequest) reqReal, ok := request.(*cachetype.TrustBundleListRequest)
require.True(t, ok) require.True(t, ok)
require.Equal(t, string(structs.ServiceKindMeshGateway), reqReal.Kind) require.Equal(t, string(structs.ServiceKindMeshGateway), reqReal.Request.Kind)
require.True(t, acl.EqualPartitions(partition, reqReal.Partition), "%q != %q", partition, reqReal.Partition) require.True(t, acl.EqualPartitions(partition, reqReal.Request.Partition), "%q != %q", partition, reqReal.Request.Partition)
require.Empty(t, reqReal.ServiceName) require.NotEmpty(t, reqReal.Request.ServiceName)
} }
} }

View File

@ -751,8 +751,8 @@ func testConfigSnapshotFixture(
PreparedQuery: &noopDataSource[*structs.PreparedQueryExecuteRequest]{}, PreparedQuery: &noopDataSource[*structs.PreparedQueryExecuteRequest]{},
ResolvedServiceConfig: &noopDataSource[*structs.ServiceConfigRequest]{}, ResolvedServiceConfig: &noopDataSource[*structs.ServiceConfigRequest]{},
ServiceList: &noopDataSource[*structs.DCSpecificRequest]{}, ServiceList: &noopDataSource[*structs.DCSpecificRequest]{},
TrustBundle: &noopDataSource[*pbpeering.TrustBundleReadRequest]{}, TrustBundle: &noopDataSource[*cachetype.TrustBundleReadRequest]{},
TrustBundleList: &noopDataSource[*pbpeering.TrustBundleListByServiceRequest]{}, TrustBundleList: &noopDataSource[*cachetype.TrustBundleListRequest]{},
ExportedPeeredServices: &noopDataSource[*structs.DCSpecificRequest]{}, ExportedPeeredServices: &noopDataSource[*structs.DCSpecificRequest]{},
}, },
dnsConfig: DNSConfig{ // TODO: make configurable dnsConfig: DNSConfig{ // TODO: make configurable
@ -954,8 +954,8 @@ func NewTestDataSources() *TestDataSources {
PreparedQuery: NewTestDataSource[*structs.PreparedQueryExecuteRequest, *structs.PreparedQueryExecuteResponse](), PreparedQuery: NewTestDataSource[*structs.PreparedQueryExecuteRequest, *structs.PreparedQueryExecuteResponse](),
ResolvedServiceConfig: NewTestDataSource[*structs.ServiceConfigRequest, *structs.ServiceConfigResponse](), ResolvedServiceConfig: NewTestDataSource[*structs.ServiceConfigRequest, *structs.ServiceConfigResponse](),
ServiceList: NewTestDataSource[*structs.DCSpecificRequest, *structs.IndexedServiceList](), ServiceList: NewTestDataSource[*structs.DCSpecificRequest, *structs.IndexedServiceList](),
TrustBundle: NewTestDataSource[*pbpeering.TrustBundleReadRequest, *pbpeering.TrustBundleReadResponse](), TrustBundle: NewTestDataSource[*cachetype.TrustBundleReadRequest, *pbpeering.TrustBundleReadResponse](),
TrustBundleList: NewTestDataSource[*pbpeering.TrustBundleListByServiceRequest, *pbpeering.TrustBundleListByServiceResponse](), TrustBundleList: NewTestDataSource[*cachetype.TrustBundleListRequest, *pbpeering.TrustBundleListByServiceResponse](),
} }
srcs.buildEnterpriseSources() srcs.buildEnterpriseSources()
return srcs return srcs
@ -981,8 +981,8 @@ type TestDataSources struct {
PreparedQuery *TestDataSource[*structs.PreparedQueryExecuteRequest, *structs.PreparedQueryExecuteResponse] PreparedQuery *TestDataSource[*structs.PreparedQueryExecuteRequest, *structs.PreparedQueryExecuteResponse]
ResolvedServiceConfig *TestDataSource[*structs.ServiceConfigRequest, *structs.ServiceConfigResponse] ResolvedServiceConfig *TestDataSource[*structs.ServiceConfigRequest, *structs.ServiceConfigResponse]
ServiceList *TestDataSource[*structs.DCSpecificRequest, *structs.IndexedServiceList] ServiceList *TestDataSource[*structs.DCSpecificRequest, *structs.IndexedServiceList]
TrustBundle *TestDataSource[*pbpeering.TrustBundleReadRequest, *pbpeering.TrustBundleReadResponse] TrustBundle *TestDataSource[*cachetype.TrustBundleReadRequest, *pbpeering.TrustBundleReadResponse]
TrustBundleList *TestDataSource[*pbpeering.TrustBundleListByServiceRequest, *pbpeering.TrustBundleListByServiceResponse] TrustBundleList *TestDataSource[*cachetype.TrustBundleListRequest, *pbpeering.TrustBundleListByServiceResponse]
TestDataSourcesEnterprise TestDataSourcesEnterprise
} }

View File

@ -16,9 +16,11 @@ import (
"google.golang.org/protobuf/proto" "google.golang.org/protobuf/proto"
"github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/acl/resolver"
"github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/consul/state"
"github.com/hashicorp/consul/agent/consul/stream" "github.com/hashicorp/consul/agent/consul/stream"
"github.com/hashicorp/consul/agent/dns" "github.com/hashicorp/consul/agent/dns"
external "github.com/hashicorp/consul/agent/grpc-external"
"github.com/hashicorp/consul/agent/grpc-external/services/peerstream" "github.com/hashicorp/consul/agent/grpc-external/services/peerstream"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib"
@ -43,6 +45,20 @@ func (e *errPeeringInvalidServerAddress) Error() string {
return fmt.Sprintf("%s is not a valid peering server address", e.addr) return fmt.Sprintf("%s is not a valid peering server address", e.addr)
} }
// For private/internal gRPC handlers, protoc-gen-rpc-glue generates the
// requisite methods to satisfy the structs.RPCInfo interface using fields
// from the pbcommon package. This service is public, so we can't use those
// fields in our proto definition. Instead, we construct our RPCInfo manually.
var writeRequest struct {
structs.WriteRequest
structs.DCSpecificRequest
}
var readRequest struct {
structs.QueryOptions
structs.DCSpecificRequest
}
// Server implements pbpeering.PeeringService to provide RPC operations for // Server implements pbpeering.PeeringService to provide RPC operations for
// managing peering relationships. // managing peering relationships.
type Server struct { type Server struct {
@ -90,6 +106,12 @@ func (s *Server) Register(grpcServer *grpc.Server) {
// providing access to CA data and the RPC system for forwarding requests to // providing access to CA data and the RPC system for forwarding requests to
// other servers. // other servers.
type Backend interface { type Backend interface {
// ResolveTokenAndDefaultMeta returns an acl.Authorizer which authorizes
// actions based on the permissions granted to the token.
// If either entMeta or authzContext are non-nil they will be populated with the
// partition and namespace from the token.
ResolveTokenAndDefaultMeta(token string, entMeta *acl.EnterpriseMeta, authzCtx *acl.AuthorizerContext) (resolver.Result, error)
// GetAgentCACertificates returns the CA certificate to be returned in the peering token data // GetAgentCACertificates returns the CA certificate to be returned in the peering token data
GetAgentCACertificates() ([]string, error) GetAgentCACertificates() ([]string, error)
@ -165,11 +187,11 @@ func (s *Server) GenerateToken(
return nil, fmt.Errorf("meta tags failed validation: %w", err) return nil, fmt.Errorf("meta tags failed validation: %w", err)
} }
// TODO(peering): add metrics defer metrics.MeasureSince([]string{"peering", "generate_token"}, time.Now())
// TODO(peering): add tracing
resp := &pbpeering.GenerateTokenResponse{} resp := &pbpeering.GenerateTokenResponse{}
handled, err := s.ForwardRPC(req, func(conn *grpc.ClientConn) error { handled, err := s.ForwardRPC(&writeRequest, func(conn *grpc.ClientConn) error {
ctx := external.ForwardMetadataContext(ctx)
var err error var err error
resp, err = pbpeering.NewPeeringServiceClient(conn).GenerateToken(ctx, req) resp, err = pbpeering.NewPeeringServiceClient(conn).GenerateToken(ctx, req)
return err return err
@ -178,6 +200,17 @@ func (s *Server) GenerateToken(
return resp, err return resp, err
} }
var authzCtx acl.AuthorizerContext
entMeta := structs.DefaultEnterpriseMetaInPartition(req.Partition)
authz, err := s.Backend.ResolveTokenAndDefaultMeta(external.TokenFromContext(ctx), entMeta, &authzCtx)
if err != nil {
return nil, err
}
if err := authz.ToAllowAuthorizer().PeeringWriteAllowed(&authzCtx); err != nil {
return nil, err
}
ca, err := s.Backend.GetAgentCACertificates() ca, err := s.Backend.GetAgentCACertificates()
if err != nil { if err != nil {
return nil, err return nil, err
@ -194,7 +227,7 @@ func (s *Server) GenerateToken(
} }
} }
peeringOrNil, err := s.getExistingPeering(req.PeerName, req.Partition) peeringOrNil, err := s.getExistingPeering(req.PeerName, entMeta.PartitionOrDefault())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -206,7 +239,7 @@ func (s *Server) GenerateToken(
canRetry := true canRetry := true
RETRY_ONCE: RETRY_ONCE:
id, err := s.getExistingOrCreateNewPeerID(req.PeerName, req.Partition) id, err := s.getExistingOrCreateNewPeerID(req.PeerName, entMeta.PartitionOrDefault())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -214,9 +247,10 @@ RETRY_ONCE:
Peering: &pbpeering.Peering{ Peering: &pbpeering.Peering{
ID: id, ID: id,
Name: req.PeerName, Name: req.PeerName,
// TODO(peering): Normalize from ACL token once this endpoint is guarded by ACLs. Meta: req.Meta,
Partition: req.PartitionOrDefault(),
Meta: req.Meta, // PartitionOrEmpty is used to avoid writing "default" in OSS.
Partition: entMeta.PartitionOrEmpty(),
}, },
} }
if err := s.Backend.PeeringWrite(&writeReq); err != nil { if err := s.Backend.PeeringWrite(&writeReq); err != nil {
@ -234,7 +268,7 @@ RETRY_ONCE:
q := state.Query{ q := state.Query{
Value: strings.ToLower(req.PeerName), Value: strings.ToLower(req.PeerName),
EnterpriseMeta: *structs.NodeEnterpriseMetaInPartition(req.Partition), EnterpriseMeta: *entMeta,
} }
_, peering, err := s.Backend.Store().PeeringRead(nil, q) _, peering, err := s.Backend.Store().PeeringRead(nil, q)
if err != nil { if err != nil {
@ -288,7 +322,8 @@ func (s *Server) Establish(
} }
resp := &pbpeering.EstablishResponse{} resp := &pbpeering.EstablishResponse{}
handled, err := s.ForwardRPC(req, func(conn *grpc.ClientConn) error { handled, err := s.ForwardRPC(&writeRequest, func(conn *grpc.ClientConn) error {
ctx := external.ForwardMetadataContext(ctx)
var err error var err error
resp, err = pbpeering.NewPeeringServiceClient(conn).Establish(ctx, req) resp, err = pbpeering.NewPeeringServiceClient(conn).Establish(ctx, req)
return err return err
@ -299,7 +334,18 @@ func (s *Server) Establish(
defer metrics.MeasureSince([]string{"peering", "establish"}, time.Now()) defer metrics.MeasureSince([]string{"peering", "establish"}, time.Now())
peeringOrNil, err := s.getExistingPeering(req.PeerName, req.Partition) var authzCtx acl.AuthorizerContext
entMeta := structs.DefaultEnterpriseMetaInPartition(req.Partition)
authz, err := s.Backend.ResolveTokenAndDefaultMeta(external.TokenFromContext(ctx), entMeta, &authzCtx)
if err != nil {
return nil, err
}
if err := authz.ToAllowAuthorizer().PeeringWriteAllowed(&authzCtx); err != nil {
return nil, err
}
peeringOrNil, err := s.getExistingPeering(req.PeerName, entMeta.PartitionOrDefault())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -341,6 +387,9 @@ func (s *Server) Establish(
PeerID: tok.PeerID, PeerID: tok.PeerID,
Meta: req.Meta, Meta: req.Meta,
State: pbpeering.PeeringState_ESTABLISHING, State: pbpeering.PeeringState_ESTABLISHING,
// PartitionOrEmpty is used to avoid writing "default" in OSS.
Partition: entMeta.PartitionOrEmpty(),
}, },
} }
if err = s.Backend.PeeringWrite(writeReq); err != nil { if err = s.Backend.PeeringWrite(writeReq); err != nil {
@ -350,6 +399,7 @@ func (s *Server) Establish(
return resp, nil return resp, nil
} }
// OPTIMIZE: Handle blocking queries
func (s *Server) PeeringRead(ctx context.Context, req *pbpeering.PeeringReadRequest) (*pbpeering.PeeringReadResponse, error) { func (s *Server) PeeringRead(ctx context.Context, req *pbpeering.PeeringReadRequest) (*pbpeering.PeeringReadResponse, error) {
if !s.Config.PeeringEnabled { if !s.Config.PeeringEnabled {
return nil, peeringNotEnabledErr return nil, peeringNotEnabledErr
@ -360,7 +410,8 @@ func (s *Server) PeeringRead(ctx context.Context, req *pbpeering.PeeringReadRequ
} }
var resp *pbpeering.PeeringReadResponse var resp *pbpeering.PeeringReadResponse
handled, err := s.ForwardRPC(req, func(conn *grpc.ClientConn) error { handled, err := s.ForwardRPC(&readRequest, func(conn *grpc.ClientConn) error {
ctx := external.ForwardMetadataContext(ctx)
var err error var err error
resp, err = pbpeering.NewPeeringServiceClient(conn).PeeringRead(ctx, req) resp, err = pbpeering.NewPeeringServiceClient(conn).PeeringRead(ctx, req)
return err return err
@ -370,12 +421,22 @@ func (s *Server) PeeringRead(ctx context.Context, req *pbpeering.PeeringReadRequ
} }
defer metrics.MeasureSince([]string{"peering", "read"}, time.Now()) defer metrics.MeasureSince([]string{"peering", "read"}, time.Now())
// TODO(peering): ACL check request token
// TODO(peering): handle blocking queries var authzCtx acl.AuthorizerContext
entMeta := structs.DefaultEnterpriseMetaInPartition(req.Partition)
authz, err := s.Backend.ResolveTokenAndDefaultMeta(external.TokenFromContext(ctx), entMeta, &authzCtx)
if err != nil {
return nil, err
}
if err := authz.ToAllowAuthorizer().PeeringReadAllowed(&authzCtx); err != nil {
return nil, err
}
q := state.Query{ q := state.Query{
Value: strings.ToLower(req.Name), Value: strings.ToLower(req.Name),
EnterpriseMeta: *structs.NodeEnterpriseMetaInPartition(req.Partition)} EnterpriseMeta: *entMeta,
}
_, peering, err := s.Backend.Store().PeeringRead(nil, q) _, peering, err := s.Backend.Store().PeeringRead(nil, q)
if err != nil { if err != nil {
return nil, err return nil, err
@ -388,6 +449,7 @@ func (s *Server) PeeringRead(ctx context.Context, req *pbpeering.PeeringReadRequ
return &pbpeering.PeeringReadResponse{Peering: cp}, nil return &pbpeering.PeeringReadResponse{Peering: cp}, nil
} }
// OPTIMIZE: Handle blocking queries
func (s *Server) PeeringList(ctx context.Context, req *pbpeering.PeeringListRequest) (*pbpeering.PeeringListResponse, error) { func (s *Server) PeeringList(ctx context.Context, req *pbpeering.PeeringListRequest) (*pbpeering.PeeringListResponse, error) {
if !s.Config.PeeringEnabled { if !s.Config.PeeringEnabled {
return nil, peeringNotEnabledErr return nil, peeringNotEnabledErr
@ -398,7 +460,8 @@ func (s *Server) PeeringList(ctx context.Context, req *pbpeering.PeeringListRequ
} }
var resp *pbpeering.PeeringListResponse var resp *pbpeering.PeeringListResponse
handled, err := s.ForwardRPC(req, func(conn *grpc.ClientConn) error { handled, err := s.ForwardRPC(&readRequest, func(conn *grpc.ClientConn) error {
ctx := external.ForwardMetadataContext(ctx)
var err error var err error
resp, err = pbpeering.NewPeeringServiceClient(conn).PeeringList(ctx, req) resp, err = pbpeering.NewPeeringServiceClient(conn).PeeringList(ctx, req)
return err return err
@ -407,11 +470,20 @@ func (s *Server) PeeringList(ctx context.Context, req *pbpeering.PeeringListRequ
return resp, err return resp, err
} }
defer metrics.MeasureSince([]string{"peering", "list"}, time.Now()) var authzCtx acl.AuthorizerContext
// TODO(peering): ACL check request token entMeta := structs.DefaultEnterpriseMetaInPartition(req.Partition)
authz, err := s.Backend.ResolveTokenAndDefaultMeta(external.TokenFromContext(ctx), entMeta, &authzCtx)
if err != nil {
return nil, err
}
// TODO(peering): handle blocking queries if err := authz.ToAllowAuthorizer().PeeringReadAllowed(&authzCtx); err != nil {
_, peerings, err := s.Backend.Store().PeeringList(nil, *structs.NodeEnterpriseMetaInPartition(req.Partition)) return nil, err
}
defer metrics.MeasureSince([]string{"peering", "list"}, time.Now())
_, peerings, err := s.Backend.Store().PeeringList(nil, *entMeta)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -465,7 +537,8 @@ func (s *Server) PeeringWrite(ctx context.Context, req *pbpeering.PeeringWriteRe
} }
var resp *pbpeering.PeeringWriteResponse var resp *pbpeering.PeeringWriteResponse
handled, err := s.ForwardRPC(req, func(conn *grpc.ClientConn) error { handled, err := s.ForwardRPC(&writeRequest, func(conn *grpc.ClientConn) error {
ctx := external.ForwardMetadataContext(ctx)
var err error var err error
resp, err = pbpeering.NewPeeringServiceClient(conn).PeeringWrite(ctx, req) resp, err = pbpeering.NewPeeringServiceClient(conn).PeeringWrite(ctx, req)
return err return err
@ -475,19 +548,28 @@ func (s *Server) PeeringWrite(ctx context.Context, req *pbpeering.PeeringWriteRe
} }
defer metrics.MeasureSince([]string{"peering", "write"}, time.Now()) defer metrics.MeasureSince([]string{"peering", "write"}, time.Now())
// TODO(peering): ACL check request token
var authzCtx acl.AuthorizerContext
entMeta := structs.DefaultEnterpriseMetaInPartition(req.Peering.Partition)
authz, err := s.Backend.ResolveTokenAndDefaultMeta(external.TokenFromContext(ctx), entMeta, &authzCtx)
if err != nil {
return nil, err
}
if err := authz.ToAllowAuthorizer().PeeringWriteAllowed(&authzCtx); err != nil {
return nil, err
}
if req.Peering == nil { if req.Peering == nil {
return nil, fmt.Errorf("missing required peering body") return nil, fmt.Errorf("missing required peering body")
} }
id, err := s.getExistingOrCreateNewPeerID(req.Peering.Name, req.Peering.Partition) id, err := s.getExistingOrCreateNewPeerID(req.Peering.Name, entMeta.PartitionOrDefault())
if err != nil { if err != nil {
return nil, err return nil, err
} }
req.Peering.ID = id req.Peering.ID = id
// TODO(peering): handle blocking queries
err = s.Backend.PeeringWrite(req) err = s.Backend.PeeringWrite(req)
if err != nil { if err != nil {
return nil, err return nil, err
@ -505,7 +587,8 @@ func (s *Server) PeeringDelete(ctx context.Context, req *pbpeering.PeeringDelete
} }
var resp *pbpeering.PeeringDeleteResponse var resp *pbpeering.PeeringDeleteResponse
handled, err := s.ForwardRPC(req, func(conn *grpc.ClientConn) error { handled, err := s.ForwardRPC(&writeRequest, func(conn *grpc.ClientConn) error {
ctx := external.ForwardMetadataContext(ctx)
var err error var err error
resp, err = pbpeering.NewPeeringServiceClient(conn).PeeringDelete(ctx, req) resp, err = pbpeering.NewPeeringServiceClient(conn).PeeringDelete(ctx, req)
return err return err
@ -515,13 +598,21 @@ func (s *Server) PeeringDelete(ctx context.Context, req *pbpeering.PeeringDelete
} }
defer metrics.MeasureSince([]string{"peering", "delete"}, time.Now()) defer metrics.MeasureSince([]string{"peering", "delete"}, time.Now())
// TODO(peering): ACL check request token
// TODO(peering): handle blocking queries var authzCtx acl.AuthorizerContext
entMeta := structs.DefaultEnterpriseMetaInPartition(req.Partition)
authz, err := s.Backend.ResolveTokenAndDefaultMeta(external.TokenFromContext(ctx), entMeta, &authzCtx)
if err != nil {
return nil, err
}
if err := authz.ToAllowAuthorizer().PeeringWriteAllowed(&authzCtx); err != nil {
return nil, err
}
q := state.Query{ q := state.Query{
Value: strings.ToLower(req.Name), Value: strings.ToLower(req.Name),
EnterpriseMeta: *structs.NodeEnterpriseMetaInPartition(req.Partition), EnterpriseMeta: *entMeta,
} }
_, existing, err := s.Backend.Store().PeeringRead(nil, q) _, existing, err := s.Backend.Store().PeeringRead(nil, q)
if err != nil { if err != nil {
@ -543,9 +634,11 @@ func (s *Server) PeeringDelete(ctx context.Context, req *pbpeering.PeeringDelete
// for deletion the peering is effectively gone. // for deletion the peering is effectively gone.
ID: existing.ID, ID: existing.ID,
Name: req.Name, Name: req.Name,
Partition: req.Partition,
State: pbpeering.PeeringState_DELETING, State: pbpeering.PeeringState_DELETING,
DeletedAt: structs.TimeToProto(time.Now().UTC()), DeletedAt: structs.TimeToProto(time.Now().UTC()),
// PartitionOrEmpty is used to avoid writing "default" in OSS.
Partition: entMeta.PartitionOrEmpty(),
}, },
} }
err = s.Backend.PeeringWrite(writeReq) err = s.Backend.PeeringWrite(writeReq)
@ -555,6 +648,7 @@ func (s *Server) PeeringDelete(ctx context.Context, req *pbpeering.PeeringDelete
return &pbpeering.PeeringDeleteResponse{}, nil return &pbpeering.PeeringDeleteResponse{}, nil
} }
// OPTIMIZE: Handle blocking queries
func (s *Server) TrustBundleRead(ctx context.Context, req *pbpeering.TrustBundleReadRequest) (*pbpeering.TrustBundleReadResponse, error) { func (s *Server) TrustBundleRead(ctx context.Context, req *pbpeering.TrustBundleReadRequest) (*pbpeering.TrustBundleReadResponse, error) {
if !s.Config.PeeringEnabled { if !s.Config.PeeringEnabled {
return nil, peeringNotEnabledErr return nil, peeringNotEnabledErr
@ -565,7 +659,8 @@ func (s *Server) TrustBundleRead(ctx context.Context, req *pbpeering.TrustBundle
} }
var resp *pbpeering.TrustBundleReadResponse var resp *pbpeering.TrustBundleReadResponse
handled, err := s.ForwardRPC(req, func(conn *grpc.ClientConn) error { handled, err := s.ForwardRPC(&readRequest, func(conn *grpc.ClientConn) error {
ctx := external.ForwardMetadataContext(ctx)
var err error var err error
resp, err = pbpeering.NewPeeringServiceClient(conn).TrustBundleRead(ctx, req) resp, err = pbpeering.NewPeeringServiceClient(conn).TrustBundleRead(ctx, req)
return err return err
@ -575,13 +670,21 @@ func (s *Server) TrustBundleRead(ctx context.Context, req *pbpeering.TrustBundle
} }
defer metrics.MeasureSince([]string{"peering", "trust_bundle_read"}, time.Now()) defer metrics.MeasureSince([]string{"peering", "trust_bundle_read"}, time.Now())
// TODO(peering): ACL check request token
// TODO(peering): handle blocking queries var authzCtx acl.AuthorizerContext
entMeta := structs.DefaultEnterpriseMetaInPartition(req.Partition)
authz, err := s.Backend.ResolveTokenAndDefaultMeta(external.TokenFromContext(ctx), entMeta, &authzCtx)
if err != nil {
return nil, err
}
if err := authz.ToAllowAuthorizer().ServiceWriteAnyAllowed(&authzCtx); err != nil {
return nil, err
}
idx, trustBundle, err := s.Backend.Store().PeeringTrustBundleRead(nil, state.Query{ idx, trustBundle, err := s.Backend.Store().PeeringTrustBundleRead(nil, state.Query{
Value: req.Name, Value: req.Name,
EnterpriseMeta: *structs.NodeEnterpriseMetaInPartition(req.Partition), EnterpriseMeta: *entMeta,
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to read trust bundle for peer %s: %w", req.Name, err) return nil, fmt.Errorf("failed to read trust bundle for peer %s: %w", req.Name, err)
@ -594,6 +697,7 @@ func (s *Server) TrustBundleRead(ctx context.Context, req *pbpeering.TrustBundle
} }
// TODO(peering): rename rpc & request/response to drop the "service" part // TODO(peering): rename rpc & request/response to drop the "service" part
// OPTIMIZE: Handle blocking queries
func (s *Server) TrustBundleListByService(ctx context.Context, req *pbpeering.TrustBundleListByServiceRequest) (*pbpeering.TrustBundleListByServiceResponse, error) { func (s *Server) TrustBundleListByService(ctx context.Context, req *pbpeering.TrustBundleListByServiceRequest) (*pbpeering.TrustBundleListByServiceResponse, error) {
if !s.Config.PeeringEnabled { if !s.Config.PeeringEnabled {
return nil, peeringNotEnabledErr return nil, peeringNotEnabledErr
@ -605,9 +709,13 @@ func (s *Server) TrustBundleListByService(ctx context.Context, req *pbpeering.Tr
if err := s.Backend.EnterpriseCheckNamespaces(req.Namespace); err != nil { if err := s.Backend.EnterpriseCheckNamespaces(req.Namespace); err != nil {
return nil, grpcstatus.Error(codes.InvalidArgument, err.Error()) return nil, grpcstatus.Error(codes.InvalidArgument, err.Error())
} }
if req.ServiceName == "" {
return nil, errors.New("missing service name")
}
var resp *pbpeering.TrustBundleListByServiceResponse var resp *pbpeering.TrustBundleListByServiceResponse
handled, err := s.ForwardRPC(req, func(conn *grpc.ClientConn) error { handled, err := s.ForwardRPC(&readRequest, func(conn *grpc.ClientConn) error {
ctx := external.ForwardMetadataContext(ctx)
var err error var err error
resp, err = pbpeering.NewPeeringServiceClient(conn).TrustBundleListByService(ctx, req) resp, err = pbpeering.NewPeeringServiceClient(conn).TrustBundleListByService(ctx, req)
return err return err
@ -617,11 +725,17 @@ func (s *Server) TrustBundleListByService(ctx context.Context, req *pbpeering.Tr
} }
defer metrics.MeasureSince([]string{"peering", "trust_bundle_list_by_service"}, time.Now()) defer metrics.MeasureSince([]string{"peering", "trust_bundle_list_by_service"}, time.Now())
// TODO(peering): ACL check request token for service:write on the service name
// TODO(peering): handle blocking queries
var authzCtx acl.AuthorizerContext
entMeta := acl.NewEnterpriseMetaWithPartition(req.Partition, req.Namespace) entMeta := acl.NewEnterpriseMetaWithPartition(req.Partition, req.Namespace)
authz, err := s.Backend.ResolveTokenAndDefaultMeta(external.TokenFromContext(ctx), &entMeta, &authzCtx)
if err != nil {
return nil, err
}
if err := authz.ToAllowAuthorizer().ServiceWriteAllowed(req.ServiceName, &authzCtx); err != nil {
return nil, err
}
var ( var (
idx uint64 idx uint64
@ -629,10 +743,10 @@ func (s *Server) TrustBundleListByService(ctx context.Context, req *pbpeering.Tr
) )
switch { switch {
case req.ServiceName != "":
idx, bundles, err = s.Backend.Store().TrustBundleListByService(nil, req.ServiceName, s.Datacenter, entMeta)
case req.Kind == string(structs.ServiceKindMeshGateway): case req.Kind == string(structs.ServiceKindMeshGateway):
idx, bundles, err = s.Backend.Store().PeeringTrustBundleList(nil, entMeta) idx, bundles, err = s.Backend.Store().PeeringTrustBundleList(nil, entMeta)
case req.ServiceName != "":
idx, bundles, err = s.Backend.Store().TrustBundleListByService(nil, req.ServiceName, s.Datacenter, entMeta)
case req.Kind != "": case req.Kind != "":
return nil, grpcstatus.Error(codes.InvalidArgument, "kind must be mesh-gateway if set") return nil, grpcstatus.Error(codes.InvalidArgument, "kind must be mesh-gateway if set")
default: default:

View File

@ -22,6 +22,7 @@ import (
"github.com/hashicorp/consul/agent/consul" "github.com/hashicorp/consul/agent/consul"
"github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/consul/state"
"github.com/hashicorp/consul/agent/consul/stream" "github.com/hashicorp/consul/agent/consul/stream"
external "github.com/hashicorp/consul/agent/grpc-external"
grpc "github.com/hashicorp/consul/agent/grpc-internal" grpc "github.com/hashicorp/consul/agent/grpc-internal"
"github.com/hashicorp/consul/agent/grpc-internal/resolver" "github.com/hashicorp/consul/agent/grpc-internal/resolver"
"github.com/hashicorp/consul/agent/pool" "github.com/hashicorp/consul/agent/pool"
@ -41,6 +42,13 @@ import (
"github.com/hashicorp/consul/types" "github.com/hashicorp/consul/types"
) )
const (
testTokenPeeringReadSecret = "9a83c138-a0c7-40f1-89fa-6acf9acd78f5"
testTokenPeeringWriteSecret = "91f90a41-0840-4afe-b615-68745f9e16c1"
testTokenServiceReadSecret = "1ef8e3cf-6e95-49aa-9f73-a0d3ad1a77d4"
testTokenServiceWriteSecret = "4a3dc05d-d86c-4f20-be43-8f4f8f045fea"
)
func generateTooManyMetaKeys() map[string]string { func generateTooManyMetaKeys() map[string]string {
// todo -- modularize in structs.go or testing.go // todo -- modularize in structs.go or testing.go
tooMuchMeta := make(map[string]string) tooMuchMeta := make(map[string]string)
@ -70,12 +78,12 @@ func TestPeeringService_GenerateToken(t *testing.T) {
// TODO(peering): for more failure cases, consider using a table test // TODO(peering): for more failure cases, consider using a table test
// check meta tags // check meta tags
reqE := pbpeering.GenerateTokenRequest{PeerName: "peerB", Datacenter: "dc1", Meta: generateTooManyMetaKeys()} reqE := pbpeering.GenerateTokenRequest{PeerName: "peerB", Meta: generateTooManyMetaKeys()}
_, errE := client.GenerateToken(ctx, &reqE) _, errE := client.GenerateToken(ctx, &reqE)
require.EqualError(t, errE, "rpc error: code = Unknown desc = meta tags failed validation: Node metadata cannot contain more than 64 key/value pairs") require.EqualError(t, errE, "rpc error: code = Unknown desc = meta tags failed validation: Node metadata cannot contain more than 64 key/value pairs")
// happy path // happy path
req := pbpeering.GenerateTokenRequest{PeerName: "peerB", Datacenter: "dc1", Meta: map[string]string{"foo": "bar"}} req := pbpeering.GenerateTokenRequest{PeerName: "peerB", Meta: map[string]string{"foo": "bar"}}
resp, err := client.GenerateToken(ctx, &req) resp, err := client.GenerateToken(ctx, &req)
require.NoError(t, err) require.NoError(t, err)
@ -129,7 +137,7 @@ func TestPeeringService_GenerateTokenExternalAddress(t *testing.T) {
externalAddress := "32.1.2.3:8502" externalAddress := "32.1.2.3:8502"
// happy path // happy path
req := pbpeering.GenerateTokenRequest{PeerName: "peerB", Datacenter: "dc1", Meta: map[string]string{"foo": "bar"}, ServerExternalAddresses: []string{externalAddress}} req := pbpeering.GenerateTokenRequest{PeerName: "peerB", Meta: map[string]string{"foo": "bar"}, ServerExternalAddresses: []string{externalAddress}}
resp, err := client.GenerateToken(ctx, &req) resp, err := client.GenerateToken(ctx, &req)
require.NoError(t, err) require.NoError(t, err)
@ -144,6 +152,62 @@ func TestPeeringService_GenerateTokenExternalAddress(t *testing.T) {
require.Equal(t, []string{ca}, token.CA) require.Equal(t, []string{ca}, token.CA)
} }
func TestPeeringService_GenerateToken_ACLEnforcement(t *testing.T) {
// TODO(peering): see note on newTestServer, refactor to not use this
s := newTestServer(t, func(conf *consul.Config) {
conf.ACLsEnabled = true
conf.ACLResolverSettings.ACLDefaultPolicy = acl.PolicyDeny
})
upsertTestACLs(t, s.Server.FSM().State())
client := pbpeering.NewPeeringServiceClient(s.ClientConn(t))
type testcase struct {
name string
req *pbpeering.GenerateTokenRequest
token string
expectErr string
}
run := func(t *testing.T, tc testcase) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
t.Cleanup(cancel)
_, err := client.GenerateToken(external.ContextWithToken(ctx, tc.token), tc.req)
if tc.expectErr != "" {
require.Contains(t, err.Error(), tc.expectErr)
return
}
require.NoError(t, err)
}
tcs := []testcase{
{
name: "anonymous token lacks permissions",
req: &pbpeering.GenerateTokenRequest{PeerName: "foo"},
expectErr: "lacks permission 'peering:write'",
},
{
name: "read token lacks permissions",
req: &pbpeering.GenerateTokenRequest{
PeerName: "foo",
},
token: testTokenPeeringReadSecret,
expectErr: "lacks permission 'peering:write'",
},
{
name: "write token grants permission",
req: &pbpeering.GenerateTokenRequest{
PeerName: "foo",
},
token: testTokenPeeringWriteSecret,
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
run(t, tc)
})
}
}
func TestPeeringService_Establish(t *testing.T) { func TestPeeringService_Establish(t *testing.T) {
validToken := peering.TestPeeringToken("83474a06-cca4-4ff4-99a4-4152929c8160") validToken := peering.TestPeeringToken("83474a06-cca4-4ff4-99a4-4152929c8160")
validTokenJSON, _ := json.Marshal(&validToken) validTokenJSON, _ := json.Marshal(&validToken)
@ -250,6 +314,71 @@ func TestPeeringService_Establish(t *testing.T) {
} }
} }
func TestPeeringService_Establish_ACLEnforcement(t *testing.T) {
validToken := peering.TestPeeringToken("83474a06-cca4-4ff4-99a4-4152929c8160")
validTokenJSON, _ := json.Marshal(&validToken)
validTokenB64 := base64.StdEncoding.EncodeToString(validTokenJSON)
// TODO(peering): see note on newTestServer, refactor to not use this
s := newTestServer(t, func(conf *consul.Config) {
conf.ACLsEnabled = true
conf.ACLResolverSettings.ACLDefaultPolicy = acl.PolicyDeny
})
upsertTestACLs(t, s.Server.FSM().State())
client := pbpeering.NewPeeringServiceClient(s.ClientConn(t))
type testcase struct {
name string
req *pbpeering.EstablishRequest
token string
expectErr string
}
run := func(t *testing.T, tc testcase) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
t.Cleanup(cancel)
_, err := client.Establish(external.ContextWithToken(ctx, tc.token), tc.req)
if tc.expectErr != "" {
require.Contains(t, err.Error(), tc.expectErr)
return
}
require.NoError(t, err)
}
tcs := []testcase{
{
name: "anonymous token lacks permissions",
req: &pbpeering.EstablishRequest{
PeerName: "foo",
PeeringToken: validTokenB64,
},
expectErr: "lacks permission 'peering:write'",
},
{
name: "read token lacks permissions",
req: &pbpeering.EstablishRequest{
PeerName: "foo",
PeeringToken: validTokenB64,
},
token: testTokenPeeringReadSecret,
expectErr: "lacks permission 'peering:write'",
},
{
name: "write token grants permission",
req: &pbpeering.EstablishRequest{
PeerName: "foo",
PeeringToken: validTokenB64,
},
token: testTokenPeeringWriteSecret,
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
run(t, tc)
})
}
}
func TestPeeringService_Read(t *testing.T) { func TestPeeringService_Read(t *testing.T) {
// TODO(peering): see note on newTestServer, refactor to not use this // TODO(peering): see note on newTestServer, refactor to not use this
s := newTestServer(t, nil) s := newTestServer(t, nil)
@ -309,6 +438,72 @@ func TestPeeringService_Read(t *testing.T) {
} }
} }
func TestPeeringService_Read_ACLEnforcement(t *testing.T) {
// TODO(peering): see note on newTestServer, refactor to not use this
s := newTestServer(t, func(conf *consul.Config) {
conf.ACLsEnabled = true
conf.ACLResolverSettings.ACLDefaultPolicy = acl.PolicyDeny
})
upsertTestACLs(t, s.Server.FSM().State())
// insert peering directly to state store
p := &pbpeering.Peering{
ID: testUUID(t),
Name: "foo",
State: pbpeering.PeeringState_ESTABLISHING,
PeerCAPems: nil,
PeerServerName: "test",
PeerServerAddresses: []string{"addr1"},
ImportedServiceCount: 0,
ExportedServiceCount: 0,
}
err := s.Server.FSM().State().PeeringWrite(10, p)
require.NoError(t, err)
client := pbpeering.NewPeeringServiceClient(s.ClientConn(t))
type testcase struct {
name string
req *pbpeering.PeeringReadRequest
expect *pbpeering.PeeringReadResponse
token string
expectErr string
}
run := func(t *testing.T, tc testcase) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
t.Cleanup(cancel)
resp, err := client.PeeringRead(external.ContextWithToken(ctx, tc.token), tc.req)
if tc.expectErr != "" {
require.Contains(t, err.Error(), tc.expectErr)
return
}
require.NoError(t, err)
prototest.AssertDeepEqual(t, tc.expect, resp)
}
tcs := []testcase{
{
name: "anonymous token lacks permissions",
req: &pbpeering.PeeringReadRequest{Name: "foo"},
expect: &pbpeering.PeeringReadResponse{Peering: p},
expectErr: "lacks permission 'peering:read'",
},
{
name: "read token grants permission",
req: &pbpeering.PeeringReadRequest{
Name: "foo",
},
expect: &pbpeering.PeeringReadResponse{Peering: p},
token: testTokenPeeringReadSecret,
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
run(t, tc)
})
}
}
func TestPeeringService_Delete(t *testing.T) { func TestPeeringService_Delete(t *testing.T) {
// TODO(peering): see note on newTestServer, refactor to not use this // TODO(peering): see note on newTestServer, refactor to not use this
s := newTestServer(t, nil) s := newTestServer(t, nil)
@ -344,6 +539,76 @@ func TestPeeringService_Delete(t *testing.T) {
}) })
} }
func TestPeeringService_Delete_ACLEnforcement(t *testing.T) {
// TODO(peering): see note on newTestServer, refactor to not use this
s := newTestServer(t, func(conf *consul.Config) {
conf.ACLsEnabled = true
conf.ACLResolverSettings.ACLDefaultPolicy = acl.PolicyDeny
})
upsertTestACLs(t, s.Server.FSM().State())
p := &pbpeering.Peering{
ID: testUUID(t),
Name: "foo",
State: pbpeering.PeeringState_ESTABLISHING,
PeerCAPems: nil,
PeerServerName: "test",
PeerServerAddresses: []string{"addr1"},
}
err := s.Server.FSM().State().PeeringWrite(10, p)
require.NoError(t, err)
require.Nil(t, p.DeletedAt)
require.True(t, p.IsActive())
client := pbpeering.NewPeeringServiceClient(s.ClientConn(t))
type testcase struct {
name string
req *pbpeering.PeeringDeleteRequest
token string
expectErr string
}
run := func(t *testing.T, tc testcase) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
t.Cleanup(cancel)
_, err = client.PeeringDelete(external.ContextWithToken(ctx, tc.token), tc.req)
if tc.expectErr != "" {
require.Contains(t, err.Error(), tc.expectErr)
return
}
require.NoError(t, err)
}
tcs := []testcase{
{
name: "anonymous token lacks permissions",
req: &pbpeering.PeeringDeleteRequest{Name: "foo"},
expectErr: "lacks permission 'peering:write'",
},
{
name: "read token lacks permissions",
req: &pbpeering.PeeringDeleteRequest{
Name: "foo",
},
token: testTokenPeeringReadSecret,
expectErr: "lacks permission 'peering:write'",
},
{
name: "write token grants permission",
req: &pbpeering.PeeringDeleteRequest{
Name: "foo",
},
token: testTokenPeeringWriteSecret,
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
run(t, tc)
})
}
}
func TestPeeringService_List(t *testing.T) { func TestPeeringService_List(t *testing.T) {
// TODO(peering): see note on newTestServer, refactor to not use this // TODO(peering): see note on newTestServer, refactor to not use this
s := newTestServer(t, nil) s := newTestServer(t, nil)
@ -388,6 +653,78 @@ func TestPeeringService_List(t *testing.T) {
prototest.AssertDeepEqual(t, expect, resp) prototest.AssertDeepEqual(t, expect, resp)
} }
func TestPeeringService_List_ACLEnforcement(t *testing.T) {
// TODO(peering): see note on newTestServer, refactor to not use this
s := newTestServer(t, func(conf *consul.Config) {
conf.ACLsEnabled = true
conf.ACLResolverSettings.ACLDefaultPolicy = acl.PolicyDeny
})
upsertTestACLs(t, s.Server.FSM().State())
// insert peering directly to state store
foo := &pbpeering.Peering{
ID: testUUID(t),
Name: "foo",
State: pbpeering.PeeringState_ESTABLISHING,
PeerCAPems: nil,
PeerServerName: "fooservername",
PeerServerAddresses: []string{"addr1"},
ImportedServiceCount: 0,
ExportedServiceCount: 0,
}
require.NoError(t, s.Server.FSM().State().PeeringWrite(10, foo))
bar := &pbpeering.Peering{
ID: testUUID(t),
Name: "bar",
State: pbpeering.PeeringState_ACTIVE,
PeerCAPems: nil,
PeerServerName: "barservername",
PeerServerAddresses: []string{"addr1"},
ImportedServiceCount: 0,
ExportedServiceCount: 0,
}
require.NoError(t, s.Server.FSM().State().PeeringWrite(15, bar))
client := pbpeering.NewPeeringServiceClient(s.ClientConn(t))
type testcase struct {
name string
token string
expect *pbpeering.PeeringListResponse
expectErr string
}
run := func(t *testing.T, tc testcase) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
t.Cleanup(cancel)
resp, err := client.PeeringList(external.ContextWithToken(ctx, tc.token), &pbpeering.PeeringListRequest{})
if tc.expectErr != "" {
require.Contains(t, err.Error(), tc.expectErr)
return
}
require.NoError(t, err)
prototest.AssertDeepEqual(t, tc.expect, resp)
}
tcs := []testcase{
{
name: "anonymous token lacks permissions",
expectErr: "lacks permission 'peering:read'",
},
{
name: "read token grants permission",
token: testTokenPeeringReadSecret,
expect: &pbpeering.PeeringListResponse{
Peerings: []*pbpeering.Peering{bar, foo},
},
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
run(t, tc)
})
}
}
func TestPeeringService_TrustBundleRead(t *testing.T) { func TestPeeringService_TrustBundleRead(t *testing.T) {
srv := newTestServer(t, nil) srv := newTestServer(t, nil)
store := srv.Server.FSM().State() store := srv.Server.FSM().State()
@ -396,25 +733,6 @@ func TestPeeringService_TrustBundleRead(t *testing.T) {
var lastIdx uint64 = 1 var lastIdx uint64 = 1
_ = setupTestPeering(t, store, "my-peering", lastIdx) _ = setupTestPeering(t, store, "my-peering", lastIdx)
mysql := &structs.CheckServiceNode{
Node: &structs.Node{
Node: "node1",
Address: "10.0.0.1",
PeerName: "my-peering",
},
Service: &structs.NodeService{
ID: "mysql-1",
Service: "mysql",
Port: 5000,
PeerName: "my-peering",
},
}
lastIdx++
require.NoError(t, store.EnsureNode(lastIdx, mysql.Node))
lastIdx++
require.NoError(t, store.EnsureService(lastIdx, mysql.Node.Node, mysql.Service))
bundle := &pbpeering.PeeringTrustBundle{ bundle := &pbpeering.PeeringTrustBundle{
TrustDomain: "peer1.com", TrustDomain: "peer1.com",
PeerName: "my-peering", PeerName: "my-peering",
@ -435,6 +753,76 @@ func TestPeeringService_TrustBundleRead(t *testing.T) {
prototest.AssertDeepEqual(t, bundle, resp.Bundle) prototest.AssertDeepEqual(t, bundle, resp.Bundle)
} }
func TestPeeringService_TrustBundleRead_ACLEnforcement(t *testing.T) {
// TODO(peering): see note on newTestServer, refactor to not use this
s := newTestServer(t, func(conf *consul.Config) {
conf.ACLsEnabled = true
conf.ACLResolverSettings.ACLDefaultPolicy = acl.PolicyDeny
})
store := s.Server.FSM().State()
upsertTestACLs(t, s.Server.FSM().State())
// Insert peering and trust bundle directly to state store.
_ = setupTestPeering(t, store, "my-peering", 10)
bundle := &pbpeering.PeeringTrustBundle{
TrustDomain: "peer1.com",
PeerName: "my-peering",
RootPEMs: []string{"peer1-root-1"},
}
require.NoError(t, store.PeeringTrustBundleWrite(11, bundle))
client := pbpeering.NewPeeringServiceClient(s.ClientConn(t))
type testcase struct {
name string
req *pbpeering.TrustBundleReadRequest
token string
expect *pbpeering.PeeringTrustBundle
expectErr string
}
run := func(t *testing.T, tc testcase) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
t.Cleanup(cancel)
resp, err := client.TrustBundleRead(external.ContextWithToken(ctx, tc.token), tc.req)
if tc.expectErr != "" {
require.Contains(t, err.Error(), tc.expectErr)
return
}
require.NoError(t, err)
prototest.AssertDeepEqual(t, tc.expect, resp.Bundle)
}
tcs := []testcase{
{
name: "anonymous token lacks permissions",
req: &pbpeering.TrustBundleReadRequest{Name: "foo"},
expectErr: "lacks permission 'service:write'",
},
{
name: "service read token lacks permissions",
req: &pbpeering.TrustBundleReadRequest{
Name: "my-peering",
},
token: testTokenServiceReadSecret,
expectErr: "lacks permission 'service:write'",
},
{
name: "with service write token",
req: &pbpeering.TrustBundleReadRequest{
Name: "my-peering",
},
token: testTokenServiceWriteSecret,
expect: bundle,
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
run(t, tc)
})
}
}
// Setup: // Setup:
// - Peerings "foo" and "bar" with trust bundles saved // - Peerings "foo" and "bar" with trust bundles saved
// - "api" service exported to both "foo" and "bar" // - "api" service exported to both "foo" and "bar"
@ -667,6 +1055,116 @@ func TestPeeringService_PeeringDisabled(t *testing.T) {
}) })
} }
func TestPeeringService_TrustBundleListByService_ACLEnforcement(t *testing.T) {
// TODO(peering): see note on newTestServer, refactor to not use this
s := newTestServer(t, func(conf *consul.Config) {
conf.ACLsEnabled = true
conf.ACLResolverSettings.ACLDefaultPolicy = acl.PolicyDeny
})
store := s.Server.FSM().State()
upsertTestACLs(t, s.Server.FSM().State())
var lastIdx uint64 = 10
lastIdx++
require.NoError(t, s.Server.FSM().State().PeeringWrite(lastIdx, &pbpeering.Peering{
ID: testUUID(t),
Name: "foo",
State: pbpeering.PeeringState_ESTABLISHING,
PeerServerName: "test",
PeerServerAddresses: []string{"addr1"},
}))
lastIdx++
require.NoError(t, store.PeeringTrustBundleWrite(lastIdx, &pbpeering.PeeringTrustBundle{
TrustDomain: "foo.com",
PeerName: "foo",
RootPEMs: []string{"foo-root-1"},
}))
lastIdx++
require.NoError(t, store.EnsureNode(lastIdx, &structs.Node{
Node: "my-node", Address: "127.0.0.1",
}))
lastIdx++
require.NoError(t, store.EnsureService(lastIdx, "my-node", &structs.NodeService{
ID: "api",
Service: "api",
Port: 8000,
}))
entry := structs.ExportedServicesConfigEntry{
Name: "default",
Services: []structs.ExportedService{
{
Name: "api",
Consumers: []structs.ServiceConsumer{
{
PeerName: "foo",
},
},
},
},
}
require.NoError(t, entry.Normalize())
require.NoError(t, entry.Validate())
lastIdx++
require.NoError(t, store.EnsureConfigEntry(lastIdx, &entry))
client := pbpeering.NewPeeringServiceClient(s.ClientConn(t))
type testcase struct {
name string
req *pbpeering.TrustBundleListByServiceRequest
token string
expect []string
expectErr string
}
run := func(t *testing.T, tc testcase) {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
t.Cleanup(cancel)
resp, err := client.TrustBundleListByService(external.ContextWithToken(ctx, tc.token), tc.req)
if tc.expectErr != "" {
require.Contains(t, err.Error(), tc.expectErr)
return
}
require.NoError(t, err)
require.Len(t, resp.Bundles, 1)
require.Equal(t, tc.expect, resp.Bundles[0].RootPEMs)
}
tcs := []testcase{
{
name: "anonymous token lacks permissions",
req: &pbpeering.TrustBundleListByServiceRequest{ServiceName: "api"},
expectErr: "lacks permission 'service:write'",
},
{
name: "service read token lacks permission",
req: &pbpeering.TrustBundleListByServiceRequest{
ServiceName: "api",
},
token: testTokenServiceReadSecret,
expectErr: "lacks permission 'service:write'",
},
{
name: "with service write token",
req: &pbpeering.TrustBundleListByServiceRequest{
ServiceName: "api",
},
token: testTokenServiceWriteSecret,
expect: []string{"foo-root-1"},
},
}
for _, tc := range tcs {
t.Run(tc.name, func(t *testing.T) {
run(t, tc)
})
}
}
// newTestServer is copied from partition/service_test.go, with the addition of certs/cas. // newTestServer is copied from partition/service_test.go, with the addition of certs/cas.
// TODO(peering): these are endpoint tests and should live in the agent/consul // TODO(peering): these are endpoint tests and should live in the agent/consul
// package. Instead, these can be written around a mock client (see testing.go) // package. Instead, these can be written around a mock client (see testing.go)
@ -831,6 +1329,87 @@ func newDefaultDeps(t *testing.T, c *consul.Config) consul.Deps {
} }
} }
func upsertTestACLs(t *testing.T, store *state.Store) {
var (
testPolicyPeeringReadID = "43fed171-ad1d-4d3b-9df3-c99c1c835c37"
testPolicyPeeringWriteID = "cddb0821-e720-4411-bbdd-cc62ce417eac"
testPolicyServiceReadID = "0e054136-f5d3-4627-a7e6-198f1df923d3"
testPolicyServiceWriteID = "b55e03f4-c9dd-4210-8d24-f7ea8e2a1918"
)
policies := structs.ACLPolicies{
{
ID: testPolicyPeeringReadID,
Name: "peering-read",
Rules: `peering = "read"`,
Syntax: acl.SyntaxCurrent,
},
{
ID: testPolicyPeeringWriteID,
Name: "peering-write",
Rules: `peering = "write"`,
Syntax: acl.SyntaxCurrent,
},
{
ID: testPolicyServiceReadID,
Name: "service-read",
Rules: `service "api" { policy = "read" }`,
Syntax: acl.SyntaxCurrent,
},
{
ID: testPolicyServiceWriteID,
Name: "service-write",
Rules: `service "api" { policy = "write" }`,
Syntax: acl.SyntaxCurrent,
},
}
require.NoError(t, store.ACLPolicyBatchSet(100, policies))
tokens := structs.ACLTokens{
&structs.ACLToken{
AccessorID: "22500c91-723c-4335-be8a-6697417dc35b",
SecretID: testTokenPeeringReadSecret,
Description: "peering read",
Policies: []structs.ACLTokenPolicyLink{
{
ID: testPolicyPeeringReadID,
},
},
},
&structs.ACLToken{
AccessorID: "de924f93-cfec-404c-9a7e-c1c9b96b8cae",
SecretID: testTokenPeeringWriteSecret,
Description: "peering write",
Policies: []structs.ACLTokenPolicyLink{
{
ID: testPolicyPeeringWriteID,
},
},
},
&structs.ACLToken{
AccessorID: "53c54f79-ffed-47d4-904e-e2e0e40c0a01",
SecretID: testTokenServiceReadSecret,
Description: "service read",
Policies: []structs.ACLTokenPolicyLink{
{
ID: testPolicyServiceReadID,
},
},
},
&structs.ACLToken{
AccessorID: "a100fa5f-db72-49f0-8f61-aa1f9f92f657",
SecretID: testTokenServiceWriteSecret,
Description: "service write",
Policies: []structs.ACLTokenPolicyLink{
{
ID: testPolicyServiceWriteID,
},
},
},
}
require.NoError(t, store.ACLTokenBatchSet(101, tokens, state.ACLTokenSetOptions{}))
}
func setupTestPeering(t *testing.T, store *state.Store, name string, index uint64) string { func setupTestPeering(t *testing.T, store *state.Store, name string, index uint64) string {
t.Helper() t.Helper()
err := store.PeeringWrite(index, &pbpeering.Peering{ err := store.PeeringWrite(index, &pbpeering.Peering{

View File

@ -1,6 +1,7 @@
package peering package peering
import ( import (
"github.com/hashicorp/consul/acl"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/proto/pbpeering" "github.com/hashicorp/consul/proto/pbpeering"
) )
@ -53,6 +54,7 @@ func TestPeering(peerName string, state pbpeering.PeeringState, meta map[string]
State: state, State: state,
PeerID: validPeerID, PeerID: validPeerID,
Meta: meta, Meta: meta,
Partition: acl.DefaultPartitionName,
} }
} }

View File

@ -80,10 +80,8 @@ type PeeringGenerateTokenRequest struct {
// PeerName is the name of the remote peer. // PeerName is the name of the remote peer.
PeerName string PeerName string
// Partition to be peered. // Partition to be peered.
Partition string `json:",omitempty"` Partition string `json:",omitempty"`
Datacenter string `json:",omitempty"` // Meta is a mapping of some string value to any other string value
Token string `json:",omitempty"`
// Meta is a mapping of some string value to any other string value.
Meta map[string]string `json:",omitempty"` Meta map[string]string `json:",omitempty"`
// ServerExternalAddresses is a list of addresses to put into the generated token. This could be used to specify // ServerExternalAddresses is a list of addresses to put into the generated token. This could be used to specify
// load balancer(s) or external IPs to reach the servers from the dialing side, and will override any server // load balancer(s) or external IPs to reach the servers from the dialing side, and will override any server
@ -103,9 +101,7 @@ type PeeringEstablishRequest struct {
// The peering token returned from the peer's GenerateToken endpoint. // The peering token returned from the peer's GenerateToken endpoint.
PeeringToken string `json:",omitempty"` PeeringToken string `json:",omitempty"`
// Partition to be peered. // Partition to be peered.
Partition string `json:",omitempty"` Partition string `json:",omitempty"`
Datacenter string `json:",omitempty"`
Token string `json:",omitempty"`
// Meta is a mapping of some string value to any other string value // Meta is a mapping of some string value to any other string value
Meta map[string]string `json:",omitempty"` Meta map[string]string `json:",omitempty"`
} }

View File

@ -37,6 +37,97 @@ func peerExistsInPeerListings(peer *Peering, peerings []*Peering) bool {
return false return false
} }
func TestAPI_Peering_ACLDeny(t *testing.T) {
c, s := makeACLClient(t)
defer s.Stop()
peerings := c.Peerings()
testutil.RunStep(t, "generate token", func(t *testing.T) {
req := PeeringGenerateTokenRequest{PeerName: "peer1"}
testutil.RunStep(t, "without ACL token", func(t *testing.T) {
_, _, err := peerings.GenerateToken(context.Background(), req, &WriteOptions{Token: "anonymous"})
require.Error(t, err)
testutil.RequireErrorContains(t, err, "Permission denied")
})
testutil.RunStep(t, "with ACL token", func(t *testing.T) {
resp, wm, err := peerings.GenerateToken(context.Background(), req, &WriteOptions{Token: "root"})
require.NoError(t, err)
require.NotNil(t, wm)
require.NotNil(t, resp)
})
})
testutil.RunStep(t, "establish peering", func(t *testing.T) {
tokenJSON := `{"ServerAddresses":["127.0.0.1:8502"],"ServerName":"foo","PeerID":"716af65f-b844-f3bb-8aef-cfd7949f6873"}`
tokenB64 := base64.StdEncoding.EncodeToString([]byte(tokenJSON))
req := PeeringEstablishRequest{
PeerName: "peer2",
PeeringToken: tokenB64,
}
testutil.RunStep(t, "without ACL token", func(t *testing.T) {
_, _, err := peerings.Establish(context.Background(), req, &WriteOptions{Token: "anonymous"})
require.Error(t, err)
testutil.RequireErrorContains(t, err, "Permission denied")
})
testutil.RunStep(t, "with ACL token", func(t *testing.T) {
resp, wm, err := peerings.Establish(context.Background(), req, &WriteOptions{Token: "root"})
require.NoError(t, err)
require.NotNil(t, wm)
require.NotNil(t, resp)
})
})
testutil.RunStep(t, "read peering", func(t *testing.T) {
testutil.RunStep(t, "without ACL token", func(t *testing.T) {
_, _, err := peerings.Read(context.Background(), "peer1", &QueryOptions{Token: "anonymous"})
require.Error(t, err)
testutil.RequireErrorContains(t, err, "Permission denied")
})
testutil.RunStep(t, "with ACL token", func(t *testing.T) {
resp, qm, err := peerings.Read(context.Background(), "peer1", &QueryOptions{Token: "root"})
require.NoError(t, err)
require.NotNil(t, qm)
require.NotNil(t, resp)
})
})
testutil.RunStep(t, "list peerings", func(t *testing.T) {
testutil.RunStep(t, "without ACL token", func(t *testing.T) {
_, _, err := peerings.List(context.Background(), &QueryOptions{Token: "anonymous"})
require.Error(t, err)
testutil.RequireErrorContains(t, err, "Permission denied")
})
testutil.RunStep(t, "with ACL token", func(t *testing.T) {
resp, qm, err := peerings.List(context.Background(), &QueryOptions{Token: "root"})
require.NoError(t, err)
require.NotNil(t, qm)
require.NotNil(t, resp)
require.Len(t, resp, 2)
})
})
testutil.RunStep(t, "delete peering", func(t *testing.T) {
testutil.RunStep(t, "without ACL token", func(t *testing.T) {
_, err := peerings.Delete(context.Background(), "peer1", &WriteOptions{Token: "anonymous"})
require.Error(t, err)
testutil.RequireErrorContains(t, err, "Permission denied")
})
testutil.RunStep(t, "with ACL token", func(t *testing.T) {
wm, err := peerings.Delete(context.Background(), "peer1", &WriteOptions{Token: "root"})
require.NoError(t, err)
require.NotNil(t, wm)
})
})
}
func TestAPI_Peering_Read_ErrorHandling(t *testing.T) { func TestAPI_Peering_Read_ErrorHandling(t *testing.T) {
t.Parallel() t.Parallel()
@ -115,25 +206,6 @@ func TestAPI_Peering_List(t *testing.T) {
}) })
} }
func TestAPI_Peering_GenerateToken(t *testing.T) {
t.Parallel()
c, s := makeClientWithCA(t)
defer s.Stop()
s.WaitForSerfCheck(t)
ctx, cancel := context.WithTimeout(context.Background(), DefaultCtxDuration)
defer cancel()
peerings := c.Peerings()
t.Run("cannot have GenerateToken forward DC requests", func(t *testing.T) {
// Try to generate a token in dc2
_, _, err := peerings.GenerateToken(ctx, PeeringGenerateTokenRequest{PeerName: "peer2", Datacenter: "dc2"}, nil)
require.Error(t, err)
})
}
func TestAPI_Peering_GenerateToken_ExternalAddresses(t *testing.T) { func TestAPI_Peering_GenerateToken_ExternalAddresses(t *testing.T) {
t.Parallel() t.Parallel()
@ -163,9 +235,6 @@ func TestAPI_Peering_GenerateToken_ExternalAddresses(t *testing.T) {
require.Contains(t, string(tokenJSON), externalAddress) require.Contains(t, string(tokenJSON), externalAddress)
} }
// TODO(peering): cover the following test cases: bad/ malformed input, peering with wrong token,
// peering with the wrong PeerName
// TestAPI_Peering_GenerateToken_Read_Establish_Delete tests the following use case: // TestAPI_Peering_GenerateToken_Read_Establish_Delete tests the following use case:
// a server creates a peering token, reads the token, then another server calls establish peering // a server creates a peering token, reads the token, then another server calls establish peering
// finally, we delete the token on the first server // finally, we delete the token on the first server
@ -217,7 +286,6 @@ func TestAPI_Peering_GenerateToken_Read_Establish_Delete(t *testing.T) {
testutil.RunStep(t, "establish peering", func(t *testing.T) { testutil.RunStep(t, "establish peering", func(t *testing.T) {
i := PeeringEstablishRequest{ i := PeeringEstablishRequest{
Datacenter: c2.config.Datacenter,
PeerName: "peer1", PeerName: "peer1",
PeeringToken: token1, PeeringToken: token1,
Meta: map[string]string{"foo": "bar"}, Meta: map[string]string{"foo": "bar"},

View File

@ -11,8 +11,6 @@ func EstablishRequestToAPI(s *EstablishRequest, t *api.PeeringEstablishRequest)
t.PeerName = s.PeerName t.PeerName = s.PeerName
t.PeeringToken = s.PeeringToken t.PeeringToken = s.PeeringToken
t.Partition = s.Partition t.Partition = s.Partition
t.Datacenter = s.Datacenter
t.Token = s.Token
t.Meta = s.Meta t.Meta = s.Meta
} }
func EstablishRequestFromAPI(t *api.PeeringEstablishRequest, s *EstablishRequest) { func EstablishRequestFromAPI(t *api.PeeringEstablishRequest, s *EstablishRequest) {
@ -22,8 +20,6 @@ func EstablishRequestFromAPI(t *api.PeeringEstablishRequest, s *EstablishRequest
s.PeerName = t.PeerName s.PeerName = t.PeerName
s.PeeringToken = t.PeeringToken s.PeeringToken = t.PeeringToken
s.Partition = t.Partition s.Partition = t.Partition
s.Datacenter = t.Datacenter
s.Token = t.Token
s.Meta = t.Meta s.Meta = t.Meta
} }
func EstablishResponseToAPI(s *EstablishResponse, t *api.PeeringEstablishResponse) { func EstablishResponseToAPI(s *EstablishResponse, t *api.PeeringEstablishResponse) {
@ -42,8 +38,6 @@ func GenerateTokenRequestToAPI(s *GenerateTokenRequest, t *api.PeeringGenerateTo
} }
t.PeerName = s.PeerName t.PeerName = s.PeerName
t.Partition = s.Partition t.Partition = s.Partition
t.Datacenter = s.Datacenter
t.Token = s.Token
t.Meta = s.Meta t.Meta = s.Meta
t.ServerExternalAddresses = s.ServerExternalAddresses t.ServerExternalAddresses = s.ServerExternalAddresses
} }
@ -53,8 +47,6 @@ func GenerateTokenRequestFromAPI(t *api.PeeringGenerateTokenRequest, s *Generate
} }
s.PeerName = t.PeerName s.PeerName = t.PeerName
s.Partition = t.Partition s.Partition = t.Partition
s.Datacenter = t.Datacenter
s.Token = t.Token
s.Meta = t.Meta s.Meta = t.Meta
s.ServerExternalAddresses = t.ServerExternalAddresses s.ServerExternalAddresses = t.ServerExternalAddresses
} }

View File

@ -1,86 +1,68 @@
package pbpeering package pbpeering
import ( import (
"strconv"
"time" "time"
"github.com/golang/protobuf/ptypes/timestamp" "github.com/golang/protobuf/ptypes/timestamp"
"github.com/mitchellh/hashstructure"
"github.com/hashicorp/consul/agent/cache"
"github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/structs"
"github.com/hashicorp/consul/api" "github.com/hashicorp/consul/api"
"github.com/hashicorp/consul/lib" "github.com/hashicorp/consul/lib"
) )
// TODO(peering): These are byproducts of not embedding
// types in our protobuf definitions and are temporary;
// Hoping to replace them with 1 or 2 methods per request
// using https://github.com/hashicorp/consul/pull/12507
// RequestDatacenter implements structs.RPCInfo // RequestDatacenter implements structs.RPCInfo
func (req *GenerateTokenRequest) RequestDatacenter() string { func (req *GenerateTokenRequest) RequestDatacenter() string {
return req.Datacenter // Cross-datacenter requests are not allowed for peering actions because
// they rely on WAN-federation.
return ""
} }
// IsRead implements structs.RPCInfo // RequestDatacenter implements structs.RPCInfo
func (req *GenerateTokenRequest) IsRead() bool { func (req *EstablishRequest) RequestDatacenter() string {
return false // Cross-datacenter requests are not allowed for peering actions because
// they rely on WAN-federation.
return ""
} }
// AllowStaleRead implements structs.RPCInfo // RequestDatacenter implements structs.RPCInfo
func (req *GenerateTokenRequest) AllowStaleRead() bool { func (req *PeeringReadRequest) RequestDatacenter() string {
return false // Cross-datacenter requests are not allowed for peering actions because
// they rely on WAN-federation.
return ""
} }
// TokenSecret implements structs.RPCInfo // RequestDatacenter implements structs.RPCInfo
func (req *GenerateTokenRequest) TokenSecret() string { func (req *PeeringListRequest) RequestDatacenter() string {
return req.Token // Cross-datacenter requests are not allowed for peering actions because
// they rely on WAN-federation.
return ""
} }
// SetTokenSecret implements structs.RPCInfo // RequestDatacenter implements structs.RPCInfo
func (req *GenerateTokenRequest) SetTokenSecret(token string) { func (req *PeeringWriteRequest) RequestDatacenter() string {
req.Token = token // Cross-datacenter requests are not allowed for peering actions because
// they rely on WAN-federation.
return ""
} }
// HasTimedOut implements structs.RPCInfo // RequestDatacenter implements structs.RPCInfo
func (req *GenerateTokenRequest) HasTimedOut(start time.Time, rpcHoldTimeout, _, _ time.Duration) (bool, error) { func (req *PeeringDeleteRequest) RequestDatacenter() string {
return time.Since(start) > rpcHoldTimeout, nil // Cross-datacenter requests are not allowed for peering actions because
// they rely on WAN-federation.
return ""
} }
// Timeout implements structs.RPCInfo // RequestDatacenter implements structs.RPCInfo
func (msg *GenerateTokenRequest) Timeout(rpcHoldTimeout time.Duration, maxQueryTime time.Duration, defaultQueryTime time.Duration) time.Duration { func (req *TrustBundleReadRequest) RequestDatacenter() string {
return rpcHoldTimeout // Cross-datacenter requests are not allowed for peering actions because
// they rely on WAN-federation.
return ""
} }
// IsRead implements structs.RPCInfo // RequestDatacenter implements structs.RPCInfo
func (req *EstablishRequest) IsRead() bool { func (req *TrustBundleListByServiceRequest) RequestDatacenter() string {
return false // Cross-datacenter requests are not allowed for peering actions because
} // they rely on WAN-federation.
return ""
// AllowStaleRead implements structs.RPCInfo
func (req *EstablishRequest) AllowStaleRead() bool {
return false
}
// TokenSecret implements structs.RPCInfo
func (req *EstablishRequest) TokenSecret() string {
return req.Token
}
// SetTokenSecret implements structs.RPCInfo
func (req *EstablishRequest) SetTokenSecret(token string) {
req.Token = token
}
// HasTimedOut implements structs.RPCInfo
func (req *EstablishRequest) HasTimedOut(start time.Time, rpcHoldTimeout, _, _ time.Duration) (bool, error) {
return time.Since(start) > rpcHoldTimeout, nil
}
// Timeout implements structs.RPCInfo
func (msg *EstablishRequest) Timeout(rpcHoldTimeout time.Duration, maxQueryTime time.Duration, defaultQueryTime time.Duration) time.Duration {
return rpcHoldTimeout
} }
// ShouldDial returns true when the peering was stored via the peering initiation endpoint, // ShouldDial returns true when the peering was stored via the peering initiation endpoint,
@ -95,34 +77,6 @@ func (x PeeringState) GoString() string {
return x.String() return x.String()
} }
func (r *TrustBundleReadRequest) CacheInfo() cache.RequestInfo {
info := cache.RequestInfo{
// TODO(peering): Revisit whether this is the token to use once request types accept a token.
Token: r.Token(),
Datacenter: r.Datacenter,
MinIndex: 0,
Timeout: 0,
MustRevalidate: false,
// TODO(peering): Cache.notifyPollingQuery polls at this interval. We need to revisit how that polling works.
// Using an exponential backoff when the result hasn't changed may be preferable.
MaxAge: 1 * time.Second,
}
v, err := hashstructure.Hash([]interface{}{
r.Partition,
r.Name,
}, nil)
if err == nil {
// If there is an error, we don't set the key. A blank key forces
// no cache for this request so the request is forwarded directly
// to the server.
info.Key = strconv.FormatUint(v, 10)
}
return info
}
// ConcatenatedRootPEMs concatenates and returns all PEM-encoded public certificates // ConcatenatedRootPEMs concatenates and returns all PEM-encoded public certificates
// in a peer's trust bundle. // in a peer's trust bundle.
func (b *PeeringTrustBundle) ConcatenatedRootPEMs() string { func (b *PeeringTrustBundle) ConcatenatedRootPEMs() string {
@ -242,35 +196,6 @@ func NewEstablishRequestFromAPI(req *api.PeeringEstablishRequest) *EstablishRequ
return t return t
} }
func (r *TrustBundleListByServiceRequest) CacheInfo() cache.RequestInfo {
info := cache.RequestInfo{
// TODO(peering): Revisit whether this is the token to use once request types accept a token.
Token: r.Token(),
Datacenter: r.Datacenter,
MinIndex: 0,
Timeout: 0,
MustRevalidate: false,
// TODO(peering): Cache.notifyPollingQuery polls at this interval. We need to revisit how that polling works.
// Using an exponential backoff when the result hasn't changed may be preferable.
MaxAge: 1 * time.Second,
}
v, err := hashstructure.Hash([]interface{}{
r.Partition,
r.Namespace,
r.ServiceName,
}, nil)
if err == nil {
// If there is an error, we don't set the key. A blank key forces
// no cache for this request so the request is forwarded directly
// to the server.
info.Key = strconv.FormatUint(v, 10)
}
return info
}
func TimePtrFromProto(s *timestamp.Timestamp) *time.Time { func TimePtrFromProto(s *timestamp.Timestamp) *time.Time {
if s == nil { if s == nil {
return nil return nil

View File

@ -140,9 +140,11 @@ type Peering struct {
// ExportedServiceCount is the count of how many services are exported to this peering. // ExportedServiceCount is the count of how many services are exported to this peering.
ExportedServiceCount uint64 `protobuf:"varint,14,opt,name=ExportedServiceCount,proto3" json:"ExportedServiceCount,omitempty"` ExportedServiceCount uint64 `protobuf:"varint,14,opt,name=ExportedServiceCount,proto3" json:"ExportedServiceCount,omitempty"`
// CreateIndex is the Raft index at which the Peering was created. // CreateIndex is the Raft index at which the Peering was created.
CreateIndex uint64 `protobuf:"varint,11,opt,name=CreateIndex,proto3" json:"CreateIndex,omitempty"` // @gotags: bexpr:"-"
CreateIndex uint64 `protobuf:"varint,11,opt,name=CreateIndex,proto3" json:"CreateIndex,omitempty" bexpr:"-"`
// ModifyIndex is the latest Raft index at which the Peering. was modified. // ModifyIndex is the latest Raft index at which the Peering. was modified.
ModifyIndex uint64 `protobuf:"varint,12,opt,name=ModifyIndex,proto3" json:"ModifyIndex,omitempty"` // @gotags: bexpr:"-"
ModifyIndex uint64 `protobuf:"varint,12,opt,name=ModifyIndex,proto3" json:"ModifyIndex,omitempty" bexpr:"-"`
} }
func (x *Peering) Reset() { func (x *Peering) Reset() {
@ -293,9 +295,11 @@ type PeeringTrustBundle struct {
// which sent this trust bundle. Used for generating SpiffeIDs. // which sent this trust bundle. Used for generating SpiffeIDs.
ExportedPartition string `protobuf:"bytes,5,opt,name=ExportedPartition,proto3" json:"ExportedPartition,omitempty"` ExportedPartition string `protobuf:"bytes,5,opt,name=ExportedPartition,proto3" json:"ExportedPartition,omitempty"`
// CreateIndex is the Raft index at which the trust domain was created. // CreateIndex is the Raft index at which the trust domain was created.
CreateIndex uint64 `protobuf:"varint,6,opt,name=CreateIndex,proto3" json:"CreateIndex,omitempty"` // @gotags: bexpr:"-"
CreateIndex uint64 `protobuf:"varint,6,opt,name=CreateIndex,proto3" json:"CreateIndex,omitempty" bexpr:"-"`
// ModifyIndex is the latest Raft index at which the trust bundle was modified. // ModifyIndex is the latest Raft index at which the trust bundle was modified.
ModifyIndex uint64 `protobuf:"varint,7,opt,name=ModifyIndex,proto3" json:"ModifyIndex,omitempty"` // @gotags: bexpr:"-"
ModifyIndex uint64 `protobuf:"varint,7,opt,name=ModifyIndex,proto3" json:"ModifyIndex,omitempty" bexpr:"-"`
} }
func (x *PeeringTrustBundle) Reset() { func (x *PeeringTrustBundle) Reset() {
@ -379,15 +383,14 @@ func (x *PeeringTrustBundle) GetModifyIndex() uint64 {
return 0 return 0
} }
// @consul-rpc-glue: Datacenter,LeaderReadTODO // @consul-rpc-glue: LeaderReadTODO
type PeeringReadRequest struct { type PeeringReadRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
Partition string `protobuf:"bytes,2,opt,name=Partition,proto3" json:"Partition,omitempty"` Partition string `protobuf:"bytes,2,opt,name=Partition,proto3" json:"Partition,omitempty"`
Datacenter string `protobuf:"bytes,3,opt,name=Datacenter,proto3" json:"Datacenter,omitempty"`
} }
func (x *PeeringReadRequest) Reset() { func (x *PeeringReadRequest) Reset() {
@ -436,13 +439,6 @@ func (x *PeeringReadRequest) GetPartition() string {
return "" return ""
} }
func (x *PeeringReadRequest) GetDatacenter() string {
if x != nil {
return x.Datacenter
}
return ""
}
type PeeringReadResponse struct { type PeeringReadResponse struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -490,14 +486,13 @@ func (x *PeeringReadResponse) GetPeering() *Peering {
return nil return nil
} }
// @consul-rpc-glue: Datacenter,LeaderReadTODO // @consul-rpc-glue: LeaderReadTODO
type PeeringListRequest struct { type PeeringListRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Partition string `protobuf:"bytes,1,opt,name=Partition,proto3" json:"Partition,omitempty"` Partition string `protobuf:"bytes,1,opt,name=Partition,proto3" json:"Partition,omitempty"`
Datacenter string `protobuf:"bytes,2,opt,name=Datacenter,proto3" json:"Datacenter,omitempty"`
} }
func (x *PeeringListRequest) Reset() { func (x *PeeringListRequest) Reset() {
@ -539,13 +534,6 @@ func (x *PeeringListRequest) GetPartition() string {
return "" return ""
} }
func (x *PeeringListRequest) GetDatacenter() string {
if x != nil {
return x.Datacenter
}
return ""
}
type PeeringListResponse struct { type PeeringListResponse struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -593,17 +581,14 @@ func (x *PeeringListResponse) GetPeerings() []*Peering {
return nil return nil
} }
// @consul-rpc-glue: Datacenter,WriteTODO
type PeeringWriteRequest struct { type PeeringWriteRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
Peering *Peering `protobuf:"bytes,1,opt,name=Peering,proto3" json:"Peering,omitempty"` Peering *Peering `protobuf:"bytes,1,opt,name=Peering,proto3" json:"Peering,omitempty"`
//TODO(peering): what to do with embedded write request?
Datacenter string `protobuf:"bytes,2,opt,name=Datacenter,proto3" json:"Datacenter,omitempty"`
// Meta is a mapping of some string value to any other string value // Meta is a mapping of some string value to any other string value
Meta map[string]string `protobuf:"bytes,3,rep,name=Meta,proto3" json:"Meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Meta map[string]string `protobuf:"bytes,2,rep,name=Meta,proto3" json:"Meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
} }
func (x *PeeringWriteRequest) Reset() { func (x *PeeringWriteRequest) Reset() {
@ -645,13 +630,6 @@ func (x *PeeringWriteRequest) GetPeering() *Peering {
return nil return nil
} }
func (x *PeeringWriteRequest) GetDatacenter() string {
if x != nil {
return x.Datacenter
}
return ""
}
func (x *PeeringWriteRequest) GetMeta() map[string]string { func (x *PeeringWriteRequest) GetMeta() map[string]string {
if x != nil { if x != nil {
return x.Meta return x.Meta
@ -698,7 +676,6 @@ func (*PeeringWriteResponse) Descriptor() ([]byte, []int) {
return file_proto_pbpeering_peering_proto_rawDescGZIP(), []int{7} return file_proto_pbpeering_peering_proto_rawDescGZIP(), []int{7}
} }
// @consul-rpc-glue: Datacenter,WriteTODO
type PeeringDeleteRequest struct { type PeeringDeleteRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -706,8 +683,6 @@ type PeeringDeleteRequest struct {
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
Partition string `protobuf:"bytes,2,opt,name=Partition,proto3" json:"Partition,omitempty"` Partition string `protobuf:"bytes,2,opt,name=Partition,proto3" json:"Partition,omitempty"`
//TODO(peering): what to do with embedded write request?
Datacenter string `protobuf:"bytes,3,opt,name=Datacenter,proto3" json:"Datacenter,omitempty"`
} }
func (x *PeeringDeleteRequest) Reset() { func (x *PeeringDeleteRequest) Reset() {
@ -756,13 +731,6 @@ func (x *PeeringDeleteRequest) GetPartition() string {
return "" return ""
} }
func (x *PeeringDeleteRequest) GetDatacenter() string {
if x != nil {
return x.Datacenter
}
return ""
}
type PeeringDeleteResponse struct { type PeeringDeleteResponse struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -801,7 +769,6 @@ func (*PeeringDeleteResponse) Descriptor() ([]byte, []int) {
return file_proto_pbpeering_peering_proto_rawDescGZIP(), []int{9} return file_proto_pbpeering_peering_proto_rawDescGZIP(), []int{9}
} }
// @consul-rpc-glue: Datacenter,ReadTODO
type TrustBundleListByServiceRequest struct { type TrustBundleListByServiceRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -811,9 +778,6 @@ type TrustBundleListByServiceRequest struct {
Namespace string `protobuf:"bytes,2,opt,name=Namespace,proto3" json:"Namespace,omitempty"` Namespace string `protobuf:"bytes,2,opt,name=Namespace,proto3" json:"Namespace,omitempty"`
Partition string `protobuf:"bytes,3,opt,name=Partition,proto3" json:"Partition,omitempty"` Partition string `protobuf:"bytes,3,opt,name=Partition,proto3" json:"Partition,omitempty"`
Kind string `protobuf:"bytes,4,opt,name=Kind,proto3" json:"Kind,omitempty"` Kind string `protobuf:"bytes,4,opt,name=Kind,proto3" json:"Kind,omitempty"`
// these are common fields required for implementing structs.RPCInfo methods
// that are used to forward requests
Datacenter string `protobuf:"bytes,5,opt,name=Datacenter,proto3" json:"Datacenter,omitempty"`
} }
func (x *TrustBundleListByServiceRequest) Reset() { func (x *TrustBundleListByServiceRequest) Reset() {
@ -876,13 +840,6 @@ func (x *TrustBundleListByServiceRequest) GetKind() string {
return "" return ""
} }
func (x *TrustBundleListByServiceRequest) GetDatacenter() string {
if x != nil {
return x.Datacenter
}
return ""
}
type TrustBundleListByServiceResponse struct { type TrustBundleListByServiceResponse struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -938,7 +895,6 @@ func (x *TrustBundleListByServiceResponse) GetBundles() []*PeeringTrustBundle {
return nil return nil
} }
// @consul-rpc-glue: Datacenter,ReadTODO
type TrustBundleReadRequest struct { type TrustBundleReadRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -946,9 +902,6 @@ type TrustBundleReadRequest struct {
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
Partition string `protobuf:"bytes,2,opt,name=Partition,proto3" json:"Partition,omitempty"` Partition string `protobuf:"bytes,2,opt,name=Partition,proto3" json:"Partition,omitempty"`
// these are common fields required for implementing structs.RPCInfo methods
// that are used to forward requests
Datacenter string `protobuf:"bytes,3,opt,name=Datacenter,proto3" json:"Datacenter,omitempty"`
} }
func (x *TrustBundleReadRequest) Reset() { func (x *TrustBundleReadRequest) Reset() {
@ -997,13 +950,6 @@ func (x *TrustBundleReadRequest) GetPartition() string {
return "" return ""
} }
func (x *TrustBundleReadRequest) GetDatacenter() string {
if x != nil {
return x.Datacenter
}
return ""
}
type TrustBundleReadResponse struct { type TrustBundleReadResponse struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -1059,6 +1005,7 @@ func (x *TrustBundleReadResponse) GetBundle() *PeeringTrustBundle {
return nil return nil
} }
// This is a purely internal type and does not require query metadata.
type PeeringTerminateByIDRequest struct { type PeeringTerminateByIDRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -1144,15 +1091,12 @@ func (*PeeringTerminateByIDResponse) Descriptor() ([]byte, []int) {
return file_proto_pbpeering_peering_proto_rawDescGZIP(), []int{15} return file_proto_pbpeering_peering_proto_rawDescGZIP(), []int{15}
} }
// @consul-rpc-glue: Datacenter
type PeeringTrustBundleWriteRequest struct { type PeeringTrustBundleWriteRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields unknownFields protoimpl.UnknownFields
PeeringTrustBundle *PeeringTrustBundle `protobuf:"bytes,1,opt,name=PeeringTrustBundle,proto3" json:"PeeringTrustBundle,omitempty"` PeeringTrustBundle *PeeringTrustBundle `protobuf:"bytes,1,opt,name=PeeringTrustBundle,proto3" json:"PeeringTrustBundle,omitempty"`
//TODO(peering): what to do with embedded write request?
Datacenter string `protobuf:"bytes,2,opt,name=Datacenter,proto3" json:"Datacenter,omitempty"`
} }
func (x *PeeringTrustBundleWriteRequest) Reset() { func (x *PeeringTrustBundleWriteRequest) Reset() {
@ -1194,13 +1138,6 @@ func (x *PeeringTrustBundleWriteRequest) GetPeeringTrustBundle() *PeeringTrustBu
return nil return nil
} }
func (x *PeeringTrustBundleWriteRequest) GetDatacenter() string {
if x != nil {
return x.Datacenter
}
return ""
}
type PeeringTrustBundleWriteResponse struct { type PeeringTrustBundleWriteResponse struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -1239,7 +1176,6 @@ func (*PeeringTrustBundleWriteResponse) Descriptor() ([]byte, []int) {
return file_proto_pbpeering_peering_proto_rawDescGZIP(), []int{17} return file_proto_pbpeering_peering_proto_rawDescGZIP(), []int{17}
} }
// @consul-rpc-glue: Datacenter
type PeeringTrustBundleDeleteRequest struct { type PeeringTrustBundleDeleteRequest struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -1247,8 +1183,6 @@ type PeeringTrustBundleDeleteRequest struct {
Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"` Name string `protobuf:"bytes,1,opt,name=Name,proto3" json:"Name,omitempty"`
Partition string `protobuf:"bytes,2,opt,name=Partition,proto3" json:"Partition,omitempty"` Partition string `protobuf:"bytes,2,opt,name=Partition,proto3" json:"Partition,omitempty"`
//TODO(peering): what to do with embedded write request?
Datacenter string `protobuf:"bytes,3,opt,name=Datacenter,proto3" json:"Datacenter,omitempty"`
} }
func (x *PeeringTrustBundleDeleteRequest) Reset() { func (x *PeeringTrustBundleDeleteRequest) Reset() {
@ -1297,13 +1231,6 @@ func (x *PeeringTrustBundleDeleteRequest) GetPartition() string {
return "" return ""
} }
func (x *PeeringTrustBundleDeleteRequest) GetDatacenter() string {
if x != nil {
return x.Datacenter
}
return ""
}
type PeeringTrustBundleDeleteResponse struct { type PeeringTrustBundleDeleteResponse struct {
state protoimpl.MessageState state protoimpl.MessageState
sizeCache protoimpl.SizeCache sizeCache protoimpl.SizeCache
@ -1356,10 +1283,6 @@ type GenerateTokenRequest struct {
PeerName string `protobuf:"bytes,1,opt,name=PeerName,proto3" json:"PeerName,omitempty"` PeerName string `protobuf:"bytes,1,opt,name=PeerName,proto3" json:"PeerName,omitempty"`
// Partition is the local partition being peered. // Partition is the local partition being peered.
Partition string `protobuf:"bytes,2,opt,name=Partition,proto3" json:"Partition,omitempty"` Partition string `protobuf:"bytes,2,opt,name=Partition,proto3" json:"Partition,omitempty"`
// these are common fields required for implementing structs.RPCInfo methods
// that are used to forward requests
Datacenter string `protobuf:"bytes,3,opt,name=Datacenter,proto3" json:"Datacenter,omitempty"`
Token string `protobuf:"bytes,4,opt,name=Token,proto3" json:"Token,omitempty"`
// Meta is a mapping of some string value to any other string value // Meta is a mapping of some string value to any other string value
Meta map[string]string `protobuf:"bytes,5,rep,name=Meta,proto3" json:"Meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Meta map[string]string `protobuf:"bytes,5,rep,name=Meta,proto3" json:"Meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
// ServerExternalAddresses is a list of addresses to put into the generated token. This could be used to specify // ServerExternalAddresses is a list of addresses to put into the generated token. This could be used to specify
@ -1414,20 +1337,6 @@ func (x *GenerateTokenRequest) GetPartition() string {
return "" return ""
} }
func (x *GenerateTokenRequest) GetDatacenter() string {
if x != nil {
return x.Datacenter
}
return ""
}
func (x *GenerateTokenRequest) GetToken() string {
if x != nil {
return x.Token
}
return ""
}
func (x *GenerateTokenRequest) GetMeta() map[string]string { func (x *GenerateTokenRequest) GetMeta() map[string]string {
if x != nil { if x != nil {
return x.Meta return x.Meta
@ -1496,8 +1405,6 @@ func (x *GenerateTokenResponse) GetPeeringToken() string {
return "" return ""
} }
// @consul-rpc-glue: Datacenter
//
// mog annotation: // mog annotation:
// //
// target=github.com/hashicorp/consul/api.PeeringEstablishRequest // target=github.com/hashicorp/consul/api.PeeringEstablishRequest
@ -1514,12 +1421,8 @@ type EstablishRequest struct {
PeeringToken string `protobuf:"bytes,2,opt,name=PeeringToken,proto3" json:"PeeringToken,omitempty"` PeeringToken string `protobuf:"bytes,2,opt,name=PeeringToken,proto3" json:"PeeringToken,omitempty"`
// Partition is the local partition being peered. // Partition is the local partition being peered.
Partition string `protobuf:"bytes,3,opt,name=Partition,proto3" json:"Partition,omitempty"` Partition string `protobuf:"bytes,3,opt,name=Partition,proto3" json:"Partition,omitempty"`
// these are common fields required for implementing structs.RPCInfo methods
// that are used to forward requests
Datacenter string `protobuf:"bytes,4,opt,name=Datacenter,proto3" json:"Datacenter,omitempty"`
Token string `protobuf:"bytes,5,opt,name=Token,proto3" json:"Token,omitempty"`
// Meta is a mapping of some string value to any other string value // Meta is a mapping of some string value to any other string value
Meta map[string]string `protobuf:"bytes,6,rep,name=Meta,proto3" json:"Meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` Meta map[string]string `protobuf:"bytes,4,rep,name=Meta,proto3" json:"Meta,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
} }
func (x *EstablishRequest) Reset() { func (x *EstablishRequest) Reset() {
@ -1575,20 +1478,6 @@ func (x *EstablishRequest) GetPartition() string {
return "" return ""
} }
func (x *EstablishRequest) GetDatacenter() string {
if x != nil {
return x.Datacenter
}
return ""
}
func (x *EstablishRequest) GetToken() string {
if x != nil {
return x.Token
}
return ""
}
func (x *EstablishRequest) GetMeta() map[string]string { func (x *EstablishRequest) GetMeta() map[string]string {
if x != nil { if x != nil {
return x.Meta return x.Meta
@ -1596,7 +1485,6 @@ func (x *EstablishRequest) GetMeta() map[string]string {
return nil return nil
} }
//
// mog annotation: // mog annotation:
// //
// target=github.com/hashicorp/consul/api.PeeringEstablishResponse // target=github.com/hashicorp/consul/api.PeeringEstablishResponse
@ -1706,39 +1594,33 @@ var file_proto_pbpeering_peering_proto_rawDesc = []byte{
0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x64,
0x65, 0x78, 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x64, 0x65, 0x65, 0x78, 0x12, 0x20, 0x0a, 0x0b, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x49, 0x6e, 0x64, 0x65,
0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x49, 0x78, 0x18, 0x07, 0x20, 0x01, 0x28, 0x04, 0x52, 0x0b, 0x4d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x49,
0x6e, 0x64, 0x65, 0x78, 0x22, 0x66, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x46, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52,
0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61,
0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c,
0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5b, 0x0a, 0x13,
0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
0x52, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x5b, 0x0a, 0x13,
0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f,
0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x01, 0x6e, 0x73, 0x65, 0x12, 0x44, 0x0a, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x01,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67,
0x52, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x52, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x52, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x22, 0x32, 0x0a, 0x12, 0x50, 0x65, 0x65,
0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12,
0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x5d, 0x0a,
0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x5d, 0x0a,
0x13, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x13, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x73,
0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f,
0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69,
0x6e, 0x67, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x22, 0x8a, 0x02, 0x0a, 0x6e, 0x67, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x73, 0x22, 0xea, 0x01, 0x0a,
0x13, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x13, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x18, 0x75, 0x65, 0x73, 0x74, 0x12, 0x44, 0x0a, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72,
0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e,
0x67, 0x52, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x61, 0x67, 0x52, 0x07, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x12, 0x54, 0x0a, 0x04, 0x4d, 0x65,
0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69,
0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x54, 0x0a, 0x04, 0x4d, 0x65,
0x74, 0x61, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69,
0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65,
0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
@ -1748,15 +1630,13 @@ var file_proto_pbpeering_peering_proto_rawDesc = []byte{
0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05,
0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x16, 0x0a, 0x14, 0x50, 0x65, 0x65, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x16, 0x0a, 0x14, 0x50, 0x65, 0x65,
0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x68, 0x0a, 0x14, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, 0x65, 0x22, 0x48, 0x0a, 0x14, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65,
0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a,
0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x17, 0x0a, 0x15, 0x50,
0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x17, 0x0a, 0x15, 0x50,
0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x22, 0xb3, 0x01, 0x0a, 0x1f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x93, 0x01, 0x0a, 0x1f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75,
0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63,
0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x20, 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76,
0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x53, 0x69, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x53,
@ -1765,9 +1645,7 @@ var file_proto_pbpeering_peering_proto_rawDesc = []byte{
0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74,
0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72,
0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x18, 0x04,
0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x61, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x4b, 0x69, 0x6e, 0x64, 0x22, 0x89, 0x01, 0x0a, 0x20, 0x54,
0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x89, 0x01, 0x0a, 0x20, 0x54,
0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79,
0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
0x14, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x14, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05,
@ -1776,14 +1654,12 @@ var file_proto_pbpeering_peering_proto_rawDesc = []byte{
0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69,
0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x07, 0x42, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x07, 0x42,
0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x22, 0x6a, 0x0a, 0x16, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x73, 0x22, 0x4a, 0x0a, 0x16, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42,
0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04,
0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f,
0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69,
0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x6f, 0x6e, 0x22, 0x7e, 0x0a, 0x17, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74,
0x65, 0x72, 0x22, 0x7e, 0x0a, 0x17, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c,
0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x14, 0x0a,
0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x49, 0x6e, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x49, 0x6e,
0x64, 0x65, 0x78, 0x12, 0x4d, 0x0a, 0x06, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x64, 0x65, 0x78, 0x12, 0x4d, 0x0a, 0x06, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x02, 0x20,
@ -1796,7 +1672,7 @@ var file_proto_pbpeering_peering_proto_rawDesc = []byte{
0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x49,
0x44, 0x22, 0x1e, 0x0a, 0x1c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x72, 0x6d, 0x44, 0x22, 0x1e, 0x0a, 0x1c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x65, 0x72, 0x6d,
0x69, 0x6e, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x69, 0x6e, 0x61, 0x74, 0x65, 0x42, 0x79, 0x49, 0x44, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0xa7, 0x01, 0x0a, 0x1e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x65, 0x22, 0x87, 0x01, 0x0a, 0x1e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75,
0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x12, 0x65, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x75, 0x65, 0x73, 0x74, 0x12, 0x65, 0x0a, 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54,
0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b,
@ -1804,159 +1680,149 @@ var file_proto_pbpeering_peering_proto_rawDesc = []byte{
0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65,
0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73,
0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x12, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67,
0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x22, 0x21, 0x0a, 0x1f, 0x50,
0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x21, 0x0a, 0x1f, 0x50,
0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c,
0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x73, 0x65, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x53,
0x0a, 0x1f, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x0a, 0x1f, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75,
0x6e, 0x64, 0x6c, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x6e, 0x64, 0x6c, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69,
0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74,
0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x69, 0x6f, 0x6e, 0x22, 0x22, 0x0a, 0x20, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72,
0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e,
0x74, 0x65, 0x72, 0x22, 0x22, 0x0a, 0x20, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x72,
0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0xd0, 0x02, 0x0a, 0x14, 0x47, 0x65, 0x6e, 0x65, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x9a, 0x02, 0x0a, 0x14, 0x47, 0x65, 0x6e, 0x65,
0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09,
0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x61, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x55, 0x0a, 0x04, 0x4d, 0x65,
0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69,
0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x6f, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65,
0x6b, 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x47, 0x65, 0x6e,
0x12, 0x55, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x41, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d, 0x65, 0x74,
0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x61, 0x12, 0x38, 0x0a, 0x17, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x72,
0x6e, 0x67, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x6e, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x18, 0x06, 0x20, 0x03,
0x28, 0x09, 0x52, 0x17, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e,
0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x73, 0x1a, 0x37, 0x0a, 0x09, 0x4d,
0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61,
0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x3a, 0x02, 0x38, 0x01, 0x22, 0x3b, 0x0a, 0x15, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65,
0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a,
0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x6b, 0x65,
0x6e, 0x22, 0xfc, 0x01, 0x0a, 0x10, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61,
0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61,
0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x6b,
0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e,
0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74,
0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69,
0x74, 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03,
0x28, 0x0b, 0x32, 0x3d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63,
0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70,
0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68,
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x38, 0x0a, 0x17, 0x53, 0x65, 0x72, 0x76, 0x65, 0x79, 0x52, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45,
0x72, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28,
0x65, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x09, 0x52, 0x17, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18,
0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x65, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01,
0x73, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x22, 0x13, 0x0a, 0x11, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73,
0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2a, 0x73, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67,
0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e,
0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x3b, 0x0a, 0x15, 0x47, 0x65, 0x45, 0x44, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10,
0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x45, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x49, 0x4e,
0x6e, 0x73, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x47, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x03, 0x12,
0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x0b, 0x0a, 0x07, 0x46, 0x41, 0x49, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08,
0x6e, 0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xb2, 0x02, 0x0a, 0x10, 0x45, 0x73, 0x74, 0x61, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x45,
0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x52, 0x4d, 0x49, 0x4e, 0x41, 0x54, 0x45, 0x44, 0x10, 0x06, 0x32, 0xc0, 0x08, 0x0a, 0x0e, 0x50,
0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x82, 0x01,
0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x22, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x0a, 0x0d, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12,
0x69, 0x6e, 0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c,
0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x1c, 0x0a, 0x09,
0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x61,
0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a,
0x44, 0x61, 0x74, 0x61, 0x63, 0x65, 0x6e, 0x74, 0x65, 0x72, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x6f,
0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e,
0x12, 0x51, 0x0a, 0x04, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3d,
0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75,
0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69,
0x6e, 0x67, 0x2e, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x04, 0x4d,
0x65, 0x74, 0x61, 0x1a, 0x37, 0x0a, 0x09, 0x4d, 0x65, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79,
0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b,
0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x13, 0x0a, 0x11,
0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x2a, 0x73, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x53, 0x74, 0x61, 0x74,
0x65, 0x12, 0x0d, 0x0a, 0x09, 0x55, 0x4e, 0x44, 0x45, 0x46, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x00,
0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, 0x12, 0x10, 0x0a,
0x0c, 0x45, 0x53, 0x54, 0x41, 0x42, 0x4c, 0x49, 0x53, 0x48, 0x49, 0x4e, 0x47, 0x10, 0x02, 0x12,
0x0a, 0x0a, 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x46,
0x41, 0x49, 0x4c, 0x49, 0x4e, 0x47, 0x10, 0x04, 0x12, 0x0c, 0x0a, 0x08, 0x44, 0x45, 0x4c, 0x45,
0x54, 0x49, 0x4e, 0x47, 0x10, 0x05, 0x12, 0x0e, 0x0a, 0x0a, 0x54, 0x45, 0x52, 0x4d, 0x49, 0x4e,
0x41, 0x54, 0x45, 0x44, 0x10, 0x06, 0x32, 0xc0, 0x08, 0x0a, 0x0e, 0x50, 0x65, 0x65, 0x72, 0x69,
0x6e, 0x67, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x0d, 0x47, 0x65,
0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x37, 0x2e, 0x68, 0x61,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e,
0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74,
0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x76,
0x0a, 0x09, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12, 0x33, 0x2e, 0x68, 0x61,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e,
0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e,
0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65,
0x72, 0x69, 0x6e, 0x67, 0x2e, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e,
0x67, 0x52, 0x65, 0x61, 0x64, 0x12, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72,
0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e,
0x67, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x68,
0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e,
0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67,
0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70,
0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c,
0x69, 0x73, 0x74, 0x12, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e,
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e,
0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c,
0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36, 0x2e, 0x68, 0x61, 0x73,
0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e,
0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50,
0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65,
0x6c, 0x65, 0x74, 0x65, 0x12, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67,
0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e,
0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e,
0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52,
0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7f, 0x0a, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69,
0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72,
0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73,
0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72,
0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x69, 0x6e, 0x67, 0x2e, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa3, 0x01, 0x0a, 0x18, 0x54, 0x72, 0x75, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69,
0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x42, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x47, 0x65, 0x6e,
0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x65, 0x72, 0x61, 0x74, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x73, 0x65, 0x12, 0x76, 0x0a, 0x09, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x12,
0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x33, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73,
0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x43, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72,
0x69, 0x6e, 0x67, 0x2e, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69, 0x73, 0x68, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70,
0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c,
0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x45, 0x73, 0x74, 0x61, 0x62, 0x6c, 0x69,
0x73, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x0b, 0x50, 0x65,
0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x12, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68,
0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65,
0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
0x1a, 0x36, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e,
0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65,
0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x52, 0x65, 0x61, 0x64,
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7c, 0x0a, 0x0b, 0x50, 0x65, 0x65, 0x72,
0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63,
0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72,
0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72,
0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x36,
0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75,
0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69,
0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65,
0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x82, 0x01, 0x0a, 0x0d, 0x50, 0x65, 0x65, 0x72, 0x69,
0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69,
0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65,
0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65,
0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x74, 0x1a, 0x38, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f,
0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65,
0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x6c,
0x65, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x7f, 0x0a, 0x0c, 0x50,
0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x36, 0x2e, 0x68, 0x61,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e,
0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57, 0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e,
0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e,
0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x57,
0x72, 0x69, 0x74, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0xa3, 0x01, 0x0a,
0x18, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74,
0x42, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x42, 0x2e, 0x68, 0x61, 0x73, 0x68,
0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74,
0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x72, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x72,
0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x42, 0x79, 0x53,
0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x88, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x43, 0x2e,
0x01, 0x0a, 0x0f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65,
0x61, 0x64, 0x12, 0x39, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63,
0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70,
0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64,
0x6c, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x3a, 0x2e,
0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c,
0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e,
0x67, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x61, 0x67, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x4c, 0x69, 0x73,
0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x8a, 0x02, 0x0a, 0x25, 0x63, 0x6f, 0x74, 0x42, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x73, 0x65, 0x12, 0x88, 0x01, 0x0a, 0x0f, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64,
0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x6c, 0x65, 0x52, 0x65, 0x61, 0x64, 0x12, 0x39, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f,
0x69, 0x6e, 0x67, 0x42, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x50, 0x72, 0x6f, 0x74, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e,
0x6f, 0x50, 0x01, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x6c, 0x2e, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74,
0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x42, 0x75, 0x6e, 0x64, 0x6c, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x74, 0x1a, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f,
0xa2, 0x02, 0x04, 0x48, 0x43, 0x49, 0x50, 0xaa, 0x02, 0x21, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x70, 0x65,
0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x54, 0x72, 0x75, 0x73, 0x74, 0x42, 0x75, 0x6e, 0x64, 0x6c,
0x6e, 0x61, 0x6c, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0xca, 0x02, 0x21, 0x48, 0x61, 0x65, 0x52, 0x65, 0x61, 0x64, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x8a, 0x02,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x0a, 0x25, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0xe2, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e,
0x02, 0x2d, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x70, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x42, 0x0c, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67,
0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2b, 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, 0x2f, 0x70, 0x62, 0x70, 0x65, 0x65,
0x72, 0x69, 0x6e, 0x67, 0xa2, 0x02, 0x04, 0x48, 0x43, 0x49, 0x50, 0xaa, 0x02, 0x21, 0x48, 0x61,
0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x49,
0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0xca,
0x02, 0x21, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73,
0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x50, 0x65, 0x65, 0x72, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c, 0x50, 0x65, 0x65, 0x72,
0x69, 0x6e, 0x67, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x69, 0x6e, 0x67, 0xe2, 0x02, 0x2d, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c,
0x02, 0x24, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5c,
0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x3a, 0x3a, 0x50, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64,
0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, 0x61, 0x74, 0x61, 0xea, 0x02, 0x24, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a,
0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61,
0x6c, 0x3a, 0x3a, 0x50, 0x65, 0x65, 0x72, 0x69, 0x6e, 0x67, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
} }
var ( var (

View File

@ -105,9 +105,11 @@ message Peering {
uint64 ExportedServiceCount = 14; uint64 ExportedServiceCount = 14;
// CreateIndex is the Raft index at which the Peering was created. // CreateIndex is the Raft index at which the Peering was created.
// @gotags: bexpr:"-"
uint64 CreateIndex = 11; uint64 CreateIndex = 11;
// ModifyIndex is the latest Raft index at which the Peering. was modified. // ModifyIndex is the latest Raft index at which the Peering. was modified.
// @gotags: bexpr:"-"
uint64 ModifyIndex = 12; uint64 ModifyIndex = 12;
} }
@ -130,79 +132,56 @@ message PeeringTrustBundle {
string ExportedPartition = 5; string ExportedPartition = 5;
// CreateIndex is the Raft index at which the trust domain was created. // CreateIndex is the Raft index at which the trust domain was created.
// @gotags: bexpr:"-"
uint64 CreateIndex = 6; uint64 CreateIndex = 6;
// ModifyIndex is the latest Raft index at which the trust bundle was modified. // ModifyIndex is the latest Raft index at which the trust bundle was modified.
// @gotags: bexpr:"-"
uint64 ModifyIndex = 7; uint64 ModifyIndex = 7;
} }
// @consul-rpc-glue: Datacenter,LeaderReadTODO // @consul-rpc-glue: LeaderReadTODO
message PeeringReadRequest { message PeeringReadRequest {
string Name = 1; string Name = 1;
string Partition = 2; string Partition = 2;
string Datacenter = 3;
//TODO(peering) query metadata
} }
message PeeringReadResponse { message PeeringReadResponse {
Peering Peering = 1; Peering Peering = 1;
//TODO(peering) query metadata
} }
// @consul-rpc-glue: Datacenter,LeaderReadTODO // @consul-rpc-glue: LeaderReadTODO
message PeeringListRequest { message PeeringListRequest {
string Partition = 1; string Partition = 1;
string Datacenter = 2;
//TODO(peering) query metadata
} }
message PeeringListResponse { message PeeringListResponse {
repeated Peering Peerings = 1; repeated Peering Peerings = 1;
//TODO(peering) query metadata
} }
// @consul-rpc-glue: Datacenter,WriteTODO
message PeeringWriteRequest { message PeeringWriteRequest {
Peering Peering = 1; Peering Peering = 1;
//TODO(peering): what to do with embedded write request?
string Datacenter = 2;
// Meta is a mapping of some string value to any other string value // Meta is a mapping of some string value to any other string value
map<string, string> Meta = 3; map<string, string> Meta = 2;
} }
// TODO(peering): Consider returning Peering if we keep this endpoint around // TODO(peering): Consider returning Peering if we keep this endpoint around
message PeeringWriteResponse {} message PeeringWriteResponse {}
// @consul-rpc-glue: Datacenter,WriteTODO
message PeeringDeleteRequest { message PeeringDeleteRequest {
string Name = 1; string Name = 1;
string Partition = 2; string Partition = 2;
//TODO(peering): what to do with embedded write request?
string Datacenter = 3;
} }
message PeeringDeleteResponse {} message PeeringDeleteResponse {}
// @consul-rpc-glue: Datacenter,ReadTODO
message TrustBundleListByServiceRequest { message TrustBundleListByServiceRequest {
string ServiceName = 1; string ServiceName = 1;
string Namespace = 2; string Namespace = 2;
string Partition = 3; string Partition = 3;
string Kind = 4; string Kind = 4;
// these are common fields required for implementing structs.RPCInfo methods
// that are used to forward requests
string Datacenter = 5;
} }
message TrustBundleListByServiceResponse { message TrustBundleListByServiceResponse {
@ -210,14 +189,9 @@ message TrustBundleListByServiceResponse {
repeated PeeringTrustBundle Bundles = 2; repeated PeeringTrustBundle Bundles = 2;
} }
// @consul-rpc-glue: Datacenter,ReadTODO
message TrustBundleReadRequest { message TrustBundleReadRequest {
string Name = 1; string Name = 1;
string Partition = 2; string Partition = 2;
// these are common fields required for implementing structs.RPCInfo methods
// that are used to forward requests
string Datacenter = 3;
} }
message TrustBundleReadResponse { message TrustBundleReadResponse {
@ -225,30 +199,23 @@ message TrustBundleReadResponse {
PeeringTrustBundle Bundle = 2; PeeringTrustBundle Bundle = 2;
} }
// This is a purely internal type and does not require query metadata.
message PeeringTerminateByIDRequest { message PeeringTerminateByIDRequest {
string ID = 1; string ID = 1;
} }
message PeeringTerminateByIDResponse {} message PeeringTerminateByIDResponse {}
// @consul-rpc-glue: Datacenter
message PeeringTrustBundleWriteRequest { message PeeringTrustBundleWriteRequest {
PeeringTrustBundle PeeringTrustBundle = 1; PeeringTrustBundle PeeringTrustBundle = 1;
//TODO(peering): what to do with embedded write request?
string Datacenter = 2;
} }
message PeeringTrustBundleWriteResponse {} message PeeringTrustBundleWriteResponse {}
// @consul-rpc-glue: Datacenter
message PeeringTrustBundleDeleteRequest { message PeeringTrustBundleDeleteRequest {
string Name = 1; string Name = 1;
string Partition = 2; string Partition = 2;
//TODO(peering): what to do with embedded write request?
string Datacenter = 3;
} }
message PeeringTrustBundleDeleteResponse {} message PeeringTrustBundleDeleteResponse {}
@ -265,11 +232,6 @@ message GenerateTokenRequest {
// Partition is the local partition being peered. // Partition is the local partition being peered.
string Partition = 2; string Partition = 2;
// these are common fields required for implementing structs.RPCInfo methods
// that are used to forward requests
string Datacenter = 3;
string Token = 4;
// Meta is a mapping of some string value to any other string value // Meta is a mapping of some string value to any other string value
map<string, string> Meta = 5; map<string, string> Meta = 5;
@ -290,8 +252,6 @@ message GenerateTokenResponse {
string PeeringToken = 1; string PeeringToken = 1;
} }
// @consul-rpc-glue: Datacenter
//
// mog annotation: // mog annotation:
// //
// target=github.com/hashicorp/consul/api.PeeringEstablishRequest // target=github.com/hashicorp/consul/api.PeeringEstablishRequest
@ -307,16 +267,10 @@ message EstablishRequest {
// Partition is the local partition being peered. // Partition is the local partition being peered.
string Partition = 3; string Partition = 3;
// these are common fields required for implementing structs.RPCInfo methods
// that are used to forward requests
string Datacenter = 4;
string Token = 5;
// Meta is a mapping of some string value to any other string value // Meta is a mapping of some string value to any other string value
map<string, string> Meta = 6; map<string, string> Meta = 4;
} }
//
// mog annotation: // mog annotation:
// //
// target=github.com/hashicorp/consul/api.PeeringEstablishResponse // target=github.com/hashicorp/consul/api.PeeringEstablishResponse

View File

@ -12,14 +12,6 @@ import (
var _ structs.RPCInfo var _ structs.RPCInfo
var _ time.Month var _ time.Month
// RequestDatacenter implements structs.RPCInfo
func (msg *PeeringReadRequest) RequestDatacenter() string {
if msg == nil {
return ""
}
return msg.Datacenter
}
// IsRead implements structs.RPCInfo // IsRead implements structs.RPCInfo
func (msg *PeeringReadRequest) IsRead() bool { func (msg *PeeringReadRequest) IsRead() bool {
// TODO(peering): figure out read semantics here // TODO(peering): figure out read semantics here
@ -64,14 +56,6 @@ func (msg *PeeringReadRequest) Token() string {
return "" return ""
} }
// RequestDatacenter implements structs.RPCInfo
func (msg *PeeringListRequest) RequestDatacenter() string {
if msg == nil {
return ""
}
return msg.Datacenter
}
// IsRead implements structs.RPCInfo // IsRead implements structs.RPCInfo
func (msg *PeeringListRequest) IsRead() bool { func (msg *PeeringListRequest) IsRead() bool {
// TODO(peering): figure out read semantics here // TODO(peering): figure out read semantics here
@ -115,211 +99,3 @@ func (msg *PeeringListRequest) Token() string {
// TODO(peering): figure out read semantics here // TODO(peering): figure out read semantics here
return "" return ""
} }
// RequestDatacenter implements structs.RPCInfo
func (msg *PeeringWriteRequest) RequestDatacenter() string {
if msg == nil {
return ""
}
return msg.Datacenter
}
// IsRead implements structs.RPCInfo
func (msg *PeeringWriteRequest) IsRead() bool {
// TODO(peering): figure out write semantics here
return false
}
// AllowStaleRead implements structs.RPCInfo
func (msg *PeeringWriteRequest) AllowStaleRead() bool {
// TODO(peering): figure out write semantics here
return false
}
// HasTimedOut implements structs.RPCInfo
func (msg *PeeringWriteRequest) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) {
// TODO(peering): figure out write semantics here
return time.Since(start) > rpcHoldTimeout, nil
}
// Timeout implements structs.RPCInfo
func (msg *PeeringWriteRequest) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration {
// TODO(peering): figure out write semantics here
return rpcHoldTimeout
}
// SetTokenSecret implements structs.RPCInfo
func (msg *PeeringWriteRequest) SetTokenSecret(s string) {
// TODO(peering): figure out write semantics here
}
// TokenSecret implements structs.RPCInfo
func (msg *PeeringWriteRequest) TokenSecret() string {
// TODO(peering): figure out write semantics here
return ""
}
// RequestDatacenter implements structs.RPCInfo
func (msg *PeeringDeleteRequest) RequestDatacenter() string {
if msg == nil {
return ""
}
return msg.Datacenter
}
// IsRead implements structs.RPCInfo
func (msg *PeeringDeleteRequest) IsRead() bool {
// TODO(peering): figure out write semantics here
return false
}
// AllowStaleRead implements structs.RPCInfo
func (msg *PeeringDeleteRequest) AllowStaleRead() bool {
// TODO(peering): figure out write semantics here
return false
}
// HasTimedOut implements structs.RPCInfo
func (msg *PeeringDeleteRequest) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) {
// TODO(peering): figure out write semantics here
return time.Since(start) > rpcHoldTimeout, nil
}
// Timeout implements structs.RPCInfo
func (msg *PeeringDeleteRequest) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration {
// TODO(peering): figure out write semantics here
return rpcHoldTimeout
}
// SetTokenSecret implements structs.RPCInfo
func (msg *PeeringDeleteRequest) SetTokenSecret(s string) {
// TODO(peering): figure out write semantics here
}
// TokenSecret implements structs.RPCInfo
func (msg *PeeringDeleteRequest) TokenSecret() string {
// TODO(peering): figure out write semantics here
return ""
}
// RequestDatacenter implements structs.RPCInfo
func (msg *TrustBundleListByServiceRequest) RequestDatacenter() string {
if msg == nil {
return ""
}
return msg.Datacenter
}
// IsRead implements structs.RPCInfo
func (msg *TrustBundleListByServiceRequest) IsRead() bool {
// TODO(peering): figure out read semantics here
return true
}
// AllowStaleRead implements structs.RPCInfo
func (msg *TrustBundleListByServiceRequest) AllowStaleRead() bool {
// TODO(peering): figure out read semantics here
return false
}
// HasTimedOut implements structs.RPCInfo
func (msg *TrustBundleListByServiceRequest) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) {
// TODO(peering): figure out read semantics here
return time.Since(start) > rpcHoldTimeout, nil
}
// Timeout implements structs.RPCInfo
func (msg *TrustBundleListByServiceRequest) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration {
// TODO(peering): figure out read semantics here
return rpcHoldTimeout
}
// SetTokenSecret implements structs.RPCInfo
func (msg *TrustBundleListByServiceRequest) SetTokenSecret(s string) {
// TODO(peering): figure out read semantics here
}
// TokenSecret implements structs.RPCInfo
func (msg *TrustBundleListByServiceRequest) TokenSecret() string {
// TODO(peering): figure out read semantics here
return ""
}
// Token implements structs.RPCInfo
func (msg *TrustBundleListByServiceRequest) Token() string {
// TODO(peering): figure out read semantics here
return ""
}
// RequestDatacenter implements structs.RPCInfo
func (msg *TrustBundleReadRequest) RequestDatacenter() string {
if msg == nil {
return ""
}
return msg.Datacenter
}
// IsRead implements structs.RPCInfo
func (msg *TrustBundleReadRequest) IsRead() bool {
// TODO(peering): figure out read semantics here
return true
}
// AllowStaleRead implements structs.RPCInfo
func (msg *TrustBundleReadRequest) AllowStaleRead() bool {
// TODO(peering): figure out read semantics here
return false
}
// HasTimedOut implements structs.RPCInfo
func (msg *TrustBundleReadRequest) HasTimedOut(start time.Time, rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) (bool, error) {
// TODO(peering): figure out read semantics here
return time.Since(start) > rpcHoldTimeout, nil
}
// Timeout implements structs.RPCInfo
func (msg *TrustBundleReadRequest) Timeout(rpcHoldTimeout time.Duration, a time.Duration, b time.Duration) time.Duration {
// TODO(peering): figure out read semantics here
return rpcHoldTimeout
}
// SetTokenSecret implements structs.RPCInfo
func (msg *TrustBundleReadRequest) SetTokenSecret(s string) {
// TODO(peering): figure out read semantics here
}
// TokenSecret implements structs.RPCInfo
func (msg *TrustBundleReadRequest) TokenSecret() string {
// TODO(peering): figure out read semantics here
return ""
}
// Token implements structs.RPCInfo
func (msg *TrustBundleReadRequest) Token() string {
// TODO(peering): figure out read semantics here
return ""
}
// RequestDatacenter implements structs.RPCInfo
func (msg *PeeringTrustBundleWriteRequest) RequestDatacenter() string {
if msg == nil {
return ""
}
return msg.Datacenter
}
// RequestDatacenter implements structs.RPCInfo
func (msg *PeeringTrustBundleDeleteRequest) RequestDatacenter() string {
if msg == nil {
return ""
}
return msg.Datacenter
}
// RequestDatacenter implements structs.RPCInfo
func (msg *EstablishRequest) RequestDatacenter() string {
if msg == nil {
return ""
}
return msg.Datacenter
}