From 688dfe31381c2ea74cb86a7811061db2a55a461e Mon Sep 17 00:00:00 2001 From: Daniel Upton Date: Tue, 12 Jul 2022 11:35:52 +0100 Subject: [PATCH] proxycfg-glue: server-local implementation of `ServiceList` This is the OSS portion of enterprise PR 2242. This PR introduces a server-local implementation of the proxycfg.ServiceList interface, backed by streaming events and a local materializer. --- agent/agent.go | 1 + agent/consul/fsm/fsm.go | 7 + agent/consul/state/catalog_events.go | 93 ++++++ agent/consul/state/catalog_events_test.go | 112 +++++++ agent/consul/state/events.go | 6 + agent/consul/state/memdb.go | 2 + agent/proxycfg-glue/config_entry.go | 23 +- agent/proxycfg-glue/glue.go | 6 - agent/proxycfg-glue/service_list.go | 124 +++++++ agent/proxycfg-glue/service_list_test.go | 140 ++++++++ proto/pbsubscribe/subscribe.pb.binary.go | 10 + proto/pbsubscribe/subscribe.pb.go | 380 +++++++++++++++------- proto/pbsubscribe/subscribe.proto | 19 ++ 13 files changed, 784 insertions(+), 139 deletions(-) create mode 100644 agent/proxycfg-glue/service_list.go create mode 100644 agent/proxycfg-glue/service_list_test.go diff --git a/agent/agent.go b/agent/agent.go index c1381d0d2..7aa42e3d9 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -4249,6 +4249,7 @@ func (a *Agent) proxyDataSources() proxycfg.DataSources { sources.CompiledDiscoveryChain = proxycfgglue.ServerCompiledDiscoveryChain(deps, proxycfgglue.CacheCompiledDiscoveryChain(a.cache)) sources.Intentions = proxycfgglue.ServerIntentions(deps) sources.IntentionUpstreams = proxycfgglue.ServerIntentionUpstreams(deps) + sources.ServiceList = proxycfgglue.ServerServiceList(deps, proxycfgglue.CacheServiceList(a.cache)) } a.fillEnterpriseProxyDataSources(&sources) diff --git a/agent/consul/fsm/fsm.go b/agent/consul/fsm/fsm.go index 8fa617b45..432e64631 100644 --- a/agent/consul/fsm/fsm.go +++ b/agent/consul/fsm/fsm.go @@ -324,4 +324,11 @@ func (c *FSM) registerStreamSnapshotHandlers() { if err != nil { panic(fmt.Errorf("fatal error encountered registering streaming snapshot handlers: %w", err)) } + + err = c.deps.Publisher.RegisterHandler(state.EventTopicServiceList, func(req stream.SubscribeRequest, buf stream.SnapshotAppender) (uint64, error) { + return c.State().ServiceListSnapshot(req, buf) + }, true) + if err != nil { + panic(fmt.Errorf("fatal error encountered registering streaming snapshot handlers: %w", err)) + } } diff --git a/agent/consul/state/catalog_events.go b/agent/consul/state/catalog_events.go index b4b498b98..06d6414af 100644 --- a/agent/consul/state/catalog_events.go +++ b/agent/consul/state/catalog_events.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/consul/stream" "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/proto/pbcommon" "github.com/hashicorp/consul/proto/pbservice" "github.com/hashicorp/consul/proto/pbsubscribe" ) @@ -71,6 +72,39 @@ func (e EventPayloadCheckServiceNode) ToSubscriptionEvent(idx uint64) *pbsubscri } } +// EventPayloadServiceListUpdate is used as the Payload for a stream.Event when +// services (not service instances) are registered/deregistered. These events +// are used to materialize the list of services in a datacenter. +type EventPayloadServiceListUpdate struct { + Op pbsubscribe.CatalogOp + + Name string + EnterpriseMeta acl.EnterpriseMeta + PeerName string +} + +func (e *EventPayloadServiceListUpdate) ToSubscriptionEvent(idx uint64) *pbsubscribe.Event { + return &pbsubscribe.Event{ + Index: idx, + Payload: &pbsubscribe.Event_Service{ + Service: &pbsubscribe.ServiceListUpdate{ + Op: e.Op, + Name: e.Name, + EnterpriseMeta: pbcommon.NewEnterpriseMetaFromStructs(e.EnterpriseMeta), + PeerName: e.PeerName, + }, + }, + } +} + +func (e *EventPayloadServiceListUpdate) Subject() stream.Subject { return stream.SubjectNone } + +func (e *EventPayloadServiceListUpdate) HasReadPermission(authz acl.Authorizer) bool { + var authzContext acl.AuthorizerContext + e.EnterpriseMeta.FillAuthzContext(&authzContext) + return authz.ServiceRead(e.Name, &authzContext) == acl.Allow +} + // serviceHealthSnapshot returns a stream.SnapshotFunc that provides a snapshot // of stream.Events that describe the current state of a service health query. func (s *Store) ServiceHealthSnapshot(req stream.SubscribeRequest, buf stream.SnapshotAppender) (index uint64, err error) { @@ -156,6 +190,65 @@ type nodeTuple struct { var serviceChangeIndirect = serviceChange{changeType: changeIndirect} +// ServiceListUpdateEventsFromChanges returns events representing changes to +// the list of services from the given set of state store changes. +func ServiceListUpdateEventsFromChanges(tx ReadTxn, changes Changes) ([]stream.Event, error) { + var events []stream.Event + for _, change := range changes.Changes { + if change.Table != tableKindServiceNames { + continue + } + + kindName := changeObject(change).(*KindServiceName) + + // TODO(peering): make this peer-aware. + payload := &EventPayloadServiceListUpdate{ + Name: kindName.Service.Name, + EnterpriseMeta: kindName.Service.EnterpriseMeta, + } + + if change.Deleted() { + payload.Op = pbsubscribe.CatalogOp_Deregister + } else { + payload.Op = pbsubscribe.CatalogOp_Register + } + + events = append(events, stream.Event{ + Topic: EventTopicServiceList, + Index: changes.Index, + Payload: payload, + }) + } + return events, nil +} + +// ServiceListSnapshot is a stream.SnapshotFunc that returns a snapshot of +// all service names. +func (s *Store) ServiceListSnapshot(_ stream.SubscribeRequest, buf stream.SnapshotAppender) (uint64, error) { + index, names, err := s.ServiceNamesOfKind(nil, "") + if err != nil { + return 0, err + } + + if l := len(names); l > 0 { + events := make([]stream.Event, l) + for idx, name := range names { + events[idx] = stream.Event{ + Topic: EventTopicServiceList, + Index: index, + Payload: &EventPayloadServiceListUpdate{ + Op: pbsubscribe.CatalogOp_Register, + Name: name.Service.Name, + EnterpriseMeta: name.Service.EnterpriseMeta, + }, + } + } + buf.Append(events) + } + + return index, nil +} + // ServiceHealthEventsFromChanges returns all the service and Connect health // events that should be emitted given a set of changes to the state store. func ServiceHealthEventsFromChanges(tx ReadTxn, changes Changes) ([]stream.Event, error) { diff --git a/agent/consul/state/catalog_events_test.go b/agent/consul/state/catalog_events_test.go index 129b834b8..ef398ed6c 100644 --- a/agent/consul/state/catalog_events_test.go +++ b/agent/consul/state/catalog_events_test.go @@ -8,6 +8,7 @@ import ( "github.com/google/go-cmp/cmp/cmpopts" "github.com/stretchr/testify/require" + "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/consul/stream" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/api" @@ -2543,3 +2544,114 @@ func newPayloadCheckServiceNodeWithOverride( overrideNamespace: overrideNamespace, } } + +func TestServiceListUpdateSnapshot(t *testing.T) { + const index uint64 = 123 + + store := testStateStore(t) + require.NoError(t, store.EnsureRegistration(index, testServiceRegistration(t, "db"))) + + buf := &snapshotAppender{} + idx, err := store.ServiceListSnapshot(stream.SubscribeRequest{Subject: stream.SubjectNone}, buf) + require.NoError(t, err) + require.NotZero(t, idx) + + require.Len(t, buf.events, 1) + require.Len(t, buf.events[0], 1) + + payload := buf.events[0][0].Payload.(*EventPayloadServiceListUpdate) + require.Equal(t, pbsubscribe.CatalogOp_Register, payload.Op) + require.Equal(t, "db", payload.Name) +} + +func TestServiceListUpdateEventsFromChanges(t *testing.T) { + const changeIndex = 123 + + testCases := map[string]struct { + setup func(*Store, *txn) error + mutate func(*Store, *txn) error + events []stream.Event + }{ + "register new service": { + mutate: func(store *Store, tx *txn) error { + return store.ensureRegistrationTxn(tx, changeIndex, false, testServiceRegistration(t, "db"), false) + }, + events: []stream.Event{ + { + Topic: EventTopicServiceList, + Index: changeIndex, + Payload: &EventPayloadServiceListUpdate{ + Op: pbsubscribe.CatalogOp_Register, + Name: "db", + EnterpriseMeta: *acl.DefaultEnterpriseMeta(), + }, + }, + }, + }, + "service already registered": { + setup: func(store *Store, tx *txn) error { + return store.ensureRegistrationTxn(tx, changeIndex, false, testServiceRegistration(t, "db"), false) + }, + mutate: func(store *Store, tx *txn) error { + return store.ensureRegistrationTxn(tx, changeIndex, false, testServiceRegistration(t, "db"), false) + }, + events: nil, + }, + "deregister last instance of service": { + setup: func(store *Store, tx *txn) error { + return store.ensureRegistrationTxn(tx, changeIndex, false, testServiceRegistration(t, "db"), false) + }, + mutate: func(store *Store, tx *txn) error { + return store.deleteServiceTxn(tx, tx.Index, "node1", "db", nil, "") + }, + events: []stream.Event{ + { + Topic: EventTopicServiceList, + Index: changeIndex, + Payload: &EventPayloadServiceListUpdate{ + Op: pbsubscribe.CatalogOp_Deregister, + Name: "db", + EnterpriseMeta: *acl.DefaultEnterpriseMeta(), + }, + }, + }, + }, + "deregister (not the last) instance of service": { + setup: func(store *Store, tx *txn) error { + if err := store.ensureRegistrationTxn(tx, changeIndex, false, testServiceRegistration(t, "db"), false); err != nil { + return err + } + if err := store.ensureRegistrationTxn(tx, changeIndex, false, testServiceRegistration(t, "db", regNode2), false); err != nil { + return err + } + return nil + }, + mutate: func(store *Store, tx *txn) error { + return store.deleteServiceTxn(tx, tx.Index, "node1", "db", nil, "") + }, + events: nil, + }, + } + for desc, tc := range testCases { + t.Run(desc, func(t *testing.T) { + store := testStateStore(t) + + if tc.setup != nil { + tx := store.db.WriteTxn(0) + require.NoError(t, tc.setup(store, tx)) + require.NoError(t, tx.Commit()) + } + + tx := store.db.WriteTxn(0) + t.Cleanup(tx.Abort) + + if tc.mutate != nil { + require.NoError(t, tc.mutate(store, tx)) + } + + events, err := ServiceListUpdateEventsFromChanges(tx, Changes{Index: changeIndex, Changes: tx.Changes()}) + require.NoError(t, err) + require.Equal(t, tc.events, events) + }) + } +} diff --git a/agent/consul/state/events.go b/agent/consul/state/events.go index e59624511..2e74c44c9 100644 --- a/agent/consul/state/events.go +++ b/agent/consul/state/events.go @@ -43,6 +43,12 @@ func PBToStreamSubscribeRequest(req *pbsubscribe.SubscribeRequest, entMeta acl.E Name: named.Key, EnterpriseMeta: &entMeta, } + case EventTopicServiceList: + // Events on this topic are published to SubjectNone, but rather than + // exposing this in (and further complicating) the streaming API we rely + // on consumers passing WildcardSubject instead, which is functionally the + // same for this purpose. + return nil, fmt.Errorf("topic %s can only be consumed using WildcardSubject", EventTopicServiceList) default: return nil, fmt.Errorf("cannot construct subject for topic %s", req.Topic) } diff --git a/agent/consul/state/memdb.go b/agent/consul/state/memdb.go index 95a291061..751622977 100644 --- a/agent/consul/state/memdb.go +++ b/agent/consul/state/memdb.go @@ -184,6 +184,7 @@ var ( EventTopicServiceResolver = pbsubscribe.Topic_ServiceResolver EventTopicIngressGateway = pbsubscribe.Topic_IngressGateway EventTopicServiceIntentions = pbsubscribe.Topic_ServiceIntentions + EventTopicServiceList = pbsubscribe.Topic_ServiceList ) func processDBChanges(tx ReadTxn, changes Changes) ([]stream.Event, error) { @@ -192,6 +193,7 @@ func processDBChanges(tx ReadTxn, changes Changes) ([]stream.Event, error) { aclChangeUnsubscribeEvent, caRootsChangeEvents, ServiceHealthEventsFromChanges, + ServiceListUpdateEventsFromChanges, ConfigEntryEventsFromChanges, // TODO: add other table handlers here. } diff --git a/agent/proxycfg-glue/config_entry.go b/agent/proxycfg-glue/config_entry.go index 138909369..1f6fbf245 100644 --- a/agent/proxycfg-glue/config_entry.go +++ b/agent/proxycfg-glue/config_entry.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/consul/agent/proxycfg" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/agent/submatview" + "github.com/hashicorp/consul/proto/pbcommon" "github.com/hashicorp/consul/proto/pbconfigentry" "github.com/hashicorp/consul/proto/pbsubscribe" ) @@ -194,7 +195,7 @@ func (v *configEntryListView) Result(index uint64) any { } func (v *configEntryListView) Update(events []*pbsubscribe.Event) error { - for _, event := range v.filterByEnterpriseMeta(events) { + for _, event := range filterByEnterpriseMeta(events, v.entMeta) { update := event.GetConfigEntry() configEntry := pbconfigentry.ConfigEntryToStructs(update.ConfigEntry) name := structs.NewServiceName(configEntry.GetName(), configEntry.GetEnterpriseMeta()).String() @@ -213,22 +214,26 @@ func (v *configEntryListView) Update(events []*pbsubscribe.Event) error { // don't match the request's enterprise meta - this is necessary because when // subscribing to a topic with SubjectWildcard we'll get events for resources // in all partitions and namespaces. -func (v *configEntryListView) filterByEnterpriseMeta(events []*pbsubscribe.Event) []*pbsubscribe.Event { - partition := v.entMeta.PartitionOrDefault() - namespace := v.entMeta.NamespaceOrDefault() +func filterByEnterpriseMeta(events []*pbsubscribe.Event, entMeta acl.EnterpriseMeta) []*pbsubscribe.Event { + partition := entMeta.PartitionOrDefault() + namespace := entMeta.NamespaceOrDefault() filtered := make([]*pbsubscribe.Event, 0, len(events)) for _, event := range events { - configEntry := event.GetConfigEntry().GetConfigEntry() - if configEntry == nil { + var eventEntMeta *pbcommon.EnterpriseMeta + switch payload := event.Payload.(type) { + case *pbsubscribe.Event_ConfigEntry: + eventEntMeta = payload.ConfigEntry.ConfigEntry.GetEnterpriseMeta() + case *pbsubscribe.Event_Service: + eventEntMeta = payload.Service.GetEnterpriseMeta() + default: continue } - entMeta := configEntry.GetEnterpriseMeta() - if partition != acl.WildcardName && !acl.EqualPartitions(partition, entMeta.GetPartition()) { + if partition != acl.WildcardName && !acl.EqualPartitions(partition, eventEntMeta.GetPartition()) { continue } - if namespace != acl.WildcardName && !acl.EqualNamespaces(namespace, entMeta.GetNamespace()) { + if namespace != acl.WildcardName && !acl.EqualNamespaces(namespace, eventEntMeta.GetNamespace()) { continue } diff --git a/agent/proxycfg-glue/glue.go b/agent/proxycfg-glue/glue.go index f06df2827..739cc7f64 100644 --- a/agent/proxycfg-glue/glue.go +++ b/agent/proxycfg-glue/glue.go @@ -103,12 +103,6 @@ func CacheResolvedServiceConfig(c *cache.Cache) proxycfg.ResolvedServiceConfig { return &cacheProxyDataSource[*structs.ServiceConfigRequest]{c, cachetype.ResolvedServiceConfigName} } -// CacheServiceList satisfies the proxycfg.ServiceList interface by sourcing -// data from the agent cache. -func CacheServiceList(c *cache.Cache) proxycfg.ServiceList { - return &cacheProxyDataSource[*structs.DCSpecificRequest]{c, cachetype.CatalogServiceListName} -} - // CacheTrustBundle satisfies the proxycfg.TrustBundle interface by sourcing // data from the agent cache. func CacheTrustBundle(c *cache.Cache) proxycfg.TrustBundle { diff --git a/agent/proxycfg-glue/service_list.go b/agent/proxycfg-glue/service_list.go new file mode 100644 index 000000000..14dc13f31 --- /dev/null +++ b/agent/proxycfg-glue/service_list.go @@ -0,0 +1,124 @@ +package proxycfgglue + +import ( + "context" + "sort" + + "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/agent/cache" + cachetype "github.com/hashicorp/consul/agent/cache-types" + "github.com/hashicorp/consul/agent/proxycfg" + "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/agent/submatview" + "github.com/hashicorp/consul/proto/pbcommon" + "github.com/hashicorp/consul/proto/pbsubscribe" +) + +// CacheServiceList satisfies the proxycfg.ServiceList interface by sourcing +// data from the agent cache. +func CacheServiceList(c *cache.Cache) proxycfg.ServiceList { + return &cacheProxyDataSource[*structs.DCSpecificRequest]{c, cachetype.CatalogServiceListName} +} + +func ServerServiceList(deps ServerDataSourceDeps, remoteSource proxycfg.ServiceList) proxycfg.ServiceList { + return &serverServiceList{deps, remoteSource} +} + +type serverServiceList struct { + deps ServerDataSourceDeps + remoteSource proxycfg.ServiceList +} + +func (s *serverServiceList) Notify(ctx context.Context, req *structs.DCSpecificRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error { + if req.Datacenter != s.deps.Datacenter { + return s.remoteSource.Notify(ctx, req, correlationID, ch) + } + return s.deps.ViewStore.NotifyCallback( + ctx, + &serviceListRequest{s.deps, req}, + correlationID, + dispatchCacheUpdate(ch), + ) +} + +type serviceListRequest struct { + deps ServerDataSourceDeps + req *structs.DCSpecificRequest +} + +func (r *serviceListRequest) Request(index uint64) *pbsubscribe.SubscribeRequest { + return &pbsubscribe.SubscribeRequest{ + Topic: pbsubscribe.Topic_ServiceList, + Subject: &pbsubscribe.SubscribeRequest_WildcardSubject{WildcardSubject: true}, + Index: index, + Datacenter: r.req.Datacenter, + Token: r.req.QueryOptions.Token, + } +} + +func (r *serviceListRequest) CacheInfo() cache.RequestInfo { return r.req.CacheInfo() } + +func (r *serviceListRequest) NewMaterializer() (submatview.Materializer, error) { + return submatview.NewLocalMaterializer(submatview.LocalMaterializerDeps{ + Backend: r.deps.EventPublisher, + ACLResolver: r.deps.ACLResolver, + Deps: submatview.Deps{ + View: newServiceListView(r.req.EnterpriseMeta), + Logger: r.deps.Logger, + Request: r.Request, + }, + }), nil +} + +func (serviceListRequest) Type() string { return "proxycfgglue.ServiceList" } + +func newServiceListView(entMeta acl.EnterpriseMeta) *serviceListView { + view := &serviceListView{entMeta: entMeta} + view.Reset() + return view +} + +type serviceListView struct { + entMeta acl.EnterpriseMeta + state map[string]structs.ServiceName +} + +func (v *serviceListView) Reset() { v.state = make(map[string]structs.ServiceName) } + +func (v *serviceListView) Update(events []*pbsubscribe.Event) error { + for _, event := range filterByEnterpriseMeta(events, v.entMeta) { + update := event.GetService() + if update == nil { + continue + } + + var entMeta acl.EnterpriseMeta + pbcommon.EnterpriseMetaToStructs(update.EnterpriseMeta, &entMeta) + name := structs.NewServiceName(update.Name, &entMeta) + + switch update.Op { + case pbsubscribe.CatalogOp_Register: + v.state[name.String()] = name + case pbsubscribe.CatalogOp_Deregister: + delete(v.state, name.String()) + } + } + return nil +} + +func (v *serviceListView) Result(index uint64) any { + serviceList := make(structs.ServiceList, 0, len(v.state)) + for _, name := range v.state { + serviceList = append(serviceList, name) + } + sort.Slice(serviceList, func(a, b int) bool { + return serviceList[a].String() < serviceList[b].String() + }) + return &structs.IndexedServiceList{ + Services: serviceList, + QueryMeta: structs.QueryMeta{ + Backend: structs.QueryBackendStreaming, + Index: index, + }, + } +} diff --git a/agent/proxycfg-glue/service_list_test.go b/agent/proxycfg-glue/service_list_test.go new file mode 100644 index 000000000..eedb211b3 --- /dev/null +++ b/agent/proxycfg-glue/service_list_test.go @@ -0,0 +1,140 @@ +package proxycfgglue + +import ( + "context" + "errors" + "testing" + "time" + + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + + "github.com/hashicorp/consul/acl" + "github.com/hashicorp/consul/agent/consul/state" + "github.com/hashicorp/consul/agent/consul/stream" + "github.com/hashicorp/consul/agent/proxycfg" + "github.com/hashicorp/consul/agent/structs" + "github.com/hashicorp/consul/agent/submatview" + "github.com/hashicorp/consul/proto/pbsubscribe" + "github.com/hashicorp/consul/sdk/testutil" +) + +func TestServerServiceList(t *testing.T) { + t.Run("remote queries are delegated to the remote source", func(t *testing.T) { + var ( + ctx = context.Background() + req = &structs.DCSpecificRequest{Datacenter: "dc2"} + correlationID = "correlation-id" + ch = make(chan<- proxycfg.UpdateEvent) + result = errors.New("KABOOM") + ) + + remoteSource := newMockServiceList(t) + remoteSource.On("Notify", ctx, req, correlationID, ch).Return(result) + + dataSource := ServerServiceList(ServerDataSourceDeps{Datacenter: "dc1"}, remoteSource) + err := dataSource.Notify(ctx, req, correlationID, ch) + require.Equal(t, result, err) + }) + + t.Run("local queries are served from a materialized view", func(t *testing.T) { + const ( + index uint64 = 123 + datacenter = "dc1" + ) + + logger := testutil.Logger(t) + + ctx, cancel := context.WithCancel(context.Background()) + t.Cleanup(cancel) + + store := submatview.NewStore(logger) + go store.Run(ctx) + + publisher := stream.NewEventPublisher(10 * time.Second) + publisher.RegisterHandler(pbsubscribe.Topic_ServiceList, + func(stream.SubscribeRequest, stream.SnapshotAppender) (uint64, error) { return index, nil }, + true) + go publisher.Run(ctx) + + dataSource := ServerServiceList(ServerDataSourceDeps{ + Datacenter: datacenter, + ACLResolver: newStaticResolver(acl.ManageAll()), + ViewStore: store, + EventPublisher: publisher, + Logger: logger, + }, nil) + + eventCh := make(chan proxycfg.UpdateEvent) + require.NoError(t, dataSource.Notify(ctx, &structs.DCSpecificRequest{Datacenter: datacenter}, "", eventCh)) + + testutil.RunStep(t, "initial state", func(t *testing.T) { + result := getEventResult[*structs.IndexedServiceList](t, eventCh) + require.Empty(t, result.Services) + }) + + testutil.RunStep(t, "register services", func(t *testing.T) { + publisher.Publish([]stream.Event{ + { + Index: index + 1, + Topic: pbsubscribe.Topic_ServiceList, + Payload: &state.EventPayloadServiceListUpdate{ + Op: pbsubscribe.CatalogOp_Register, + Name: "web", + }, + }, + { + Index: index + 1, + Topic: pbsubscribe.Topic_ServiceList, + Payload: &state.EventPayloadServiceListUpdate{ + Op: pbsubscribe.CatalogOp_Register, + Name: "db", + }, + }, + }) + + result := getEventResult[*structs.IndexedServiceList](t, eventCh) + require.Len(t, result.Services, 2) + + var names []string + for _, service := range result.Services { + names = append(names, service.Name) + } + require.ElementsMatch(t, names, []string{"web", "db"}) + }) + + testutil.RunStep(t, "deregister service", func(t *testing.T) { + publisher.Publish([]stream.Event{ + { + Index: index + 2, + Topic: pbsubscribe.Topic_ServiceList, + Payload: &state.EventPayloadServiceListUpdate{ + Op: pbsubscribe.CatalogOp_Deregister, + Name: "web", + }, + }, + }) + + result := getEventResult[*structs.IndexedServiceList](t, eventCh) + require.Len(t, result.Services, 1) + require.Equal(t, "db", result.Services[0].Name) + }) + }) +} + +func newMockServiceList(t *testing.T) *mockServiceList { + mock := &mockServiceList{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} + +type mockServiceList struct { + mock.Mock +} + +func (m *mockServiceList) Notify(ctx context.Context, req *structs.DCSpecificRequest, correlationID string, ch chan<- proxycfg.UpdateEvent) error { + return m.Called(ctx, req, correlationID, ch).Error(0) +} diff --git a/proto/pbsubscribe/subscribe.pb.binary.go b/proto/pbsubscribe/subscribe.pb.binary.go index 7e0e74509..43b7c8f59 100644 --- a/proto/pbsubscribe/subscribe.pb.binary.go +++ b/proto/pbsubscribe/subscribe.pb.binary.go @@ -66,3 +66,13 @@ func (msg *ConfigEntryUpdate) MarshalBinary() ([]byte, error) { func (msg *ConfigEntryUpdate) UnmarshalBinary(b []byte) error { return proto.Unmarshal(b, msg) } + +// MarshalBinary implements encoding.BinaryMarshaler +func (msg *ServiceListUpdate) MarshalBinary() ([]byte, error) { + return proto.Marshal(msg) +} + +// UnmarshalBinary implements encoding.BinaryUnmarshaler +func (msg *ServiceListUpdate) UnmarshalBinary(b []byte) error { + return proto.Unmarshal(b, msg) +} diff --git a/proto/pbsubscribe/subscribe.pb.go b/proto/pbsubscribe/subscribe.pb.go index deb43bad4..5d209df9a 100644 --- a/proto/pbsubscribe/subscribe.pb.go +++ b/proto/pbsubscribe/subscribe.pb.go @@ -16,6 +16,7 @@ package pbsubscribe import ( + pbcommon "github.com/hashicorp/consul/proto/pbcommon" pbconfigentry "github.com/hashicorp/consul/proto/pbconfigentry" pbservice "github.com/hashicorp/consul/proto/pbservice" protoreflect "google.golang.org/protobuf/reflect/protoreflect" @@ -49,6 +50,12 @@ const ( Topic_IngressGateway Topic = 5 // ServiceIntentions topic contains events for changes to service intentions. Topic_ServiceIntentions Topic = 6 + // ServiceList topic contains events about services (not service instances) + // getting registered/deregistered. It can be used to materialize a list of + // the services in the given datacenter. + // + // Note: WildcardSubject is the only supported Subject on this topic. + Topic_ServiceList Topic = 7 ) // Enum value maps for Topic. @@ -61,6 +68,7 @@ var ( 4: "ServiceResolver", 5: "IngressGateway", 6: "ServiceIntentions", + 7: "ServiceList", } Topic_value = map[string]int32{ "Unknown": 0, @@ -70,6 +78,7 @@ var ( "ServiceResolver": 4, "IngressGateway": 5, "ServiceIntentions": 6, + "ServiceList": 7, } ) @@ -467,6 +476,7 @@ type Event struct { // *Event_EventBatch // *Event_ServiceHealth // *Event_ConfigEntry + // *Event_Service Payload isEvent_Payload `protobuf_oneof:"Payload"` } @@ -551,6 +561,13 @@ func (x *Event) GetConfigEntry() *ConfigEntryUpdate { return nil } +func (x *Event) GetService() *ServiceListUpdate { + if x, ok := x.GetPayload().(*Event_Service); ok { + return x.Service + } + return nil +} + type isEvent_Payload interface { isEvent_Payload() } @@ -589,6 +606,11 @@ type Event_ConfigEntry struct { ConfigEntry *ConfigEntryUpdate `protobuf:"bytes,11,opt,name=ConfigEntry,proto3,oneof"` } +type Event_Service struct { + // Service is used for ServiceList topic. + Service *ServiceListUpdate `protobuf:"bytes,12,opt,name=Service,proto3,oneof"` +} + func (*Event_EndOfSnapshot) isEvent_Payload() {} func (*Event_NewSnapshotToFollow) isEvent_Payload() {} @@ -599,6 +621,8 @@ func (*Event_ServiceHealth) isEvent_Payload() {} func (*Event_ConfigEntry) isEvent_Payload() {} +func (*Event_Service) isEvent_Payload() {} + type EventBatch struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -756,121 +780,211 @@ func (x *ConfigEntryUpdate) GetConfigEntry() *pbconfigentry.ConfigEntry { return nil } +type ServiceListUpdate struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Op CatalogOp `protobuf:"varint,1,opt,name=Op,proto3,enum=subscribe.CatalogOp" json:"Op,omitempty"` + Name string `protobuf:"bytes,2,opt,name=Name,proto3" json:"Name,omitempty"` + EnterpriseMeta *pbcommon.EnterpriseMeta `protobuf:"bytes,3,opt,name=EnterpriseMeta,proto3" json:"EnterpriseMeta,omitempty"` + PeerName string `protobuf:"bytes,4,opt,name=PeerName,proto3" json:"PeerName,omitempty"` +} + +func (x *ServiceListUpdate) Reset() { + *x = ServiceListUpdate{} + if protoimpl.UnsafeEnabled { + mi := &file_proto_pbsubscribe_subscribe_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ServiceListUpdate) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ServiceListUpdate) ProtoMessage() {} + +func (x *ServiceListUpdate) ProtoReflect() protoreflect.Message { + mi := &file_proto_pbsubscribe_subscribe_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ServiceListUpdate.ProtoReflect.Descriptor instead. +func (*ServiceListUpdate) Descriptor() ([]byte, []int) { + return file_proto_pbsubscribe_subscribe_proto_rawDescGZIP(), []int{6} +} + +func (x *ServiceListUpdate) GetOp() CatalogOp { + if x != nil { + return x.Op + } + return CatalogOp_Register +} + +func (x *ServiceListUpdate) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ServiceListUpdate) GetEnterpriseMeta() *pbcommon.EnterpriseMeta { + if x != nil { + return x.EnterpriseMeta + } + return nil +} + +func (x *ServiceListUpdate) GetPeerName() string { + if x != nil { + return x.PeerName + } + return "" +} + var File_proto_pbsubscribe_subscribe_proto protoreflect.FileDescriptor var file_proto_pbsubscribe_subscribe_proto_rawDesc = []byte{ 0x0a, 0x21, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2f, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x1a, 0x26, - 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, - 0x74, 0x72, 0x79, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x22, 0x78, 0x0a, 0x0c, 0x4e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x03, 0x4b, 0x65, 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, + 0x6f, 0x74, 0x6f, 0x12, 0x09, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x1a, 0x1b, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2f, 0x63, + 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x26, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, + 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x5f, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x1a, 0x1a, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x62, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2f, 0x6e, 0x6f, 0x64, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, + 0x78, 0x0a, 0x0c, 0x4e, 0x61, 0x6d, 0x65, 0x64, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, + 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4b, 0x65, + 0x79, 0x12, 0x1c, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4e, 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, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, + 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xe6, 0x02, 0x0a, 0x10, 0x53, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, + 0x0a, 0x05, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x10, 0x2e, + 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x52, + 0x05, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, + 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x49, + 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x61, 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, 0x12, 0x1c, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4e, 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, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, - 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0xe6, 0x02, 0x0a, - 0x10, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x26, 0x0a, 0x05, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x10, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x54, 0x6f, 0x70, - 0x69, 0x63, 0x52, 0x05, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x10, 0x0a, 0x03, 0x4b, 0x65, 0x79, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x04, 0x20, 0x01, 0x28, 0x04, - 0x52, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x1e, 0x0a, 0x0a, 0x44, 0x61, 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, 0x12, 0x1c, 0x0a, 0x09, 0x4e, 0x61, 0x6d, 0x65, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x4e, 0x61, 0x6d, 0x65, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, - 0x2a, 0x0a, 0x0f, 0x57, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x53, 0x75, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0f, 0x57, 0x69, 0x6c, 0x64, - 0x63, 0x61, 0x72, 0x64, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x3d, 0x0a, 0x0c, 0x4e, - 0x61, 0x6d, 0x65, 0x64, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x4e, 0x61, - 0x6d, 0x65, 0x64, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x4e, 0x61, - 0x6d, 0x65, 0x64, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x53, 0x75, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0xc7, 0x02, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, - 0x14, 0x0a, 0x05, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, - 0x49, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0d, 0x45, 0x6e, 0x64, 0x4f, 0x66, 0x53, 0x6e, - 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0d, - 0x45, 0x6e, 0x64, 0x4f, 0x66, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x32, 0x0a, - 0x13, 0x4e, 0x65, 0x77, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x54, 0x6f, 0x46, 0x6f, - 0x6c, 0x6c, 0x6f, 0x77, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x13, 0x4e, 0x65, + 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x50, 0x61, 0x72, 0x74, 0x69, 0x74, 0x69, 0x6f, 0x6e, + 0x12, 0x1a, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x2a, 0x0a, 0x0f, + 0x57, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, 0x64, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, + 0x09, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0f, 0x57, 0x69, 0x6c, 0x64, 0x63, 0x61, 0x72, + 0x64, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x3d, 0x0a, 0x0c, 0x4e, 0x61, 0x6d, 0x65, + 0x64, 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, + 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x4e, 0x61, 0x6d, 0x65, 0x64, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x00, 0x52, 0x0c, 0x4e, 0x61, 0x6d, 0x65, 0x64, + 0x53, 0x75, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x42, 0x09, 0x0a, 0x07, 0x53, 0x75, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x22, 0x81, 0x03, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, + 0x49, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x01, 0x20, 0x01, 0x28, 0x04, 0x52, 0x05, 0x49, 0x6e, 0x64, + 0x65, 0x78, 0x12, 0x26, 0x0a, 0x0d, 0x45, 0x6e, 0x64, 0x4f, 0x66, 0x53, 0x6e, 0x61, 0x70, 0x73, + 0x68, 0x6f, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x0d, 0x45, 0x6e, 0x64, + 0x4f, 0x66, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x32, 0x0a, 0x13, 0x4e, 0x65, 0x77, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x54, 0x6f, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, - 0x77, 0x12, 0x37, 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, - 0x65, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68, 0x48, 0x00, 0x52, 0x0a, - 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x46, 0x0a, 0x0d, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x48, 0x00, 0x52, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, - 0x74, 0x68, 0x12, 0x40, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, - 0x69, 0x62, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, - 0x6e, 0x74, 0x72, 0x79, 0x42, 0x09, 0x0a, 0x07, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, - 0x36, 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x28, 0x0a, - 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, - 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, - 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x9c, 0x01, 0x0a, 0x13, 0x53, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, - 0x24, 0x0a, 0x02, 0x4f, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x73, 0x75, - 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x4f, - 0x70, 0x52, 0x02, 0x4f, 0x70, 0x12, 0x5f, 0x0a, 0x10, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, - 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, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x10, 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x22, 0xc4, 0x01, 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x02, - 0x4f, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x25, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x52, - 0x02, 0x4f, 0x70, 0x12, 0x54, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, - 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 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, 0x66, 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, - 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0b, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x22, 0x22, 0x0a, 0x08, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4f, 0x70, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x10, - 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x10, 0x01, 0x2a, 0x91, 0x01, - 0x0a, 0x05, 0x54, 0x6f, 0x70, 0x69, 0x63, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, - 0x77, 0x6e, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, - 0x65, 0x61, 0x6c, 0x74, 0x68, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x10, - 0x02, 0x12, 0x0e, 0x0a, 0x0a, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x10, - 0x03, 0x12, 0x13, 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, - 0x6c, 0x76, 0x65, 0x72, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, - 0x73, 0x47, 0x61, 0x74, 0x65, 0x77, 0x61, 0x79, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x10, - 0x06, 0x2a, 0x29, 0x0a, 0x09, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x4f, 0x70, 0x12, 0x0c, - 0x0a, 0x08, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, - 0x44, 0x65, 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0x01, 0x32, 0x59, 0x0a, 0x17, - 0x53, 0x74, 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x12, 0x1b, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, - 0x2e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x10, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x45, 0x76, - 0x65, 0x6e, 0x74, 0x22, 0x00, 0x30, 0x01, 0x42, 0x92, 0x01, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x2e, - 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x42, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2d, 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, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, - 0xaa, 0x02, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xca, 0x02, 0x09, 0x53, - 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xe2, 0x02, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, - 0x72, 0x69, 0x62, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0xea, 0x02, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x77, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x48, 0x00, 0x52, 0x13, 0x4e, 0x65, 0x77, 0x53, 0x6e, + 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x54, 0x6f, 0x46, 0x6f, 0x6c, 0x6c, 0x6f, 0x77, 0x12, 0x37, + 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x45, + 0x76, 0x65, 0x6e, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68, 0x48, 0x00, 0x52, 0x0a, 0x45, 0x76, 0x65, + 0x6e, 0x74, 0x42, 0x61, 0x74, 0x63, 0x68, 0x12, 0x46, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, + 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x48, 0x00, + 0x52, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x12, + 0x40, 0x0a, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x0b, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, + 0x79, 0x12, 0x38, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x18, 0x0c, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x53, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x48, 0x00, 0x52, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x42, 0x09, 0x0a, 0x07, 0x50, + 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x22, 0x36, 0x0a, 0x0a, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x42, + 0x61, 0x74, 0x63, 0x68, 0x12, 0x28, 0x0a, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, + 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x22, 0x9c, + 0x01, 0x0a, 0x13, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x24, 0x0a, 0x02, 0x4f, 0x70, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x43, + 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x4f, 0x70, 0x52, 0x02, 0x4f, 0x70, 0x12, 0x5f, 0x0a, 0x10, + 0x43, 0x68, 0x65, 0x63, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x6f, 0x64, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 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, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x43, 0x68, 0x65, 0x63, 0x6b, + 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x52, 0x10, 0x43, 0x68, 0x65, + 0x63, 0x6b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4e, 0x6f, 0x64, 0x65, 0x22, 0xc4, 0x01, + 0x0a, 0x11, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x12, 0x35, 0x0a, 0x02, 0x4f, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, + 0x25, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x43, 0x6f, 0x6e, 0x66, + 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x52, 0x02, 0x4f, 0x70, 0x12, 0x54, 0x0a, 0x0b, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x32, 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, 0x66, + 0x69, 0x67, 0x65, 0x6e, 0x74, 0x72, 0x79, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, + 0x74, 0x72, 0x79, 0x52, 0x0b, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x45, 0x6e, 0x74, 0x72, 0x79, + 0x22, 0x22, 0x0a, 0x08, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4f, 0x70, 0x12, 0x0a, 0x0a, 0x06, + 0x55, 0x70, 0x73, 0x65, 0x72, 0x74, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x10, 0x01, 0x22, 0xc3, 0x01, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x4c, 0x69, 0x73, 0x74, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x12, 0x24, 0x0a, 0x02, 0x4f, 0x70, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x14, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x2e, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x4f, 0x70, 0x52, 0x02, 0x4f, 0x70, + 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x58, 0x0a, 0x0e, 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, + 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 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, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, + 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x0e, + 0x45, 0x6e, 0x74, 0x65, 0x72, 0x70, 0x72, 0x69, 0x73, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x1a, + 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x50, 0x65, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x2a, 0xa2, 0x01, 0x0a, 0x05, 0x54, + 0x6f, 0x70, 0x69, 0x63, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x10, + 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x10, 0x01, 0x12, 0x18, 0x0a, 0x14, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x48, + 0x65, 0x61, 0x6c, 0x74, 0x68, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x10, 0x02, 0x12, 0x0e, + 0x0a, 0x0a, 0x4d, 0x65, 0x73, 0x68, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x10, 0x03, 0x12, 0x13, + 0x0a, 0x0f, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x52, 0x65, 0x73, 0x6f, 0x6c, 0x76, 0x65, + 0x72, 0x10, 0x04, 0x12, 0x12, 0x0a, 0x0e, 0x49, 0x6e, 0x67, 0x72, 0x65, 0x73, 0x73, 0x47, 0x61, + 0x74, 0x65, 0x77, 0x61, 0x79, 0x10, 0x05, 0x12, 0x15, 0x0a, 0x11, 0x53, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x10, 0x06, 0x12, 0x0f, + 0x0a, 0x0b, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x10, 0x07, 0x2a, + 0x29, 0x0a, 0x09, 0x43, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x4f, 0x70, 0x12, 0x0c, 0x0a, 0x08, + 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0x00, 0x12, 0x0e, 0x0a, 0x0a, 0x44, 0x65, + 0x72, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x10, 0x01, 0x32, 0x59, 0x0a, 0x17, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3e, 0x0a, 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x12, 0x1b, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x53, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x10, 0x2e, 0x73, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x2e, 0x45, 0x76, 0x65, 0x6e, + 0x74, 0x22, 0x00, 0x30, 0x01, 0x42, 0x92, 0x01, 0x0a, 0x0d, 0x63, 0x6f, 0x6d, 0x2e, 0x73, 0x75, + 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x42, 0x0e, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x2d, 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, 0x73, + 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xa2, 0x02, 0x03, 0x53, 0x58, 0x58, 0xaa, 0x02, + 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xca, 0x02, 0x09, 0x53, 0x75, 0x62, + 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0xe2, 0x02, 0x15, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, + 0x62, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, + 0x09, 0x53, 0x75, 0x62, 0x73, 0x63, 0x72, 0x69, 0x62, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( @@ -886,7 +1000,7 @@ func file_proto_pbsubscribe_subscribe_proto_rawDescGZIP() []byte { } var file_proto_pbsubscribe_subscribe_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_proto_pbsubscribe_subscribe_proto_msgTypes = make([]protoimpl.MessageInfo, 6) +var file_proto_pbsubscribe_subscribe_proto_msgTypes = make([]protoimpl.MessageInfo, 7) var file_proto_pbsubscribe_subscribe_proto_goTypes = []interface{}{ (Topic)(0), // 0: subscribe.Topic (CatalogOp)(0), // 1: subscribe.CatalogOp @@ -897,8 +1011,10 @@ var file_proto_pbsubscribe_subscribe_proto_goTypes = []interface{}{ (*EventBatch)(nil), // 6: subscribe.EventBatch (*ServiceHealthUpdate)(nil), // 7: subscribe.ServiceHealthUpdate (*ConfigEntryUpdate)(nil), // 8: subscribe.ConfigEntryUpdate - (*pbservice.CheckServiceNode)(nil), // 9: hashicorp.consul.internal.service.CheckServiceNode - (*pbconfigentry.ConfigEntry)(nil), // 10: hashicorp.consul.internal.configentry.ConfigEntry + (*ServiceListUpdate)(nil), // 9: subscribe.ServiceListUpdate + (*pbservice.CheckServiceNode)(nil), // 10: hashicorp.consul.internal.service.CheckServiceNode + (*pbconfigentry.ConfigEntry)(nil), // 11: hashicorp.consul.internal.configentry.ConfigEntry + (*pbcommon.EnterpriseMeta)(nil), // 12: hashicorp.consul.internal.common.EnterpriseMeta } var file_proto_pbsubscribe_subscribe_proto_depIdxs = []int32{ 0, // 0: subscribe.SubscribeRequest.Topic:type_name -> subscribe.Topic @@ -906,18 +1022,21 @@ var file_proto_pbsubscribe_subscribe_proto_depIdxs = []int32{ 6, // 2: subscribe.Event.EventBatch:type_name -> subscribe.EventBatch 7, // 3: subscribe.Event.ServiceHealth:type_name -> subscribe.ServiceHealthUpdate 8, // 4: subscribe.Event.ConfigEntry:type_name -> subscribe.ConfigEntryUpdate - 5, // 5: subscribe.EventBatch.Events:type_name -> subscribe.Event - 1, // 6: subscribe.ServiceHealthUpdate.Op:type_name -> subscribe.CatalogOp - 9, // 7: subscribe.ServiceHealthUpdate.CheckServiceNode:type_name -> hashicorp.consul.internal.service.CheckServiceNode - 2, // 8: subscribe.ConfigEntryUpdate.Op:type_name -> subscribe.ConfigEntryUpdate.UpdateOp - 10, // 9: subscribe.ConfigEntryUpdate.ConfigEntry:type_name -> hashicorp.consul.internal.configentry.ConfigEntry - 4, // 10: subscribe.StateChangeSubscription.Subscribe:input_type -> subscribe.SubscribeRequest - 5, // 11: subscribe.StateChangeSubscription.Subscribe:output_type -> subscribe.Event - 11, // [11:12] is the sub-list for method output_type - 10, // [10:11] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 9, // 5: subscribe.Event.Service:type_name -> subscribe.ServiceListUpdate + 5, // 6: subscribe.EventBatch.Events:type_name -> subscribe.Event + 1, // 7: subscribe.ServiceHealthUpdate.Op:type_name -> subscribe.CatalogOp + 10, // 8: subscribe.ServiceHealthUpdate.CheckServiceNode:type_name -> hashicorp.consul.internal.service.CheckServiceNode + 2, // 9: subscribe.ConfigEntryUpdate.Op:type_name -> subscribe.ConfigEntryUpdate.UpdateOp + 11, // 10: subscribe.ConfigEntryUpdate.ConfigEntry:type_name -> hashicorp.consul.internal.configentry.ConfigEntry + 1, // 11: subscribe.ServiceListUpdate.Op:type_name -> subscribe.CatalogOp + 12, // 12: subscribe.ServiceListUpdate.EnterpriseMeta:type_name -> hashicorp.consul.internal.common.EnterpriseMeta + 4, // 13: subscribe.StateChangeSubscription.Subscribe:input_type -> subscribe.SubscribeRequest + 5, // 14: subscribe.StateChangeSubscription.Subscribe:output_type -> subscribe.Event + 14, // [14:15] is the sub-list for method output_type + 13, // [13:14] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name } func init() { file_proto_pbsubscribe_subscribe_proto_init() } @@ -998,6 +1117,18 @@ func file_proto_pbsubscribe_subscribe_proto_init() { return nil } } + file_proto_pbsubscribe_subscribe_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ServiceListUpdate); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_proto_pbsubscribe_subscribe_proto_msgTypes[1].OneofWrappers = []interface{}{ (*SubscribeRequest_WildcardSubject)(nil), @@ -1009,6 +1140,7 @@ func file_proto_pbsubscribe_subscribe_proto_init() { (*Event_EventBatch)(nil), (*Event_ServiceHealth)(nil), (*Event_ConfigEntry)(nil), + (*Event_Service)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -1016,7 +1148,7 @@ func file_proto_pbsubscribe_subscribe_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_pbsubscribe_subscribe_proto_rawDesc, NumEnums: 3, - NumMessages: 6, + NumMessages: 7, NumExtensions: 0, NumServices: 1, }, diff --git a/proto/pbsubscribe/subscribe.proto b/proto/pbsubscribe/subscribe.proto index 4f1e092c4..e68a0cecc 100644 --- a/proto/pbsubscribe/subscribe.proto +++ b/proto/pbsubscribe/subscribe.proto @@ -10,6 +10,7 @@ syntax = "proto3"; // compatibility. package subscribe; +import "proto/pbcommon/common.proto"; import "proto/pbconfigentry/config_entry.proto"; import "proto/pbservice/node.proto"; @@ -62,6 +63,13 @@ enum Topic { // ServiceIntentions topic contains events for changes to service intentions. ServiceIntentions = 6; + + // ServiceList topic contains events about services (not service instances) + // getting registered/deregistered. It can be used to materialize a list of + // the services in the given datacenter. + // + // Note: WildcardSubject is the only supported Subject on this topic. + ServiceList = 7; } message NamedSubject { @@ -171,6 +179,9 @@ message Event { // ConfigEntry is used for config entry topics (e.g. MeshConfig). ConfigEntryUpdate ConfigEntry = 11; + + // Service is used for ServiceList topic. + ServiceListUpdate Service = 12; } } @@ -197,3 +208,11 @@ message ConfigEntryUpdate { UpdateOp Op = 1; hashicorp.consul.internal.configentry.ConfigEntry ConfigEntry = 2; } + +message ServiceListUpdate { + CatalogOp Op = 1; + + string Name = 2; + hashicorp.consul.internal.common.EnterpriseMeta EnterpriseMeta = 3; + string PeerName = 4; +}