diff --git a/internal/controller/helper.go b/internal/controller/helper.go index 431ca5e6f3..f5fe9939a6 100644 --- a/internal/controller/helper.go +++ b/internal/controller/helper.go @@ -36,3 +36,36 @@ func MakeRequests[V resource.ReferenceOrID]( return out } + +// MakeRequestsFromResources accepts a list of items and converts them into a +// slice of []controller.Request items where the Type of the items has replaced +// by 'typ'. +func MakeRequestsFromResources[V interface { + GetId() *pbresource.ID +}]( + typ *pbresource.Type, + resources []V, +) []Request { + if len(resources) == 0 { + return nil + } + + out := make([]Request, 0, len(resources)) + for _, res := range resources { + id := res.GetId() + + // if type is not provided, we will use the type in the ID or reference. + if typ == nil { + typ = id.GetType() + } + out = append(out, Request{ + ID: &pbresource.ID{ + Type: typ, + Tenancy: id.GetTenancy(), + Name: id.GetName(), + }, + }) + } + + return out +} diff --git a/internal/mesh/internal/controllers/gatewayproxy/builder/builder_test.go b/internal/mesh/internal/controllers/gatewayproxy/builder/builder_test.go index 44bbcaa7ad..eee308a7ac 100644 --- a/internal/mesh/internal/controllers/gatewayproxy/builder/builder_test.go +++ b/internal/mesh/internal/controllers/gatewayproxy/builder/builder_test.go @@ -19,7 +19,6 @@ import ( "github.com/hashicorp/consul/internal/controller" "github.com/hashicorp/consul/internal/mesh/internal/controllers/gatewayproxy/fetcher" "github.com/hashicorp/consul/internal/mesh/internal/controllers/meshgateways" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/cache" "github.com/hashicorp/consul/internal/mesh/internal/types" "github.com/hashicorp/consul/internal/multicluster" "github.com/hashicorp/consul/internal/resource/resourcetest" @@ -188,8 +187,7 @@ func (suite *proxyStateTemplateBuilderSuite) setupWithTenancy(tenancy *pbresourc func (suite *proxyStateTemplateBuilderSuite) TestProxyStateTemplateBuilder_BuildForPeeredExportedServices() { suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - c := cache.New() - f := fetcher.New(suite.client, c) + f := fetcher.New(suite.client) dc := "dc" trustDomain := "trustDomain" logger := testutil.Logger(suite.T()) diff --git a/internal/mesh/internal/controllers/gatewayproxy/controller.go b/internal/mesh/internal/controllers/gatewayproxy/controller.go index 3225ff670b..45e0a5e647 100644 --- a/internal/mesh/internal/controllers/gatewayproxy/controller.go +++ b/internal/mesh/internal/controllers/gatewayproxy/controller.go @@ -18,7 +18,6 @@ import ( "github.com/hashicorp/consul/internal/mesh/internal/controllers/gatewayproxy/mapper" "github.com/hashicorp/consul/internal/mesh/internal/controllers/meshgateways" "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/cache" "github.com/hashicorp/consul/internal/resource" pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" @@ -33,7 +32,7 @@ const ( ) // Controller is responsible for triggering reconciler for watched resources -func Controller(cache *cache.Cache, trustDomainFetcher sidecarproxy.TrustDomainFetcher, dc string, defaultAllow bool) *controller.Controller { +func Controller(trustDomainFetcher sidecarproxy.TrustDomainFetcher, dc string, defaultAllow bool) *controller.Controller { // TODO NET-7016 Use caching functionality in NewController being implemented at time of writing // TODO NET-7017 Add the host of other types we should watch // TODO NET-7565: Add watch for serviceTypes across partitions @@ -42,7 +41,6 @@ func Controller(cache *cache.Cache, trustDomainFetcher sidecarproxy.TrustDomainF WithWatch(pbmesh.ComputedProxyConfigurationType, dependency.ReplaceType(pbmesh.ProxyStateTemplateType)). WithWatch(pbmulticluster.ComputedExportedServicesType, mapper.AllMeshGatewayWorkloadsInPartition). WithReconciler(&reconciler{ - cache: cache, dc: dc, defaultAllow: defaultAllow, getTrustDomain: trustDomainFetcher, @@ -52,7 +50,6 @@ func Controller(cache *cache.Cache, trustDomainFetcher sidecarproxy.TrustDomainF // reconciler is responsible for managing the ProxyStateTemplate for all // gateway types: mesh, api (future) and terminating (future). type reconciler struct { - cache *cache.Cache dc string defaultAllow bool getTrustDomain sidecarproxy.TrustDomainFetcher @@ -67,7 +64,7 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c rt.Logger.Trace("reconciling proxy state template") // Instantiate a data fetcher to fetch all reconciliation data. - dataFetcher := fetcher.New(rt.Client, r.cache) + dataFetcher := fetcher.New(rt.Client) workloadID := resource.ReplaceType(pbcatalog.WorkloadType, req.ID) workload, err := dataFetcher.FetchWorkload(ctx, workloadID) diff --git a/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher.go b/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher.go index 036dd73ea9..3d8cdf5462 100644 --- a/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher.go +++ b/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher.go @@ -7,25 +7,23 @@ import ( "context" "fmt" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/cache" + "google.golang.org/protobuf/proto" + "github.com/hashicorp/consul/internal/mesh/internal/types" "github.com/hashicorp/consul/internal/resource" pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" pbmulticluster "github.com/hashicorp/consul/proto-public/pbmulticluster/v2" "github.com/hashicorp/consul/proto-public/pbresource" - "google.golang.org/protobuf/proto" ) type Fetcher struct { client pbresource.ResourceServiceClient - cache *cache.Cache } -func New(client pbresource.ResourceServiceClient, cache *cache.Cache) *Fetcher { +func New(client pbresource.ResourceServiceClient) *Fetcher { return &Fetcher{ client: client, - cache: cache, } } diff --git a/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher_test.go b/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher_test.go index 8f65bfbc9e..e994050c68 100644 --- a/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher_test.go +++ b/internal/mesh/internal/controllers/gatewayproxy/fetcher/data_fetcher_test.go @@ -14,7 +14,6 @@ import ( svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing" "github.com/hashicorp/consul/internal/catalog" "github.com/hashicorp/consul/internal/controller" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/cache" "github.com/hashicorp/consul/internal/mesh/internal/types" "github.com/hashicorp/consul/internal/multicluster" "github.com/hashicorp/consul/internal/resource/resourcetest" @@ -110,10 +109,7 @@ func (suite *dataFetcherSuite) setupWithTenancy(tenancy *pbresource.Tenancy) { func (suite *dataFetcherSuite) TestFetcher_FetchMeshGateway() { suite.runTestCaseWithTenancies(func(_ *pbresource.Tenancy) { - c := cache.New() - f := Fetcher{ - cache: c, client: suite.client, } @@ -143,10 +139,7 @@ func (suite *dataFetcherSuite) TestFetcher_FetchMeshGateway() { func (suite *dataFetcherSuite) TestFetcher_FetchProxyStateTemplate() { suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - c := cache.New() - f := Fetcher{ - cache: c, client: suite.client, } @@ -176,10 +169,7 @@ func (suite *dataFetcherSuite) TestFetcher_FetchProxyStateTemplate() { func (suite *dataFetcherSuite) TestFetcher_FetchWorkload() { suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - c := cache.New() - f := Fetcher{ - cache: c, client: suite.client, } @@ -200,10 +190,7 @@ func (suite *dataFetcherSuite) TestFetcher_FetchWorkload() { func (suite *dataFetcherSuite) TestFetcher_FetchExportedServices() { suite.runTestCaseWithTenancies(func(_ *pbresource.Tenancy) { - c := cache.New() - f := Fetcher{ - cache: c, client: suite.client, } @@ -224,10 +211,7 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExportedServices() { func (suite *dataFetcherSuite) TestFetcher_FetchService() { suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - c := cache.New() - f := Fetcher{ - cache: c, client: suite.client, } diff --git a/internal/mesh/internal/controllers/gatewayproxy/mapper/meshgatewayworkloads.go b/internal/mesh/internal/controllers/gatewayproxy/mapper/meshgatewayworkloads.go index effb9bb831..290dfd401b 100644 --- a/internal/mesh/internal/controllers/gatewayproxy/mapper/meshgatewayworkloads.go +++ b/internal/mesh/internal/controllers/gatewayproxy/mapper/meshgatewayworkloads.go @@ -17,7 +17,7 @@ import ( // AllMeshGatewayWorkloadsInPartition returns one controller.Request for each Workload // selected by a MeshGateway in the partition of the Resource. var AllMeshGatewayWorkloadsInPartition = func(ctx context.Context, rt controller.Runtime, res *pbresource.Resource) ([]controller.Request, error) { - fetcher := fetcher.New(rt.Client, nil) + fetcher := fetcher.New(rt.Client) gateways, err := fetcher.FetchMeshGateways(ctx, &pbresource.Tenancy{ Partition: res.Id.Tenancy.Partition, diff --git a/internal/mesh/internal/controllers/implicitdestinations/index.go b/internal/mesh/internal/controllers/implicitdestinations/index.go index 1fabf666ad..f2ab45c5d1 100644 --- a/internal/mesh/internal/controllers/implicitdestinations/index.go +++ b/internal/mesh/internal/controllers/implicitdestinations/index.go @@ -6,9 +6,9 @@ package implicitdestinations import ( "golang.org/x/exp/maps" - "github.com/hashicorp/consul/internal/catalog" "github.com/hashicorp/consul/internal/controller/cache/index" "github.com/hashicorp/consul/internal/controller/cache/indexers" + "github.com/hashicorp/consul/internal/mesh/internal/meshindexes" "github.com/hashicorp/consul/internal/mesh/internal/types" "github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/storage" @@ -33,12 +33,7 @@ import ( var boundRefsIndex = indexers.BoundRefsIndex[*pbmesh.ComputedImplicitDestinations]("bound-references") // Cache: reverse SVC[*] => WI[*] -var serviceByWorkloadIdentityIndex = indexers.RefOrIDIndex( - "service-by-workload-identity", - func(svc *types.DecodedService) []*pbresource.Reference { - return getWorkloadIdentitiesFromService(svc.Resource) - }, -) +var serviceByWorkloadIdentityIndex = meshindexes.ServiceByWorkloadIdentityIndex() // Cache: reverse CTP => WI[source] var ctpBySourceWorkloadIdentityIndex = indexers.RefOrIDIndex( @@ -109,26 +104,7 @@ func indexFromTenantedName(tn tenantedName) []byte { } // Cache: reverse CR => SVC[backend] -var computedRoutesByBackendServiceIndex = indexers.RefOrIDIndex( - "computed-routes-by-backend-service", - func(cr *types.DecodedComputedRoutes) []*pbresource.Reference { - return getBackendServiceRefsFromComputedRoutes(cr) - }, -) - -func getWorkloadIdentitiesFromService(svc *pbresource.Resource) []*pbresource.Reference { - ids := catalog.GetBoundIdentities(svc) - - out := make([]*pbresource.Reference, 0, len(ids)) - for _, id := range ids { - out = append(out, &pbresource.Reference{ - Type: pbauth.WorkloadIdentityType, - Name: id, - Tenancy: svc.Id.Tenancy, - }) - } - return out -} +var computedRoutesByBackendServiceIndex = meshindexes.ComputedRoutesByBackendServiceIndex() func getSourceWorkloadIdentitiesFromCTP( ctp *types.DecodedComputedTrafficPermissions, @@ -195,24 +171,6 @@ func getSourceWorkloadIdentitiesFromCTP( return out, sliceWildNameInNS, sliceWildNSInPartition } -func getBackendServiceRefsFromComputedRoutes(cr *types.DecodedComputedRoutes) []*pbresource.Reference { - var ( - out []*pbresource.Reference - seen = make(map[resource.ReferenceKey]struct{}) - ) - for _, pc := range cr.Data.PortedConfigs { - for _, target := range pc.Targets { - ref := target.BackendRef.Ref - rk := resource.NewReferenceKey(ref) - if _, ok := seen[rk]; !ok { - out = append(out, ref) - seen[rk] = struct{}{} - } - } - } - return out -} - type sourceType int const ( diff --git a/internal/mesh/internal/controllers/implicitdestinations/index_test.go b/internal/mesh/internal/controllers/implicitdestinations/index_test.go index 21e1d83236..fe8845b3ee 100644 --- a/internal/mesh/internal/controllers/implicitdestinations/index_test.go +++ b/internal/mesh/internal/controllers/implicitdestinations/index_test.go @@ -12,75 +12,11 @@ import ( "github.com/hashicorp/consul/internal/catalog" "github.com/hashicorp/consul/internal/mesh/internal/types" "github.com/hashicorp/consul/internal/resource" - "github.com/hashicorp/consul/internal/resource/resourcetest" - rtest "github.com/hashicorp/consul/internal/resource/resourcetest" pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" - pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" - pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" "github.com/hashicorp/consul/proto-public/pbresource" "github.com/hashicorp/consul/proto/private/prototest" ) -func TestGetWorkloadIdentitiesFromService(t *testing.T) { - tenancy := resource.DefaultNamespacedTenancy() - - build := func(conds ...*pbresource.Condition) *pbresource.Resource { - b := rtest.Resource(pbcatalog.ServiceType, "web"). - WithTenancy(tenancy). - WithData(t, &pbcatalog.Service{}) - if len(conds) > 0 { - b.WithStatus(catalog.EndpointsStatusKey, &pbresource.Status{ - Conditions: conds, - }) - } - return b.Build() - } - - fooRef := &pbresource.Reference{ - Type: pbauth.WorkloadIdentityType, - Tenancy: tenancy, - Name: "foo", - } - barRef := &pbresource.Reference{ - Type: pbauth.WorkloadIdentityType, - Tenancy: tenancy, - Name: "bar", - } - - makeRefs := func(refs ...*pbresource.Reference) []*pbresource.Reference { - return refs - } - - run := getWorkloadIdentitiesFromService - - require.Empty(t, run(build(nil))) - require.Empty(t, run(build(&pbresource.Condition{ - Type: catalog.StatusConditionBoundIdentities, - State: pbresource.Condition_STATE_TRUE, - Message: "", - }))) - prototest.AssertDeepEqual(t, makeRefs(fooRef), run(build(&pbresource.Condition{ - Type: catalog.StatusConditionBoundIdentities, - State: pbresource.Condition_STATE_TRUE, - Message: "foo", - }))) - require.Empty(t, run(build(&pbresource.Condition{ - Type: catalog.StatusConditionBoundIdentities, - State: pbresource.Condition_STATE_FALSE, - Message: "foo", - }))) - prototest.AssertDeepEqual(t, makeRefs(barRef, fooRef), run(build(&pbresource.Condition{ - Type: catalog.StatusConditionBoundIdentities, - State: pbresource.Condition_STATE_TRUE, - Message: "bar,foo", // proper order - }))) - prototest.AssertDeepEqual(t, makeRefs(barRef, fooRef), run(build(&pbresource.Condition{ - Type: catalog.StatusConditionBoundIdentities, - State: pbresource.Condition_STATE_TRUE, - Message: "foo,bar", // incorrect order gets fixed - }))) -} - func TestGetSourceWorkloadIdentitiesFromCTP(t *testing.T) { registry := resource.NewRegistry() types.Register(registry) @@ -318,91 +254,3 @@ func TestGetSourceWorkloadIdentitiesFromCTP(t *testing.T) { }) } } - -func TestGetBackendServiceRefsFromComputedRoutes(t *testing.T) { - type testcase struct { - cr *types.DecodedComputedRoutes - expect []*pbresource.Reference - } - - run := func(t *testing.T, tc testcase) { - got := getBackendServiceRefsFromComputedRoutes(tc.cr) - prototest.AssertElementsMatch(t, tc.expect, got) - } - - tenancy := resource.DefaultNamespacedTenancy() - - newRef := func(name string) *pbresource.Reference { - return &pbresource.Reference{ - Type: pbcatalog.ServiceType, - Tenancy: tenancy, - Name: name, - } - } - - cr1 := resourcetest.Resource(pbmesh.ComputedRoutesType, "cr1"). - WithTenancy(tenancy). - WithData(t, &pbmesh.ComputedRoutes{ - PortedConfigs: map[string]*pbmesh.ComputedPortRoutes{ - "http": { - Targets: map[string]*pbmesh.BackendTargetDetails{ - "opaque1": { - BackendRef: &pbmesh.BackendReference{Ref: newRef("aaa")}, - }, - }, - }, - }, - }). - Build() - - cr2 := resourcetest.Resource(pbmesh.ComputedRoutesType, "cr2"). - WithTenancy(tenancy). - WithData(t, &pbmesh.ComputedRoutes{ - PortedConfigs: map[string]*pbmesh.ComputedPortRoutes{ - "http": { - Targets: map[string]*pbmesh.BackendTargetDetails{ - "opaque1": { - BackendRef: &pbmesh.BackendReference{Ref: newRef("aaa")}, - }, - "opaque2": { - BackendRef: &pbmesh.BackendReference{Ref: newRef("bbb")}, - }, - }, - }, - "grpc": { - Targets: map[string]*pbmesh.BackendTargetDetails{ - "opaque2": { - BackendRef: &pbmesh.BackendReference{Ref: newRef("bbb")}, - }, - "opaque3": { - BackendRef: &pbmesh.BackendReference{Ref: newRef("ccc")}, - }, - }, - }, - }, - }). - Build() - - cases := map[string]testcase{ - "one": { - cr: resourcetest.MustDecode[*pbmesh.ComputedRoutes](t, cr1), - expect: []*pbresource.Reference{ - newRef("aaa"), - }, - }, - "two": { - cr: resourcetest.MustDecode[*pbmesh.ComputedRoutes](t, cr2), - expect: []*pbresource.Reference{ - newRef("aaa"), - newRef("bbb"), - newRef("ccc"), - }, - }, - } - - for name, tc := range cases { - t.Run(name, func(t *testing.T) { - run(t, tc) - }) - } -} diff --git a/internal/mesh/internal/controllers/implicitdestinations/mapper.go b/internal/mesh/internal/controllers/implicitdestinations/mapper.go index 22d648ba56..abdaf745a1 100644 --- a/internal/mesh/internal/controllers/implicitdestinations/mapper.go +++ b/internal/mesh/internal/controllers/implicitdestinations/mapper.go @@ -11,6 +11,7 @@ import ( "github.com/hashicorp/consul/internal/controller" "github.com/hashicorp/consul/internal/controller/cache" "github.com/hashicorp/consul/internal/controller/dependency" + "github.com/hashicorp/consul/internal/mesh/internal/meshindexes" "github.com/hashicorp/consul/internal/mesh/internal/types" "github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/storage" @@ -135,7 +136,7 @@ func (m *mapAndTransformer) transformServiceToWorkloadIdentities(ctx context.Con // another transformer immediately anyway, so it's largely an opaque // carrier for the WI name string only. - wiIDs := getWorkloadIdentitiesFromService(res) + wiIDs := meshindexes.GetWorkloadIdentitiesFromService(res) out := make([]*pbresource.Resource, 0, len(wiIDs)) for _, wiID := range wiIDs { @@ -154,7 +155,7 @@ func (m *mapAndTransformer) transformComputedRoutesToBackendServiceRefs(ctx cont return nil, err } - svcRefs := getBackendServiceRefsFromComputedRoutes(cr) + svcRefs := meshindexes.GetBackendServiceRefsFromComputedRoutes(cr) out := make([]*pbresource.Resource, 0, len(svcRefs)) for _, svcRef := range svcRefs { diff --git a/internal/mesh/internal/controllers/register.go b/internal/mesh/internal/controllers/register.go index d4aa1270c1..084d779bee 100644 --- a/internal/mesh/internal/controllers/register.go +++ b/internal/mesh/internal/controllers/register.go @@ -6,20 +6,18 @@ package controllers import ( "context" + "github.com/hashicorp/consul/agent/leafcert" + "github.com/hashicorp/consul/internal/controller" "github.com/hashicorp/consul/internal/mesh/internal/controllers/apigateways" + "github.com/hashicorp/consul/internal/mesh/internal/controllers/explicitdestinations" + "github.com/hashicorp/consul/internal/mesh/internal/controllers/explicitdestinations/mapper" "github.com/hashicorp/consul/internal/mesh/internal/controllers/gatewayproxy" "github.com/hashicorp/consul/internal/mesh/internal/controllers/implicitdestinations" "github.com/hashicorp/consul/internal/mesh/internal/controllers/meshconfiguration" - - "github.com/hashicorp/consul/agent/leafcert" - "github.com/hashicorp/consul/internal/controller" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/explicitdestinations" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/explicitdestinations/mapper" "github.com/hashicorp/consul/internal/mesh/internal/controllers/meshgateways" "github.com/hashicorp/consul/internal/mesh/internal/controllers/proxyconfiguration" "github.com/hashicorp/consul/internal/mesh/internal/controllers/routes" "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/cache" "github.com/hashicorp/consul/internal/mesh/internal/controllers/xds" "github.com/hashicorp/consul/internal/mesh/internal/mappers/workloadselectionmapper" "github.com/hashicorp/consul/internal/resource/mappers/bimapper" @@ -47,10 +45,10 @@ func Register(mgr *controller.Manager, deps Dependencies) { mgr.Register(xds.Controller(endpointsMapper, deps.ProxyUpdater, deps.TrustBundleFetcher, deps.LeafCertManager, leafMapper, leafCancels, deps.LocalDatacenter)) mgr.Register( - sidecarproxy.Controller(cache.New(), deps.TrustDomainFetcher, deps.LocalDatacenter, deps.DefaultAllow), + sidecarproxy.Controller(deps.TrustDomainFetcher, deps.LocalDatacenter, deps.DefaultAllow), ) - mgr.Register(gatewayproxy.Controller(cache.New(), deps.TrustDomainFetcher, deps.LocalDatacenter, deps.DefaultAllow)) + mgr.Register(gatewayproxy.Controller(deps.TrustDomainFetcher, deps.LocalDatacenter, deps.DefaultAllow)) mgr.Register(routes.Controller()) diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/destination_multiport_test.go b/internal/mesh/internal/controllers/sidecarproxy/builder/destination_multiport_test.go index 931756c32a..9e77bba692 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/destination_multiport_test.go +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/destination_multiport_test.go @@ -161,7 +161,6 @@ func TestBuildMultiportImplicitDestinations(t *testing.T) { virtualIPs []string, ) []*intermediate.Destination { svcDec := resourcetest.MustDecode[*pbcatalog.Service](t, svc) - seDec := resourcetest.MustDecode[*pbcatalog.ServiceEndpoints](t, endpoints) var out []*intermediate.Destination for _, port := range svcDec.Data.Ports { @@ -180,7 +179,6 @@ func TestBuildMultiportImplicitDestinations(t *testing.T) { MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = seDec.Data details.IdentityRefs = identities } }), diff --git a/internal/mesh/internal/controllers/sidecarproxy/builder/destinations_test.go b/internal/mesh/internal/controllers/sidecarproxy/builder/destinations_test.go index d85bb4ccd6..e3e9c4628d 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/builder/destinations_test.go +++ b/internal/mesh/internal/controllers/sidecarproxy/builder/destinations_test.go @@ -25,22 +25,6 @@ import ( ) var ( - endpointsData = &pbcatalog.ServiceEndpoints{ - Endpoints: []*pbcatalog.Endpoint{ - { - Addresses: []*pbcatalog.WorkloadAddress{ - {Host: "10.0.0.1"}, - }, - Ports: map[string]*pbcatalog.WorkloadPort{ - "tcp": {Port: 7070, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - "tcp2": {Port: 8081, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - "http": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, - "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, - }, - }, - }, - } - serviceData = &pbcatalog.Service{ Ports: []*pbcatalog.ServicePort{ { @@ -99,40 +83,19 @@ func TestBuildExplicitDestinations(t *testing.T) { resourcetest.ValidateAndNormalize(t, registry, res) } - api1Endpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "api-1"). - WithTenancy(tenancy). - WithData(t, endpointsData). - Build() - - api2Endpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "api-2"). - WithTenancy(tenancy). - WithData(t, endpointsData). - Build() - - backup1Endpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "backup-1"). - WithTenancy(tenancy). - WithData(t, endpointsData). - Build() - - for _, res := range []*pbresource.Resource{ - api1Endpoints, api2Endpoints, backup1Endpoints, - } { - resourcetest.ValidateAndNormalize(t, registry, res) - } - api1Identity := &pbresource.Reference{ Name: "api1-identity", - Tenancy: api1Endpoints.Id.Tenancy, + Tenancy: tenancy, } api2Identity := &pbresource.Reference{ Name: "api2-identity", - Tenancy: api2Endpoints.Id.Tenancy, + Tenancy: tenancy, } backup1Identity := &pbresource.Reference{ Name: "backup1-identity", - Tenancy: backup1Endpoints.Id.Tenancy, + Tenancy: tenancy, } api1DestPolicy := resourcetest.Resource(pbmesh.DestinationPolicyType, api1Service.Id.Name). @@ -311,7 +274,7 @@ func TestBuildExplicitDestinations(t *testing.T) { destinationIpPort := &intermediate.Destination{ Explicit: &pbmesh.Destination{ - DestinationRef: resource.Reference(api1Endpoints.Id, ""), + DestinationRef: resource.Reference(api1Service.Id, ""), DestinationPort: "tcp", Datacenter: "dc1", ListenAddr: &pbmesh.Destination_IpPort{ @@ -323,19 +286,17 @@ func TestBuildExplicitDestinations(t *testing.T) { switch { case resource.ReferenceOrIDMatch(api1Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: api1Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api1Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{api1Identity} case resource.ReferenceOrIDMatch(api2Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: api2Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api2Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{api2Identity} } }), @@ -343,7 +304,7 @@ func TestBuildExplicitDestinations(t *testing.T) { destinationIpPort2 := &intermediate.Destination{ Explicit: &pbmesh.Destination{ - DestinationRef: resource.Reference(api1Endpoints.Id, ""), + DestinationRef: resource.Reference(api1Service.Id, ""), DestinationPort: "tcp2", Datacenter: "dc1", ListenAddr: &pbmesh.Destination_IpPort{ @@ -355,19 +316,17 @@ func TestBuildExplicitDestinations(t *testing.T) { switch { case resource.ReferenceOrIDMatch(api1Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp2": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: api1Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api1Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{api1Identity} case resource.ReferenceOrIDMatch(api2Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp2": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: api2Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api2Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{api2Identity} } }), @@ -375,7 +334,7 @@ func TestBuildExplicitDestinations(t *testing.T) { destinationUnix := &intermediate.Destination{ Explicit: &pbmesh.Destination{ - DestinationRef: resource.Reference(api2Endpoints.Id, ""), + DestinationRef: resource.Reference(api2Service.Id, ""), DestinationPort: "tcp", Datacenter: "dc1", ListenAddr: &pbmesh.Destination_Unix{ @@ -387,11 +346,10 @@ func TestBuildExplicitDestinations(t *testing.T) { switch { case resource.ReferenceOrIDMatch(api2Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: api2Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api2Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{api2Identity} } }), @@ -399,7 +357,7 @@ func TestBuildExplicitDestinations(t *testing.T) { destinationUnix2 := &intermediate.Destination{ Explicit: &pbmesh.Destination{ - DestinationRef: resource.Reference(api2Endpoints.Id, ""), + DestinationRef: resource.Reference(api2Service.Id, ""), DestinationPort: "tcp2", Datacenter: "dc1", ListenAddr: &pbmesh.Destination_Unix{ @@ -411,18 +369,17 @@ func TestBuildExplicitDestinations(t *testing.T) { switch { case resource.ReferenceOrIDMatch(api2Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp2": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: api2Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api2Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{api2Identity} } }), } destinationIpPortHTTP := &intermediate.Destination{ Explicit: &pbmesh.Destination{ - DestinationRef: resource.Reference(api1Endpoints.Id, ""), + DestinationRef: resource.Reference(api1Service.Id, ""), DestinationPort: "http", Datacenter: "dc1", ListenAddr: &pbmesh.Destination_IpPort{ @@ -434,27 +391,24 @@ func TestBuildExplicitDestinations(t *testing.T) { switch { case resource.ReferenceOrIDMatch(api1Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "http": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: api1Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api1Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{api1Identity} case resource.ReferenceOrIDMatch(api2Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "http": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: api2Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api2Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{api2Identity} case resource.ReferenceOrIDMatch(backup1Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "http": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: backup1Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, backup1Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{backup1Identity} } }), @@ -506,24 +460,14 @@ func TestBuildImplicitDestinations(t *testing.T) { WithData(t, serviceData). Build() - api1Endpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "api-1"). - WithOwner(api1Service.Id). - WithTenancy(tenancy). - WithData(t, endpointsData).Build() - - api2Endpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "api-2"). - WithOwner(api2Service.Id). - WithTenancy(tenancy). - WithData(t, endpointsData).Build() - api1Identity := &pbresource.Reference{ Name: "api1-identity", - Tenancy: api1Endpoints.Id.Tenancy, + Tenancy: tenancy, } api2Identity := &pbresource.Reference{ Name: "api2-identity", - Tenancy: api2Endpoints.Id.Tenancy, + Tenancy: tenancy, } api1ComputedRoutesID := resource.ReplaceType(pbmesh.ComputedRoutesType, api1Service.Id) @@ -553,11 +497,10 @@ func TestBuildImplicitDestinations(t *testing.T) { switch { case resource.ReferenceOrIDMatch(api1Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: api1Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api1Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{api1Identity} } }), @@ -570,11 +513,10 @@ func TestBuildImplicitDestinations(t *testing.T) { switch { case resource.ReferenceOrIDMatch(api2Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: api2Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api2Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{api2Identity} } }), @@ -583,7 +525,7 @@ func TestBuildImplicitDestinations(t *testing.T) { destination3 := &intermediate.Destination{ Explicit: &pbmesh.Destination{ - DestinationRef: resource.Reference(api1Endpoints.Id, ""), + DestinationRef: resource.Reference(api1Service.Id, ""), DestinationPort: "tcp", Datacenter: "dc1", ListenAddr: &pbmesh.Destination_IpPort{ @@ -595,11 +537,10 @@ func TestBuildImplicitDestinations(t *testing.T) { switch { case resource.ReferenceOrIDMatch(api1Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp": details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: api1Endpoints.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api1Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = endpointsData details.IdentityRefs = []*pbresource.Reference{api1Identity} } }), diff --git a/internal/mesh/internal/controllers/sidecarproxy/cache/cache.go b/internal/mesh/internal/controllers/sidecarproxy/cache/cache.go deleted file mode 100644 index af0909739a..0000000000 --- a/internal/mesh/internal/controllers/sidecarproxy/cache/cache.go +++ /dev/null @@ -1,250 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package cache - -import ( - "context" - - "github.com/hashicorp/consul/internal/controller" - "github.com/hashicorp/consul/internal/mesh/internal/types" - "github.com/hashicorp/consul/internal/resource" - "github.com/hashicorp/consul/internal/resource/mappers/bimapper" - "github.com/hashicorp/consul/internal/resource/mappers/selectiontracker" - "github.com/hashicorp/consul/internal/storage" - pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" - pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" - pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" - "github.com/hashicorp/consul/proto-public/pbresource" -) - -type Cache struct { - // computedRoutes keeps track of computed routes IDs to service references it applies to. - computedRoutes *bimapper.Mapper - - // identities keeps track of which identity a workload is mapped to. - identities *bimapper.Mapper - - // computedDestinations keeps track of the computed explicit destinations IDs to service references that are - // referenced in that resource. - computedDestinations *bimapper.Mapper - - // serviceSelectorTracker keeps track of which workload selectors a service is currently using. - serviceSelectorTracker *selectiontracker.WorkloadSelectionTracker -} - -func New() *Cache { - return &Cache{ - computedRoutes: bimapper.New(pbmesh.ComputedRoutesType, pbcatalog.ServiceType), - identities: bimapper.New(pbcatalog.WorkloadType, pbauth.WorkloadIdentityType), - computedDestinations: bimapper.New(pbmesh.ComputedExplicitDestinationsType, pbcatalog.ServiceType), - serviceSelectorTracker: selectiontracker.New(), - } -} - -func (c *Cache) TrackComputedDestinations(computedDestinations *types.DecodedComputedDestinations) { - var serviceRefs []resource.ReferenceOrID - - for _, dest := range computedDestinations.Data.Destinations { - serviceRefs = append(serviceRefs, dest.DestinationRef) - } - - c.computedDestinations.TrackItem(computedDestinations.Resource.Id, serviceRefs) -} - -func (c *Cache) UntrackComputedDestinations(computedDestinationsID *pbresource.ID) { - c.computedDestinations.UntrackItem(computedDestinationsID) -} - -func (c *Cache) UntrackComputedRoutes(computedRoutesID *pbresource.ID) { - c.computedRoutes.UntrackItem(computedRoutesID) -} - -func (c *Cache) TrackWorkload(workload *types.DecodedWorkload) { - identityID := &pbresource.ID{ - Name: workload.GetData().Identity, - Tenancy: workload.GetResource().Id.Tenancy, - Type: pbauth.WorkloadIdentityType, - } - c.identities.TrackItem(workload.GetResource().GetId(), []resource.ReferenceOrID{identityID}) -} - -// UntrackWorkload removes tracking for the given workload ID. -func (c *Cache) UntrackWorkload(wID *pbresource.ID) { - c.identities.UntrackItem(wID) -} - -func (c *Cache) ComputedDestinationsByService(id resource.ReferenceOrID) []*pbresource.ID { - return c.computedDestinations.ItemIDsForLink(id) -} - -func (c *Cache) trackComputedRoutes(computedRoutes *types.DecodedComputedRoutes) { - var serviceRefs []resource.ReferenceOrID - - for _, pcr := range computedRoutes.Data.PortedConfigs { - for _, details := range pcr.Targets { - serviceRefs = append(serviceRefs, details.BackendRef.Ref) - } - } - - c.computedRoutes.TrackItem(computedRoutes.Resource.Id, serviceRefs) -} - -func (c *Cache) computedRoutesByService(id resource.ReferenceOrID) []*pbresource.ID { - return c.computedRoutes.ItemIDsForLink(id) -} - -func (c *Cache) WorkloadsByWorkloadIdentity(id *pbresource.ID) []*pbresource.ID { - return c.identities.ItemIDsForLink(id) -} - -func (c *Cache) ServicesForWorkload(id *pbresource.ID) []*pbresource.ID { - return c.serviceSelectorTracker.GetIDsForWorkload(id) -} - -func (c *Cache) UntrackService(id *pbresource.ID) { - c.serviceSelectorTracker.UntrackID(id) -} - -func (c *Cache) MapComputedRoutes(ctx context.Context, rt controller.Runtime, res *pbresource.Resource) ([]controller.Request, error) { - computedRoutes, err := resource.Decode[*pbmesh.ComputedRoutes](res) - if err != nil { - return nil, err - } - - ids, err := c.mapComputedRoutesToProxyStateTemplate(ctx, rt, res.Id) - if err != nil { - return nil, err - } - - c.trackComputedRoutes(computedRoutes) - - return controller.MakeRequests(pbmesh.ProxyStateTemplateType, ids), nil -} - -func (c *Cache) mapComputedRoutesToProxyStateTemplate(ctx context.Context, rt controller.Runtime, computedRoutesID *pbresource.ID) ([]*pbresource.ID, error) { - // Each Destination gets a single ComputedRoutes. - serviceID := resource.ReplaceType(pbcatalog.ServiceType, computedRoutesID) - serviceRef := resource.Reference(serviceID, "") - - return c.mapServiceThroughDestinations(ctx, rt, serviceRef) -} - -func (c *Cache) TrackService(svc *types.DecodedService) { - c.serviceSelectorTracker.TrackIDForSelector(svc.Resource.GetId(), svc.GetData().GetWorkloads()) -} - -func (c *Cache) MapService(ctx context.Context, rt controller.Runtime, res *pbresource.Resource) ([]controller.Request, error) { - // Record workload selector in the cache every time we see an event for a service. - decodedService, err := resource.Decode[*pbcatalog.Service](res) - if err != nil { - return nil, err - } - c.TrackService(decodedService) - - serviceRef := resource.Reference(res.Id, "") - - pstIDs, err := c.mapServiceThroughDestinations(ctx, rt, serviceRef) - if err != nil { - return nil, err - } - - // Now walk the mesh configuration information backwards because - // we need to find any PST that needs to DISCOVER endpoints for this - // service as a part of mesh configuration and traffic routing. - - // Find all ComputedRoutes that reference this service. - routeIDs := c.computedRoutesByService(serviceRef) - for _, routeID := range routeIDs { - // Find all Upstreams that reference a Service aligned with this ComputedRoutes. - // Afterwards, find all Workloads selected by the Upstreams, and align a PST with those. - ids, err := c.mapComputedRoutesToProxyStateTemplate(ctx, rt, routeID) - if err != nil { - return nil, err - } - - pstIDs = append(pstIDs, ids...) - } - - return controller.MakeRequests(pbmesh.ProxyStateTemplateType, pstIDs), nil -} - -// mapServiceThroughDestinations takes an explicit -// Service and traverses back through Destinations to Workloads to -// ProxyStateTemplates. -// -// This is in a separate function so it can be chained for more complicated -// relationships. -func (c *Cache) mapServiceThroughDestinations( - ctx context.Context, - rt controller.Runtime, - serviceRef *pbresource.Reference, -) ([]*pbresource.ID, error) { - - // The relationship is: - // - // - PST (replace type) Workload - // - Workload (name-aligned) ComputedDestinations - // - ComputedDestinations (contains) Service - // - // When we wake up for Service we should: - // - // - look up computed destinations for the service - // - rewrite computed destination types to PST - - var pstIDs []*pbresource.ID - - // Get all source proxies if they're referenced in any explicit destinations from computed destinations (name-aligned with workload/PST). - sources := c.ComputedDestinationsByService(serviceRef) - for _, cdID := range sources { - pstIDs = append(pstIDs, resource.ReplaceType(pbmesh.ProxyStateTemplateType, cdID)) - } - - // TODO(v2): remove this after we can do proper performant implicit upstream determination - // - // TODO(rb): shouldn't this instead list all Workloads that have a mesh port? - allIDs, err := c.listAllProxyStateTemplatesTemporarily(ctx, rt, serviceRef.Tenancy) - if err != nil { - return nil, err - } - - pstIDs = append(pstIDs, allIDs...) - - return pstIDs, nil -} - -func (c *Cache) listAllProxyStateTemplatesTemporarily(ctx context.Context, rt controller.Runtime, tenancy *pbresource.Tenancy) ([]*pbresource.ID, error) { - // todo (ishustava): this is a stub for now until we implement implicit destinations. - // For tproxy, we generate requests for all proxy states in the cluster. - // This will generate duplicate events for proxies already added above, - // however, we expect that the controller runtime will de-dup for us. - rsp, err := rt.Client.List(ctx, &pbresource.ListRequest{ - Type: pbmesh.ProxyStateTemplateType, - Tenancy: &pbresource.Tenancy{ - Namespace: storage.Wildcard, - Partition: tenancy.Partition, - }, - }) - if err != nil { - return nil, err - } - - result := make([]*pbresource.ID, 0, len(rsp.Resources)) - for _, r := range rsp.Resources { - result = append(result, r.Id) - } - return result, nil -} - -func (c *Cache) MapComputedTrafficPermissions(_ context.Context, _ controller.Runtime, res *pbresource.Resource) ([]controller.Request, error) { - var ctp pbauth.ComputedTrafficPermissions - err := res.Data.UnmarshalTo(&ctp) - if err != nil { - return nil, err - } - - workloadIdentityID := resource.ReplaceType(pbauth.WorkloadIdentityType, res.Id) - ids := c.WorkloadsByWorkloadIdentity(workloadIdentityID) - - return controller.MakeRequests(pbmesh.ProxyStateTemplateType, ids), nil -} diff --git a/internal/mesh/internal/controllers/sidecarproxy/cache/cache_test.go b/internal/mesh/internal/controllers/sidecarproxy/cache/cache_test.go deleted file mode 100644 index b3c7e6d439..0000000000 --- a/internal/mesh/internal/controllers/sidecarproxy/cache/cache_test.go +++ /dev/null @@ -1,459 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package cache - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - - svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing" - "github.com/hashicorp/consul/internal/catalog" - "github.com/hashicorp/consul/internal/controller" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/routes/routestest" - "github.com/hashicorp/consul/internal/mesh/internal/types" - "github.com/hashicorp/consul/internal/resource" - "github.com/hashicorp/consul/internal/resource/resourcetest" - pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" - pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" - pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" - "github.com/hashicorp/consul/proto-public/pbresource" - "github.com/hashicorp/consul/proto/private/prototest" -) - -func TestIdentities(t *testing.T) { - resourcetest.RunWithTenancies(func(tenancy *pbresource.Tenancy) { - cache := New() - - identityID1 := resourcetest.Resource(pbauth.WorkloadIdentityType, "workload-identity-1"). - WithTenancy(tenancy).ID() - identityID2 := resourcetest.Resource(pbauth.WorkloadIdentityType, "workload-identity-2"). - WithTenancy(tenancy).ID() - - w1 := resourcetest.Resource(pbcatalog.WorkloadType, "service-workload-1"). - WithData(t, &pbcatalog.Workload{ - Identity: identityID1.Name, - }). - WithTenancy(tenancy). - Build() - decW1 := resourcetest.MustDecode[*pbcatalog.Workload](t, w1) - w2 := resourcetest.Resource(pbcatalog.WorkloadType, "service-workload-2"). - WithData(t, &pbcatalog.Workload{ - Identity: identityID2.Name, - }). - WithTenancy(tenancy). - Build() - decW2 := resourcetest.MustDecode[*pbcatalog.Workload](t, w2) - - // Empty cache - require.Nil(t, cache.WorkloadsByWorkloadIdentity(identityID1)) - require.Nil(t, cache.WorkloadsByWorkloadIdentity(identityID2)) - - // Insert value and fetch it. - cache.TrackWorkload(decW1) - require.Equal(t, []*pbresource.ID{w1.Id}, cache.WorkloadsByWorkloadIdentity(identityID1)) - require.Nil(t, cache.WorkloadsByWorkloadIdentity(identityID2)) - - // Insert another value referencing the same identity. - decW2.GetData().Identity = identityID1.Name - cache.TrackWorkload(decW2) - require.ElementsMatch(t, []*pbresource.ID{w1.Id, w2.Id}, cache.WorkloadsByWorkloadIdentity(identityID1)) - require.Nil(t, cache.WorkloadsByWorkloadIdentity(identityID2)) - - // Now workload 1 uses identity 2 - decW1.GetData().Identity = identityID2.Name - cache.TrackWorkload(decW1) - require.Equal(t, []*pbresource.ID{w1.Id}, cache.WorkloadsByWorkloadIdentity(identityID2)) - require.Equal(t, []*pbresource.ID{w2.Id}, cache.WorkloadsByWorkloadIdentity(identityID1)) - - // Untrack workload 2 - cache.UntrackWorkload(w2.Id) - require.Equal(t, []*pbresource.ID{w1.Id}, cache.WorkloadsByWorkloadIdentity(identityID2)) - require.Nil(t, cache.WorkloadsByWorkloadIdentity(identityID1)) - - // Untrack workload 1 - cache.UntrackWorkload(w1.Id) - require.Nil(t, cache.WorkloadsByWorkloadIdentity(identityID2)) - require.Nil(t, cache.WorkloadsByWorkloadIdentity(identityID1)) - }, t) -} - -func TestMapComputedTrafficPermissions(t *testing.T) { - resourcetest.RunWithTenancies(func(tenancy *pbresource.Tenancy) { - client := svctest.NewResourceServiceBuilder(). - WithRegisterFns(types.Register, catalog.RegisterTypes). - Run(t) - - ctp := resourcetest.Resource(pbauth.ComputedTrafficPermissionsType, "workload-identity-1"). - WithTenancy(tenancy). - WithData(t, &pbauth.ComputedTrafficPermissions{}). - Build() - - c := New() - - // Empty results when the cache isn't populated. - requests, err := c.MapComputedTrafficPermissions(context.Background(), controller.Runtime{Client: client}, ctp) - require.NoError(t, err) - require.Len(t, requests, 0) - - identityID1 := resourcetest.Resource(pbauth.WorkloadIdentityType, "workload-identity-1"). - WithTenancy(tenancy).ID() - - w1 := resourcetest.Resource(pbcatalog.WorkloadType, "service-workload-1"). - WithData(t, &pbcatalog.Workload{ - Identity: identityID1.Name, - }). - WithTenancy(tenancy). - Build() - decW1 := resourcetest.MustDecode[*pbcatalog.Workload](t, w1) - w2 := resourcetest.Resource(pbcatalog.WorkloadType, "service-workload-2"). - WithData(t, &pbcatalog.Workload{ - Identity: identityID1.Name, - }). - WithTenancy(tenancy). - Build() - decW2 := resourcetest.MustDecode[*pbcatalog.Workload](t, w2) - - c.TrackWorkload(decW1) - - // Empty results when the cache isn't populated. - requests, err = c.MapComputedTrafficPermissions(context.Background(), controller.Runtime{Client: client}, ctp) - require.NoError(t, err) - prototest.AssertElementsMatch(t, - []controller.Request{{ID: resource.ReplaceType(pbmesh.ProxyStateTemplateType, w1.Id)}}, requests) - - c.TrackWorkload(decW2) - - // Empty results when the cache isn't populated. - requests, err = c.MapComputedTrafficPermissions(context.Background(), controller.Runtime{Client: client}, ctp) - require.NoError(t, err) - prototest.AssertElementsMatch(t, []controller.Request{ - {ID: resource.ReplaceType(pbmesh.ProxyStateTemplateType, w1.Id)}, - {ID: resource.ReplaceType(pbmesh.ProxyStateTemplateType, w2.Id)}, - }, requests) - }, t) -} - -func TestUnified_AllMappingsToProxyStateTemplate(t *testing.T) { - resourcetest.RunWithTenancies(func(tenancy *pbresource.Tenancy) { - var ( - cache = New() - client = svctest.NewResourceServiceBuilder(). - WithRegisterFns(types.Register, catalog.RegisterTypes). - Run(t) - ) - - anyServiceData := &pbcatalog.Service{ - Workloads: &pbcatalog.WorkloadSelector{ - Prefixes: []string{"src-workload"}, - }, - Ports: []*pbcatalog.ServicePort{ - { - TargetPort: "tcp1", - Protocol: pbcatalog.Protocol_PROTOCOL_TCP, - }, - { - TargetPort: "tcp2", - Protocol: pbcatalog.Protocol_PROTOCOL_TCP, - }, - { - TargetPort: "mesh", - Protocol: pbcatalog.Protocol_PROTOCOL_MESH, - }, - }, - } - - // The thing we link through Destinations. - destService := resourcetest.Resource(pbcatalog.ServiceType, "web"). - WithTenancy(tenancy). - WithData(t, anyServiceData). - Build() - destServiceRef := resource.Reference(destService.Id, "") - - // The thing we reach through the mesh config. - targetService := resourcetest.Resource(pbcatalog.ServiceType, "db"). - WithTenancy(tenancy). - WithData(t, anyServiceData). - Build() - targetServiceRef := resource.Reference(targetService.Id, "") - - backupTargetService := resourcetest.Resource(pbcatalog.ServiceType, "db-backup"). - WithTenancy(tenancy). - WithData(t, anyServiceData). - Build() - backupTargetServiceRef := resource.Reference(backupTargetService.Id, "") - - // The way we make 'web' actually route traffic to 'db'. - tcpRoute := resourcetest.Resource(pbmesh.TCPRouteType, "tcp-route"). - WithTenancy(tenancy). - WithData(t, &pbmesh.TCPRoute{ - ParentRefs: []*pbmesh.ParentReference{{ - Ref: destServiceRef, - }}, - Rules: []*pbmesh.TCPRouteRule{{ - BackendRefs: []*pbmesh.TCPBackendRef{{ - BackendRef: &pbmesh.BackendReference{ - Ref: targetServiceRef, - }, - }}, - }}, - }). - Build() - - failoverPolicy := &pbcatalog.FailoverPolicy{ - Config: &pbcatalog.FailoverConfig{ - Destinations: []*pbcatalog.FailoverDestination{{ - Ref: backupTargetServiceRef, - }}, - }, - } - simiplifiedFailoverPolicy := catalog.SimplifyFailoverPolicy(anyServiceData, failoverPolicy) - computedFailoverPolicy := resourcetest.ResourceID(resource.ReplaceType(pbcatalog.ComputedFailoverPolicyType, targetService.Id)). - WithTenancy(tenancy). - WithData(t, &pbcatalog.ComputedFailoverPolicy{ - PortConfigs: simiplifiedFailoverPolicy.PortConfigs, - }). - Build() - webRoutes := routestest.BuildComputedRoutes(t, resource.ReplaceType(pbmesh.ComputedRoutesType, destService.Id), - resourcetest.MustDecode[*pbcatalog.Service](t, destService), - resourcetest.MustDecode[*pbcatalog.Service](t, targetService), - resourcetest.MustDecode[*pbcatalog.Service](t, backupTargetService), - resourcetest.MustDecode[*pbmesh.TCPRoute](t, tcpRoute), - resourcetest.MustDecode[*pbcatalog.ComputedFailoverPolicy](t, computedFailoverPolicy), - ) - - var ( - sourceProxy1 = newID(pbmesh.ProxyStateTemplateType, "src-workload-1", tenancy) - sourceProxy2 = newID(pbmesh.ProxyStateTemplateType, "src-workload-2", tenancy) - sourceProxy3 = newID(pbmesh.ProxyStateTemplateType, "src-workload-3", tenancy) - sourceProxy4 = newID(pbmesh.ProxyStateTemplateType, "src-workload-4", tenancy) - sourceProxy5 = newID(pbmesh.ProxyStateTemplateType, "src-workload-5", tenancy) - sourceProxy6 = newID(pbmesh.ProxyStateTemplateType, "src-workload-6", tenancy) - ) - - compDestProxy1 := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, sourceProxy1.Name). - WithData(t, &pbmesh.ComputedExplicitDestinations{ - Destinations: []*pbmesh.Destination{ - { - DestinationRef: destServiceRef, - DestinationPort: "tcp1", - }, - }, - }). - WithTenancy(tenancy). - Build() - - compDestProxy2 := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, sourceProxy2.Name). - WithData(t, &pbmesh.ComputedExplicitDestinations{ - Destinations: []*pbmesh.Destination{ - { - DestinationRef: destServiceRef, - DestinationPort: "tcp1", - }, - }, - }). - WithTenancy(tenancy). - Build() - - compDestProxy3 := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, sourceProxy3.Name). - WithData(t, &pbmesh.ComputedExplicitDestinations{ - Destinations: []*pbmesh.Destination{ - { - DestinationRef: destServiceRef, - DestinationPort: "tcp2", - }, - }, - }). - WithTenancy(tenancy). - Build() - - compDestProxy4 := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, sourceProxy4.Name). - WithData(t, &pbmesh.ComputedExplicitDestinations{ - Destinations: []*pbmesh.Destination{ - { - DestinationRef: destServiceRef, - DestinationPort: "tcp2", - }, - }, - }). - WithTenancy(tenancy). - Build() - - compDestProxy5 := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, sourceProxy5.Name). - WithData(t, &pbmesh.ComputedExplicitDestinations{ - Destinations: []*pbmesh.Destination{ - { - DestinationRef: destServiceRef, - DestinationPort: "mesh", - }, - }, - }). - WithTenancy(tenancy). - Build() - - compDestProxy6 := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, sourceProxy6.Name). - WithData(t, &pbmesh.ComputedExplicitDestinations{ - Destinations: []*pbmesh.Destination{ - { - DestinationRef: destServiceRef, - DestinationPort: "mesh", - }, - }, - }). - WithTenancy(tenancy). - Build() - - cache.trackComputedRoutes(webRoutes) - cache.TrackComputedDestinations(resourcetest.MustDecode[*pbmesh.ComputedExplicitDestinations](t, compDestProxy1)) - cache.TrackComputedDestinations(resourcetest.MustDecode[*pbmesh.ComputedExplicitDestinations](t, compDestProxy2)) - cache.TrackComputedDestinations(resourcetest.MustDecode[*pbmesh.ComputedExplicitDestinations](t, compDestProxy3)) - cache.TrackComputedDestinations(resourcetest.MustDecode[*pbmesh.ComputedExplicitDestinations](t, compDestProxy4)) - cache.TrackComputedDestinations(resourcetest.MustDecode[*pbmesh.ComputedExplicitDestinations](t, compDestProxy5)) - cache.TrackComputedDestinations(resourcetest.MustDecode[*pbmesh.ComputedExplicitDestinations](t, compDestProxy6)) - - t.Run(resourcetest.AppendTenancyInfoSubtest(t.Name(), "Service", tenancy), func(t *testing.T) { - t.Run("map dest service", func(t *testing.T) { - requests, err := cache.MapService( - context.Background(), - controller.Runtime{Client: client}, - destService, - ) - require.NoError(t, err) - - // Only wake up things with dest as an upstream. - expRequests := []controller.Request{ - {ID: sourceProxy1}, - {ID: sourceProxy2}, - {ID: sourceProxy3}, - {ID: sourceProxy4}, - {ID: sourceProxy5}, - {ID: sourceProxy6}, - } - - prototest.AssertElementsMatch(t, expRequests, requests) - - // Check that service's workload selector is tracked. - prototest.AssertElementsMatch(t, - []*pbresource.ID{destService.Id}, - cache.serviceSelectorTracker.GetIDsForWorkload(resource.ReplaceType(pbcatalog.WorkloadType, sourceProxy1))) - prototest.AssertElementsMatch(t, - []*pbresource.ID{destService.Id}, - cache.serviceSelectorTracker.GetIDsForWorkload(resource.ReplaceType(pbcatalog.WorkloadType, sourceProxy2))) - prototest.AssertElementsMatch(t, - []*pbresource.ID{destService.Id}, - cache.serviceSelectorTracker.GetIDsForWorkload(resource.ReplaceType(pbcatalog.WorkloadType, sourceProxy3))) - prototest.AssertElementsMatch(t, - []*pbresource.ID{destService.Id}, - cache.serviceSelectorTracker.GetIDsForWorkload(resource.ReplaceType(pbcatalog.WorkloadType, sourceProxy4))) - prototest.AssertElementsMatch(t, - []*pbresource.ID{destService.Id}, - cache.serviceSelectorTracker.GetIDsForWorkload(resource.ReplaceType(pbcatalog.WorkloadType, sourceProxy5))) - prototest.AssertElementsMatch(t, - []*pbresource.ID{destService.Id}, - cache.serviceSelectorTracker.GetIDsForWorkload(resource.ReplaceType(pbcatalog.WorkloadType, sourceProxy6))) - }) - - t.Run("map target endpoints (TCPRoute)", func(t *testing.T) { - requests, err := cache.MapService( - context.Background(), - controller.Runtime{Client: client}, - targetService, - ) - require.NoError(t, err) - - requests = testDeduplicateRequests(requests) - - expRequests := []controller.Request{ - // Wakeup things that have destService as a destination b/c of the TCPRoute reference. - {ID: sourceProxy1}, - {ID: sourceProxy2}, - {ID: sourceProxy3}, - {ID: sourceProxy4}, - {ID: sourceProxy5}, - {ID: sourceProxy6}, - } - - prototest.AssertElementsMatch(t, expRequests, requests) - }) - - t.Run("map backup target endpoints (FailoverPolicy)", func(t *testing.T) { - requests, err := cache.MapService( - context.Background(), - controller.Runtime{Client: client}, - backupTargetService, - ) - require.NoError(t, err) - - requests = testDeduplicateRequests(requests) - - expRequests := []controller.Request{ - // Wakeup things that have destService as a destination b/c of the FailoverPolicy reference. - {ID: sourceProxy1}, - {ID: sourceProxy2}, - {ID: sourceProxy3}, - {ID: sourceProxy4}, - {ID: sourceProxy5}, - {ID: sourceProxy6}, - } - - prototest.AssertElementsMatch(t, expRequests, requests) - }) - }) - - t.Run(resourcetest.AppendTenancyInfoSubtest(t.Name(), "ComputedRoutes", tenancy), func(t *testing.T) { - t.Run("map web routes", func(t *testing.T) { - requests, err := cache.MapComputedRoutes( - context.Background(), - controller.Runtime{Client: client}, - webRoutes.Resource, - ) - require.NoError(t, err) - - // Only wake up things with dest as an upstream. - expRequests := []controller.Request{ - {ID: sourceProxy1}, - {ID: sourceProxy2}, - {ID: sourceProxy3}, - {ID: sourceProxy4}, - {ID: sourceProxy5}, - {ID: sourceProxy6}, - } - - prototest.AssertElementsMatch(t, expRequests, requests) - }) - }) - }, t) -} - -func newID(typ *pbresource.Type, name string, tenancy *pbresource.Tenancy) *pbresource.ID { - return &pbresource.ID{ - Type: typ, - Tenancy: tenancy, - Name: name, - } -} - -func testDeduplicateRequests(reqs []controller.Request) []controller.Request { - type resID struct { - resource.ReferenceKey - UID string - } - - out := make([]controller.Request, 0, len(reqs)) - seen := make(map[resID]struct{}) - - for _, req := range reqs { - rid := resID{ - ReferenceKey: resource.NewReferenceKey(req.ID), - UID: req.ID.Uid, - } - if _, ok := seen[rid]; !ok { - out = append(out, req) - seen[rid] = struct{}{} - } - } - - return out -} diff --git a/internal/mesh/internal/controllers/sidecarproxy/controller.go b/internal/mesh/internal/controllers/sidecarproxy/controller.go index 644ceaaf20..a040ed3e04 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/controller.go +++ b/internal/mesh/internal/controllers/sidecarproxy/controller.go @@ -6,15 +6,14 @@ package sidecarproxy import ( "context" - "github.com/hashicorp/go-hclog" "google.golang.org/protobuf/proto" "google.golang.org/protobuf/types/known/anypb" + "github.com/hashicorp/consul/internal/catalog/workloadselector" "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/controller/cache" "github.com/hashicorp/consul/internal/controller/dependency" "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/builder" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/cache" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/fetcher" "github.com/hashicorp/consul/internal/mesh/internal/types" "github.com/hashicorp/consul/internal/resource" pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" @@ -29,71 +28,86 @@ const ControllerName = "consul.io/sidecar-proxy-controller" type TrustDomainFetcher func() (string, error) func Controller( - cache *cache.Cache, trustDomainFetcher TrustDomainFetcher, dc string, defaultAllow bool, ) *controller.Controller { - if cache == nil || trustDomainFetcher == nil { - panic("cache and trust domain fetcher are required") + if trustDomainFetcher == nil { + panic("trust domain fetcher is required") } /* - Workload PST - ComputedDestinations PST(==Workload) - ComputedDestinations Service(destinations) - ComputedProxyConfiguration PST(==Workload) - ComputedRoutes Service(upstream) - ComputedRoutes Service(disco) - ComputedTrafficPermissions WorkloadIdentity - Workload WorkloadIdentity + Workload PST + ComputedExplicitDestinations PST(==Workload) + ComputedExplicitDestinations Service(destinations) + ComputedProxyConfiguration PST(==Workload) + ComputedRoutes Service(upstream) + ComputedRoutes Service(disco) + ComputedTrafficPermissions WorkloadIdentity + Workload WorkloadIdentity + ComputedImplicitDestinations WorkloadIdentity + ComputedImplicitDestinations Service(destinations) These relationships then dictate the following reconcile logic. controller: read workload for PST controller: read previous PST controller: read ComputedProxyConfiguration for Workload - controller: read ComputedDestinations for workload to walk explicit upstreams + controller: read ComputedExplicitDestinations for workload to walk explicit destinations + controller: maybe read ComputedImplicitDestinations for workload.identity to walk implicit destinations controller: read ComputedTrafficPermissions for workload using workload.identity field. - + fetcher: read Service(Destination) fetcher: read ComputedRoutes - fetcher: read ServiceEndpoints + fetcher: read Service - - - fetcher: list ALL ComputedRoutes - - fetcher: read Service(upstream) - - fetcher: read ServiceEndpoints - - - + */ /* Which means for equivalence, the following mapper relationships should exist: - Service: find destinations with Service; Recurse(ComputedDestinations); - find ComputedRoutes with this in a Target or FailoverConfig; Recurse(ComputedRoutes) - ComputedDestinations: replace type CED=>PST - ComputedProxyConfiguration: replace type CPC=>PST - ComputedRoutes: CR=>Service; find destinations with Service; Recurse(Destinations) - [implicit/temp]: trigger all - ComputedTrafficPermissions: find workloads in cache stored for this CTP=Workload, workloads=>PST reconcile requests + Service: find destinations with Service; Recurse(ComputedXDestinations); + find ComputedRoutes with this in a Target or FailoverConfig; Recurse(ComputedRoutes) + ComputedExplicitDestinations: replace type CED=>PST + ComputedImplicitDestinations: replace type CID=>WI; find workload with this identity; replace type WRK=>PST + ComputedProxyConfiguration: replace type CPC=>PST + ComputedRoutes: CR=>Service; find destinations with Service; Recurse(Destinations) + [implicit/temp]: trigger all + ComputedTrafficPermissions: find workloads in cache stored for this CTP=Workload, workloads=>PST reconcile requests */ + // TODO(rb): ultimately needs some form of BoundReferences return controller.NewController(ControllerName, pbmesh.ProxyStateTemplateType). - WithWatch(pbcatalog.ServiceType, cache.MapService). - WithWatch(pbcatalog.WorkloadType, dependency.ReplaceType(pbmesh.ProxyStateTemplateType)). - WithWatch(pbmesh.ComputedExplicitDestinationsType, dependency.ReplaceType(pbmesh.ProxyStateTemplateType)). - WithWatch(pbmesh.ComputedProxyConfigurationType, dependency.ReplaceType(pbmesh.ProxyStateTemplateType)). - WithWatch(pbmesh.ComputedRoutesType, cache.MapComputedRoutes). - WithWatch(pbauth.ComputedTrafficPermissionsType, cache.MapComputedTrafficPermissions). + WithWatch(pbcatalog.ServiceType, + MapService, + serviceByWorkloadIdentityIndex, + workloadselector.Index[*pbcatalog.Service](selectedWorkloadsIndexName), + ). + WithWatch(pbcatalog.WorkloadType, + dependency.ReplaceType(pbmesh.ProxyStateTemplateType), + workloadByWorkloadIdentityIndex, + ). + WithWatch(pbmesh.ComputedExplicitDestinationsType, + dependency.ReplaceType(pbmesh.ProxyStateTemplateType), + computedExplicitDestinationsByServiceIndex, + ). + WithWatch(pbmesh.ComputedImplicitDestinationsType, + MapComputedImplicitDestinations, + computedImplicitDestinationsByServiceIndex, + ). + WithWatch(pbmesh.ComputedProxyConfigurationType, + dependency.ReplaceType(pbmesh.ProxyStateTemplateType), + ). + WithWatch(pbmesh.ComputedRoutesType, + MapComputedRoutes, + computedRoutesByBackendServiceIndex, + ). + WithWatch(pbauth.ComputedTrafficPermissionsType, + MapComputedTrafficPermissions, + ). WithReconciler(&reconciler{ - cache: cache, getTrustDomain: trustDomainFetcher, dc: dc, defaultAllow: defaultAllow, @@ -101,7 +115,6 @@ func Controller( } type reconciler struct { - cache *cache.Cache getTrustDomain TrustDomainFetcher defaultAllow bool dc string @@ -112,12 +125,9 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c rt.Logger.Trace("reconciling proxy state template") - // Instantiate a data fetcher to fetch all reconciliation data. - dataFetcher := fetcher.New(rt.Client, r.cache) - // Check if the workload exists. workloadID := resource.ReplaceType(pbcatalog.WorkloadType, req.ID) - workload, err := dataFetcher.FetchWorkload(ctx, workloadID) + workload, err := cache.GetDecoded[*pbcatalog.Workload](rt.Cache, pbcatalog.WorkloadType, "id", workloadID) if err != nil { rt.Logger.Error("error reading the associated workload", "error", err) return err @@ -136,7 +146,7 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c return nil } - proxyStateTemplate, err := dataFetcher.FetchProxyStateTemplate(ctx, req.ID) + proxyStateTemplate, err := cache.GetDecoded[*pbmesh.ProxyStateTemplate](rt.Cache, pbmesh.ProxyStateTemplateType, "id", req.ID) if err != nil { rt.Logger.Error("error reading proxy state template", "error", err) return nil @@ -147,7 +157,7 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c rt.Logger.Trace("proxy state template for this workload doesn't yet exist; generating a new one") } - if !workload.GetData().IsMeshEnabled() { + if !workload.GetData().IsMeshEnabled() || workload.Data.Identity == "" { // Skip non-mesh workloads. // If there's existing proxy state template, delete it. @@ -171,13 +181,20 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c } // Fetch proxy configuration. - proxyCfg, err := dataFetcher.FetchComputedProxyConfiguration(ctx, req.ID) + cpcID := resource.ReplaceType(pbmesh.ComputedProxyConfigurationType, req.ID) + proxyCfg, err := cache.GetDecoded[*pbmesh.ComputedProxyConfiguration](rt.Cache, pbmesh.ComputedProxyConfigurationType, "id", cpcID) if err != nil { rt.Logger.Error("error fetching proxy and merging proxy configurations", "error", err) return err } + // note the proxyCfg may be nil - trafficPermissions, err := dataFetcher.FetchComputedTrafficPermissions(ctx, computedTrafficPermissionsIDFromWorkload(workload)) + ctpID := &pbresource.ID{ + Type: pbauth.ComputedTrafficPermissionsType, + Name: workload.Data.Identity, + Tenancy: workload.Resource.Id.Tenancy, + } + trafficPermissions, err := cache.GetDecoded[*pbauth.ComputedTrafficPermissions](rt.Cache, pbauth.ComputedTrafficPermissionsType, "id", ctpID) if err != nil { rt.Logger.Error("error fetching computed traffic permissions to compute proxy state template", "error", err) return err @@ -188,7 +205,7 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c ctp = trafficPermissions.Data } - workloadPorts, err := r.workloadPortProtocolsFromService(ctx, dataFetcher, workload, rt.Logger) + workloadPorts, err := workloadPortProtocolsFromService(rt, workload) if err != nil { rt.Logger.Error("error determining workload ports", "error", err) return err @@ -196,23 +213,34 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c workloadDataWithInheritedPorts := proto.Clone(workload.Data).(*pbcatalog.Workload) workloadDataWithInheritedPorts.Ports = workloadPorts - b := builder.New(req.ID, identityRefFromWorkload(workload), trustDomain, r.dc, r.defaultAllow, proxyCfg.GetData()). - BuildLocalApp(workloadDataWithInheritedPorts, ctp) - - // Get all destinationsData. - destinationsData, err := dataFetcher.FetchComputedExplicitDestinationsData(ctx, req.ID, proxyCfg.GetData()) - if err != nil { - rt.Logger.Error("error fetching explicit destinations for this proxy", "error", err) - return err + workloadIdentityRef := &pbresource.Reference{ + Name: workload.Data.Identity, + Tenancy: workload.Resource.Id.Tenancy, + Type: pbauth.WorkloadIdentityType, } - if proxyCfg.GetData() != nil && proxyCfg.GetData().IsTransparentProxy() { - rt.Logger.Trace("transparent proxy is enabled; fetching implicit destinations") - destinationsData, err = dataFetcher.FetchImplicitDestinationsData(ctx, req.ID, destinationsData) - if err != nil { - rt.Logger.Error("error fetching implicit destinations for this proxy", "error", err) - return err - } + b := builder.New( + req.ID, + workloadIdentityRef, + trustDomain, + r.dc, + r.defaultAllow, + proxyCfg.GetData(), + ). + BuildLocalApp(workloadDataWithInheritedPorts, ctp) + + mgwMode := pbmesh.MeshGatewayMode_MESH_GATEWAY_MODE_NONE + if dynamicCfg := proxyCfg.GetData().GetDynamicConfig(); dynamicCfg != nil { + mgwMode = dynamicCfg.GetMeshGatewayMode() + } + + // Get all destinationsData. + destinationsData, err := FetchUnifiedDestinationsData( + ctx, rt, workload, mgwMode, + proxyCfg.GetData().IsTransparentProxy()) + if err != nil { + rt.Logger.Error("error fetching destinations for this proxy", "error", err) + return err } b.BuildDestinations(destinationsData) @@ -247,30 +275,11 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c return nil } -func (r *reconciler) workloadPortProtocolsFromService( - ctx context.Context, - fetcher *fetcher.Fetcher, - workload *types.DecodedWorkload, - logger hclog.Logger, -) (map[string]*pbcatalog.WorkloadPort, error) { +func workloadPortProtocolsFromService(rt controller.Runtime, workload *types.DecodedWorkload) (map[string]*pbcatalog.WorkloadPort, error) { // Fetch all services for this workload. - serviceIDs := r.cache.ServicesForWorkload(workload.GetResource().GetId()) - - var services []*types.DecodedService - - for _, serviceID := range serviceIDs { - svc, err := fetcher.FetchService(ctx, serviceID) - if err != nil { - return nil, err - } - - // If service is not found, we should untrack it. - if svc == nil { - r.cache.UntrackService(serviceID) - continue - } - - services = append(services, svc) + services, err := cache.ParentsDecoded[*pbcatalog.Service](rt.Cache, pbcatalog.ServiceType, selectedWorkloadsIndexName, workload.Id) + if err != nil { + return nil, err } // Now walk through all workload ports. @@ -286,8 +295,8 @@ func (r *reconciler) workloadPortProtocolsFromService( } // Check if we have any service IDs or fetched services. - if len(serviceIDs) == 0 || len(services) == 0 { - logger.Trace("found no services for this workload's port; using default TCP protocol", "port", portName) + if len(services) == 0 { + rt.Logger.Trace("found no services for this workload's port; using default TCP protocol", "port", portName) result[portName] = &pbcatalog.WorkloadPort{ Port: port.GetPort(), Protocol: pbcatalog.Protocol_PROTOCOL_TCP, @@ -299,7 +308,7 @@ func (r *reconciler) workloadPortProtocolsFromService( inheritedProtocol := pbcatalog.Protocol_PROTOCOL_UNSPECIFIED for _, svc := range services { // Find workload's port as the target port. - svcPort := svc.GetData().FindTargetPort(portName) + svcPort := svc.Data.FindTargetPort(portName) // If this service doesn't select this port, go to the next service. if svcPort == nil { @@ -312,7 +321,7 @@ func (r *reconciler) workloadPortProtocolsFromService( if inheritedProtocol != pbcatalog.Protocol_PROTOCOL_UNSPECIFIED && svcPort.GetProtocol() != inheritedProtocol { - logger.Trace("found conflicting service protocols that select this workload port; using default TCP protocol", "port", portName) + rt.Logger.Trace("found conflicting service protocols that select this workload port; using default TCP protocol", "port", portName) inheritedProtocol = pbcatalog.Protocol_PROTOCOL_TCP // We won't check any remaining services as there's already a conflict. @@ -324,7 +333,7 @@ func (r *reconciler) workloadPortProtocolsFromService( // If after going through all services, we haven't found a protocol, use the default. if inheritedProtocol == pbcatalog.Protocol_PROTOCOL_UNSPECIFIED { - logger.Trace("no services select this workload port; using default TCP protocol", "port", portName) + rt.Logger.Trace("no services select this workload port; using default TCP protocol", "port", portName) result[portName] = &pbcatalog.WorkloadPort{ Port: port.GetPort(), Protocol: pbcatalog.Protocol_PROTOCOL_TCP, @@ -339,19 +348,3 @@ func (r *reconciler) workloadPortProtocolsFromService( return result, nil } - -func identityRefFromWorkload(w *types.DecodedWorkload) *pbresource.Reference { - return &pbresource.Reference{ - Name: w.Data.Identity, - Tenancy: w.Resource.Id.Tenancy, - Type: pbauth.WorkloadIdentityType, - } -} - -func computedTrafficPermissionsIDFromWorkload(w *types.DecodedWorkload) *pbresource.ID { - return &pbresource.ID{ - Type: pbauth.ComputedTrafficPermissionsType, - Name: w.Data.Identity, - Tenancy: w.Resource.Id.Tenancy, - } -} diff --git a/internal/mesh/internal/controllers/sidecarproxy/controller_test.go b/internal/mesh/internal/controllers/sidecarproxy/controller_test.go index f5aba93c1a..86116ab55a 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/controller_test.go +++ b/internal/mesh/internal/controllers/sidecarproxy/controller_test.go @@ -19,8 +19,6 @@ import ( "github.com/hashicorp/consul/internal/controller" "github.com/hashicorp/consul/internal/mesh/internal/controllers/routes/routestest" "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/builder" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/cache" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/fetcher" "github.com/hashicorp/consul/internal/mesh/internal/types" "github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/resource/resourcetest" @@ -37,23 +35,20 @@ import ( type controllerTestSuite struct { suite.Suite - client *resourcetest.Client - runtime controller.Runtime + ctx context.Context + client *resourcetest.Client + rt controller.Runtime - ctl *reconciler - ctx context.Context + ctl *controller.TestController + tenancies []*pbresource.Tenancy webWorkload *pbresource.Resource api map[tenancyKey]apiData - dbWorkloadID *pbresource.ID - dbWorkload *pbcatalog.Workload - dbService *pbresource.Resource - dbEndpoints *pbresource.Resource - dbEndpointsData *pbcatalog.ServiceEndpoints - - tenancies []*pbresource.Tenancy + dbWorkloadID *pbresource.ID + dbWorkload *pbcatalog.Workload + dbService *pbresource.Resource } type tenancyKey struct { @@ -77,28 +72,24 @@ type apiData struct { destinationListenerName string destinationClusterName string serviceData *pbcatalog.Service - endpoints *pbresource.Resource - endpointsData *pbcatalog.ServiceEndpoints proxyStateTemplate *pbmesh.ProxyStateTemplate } func (suite *controllerTestSuite) SetupTest() { + trustDomainFetcher := func() (string, error) { return "test.consul", nil } + suite.tenancies = resourcetest.TestTenancies() - resourceClient := svctest.NewResourceServiceBuilder(). + + suite.ctx = testutil.TestContext(suite.T()) + client := svctest.NewResourceServiceBuilder(). WithRegisterFns(types.Register, catalog.RegisterTypes, auth.RegisterTypes). WithTenancies(suite.tenancies...). Run(suite.T()) - suite.client = resourcetest.NewClient(resourceClient) - suite.runtime = controller.Runtime{Client: resourceClient, Logger: testutil.Logger(suite.T())} - suite.ctx = testutil.TestContext(suite.T()) - - suite.ctl = &reconciler{ - cache: cache.New(), - getTrustDomain: func() (string, error) { - return "test.consul", nil - }, - } + suite.ctl = controller.NewTestController(Controller(trustDomainFetcher, "dc1", false), client). + WithLogger(testutil.Logger(suite.T())) + suite.rt = suite.ctl.Runtime() + suite.client = resourcetest.NewClient(suite.rt.Client) suite.dbWorkload = &pbcatalog.Workload{ Identity: "db-identity", @@ -133,31 +124,11 @@ func (suite *controllerTestSuite) setupSuiteWithTenancy(tenancy *pbresource.Tena WithTenancy(tenancy). Write(suite.T(), suite.client.ResourceServiceClient).Id - suite.dbService = resourcetest.Resource(pbcatalog.ServiceType, "db-service"). - WithData(suite.T(), &pbcatalog.Service{ - Workloads: &pbcatalog.WorkloadSelector{Names: []string{"db-abc"}}, - VirtualIps: []string{"1.1.1.1"}, - Ports: []*pbcatalog.ServicePort{ - {TargetPort: "http", Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, - {TargetPort: "mesh", Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, - }}). - WithTenancy(tenancy). - Write(suite.T(), suite.client) - - suite.dbEndpointsData = &pbcatalog.ServiceEndpoints{ - Endpoints: []*pbcatalog.Endpoint{ - { - TargetRef: suite.dbWorkloadID, - Addresses: suite.dbWorkload.Addresses, - Ports: suite.dbWorkload.Ports, - Identity: "db-identity", - }, - }, - } - suite.dbEndpoints = resourcetest.Resource(pbcatalog.ServiceEndpointsType, "db-service"). - WithData(suite.T(), suite.dbEndpointsData). - WithTenancy(tenancy). - Write(suite.T(), suite.client) + suite.dbService, _, _ = suite.createService( + "db-service", tenancy, "db-abc", []*pbcatalog.ServicePort{ + {TargetPort: "http", Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + {TargetPort: "mesh", Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, []string{"1.1.1.1"}, []string{"db-identity"}, false) suite.api = make(map[tenancyKey]apiData) @@ -193,45 +164,21 @@ func (suite *controllerTestSuite) setupSuiteWithTenancy(tenancy *pbresource.Tena }, } - a.serviceData = &pbcatalog.Service{ - Workloads: &pbcatalog.WorkloadSelector{Names: []string{"api-abc"}}, - VirtualIps: []string{"1.1.1.1"}, - Ports: []*pbcatalog.ServicePort{ - {TargetPort: "tcp", Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - {TargetPort: "mesh", Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, - }, - } - a.workloadID = resourcetest.Resource(pbcatalog.WorkloadType, "api-abc"). WithTenancy(t). WithData(suite.T(), a.workload). Write(suite.T(), suite.client.ResourceServiceClient).Id - a.endpointsData = &pbcatalog.ServiceEndpoints{ - Endpoints: []*pbcatalog.Endpoint{ - { - TargetRef: a.workloadID, - Addresses: a.workload.Addresses, - Ports: a.workload.Ports, - Identity: "api-identity", - }, - }, - } - a.computedTrafficPermissions = resourcetest.Resource(pbauth.ComputedTrafficPermissionsType, a.workload.Identity). WithData(suite.T(), a.computedTrafficPermissionsData). WithTenancy(t). Write(suite.T(), suite.client.ResourceServiceClient) - a.service = resourcetest.Resource(pbcatalog.ServiceType, "api-service"). - WithData(suite.T(), a.serviceData). - WithTenancy(t). - Write(suite.T(), suite.client.ResourceServiceClient) - - a.endpoints = resourcetest.Resource(pbcatalog.ServiceEndpointsType, "api-service"). - WithData(suite.T(), a.endpointsData). - WithTenancy(t). - Write(suite.T(), suite.client.ResourceServiceClient) + a.service, a.serviceData, _ = suite.createService( + "api-service", t, "api-abc", []*pbcatalog.ServicePort{ + {TargetPort: "tcp", Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + {TargetPort: "mesh", Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, []string{"1.1.1.1"}, []string{"api-identity"}, false) identityRef := &pbresource.Reference{ Name: a.workload.Identity, @@ -260,34 +207,15 @@ func (suite *controllerTestSuite) setupSuiteWithTenancy(tenancy *pbresource.Tena WithTenancy(tenancy). Write(suite.T(), suite.client.ResourceServiceClient) - resourcetest.Resource(pbcatalog.ServiceType, "web"). - WithTenancy(tenancy). - WithData(suite.T(), &pbcatalog.Service{ - Workloads: &pbcatalog.WorkloadSelector{Names: []string{"web-def"}}, - Ports: []*pbcatalog.ServicePort{ - {TargetPort: "tcp", Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - {TargetPort: "mesh", Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, - }}). - Write(suite.T(), suite.client) - - resourcetest.Resource(pbcatalog.ServiceEndpointsType, "web"). - WithTenancy(tenancy). - WithData(suite.T(), &pbcatalog.ServiceEndpoints{ - Endpoints: []*pbcatalog.Endpoint{ - { - TargetRef: suite.webWorkload.Id, - Addresses: webWorkloadData.Addresses, - Ports: webWorkloadData.Ports, - Identity: "web-identity", - }, - }, - }).Write(suite.T(), suite.client) + suite.createService( + "web", tenancy, "web-def", []*pbcatalog.ServicePort{ + {TargetPort: "tcp", Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + {TargetPort: "mesh", Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, nil, []string{"web-identity"}, false) } func (suite *controllerTestSuite) TestWorkloadPortProtocolsFromService_NoServicesInCache() { suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - dataFetcher := fetcher.New(suite.client, suite.ctl.cache) - workload := resourcetest.Resource(pbcatalog.WorkloadType, "api-workload"). WithTenancy(tenancy). WithData(suite.T(), &pbcatalog.Workload{ @@ -298,7 +226,7 @@ func (suite *controllerTestSuite) TestWorkloadPortProtocolsFromService_NoService Build() decWorkload := resourcetest.MustDecode[*pbcatalog.Workload](suite.T(), workload) - workloadPorts, err := suite.ctl.workloadPortProtocolsFromService(suite.ctx, dataFetcher, decWorkload, suite.runtime.Logger) + workloadPorts, err := workloadPortProtocolsFromService(suite.rt, decWorkload) require.NoError(suite.T(), err) prototest.AssertDeepEqual(suite.T(), pbcatalog.Protocol_PROTOCOL_TCP, workloadPorts["tcp"].GetProtocol()) }) @@ -306,15 +234,7 @@ func (suite *controllerTestSuite) TestWorkloadPortProtocolsFromService_NoService func (suite *controllerTestSuite) TestWorkloadPortProtocolsFromService_ServiceNotFound() { suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - c := cache.New() - dataFetcher := fetcher.New(suite.client, c) - ctrl := &reconciler{ - cache: c, - getTrustDomain: func() (string, error) { - return "test.consul", nil - }, - } - svc := resourcetest.Resource(pbcatalog.ServiceType, "not-found"). + resourcetest.Resource(pbcatalog.ServiceType, "not-found"). WithData(suite.T(), &pbcatalog.Service{ Workloads: &pbcatalog.WorkloadSelector{ Names: []string{"api-workload"}, @@ -323,9 +243,6 @@ func (suite *controllerTestSuite) TestWorkloadPortProtocolsFromService_ServiceNo WithTenancy(tenancy). Build() - decSvc := resourcetest.MustDecode[*pbcatalog.Service](suite.T(), svc) - c.TrackService(decSvc) - workload := resourcetest.Resource(pbcatalog.WorkloadType, "api-workload"). WithData(suite.T(), &pbcatalog.Workload{ Ports: map[string]*pbcatalog.WorkloadPort{ @@ -337,47 +254,21 @@ func (suite *controllerTestSuite) TestWorkloadPortProtocolsFromService_ServiceNo decWorkload := resourcetest.MustDecode[*pbcatalog.Workload](suite.T(), workload) - workloadPorts, err := ctrl.workloadPortProtocolsFromService(suite.ctx, dataFetcher, decWorkload, suite.runtime.Logger) + workloadPorts, err := workloadPortProtocolsFromService(suite.rt, decWorkload) require.NoError(suite.T(), err) prototest.AssertDeepEqual(suite.T(), pbcatalog.Protocol_PROTOCOL_TCP, workloadPorts["tcp"].GetProtocol()) - // Check that the service is no longer in cache. - require.Nil(suite.T(), c.ServicesForWorkload(workload.Id)) }) } func (suite *controllerTestSuite) TestWorkloadPortProtocolsFromService() { suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - c := cache.New() - dataFetcher := fetcher.New(suite.client, c) - ctrl := &reconciler{ - cache: c, - getTrustDomain: func() (string, error) { - return "test.consul", nil - }, - } - svc1 := resourcetest.Resource(pbcatalog.ServiceType, "api-1"). - WithData(suite.T(), &pbcatalog.Service{ - Workloads: &pbcatalog.WorkloadSelector{ - Names: []string{"api-workload"}, - }, - Ports: []*pbcatalog.ServicePort{ - { - TargetPort: "http1", - Protocol: pbcatalog.Protocol_PROTOCOL_HTTP, - }, - { - TargetPort: "conflict", - Protocol: pbcatalog.Protocol_PROTOCOL_HTTP, - }, - }, - }). - WithTenancy(tenancy). - Write(suite.T(), suite.client) + suite.createService( + "api-1", tenancy, "api-workload", []*pbcatalog.ServicePort{ + {TargetPort: "http1", Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + {TargetPort: "conflict", Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, + }, nil, nil, false) - decSvc := resourcetest.MustDecode[*pbcatalog.Service](suite.T(), svc1) - c.TrackService(decSvc) - - svc2 := resourcetest.Resource(pbcatalog.ServiceType, "api-2"). + resourcetest.Resource(pbcatalog.ServiceType, "api-2"). WithTenancy(tenancy). WithData(suite.T(), &pbcatalog.Service{ Workloads: &pbcatalog.WorkloadSelector{ @@ -396,9 +287,6 @@ func (suite *controllerTestSuite) TestWorkloadPortProtocolsFromService() { }). Write(suite.T(), suite.client) - decSvc = resourcetest.MustDecode[*pbcatalog.Service](suite.T(), svc2) - c.TrackService(decSvc) - workload := resourcetest.Resource(pbcatalog.WorkloadType, "api-workload"). WithTenancy(tenancy). WithData(suite.T(), &pbcatalog.Workload{ @@ -434,7 +322,7 @@ func (suite *controllerTestSuite) TestWorkloadPortProtocolsFromService() { "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, } - workloadPorts, err := ctrl.workloadPortProtocolsFromService(suite.ctx, dataFetcher, decWorkload, suite.runtime.Logger) + workloadPorts, err := workloadPortProtocolsFromService(suite.rt, decWorkload) require.NoError(suite.T(), err) prototest.AssertDeepEqual(suite.T(), expWorkloadPorts, workloadPorts) @@ -445,10 +333,7 @@ func (suite *controllerTestSuite) TestReconcile_NoWorkload() { suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { // This test ensures that removed workloads are ignored and don't result // in the creation of the proxy state template. - err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{ - ID: resourceID(pbmesh.ProxyStateTemplateType, "not-found", tenancy), - }) - require.NoError(suite.T(), err) + suite.reconcileOnce(resourceID(pbmesh.ProxyStateTemplateType, "not-found", tenancy)) suite.client.RequireResourceNotFound(suite.T(), resourceID(pbmesh.ProxyStateTemplateType, "not-found", tenancy)) }) @@ -477,11 +362,8 @@ func (suite *controllerTestSuite) TestReconcile_GatewayWorkload() { WithMeta("gateway-kind", "mesh-gateway"). Write(suite.T(), suite.client.ResourceServiceClient) - err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{ - ID: resourceID(pbmesh.ProxyStateTemplateType, "test-gateway-workload", tenancy), - }) + suite.reconcileOnce(resourceID(pbmesh.ProxyStateTemplateType, "test-gateway-workload", tenancy)) - require.NoError(suite.T(), err) suite.client.RequireResourceNotFound(suite.T(), resourceID(pbmesh.ProxyStateTemplateType, "test-non-mesh-api-workload", tenancy)) }) } @@ -506,11 +388,8 @@ func (suite *controllerTestSuite) TestReconcile_NonMeshWorkload() { WithTenancy(tenancy). Write(suite.T(), suite.client.ResourceServiceClient) - err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{ - ID: resourceID(pbmesh.ProxyStateTemplateType, "test-non-mesh-api-workload", tenancy), - }) + suite.reconcileOnce(resourceID(pbmesh.ProxyStateTemplateType, "test-non-mesh-api-workload", tenancy)) - require.NoError(suite.T(), err) suite.client.RequireResourceNotFound(suite.T(), resourceID(pbmesh.ProxyStateTemplateType, "test-non-mesh-api-workload", tenancy)) }) } @@ -520,13 +399,9 @@ func (suite *controllerTestSuite) TestReconcile_NoExistingProxyStateTemplate() { api := suite.api[toTenancyKey(tenancy)] - err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{ - ID: resourceID(pbmesh.ProxyStateTemplateType, api.workloadID.Name, tenancy), - }) - require.NoError(suite.T(), err) + suite.reconcileOnce(resourceID(pbmesh.ProxyStateTemplateType, api.workloadID.Name, tenancy)) res := suite.client.RequireResourceExists(suite.T(), resourceID(pbmesh.ProxyStateTemplateType, api.workloadID.Name, tenancy)) - require.NoError(suite.T(), err) require.NotNil(suite.T(), res.Data) prototest.AssertDeepEqual(suite.T(), api.workloadID, res.Owner) }) @@ -552,18 +427,14 @@ func (suite *controllerTestSuite) TestReconcile_ExistingProxyStateTemplate_WithU WithData(suite.T(), api.workload). Write(suite.T(), suite.client.ResourceServiceClient).Id - err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{ - ID: resourceID(pbmesh.ProxyStateTemplateType, updatedWorkloadID.Name, tenancy), - }) - require.NoError(suite.T(), err) + suite.reconcileOnce(resourceID(pbmesh.ProxyStateTemplateType, updatedWorkloadID.Name, tenancy)) res := suite.client.RequireResourceExists(suite.T(), resourceID(pbmesh.ProxyStateTemplateType, updatedWorkloadID.Name, tenancy)) - require.NoError(suite.T(), err) require.NotNil(suite.T(), res.Data) prototest.AssertDeepEqual(suite.T(), updatedWorkloadID, res.Owner) var updatedProxyStateTemplate pbmesh.ProxyStateTemplate - err = res.Data.UnmarshalTo(&updatedProxyStateTemplate) + err := res.Data.UnmarshalTo(&updatedProxyStateTemplate) require.NoError(suite.T(), err) // Check that our value is updated in the proxy state template. @@ -594,10 +465,7 @@ func (suite *controllerTestSuite) TestReconcile_ExistingProxyStateTemplate_NoUpd WithMeta("some", "meta"). Write(suite.T(), suite.client.ResourceServiceClient).Id - err := suite.ctl.Reconcile(context.Background(), suite.runtime, controller.Request{ - ID: resourceID(pbmesh.ProxyStateTemplateType, updatedWorkloadID.Name, tenancy), - }) - require.NoError(suite.T(), err) + suite.reconcileOnce(resourceID(pbmesh.ProxyStateTemplateType, updatedWorkloadID.Name, tenancy)) updatedProxyState := suite.client.RequireResourceExists(suite.T(), resourceID(pbmesh.ProxyStateTemplateType, api.workloadID.Name, tenancy)) resourcetest.RequireVersionUnchanged(suite.T(), updatedProxyState, originalProxyState.Version) @@ -605,13 +473,11 @@ func (suite *controllerTestSuite) TestReconcile_ExistingProxyStateTemplate_NoUpd } func (suite *controllerTestSuite) TestController() { - mgr := controller.NewManager(suite.client, suite.runtime.Logger) - - // Initialize controller dependencies. - c := cache.New() trustDomainFetcher := func() (string, error) { return "test.consul", nil } - mgr.Register(Controller(c, trustDomainFetcher, "dc1", false)) + // Run the controller manager + mgr := controller.NewManager(suite.client, suite.rt.Logger) + mgr.Register(Controller(trustDomainFetcher, "dc1", false)) mgr.SetRaftLeader(true) go mgr.Run(suite.ctx) @@ -677,7 +543,7 @@ func (suite *controllerTestSuite) TestController() { testutil.RunStep(suite.T(), "add explicit destinations and check that new proxy state is generated", func(t *testing.T) { webProxyStateTemplate = suite.client.WaitForNewVersion(suite.T(), webProxyStateTemplateID, webProxyStateTemplate.Version) - suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(rt resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { + suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(t resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { for _, data := range suite.api { requireExplicitDestinationsFound(t, data.destinationListenerName, data.destinationClusterName, tmpl) } @@ -690,46 +556,25 @@ func (suite *controllerTestSuite) TestController() { // * api's proxy state template is deleted // * we get a new web proxy resource re-generated // * the status on Upstreams resource is updated with a validation error - nonMeshPorts := map[string]*pbcatalog.WorkloadPort{ - "tcp": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - } // Note: the order matters here because in reality service endpoints will only // be reconciled after the workload has been updated, and so we need to write the // workload and service before we write service endpoints. - resourcetest.Resource(pbcatalog.WorkloadType, "api-abc"). - WithTenancy(tenancy). + resourcetest.ResourceID(api.workloadID). WithData(suite.T(), &pbcatalog.Workload{ Identity: "api-identity", Addresses: api.workload.Addresses, - Ports: nonMeshPorts}). - Write(suite.T(), suite.client) - - api.service = resourcetest.ResourceID(api.service.Id). - WithTenancy(tenancy). - WithData(t, &pbcatalog.Service{ - Workloads: &pbcatalog.WorkloadSelector{Names: []string{"api-abc"}}, - VirtualIps: []string{"1.1.1.1"}, - Ports: []*pbcatalog.ServicePort{ - {TargetPort: "tcp", Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - // {TargetPort: "mesh", Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + Ports: map[string]*pbcatalog.WorkloadPort{ + "tcp": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, }, }). Write(suite.T(), suite.client) - resourcetest.Resource(pbcatalog.ServiceEndpointsType, "api-service"). - WithTenancy(tenancy). - WithData(suite.T(), &pbcatalog.ServiceEndpoints{ - Endpoints: []*pbcatalog.Endpoint{ - { - TargetRef: api.workloadID, - Addresses: api.workload.Addresses, - Ports: nonMeshPorts, - Identity: "api-identity", - }, - }, - }). - Write(suite.T(), suite.client.ResourceServiceClient) + api.service, _, _ = suite.createService( + api.service.Id.Name, api.service.Id.Tenancy, "api-abc", []*pbcatalog.ServicePort{ + {TargetPort: "tcp", Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + // {TargetPort: "mesh", Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, []string{"1.1.1.1"}, []string{"api-identity"}, false) // Refresh the computed routes in light of api losing a mesh port. routestest.ReconcileComputedRoutes(suite.T(), suite.client, apiComputedRoutesID, @@ -744,7 +589,7 @@ func (suite *controllerTestSuite) TestController() { // We should get a new web proxy template resource because this destination should be removed. webProxyStateTemplate = suite.client.WaitForNewVersion(suite.T(), webProxyStateTemplateID, webProxyStateTemplate.Version) - suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(rt resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { + suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(t resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { requireExplicitDestinationsNotFound(t, api.destinationListenerName, api.destinationClusterName, tmpl) }) }) @@ -752,22 +597,17 @@ func (suite *controllerTestSuite) TestController() { testutil.RunStep(suite.T(), "update ports to be mesh again", func(t *testing.T) { // Update destination's service endpoints back to mesh and check that we get a new web proxy resource re-generated // and that the status on Upstreams resource is updated to be empty. - suite.runtime.Logger.Trace("updating ports to mesh") + suite.rt.Logger.Trace("updating ports to mesh") - resourcetest.Resource(pbcatalog.WorkloadType, "api-abc"). - WithTenancy(tenancy). + resourcetest.ResourceID(api.workloadID). WithData(suite.T(), api.workload). Write(suite.T(), suite.client) - api.service = resourcetest.Resource(pbcatalog.ServiceType, "api-service"). - WithData(suite.T(), api.serviceData). - WithTenancy(tenancy). - Write(suite.T(), suite.client.ResourceServiceClient) - - resourcetest.Resource(pbcatalog.ServiceEndpointsType, "api-service"). - WithTenancy(tenancy). - WithData(suite.T(), api.endpointsData). - Write(suite.T(), suite.client.ResourceServiceClient) + api.service, api.serviceData, _ = suite.createService( + api.service.Id.Name, api.service.Id.Tenancy, "api-abc", []*pbcatalog.ServicePort{ + {TargetPort: "tcp", Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + {TargetPort: "mesh", Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, []string{"1.1.1.1"}, []string{"api-identity"}, false) // Refresh the computed routes in light of api losing a mesh port. routestest.ReconcileComputedRoutes(suite.T(), suite.client, apiComputedRoutesID, @@ -777,7 +617,7 @@ func (suite *controllerTestSuite) TestController() { // We should also get a new web proxy template resource as this destination should be added again. webProxyStateTemplate = suite.client.WaitForNewVersion(suite.T(), webProxyStateTemplateID, webProxyStateTemplate.Version) - suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(rt resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { + suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(t resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { for _, data := range suite.api { requireExplicitDestinationsFound(t, data.destinationListenerName, data.destinationClusterName, tmpl) } @@ -786,22 +626,24 @@ func (suite *controllerTestSuite) TestController() { testutil.RunStep(suite.T(), "delete the proxy state template and check re-generation", func(t *testing.T) { // Delete the proxy state template resource and check that it gets regenerated. - suite.runtime.Logger.Trace("deleting web proxy") + suite.rt.Logger.Trace("deleting web proxy") _, err := suite.client.Delete(suite.ctx, &pbresource.DeleteRequest{Id: webProxyStateTemplateID}) require.NoError(suite.T(), err) webProxyStateTemplate = suite.client.WaitForNewVersion(suite.T(), webProxyStateTemplateID, webProxyStateTemplate.Version) - suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(rt resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { + suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(t resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { for _, data := range suite.api { requireExplicitDestinationsFound(t, data.destinationListenerName, data.destinationClusterName, tmpl) } }) }) + webWrk := resourcetest.MustDecode[*pbcatalog.Workload](suite.T(), suite.webWorkload) + testutil.RunStep(suite.T(), "add implicit upstream and enable tproxy", func(t *testing.T) { // Delete explicit destinations resource. - suite.runtime.Logger.Trace("deleting web destinations") + suite.rt.Logger.Trace("deleting web destinations") _, err := suite.client.Delete(suite.ctx, &pbresource.DeleteRequest{Id: webComputedDestinations.Id}) require.NoError(t, err) @@ -825,10 +667,32 @@ func (suite *controllerTestSuite) TestController() { }, }).Write(suite.T(), suite.client) + // Write a CID to allow it. + cidID := &pbresource.ID{ + Type: pbmesh.ComputedImplicitDestinationsType, + Tenancy: webWrk.Id.Tenancy, + Name: webWrk.Data.Identity, + } + // Write a CID that grants web-identity access to db-identity and api-identity + resourcetest.ResourceID(cidID). + WithData(suite.T(), &pbmesh.ComputedImplicitDestinations{ + Destinations: []*pbmesh.ImplicitDestination{ + { + DestinationRef: resource.Reference(api.service.Id, ""), + DestinationPorts: []string{"tcp"}, + }, + { + DestinationRef: resource.Reference(suite.dbService.Id, ""), + DestinationPorts: []string{"http"}, + }, + }, + }). + Write(suite.T(), suite.client) + webProxyStateTemplate = suite.client.WaitForNewVersion(suite.T(), webProxyStateTemplateID, webProxyStateTemplate.Version) apiProxyStateTemplate = suite.client.WaitForNewVersion(suite.T(), apiProxyStateTemplateID, apiProxyStateTemplate.Version) - suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(rt resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { + suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(t resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { listenerNameDb := fmt.Sprintf("%s/local/%s/db-service", tenancy.Partition, tenancy.Namespace) clusterNameDb := fmt.Sprintf("db-service.%s.%s", tenancy.Namespace, tenancy.Partition) if tenancy.Partition == "default" { @@ -844,14 +708,14 @@ func (suite *controllerTestSuite) TestController() { assertTrafficPermissionDefaultPolicy(t, false, apiProxyStateTemplate) assertTrafficPermissionDefaultPolicy(t, false, webProxyStateTemplate) - suite.runtime.Logger.Trace("deleting computed traffic permissions") + suite.rt.Logger.Trace("deleting computed traffic permissions") _, err := suite.client.Delete(suite.ctx, &pbresource.DeleteRequest{Id: api.computedTrafficPermissions.Id}) require.NoError(t, err) suite.client.WaitForDeletion(t, api.computedTrafficPermissions.Id) apiProxyStateTemplate = suite.client.WaitForNewVersion(suite.T(), apiProxyStateTemplateID, apiProxyStateTemplate.Version) - suite.runtime.Logger.Trace("creating computed traffic permissions") + suite.rt.Logger.Trace("creating computed traffic permissions") resourcetest.Resource(pbauth.ComputedTrafficPermissionsType, api.workload.Identity). WithTenancy(tenancy). WithData(t, api.computedTrafficPermissionsData). @@ -908,7 +772,7 @@ func (suite *controllerTestSuite) TestController() { webProxyStateTemplate = suite.client.WaitForNewVersion(suite.T(), webProxyStateTemplateID, webProxyStateTemplate.Version) - suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(rt resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { + suite.waitForProxyStateTemplateState(t, webProxyStateTemplateID, func(t resourcetest.T, tmpl *pbmesh.ProxyStateTemplate) { listenerNameDb := fmt.Sprintf("%s/local/%s/db-service", tenancy.Partition, tenancy.Namespace) clusterNameDb := fmt.Sprintf("db-service.%s.%s", tenancy.Namespace, tenancy.Partition) if tenancy.Partition == "default" { @@ -923,14 +787,11 @@ func (suite *controllerTestSuite) TestController() { func (suite *controllerTestSuite) TestControllerDefaultAllow() { suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - // Run the controller manager - mgr := controller.NewManager(suite.client, suite.runtime.Logger) - - // Initialize controller dependencies. - c := cache.New() trustDomainFetcher := func() (string, error) { return "test.consul", nil } - mgr.Register(Controller(c, trustDomainFetcher, "dc1", true)) + // Run the controller manager + mgr := controller.NewManager(suite.client, suite.rt.Logger) + mgr.Register(Controller(trustDomainFetcher, "dc1", true)) mgr.SetRaftLeader(true) go mgr.Run(suite.ctx) @@ -955,11 +816,13 @@ func TestMeshController(t *testing.T) { suite.Run(t, new(controllerTestSuite)) } -func requireExplicitDestinationsFound(t *testing.T, listenerName, clusterName string, tmpl *pbmesh.ProxyStateTemplate) { +func requireExplicitDestinationsFound(t resourcetest.T, listenerName, clusterName string, tmpl *pbmesh.ProxyStateTemplate) { + t.Helper() requireExplicitDestinations(t, listenerName, clusterName, tmpl, true) } -func requireExplicitDestinationsNotFound(t *testing.T, listenerName, clusterName string, tmpl *pbmesh.ProxyStateTemplate) { +func requireExplicitDestinationsNotFound(t resourcetest.T, listenerName, clusterName string, tmpl *pbmesh.ProxyStateTemplate) { + t.Helper() requireExplicitDestinations(t, listenerName, clusterName, tmpl, false) } @@ -967,15 +830,20 @@ func requireExplicitDestinations(t resourcetest.T, listenerName string, clusterN t.Helper() // Check outbound listener. - var foundListener bool + var ( + foundListener bool + allListenerNames []string + ) for _, l := range tmpl.ProxyState.Listeners { + allListenerNames = append(allListenerNames, l.Name) if l.Name == listenerName && l.Direction == pbproxystate.Direction_DIRECTION_OUTBOUND { foundListener = true - break } } - require.Equal(t, found, foundListener) + require.Equal(t, found, foundListener, + "listener: needle=%q shouldFind=%v haystack=%v", + listenerName, found, allListenerNames) requireClustersAndEndpoints(t, clusterName, tmpl, found) } @@ -1026,34 +894,42 @@ func requireImplicitDestinationsFound(t resourcetest.T, listenerName string, clu func requireClustersAndEndpoints(t resourcetest.T, clusterName string, tmpl *pbmesh.ProxyStateTemplate, found bool) { t.Helper() - var foundCluster bool + var ( + foundCluster bool + allClusterNames []string + ) for c := range tmpl.ProxyState.Clusters { + allClusterNames = append(allClusterNames, c) if strings.Contains(c, clusterName) { foundCluster = true - break } } - require.Equal(t, found, foundCluster) + require.Equal(t, found, foundCluster, + "cluster: needle=%q shouldFind=%v haystack=%v", + clusterName, found, allClusterNames) - var foundEndpoints bool + var ( + foundEndpoints bool + allEndpointsNames []string + ) for c := range tmpl.RequiredEndpoints { + allEndpointsNames = append(allEndpointsNames, c) if strings.Contains(c, clusterName) { foundEndpoints = true break } } - require.Equal(t, found, foundEndpoints) + require.Equal(t, found, foundEndpoints, + "endpoints: needle=%q shouldFind=%v haystack=%v", + clusterName, found, allEndpointsNames) } func (suite *controllerTestSuite) waitForProxyStateTemplateState(t *testing.T, id *pbresource.ID, verify func(resourcetest.T, *pbmesh.ProxyStateTemplate)) { - suite.client.WaitForResourceState(t, id, func(rt resourcetest.T, res *pbresource.Resource) { - var tmpl pbmesh.ProxyStateTemplate - err := res.Data.UnmarshalTo(&tmpl) - require.NoError(rt, err) - - verify(rt, &tmpl) + suite.client.WaitForResourceState(t, id, func(t resourcetest.T, res *pbresource.Resource) { + dec := resourcetest.MustDecode[*pbmesh.ProxyStateTemplate](t, res) + verify(t, dec.Data) }) } @@ -1085,17 +961,14 @@ func (suite *controllerTestSuite) appendTenancyInfo(tenancy *pbresource.Tenancy) } func (suite *controllerTestSuite) cleanupResources() { - for _, api := range suite.api { suite.client.MustDelete(suite.T(), api.workloadID) suite.client.MustDelete(suite.T(), api.computedTrafficPermissions.Id) suite.client.MustDelete(suite.T(), api.service.Id) - suite.client.MustDelete(suite.T(), api.endpoints.Id) } suite.client.MustDelete(suite.T(), suite.webWorkload.Id) suite.client.MustDelete(suite.T(), suite.dbWorkloadID) suite.client.MustDelete(suite.T(), suite.dbService.Id) - suite.client.MustDelete(suite.T(), suite.dbEndpoints.Id) } func (suite *controllerTestSuite) runTestCaseWithTenancies(t func(*pbresource.Tenancy)) { @@ -1109,3 +982,23 @@ func (suite *controllerTestSuite) runTestCaseWithTenancies(t func(*pbresource.Te }) } } + +func (suite *controllerTestSuite) reconcileOnce(id *pbresource.ID) { + err := suite.ctl.Reconcile(suite.ctx, controller.Request{ID: id}) + require.NoError(suite.T(), err) + suite.T().Cleanup(func() { + suite.client.CleanupDelete(suite.T(), id) + }) +} + +func (suite *controllerTestSuite) createService( + name string, + tenancy *pbresource.Tenancy, + exactSelector string, + ports []*pbcatalog.ServicePort, + vips []string, + workloadIdentities []string, + deferStatusUpdate bool, +) (*pbresource.Resource, *pbcatalog.Service, func() *pbresource.Resource) { + return createService(suite.T(), suite.client, name, tenancy, exactSelector, ports, vips, workloadIdentities, deferStatusUpdate) +} diff --git a/internal/mesh/internal/controllers/sidecarproxy/data_fetcher.go b/internal/mesh/internal/controllers/sidecarproxy/data_fetcher.go new file mode 100644 index 0000000000..adb80de945 --- /dev/null +++ b/internal/mesh/internal/controllers/sidecarproxy/data_fetcher.go @@ -0,0 +1,333 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package sidecarproxy + +import ( + "context" + "strings" + + "google.golang.org/protobuf/proto" + + "github.com/hashicorp/consul/internal/catalog" + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/controller/cache" + "github.com/hashicorp/consul/internal/mesh/internal/controllers/meshgateways" + "github.com/hashicorp/consul/internal/mesh/internal/types" + intermediateTypes "github.com/hashicorp/consul/internal/mesh/internal/types/intermediate" + "github.com/hashicorp/consul/internal/resource" + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" + pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" + "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1/pbproxystate" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +func FetchUnifiedDestinationsData( + ctx context.Context, + rt controller.Runtime, + workload *types.DecodedWorkload, + mgwMode pbmesh.MeshGatewayMode, + transparentProxyEnabled bool, +) ([]*intermediateTypes.Destination, error) { + // Get all destinationsData. + destinationsData, err := fetchComputedExplicitDestinationsData(rt, workload, mgwMode) + if err != nil { + return nil, err + } + + if transparentProxyEnabled { + rt.Logger.Trace("transparent proxy is enabled; fetching implicit destinations") + destinationsData, err = fetchComputedImplicitDestinationsData(rt, workload, mgwMode, destinationsData) + if err != nil { + return nil, err + } + } + return destinationsData, nil +} + +func fetchComputedExplicitDestinationsData( + rt controller.Runtime, + workload *types.DecodedWorkload, + mgwMode pbmesh.MeshGatewayMode, +) ([]*intermediateTypes.Destination, error) { + cedID := resource.ReplaceType(pbmesh.ComputedExplicitDestinationsType, workload.Id) + + var destinations []*intermediateTypes.Destination + + // Fetch computed explicit destinations first. + cd, err := cache.GetDecoded[*pbmesh.ComputedExplicitDestinations](rt.Cache, pbmesh.ComputedExplicitDestinationsType, "id", cedID) + if err != nil { + return nil, err + } else if cd == nil { + return nil, nil + } + + for _, dest := range cd.GetData().GetDestinations() { + serviceID := resource.IDFromReference(dest.DestinationRef) + + outDests, err := fetchSingleDestinationData(rt, workload.Id, mgwMode, serviceID, nil, dest) + if err != nil { + return nil, err + } else if len(outDests) == 0 { + continue // skip + } + + // For explicit dests, we are guaranteed only one result. + destinations = append(destinations, outDests[0]) + } + + return destinations, nil +} + +type PortReferenceKey struct { + resource.ReferenceKey + Port string +} + +// fetchImplicitDestinationsData fetches all implicit destinations and adds them to existing destinations. +// If the implicit destination is already in addToDestinations, it will be skipped. +// +// Rename to include computed term +func fetchComputedImplicitDestinationsData( + rt controller.Runtime, + workload *types.DecodedWorkload, + mgwMode pbmesh.MeshGatewayMode, + addToDestinations []*intermediateTypes.Destination, +) ([]*intermediateTypes.Destination, error) { + cidID := &pbresource.ID{ + Type: pbmesh.ComputedImplicitDestinationsType, + Name: workload.Data.Identity, + Tenancy: workload.Id.Tenancy, + } + + // First, convert existing destinations to a map so we can de-dup. + // + // This is keyed by the serviceID+port of the upstream, which is effectively + // the same as the id of the computed routes for the service. + destsSeen := make(map[PortReferenceKey]struct{}) + for _, d := range addToDestinations { + prk := PortReferenceKey{ + ReferenceKey: resource.NewReferenceKey(d.Service.Resource.Id), + Port: d.ComputedPortRoutes.ParentRef.Port, + } + destsSeen[prk] = struct{}{} + } + + cid, err := cache.GetDecoded[*pbmesh.ComputedImplicitDestinations]( + rt.Cache, + pbmesh.ComputedImplicitDestinationsType, + "id", + cidID, + ) + if err != nil { + return nil, err + } else if cid == nil { + return nil, nil + } + + for _, dest := range cid.Data.GetDestinations() { + serviceID := resource.IDFromReference(dest.DestinationRef) + + outDests, err := fetchSingleDestinationData(rt, workload.Id, mgwMode, serviceID, dest.DestinationPorts, nil) + if err != nil { + return nil, err + } else if len(outDests) == 0 { + continue // skip + } + + for _, od := range outDests { + // If it's already in destinations, ignore it. + portName := od.ComputedPortRoutes.ParentRef.Port + prk := PortReferenceKey{ + ReferenceKey: resource.NewReferenceKey(od.Service.Id), + Port: portName, + } + if _, ok := destsSeen[prk]; ok { + continue + } + addToDestinations = append(addToDestinations, od) + } + } + return addToDestinations, err +} + +func fetchSingleDestinationData( + rt controller.Runtime, + workloadID *pbresource.ID, + mgwMode pbmesh.MeshGatewayMode, + serviceID *pbresource.ID, + destPorts []string, + explicitDest *pbmesh.Destination, +) ([]*intermediateTypes.Destination, error) { + assertResourceType(pbcatalog.ServiceType, serviceID.Type) + + if explicitDest != nil { + // Force this input regardless of what was asked. + destPorts = []string{explicitDest.DestinationPort} + } + + proxyTenancy := workloadID.GetTenancy() + + // Fetch Service + svc, err := cache.GetDecoded[*pbcatalog.Service](rt.Cache, pbcatalog.ServiceType, "id", serviceID) + if err != nil { + return nil, err + } else if svc == nil { + // If the Service resource is not found, skip this destination. + return nil, nil + } + + // Check if this service is mesh-enabled. If not, update the status. + if !svc.GetData().IsMeshEnabled() { + // This error should not cause the execution to stop, as we want to make sure that this non-mesh destination + // service gets removed from the proxy state. + return nil, nil + } + + // If this proxy is a part of this service, ignore it. + if explicitDest == nil && isPartOfService(workloadID, svc) { + return nil, nil + } + + ports := make(map[string]struct{}) + for _, p := range destPorts { + ports[p] = struct{}{} + } + + // Remove any desired ports that do not exist on the service. + for port := range ports { + if svc.GetData().FindPortByID(port) == nil { + delete(ports, port) + continue + } + + // No destination port should point to a port with "mesh" protocol, + // so check if destination port has the mesh protocol and skip it if it does. + if svc.GetData().FindPortByID(port).GetProtocol() == pbcatalog.Protocol_PROTOCOL_MESH { + delete(ports, port) + continue + } + } + if len(ports) == 0 { + return nil, nil + } + + // Fetch ComputedRoutes. + crID := resource.ReplaceType(pbmesh.ComputedRoutesType, serviceID) + cr, err := cache.GetDecoded[*pbmesh.ComputedRoutes](rt.Cache, pbmesh.ComputedRoutesType, "id", crID) + if err != nil { + return nil, err + } else if cr == nil { + // This is required, so wait until it exists. + return nil, nil + } + + var dests []*intermediateTypes.Destination + for port := range ports { + portConfig, ok := cr.Data.PortedConfigs[port] + if !ok { + // This is required, so wait until it exists. + delete(ports, port) + continue + } + + d := &intermediateTypes.Destination{ + Service: svc, + // Copy this so we can mutate the targets. + ComputedPortRoutes: proto.Clone(portConfig).(*pbmesh.ComputedPortRoutes), + } + + if explicitDest != nil { + // As Destinations resource contains a list of destinations, + // we need to find the one that references our service and port. + d.Explicit = explicitDest + } else { + // todo (ishustava): this should eventually grab virtual IPs resource. + d.VirtualIPs = svc.Data.VirtualIps + } + + // NOTE: we collect both DIRECT and INDIRECT target information here. + for _, routeTarget := range d.ComputedPortRoutes.Targets { + targetServiceID := resource.IDFromReference(routeTarget.BackendRef.Ref) + + // Fetch Service + targetSvc, err := rt.Cache.Get(pbcatalog.ServiceType, "id", targetServiceID) + if err != nil { + return nil, err + } else if targetSvc == nil { + continue + } + + // Gather all identities. + ids := catalog.GetBoundIdentities(targetSvc) + routeTarget.IdentityRefs = make([]*pbresource.Reference, len(ids)) + for i, id := range ids { + routeTarget.IdentityRefs[i] = &pbresource.Reference{ + Name: id, + Tenancy: svc.Id.Tenancy, + } + } + + routeTarget.ServiceEndpointsRef = &pbproxystate.EndpointRef{ + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, targetServiceID), + MeshPort: routeTarget.MeshPort, + RoutePort: routeTarget.BackendRef.Port, + } + + // If the target service is in a different partition and the mesh gateway mode is + // "local" or "remote", use the ServiceEndpoints for the corresponding MeshGateway + // instead of the ServiceEndpoints for the target service. The IdentityRefs on the + // target will remain the same for TCP targets. + // + // TODO(nathancoleman) Consider cross-datacenter case as well + if routeTarget.BackendRef.Ref.Tenancy.Partition != proxyTenancy.Partition { + switch mgwMode { + case pbmesh.MeshGatewayMode_MESH_GATEWAY_MODE_LOCAL: + // Use ServiceEndpoints for the MeshGateway in the source service's partition + routeTarget.ServiceEndpointsRef = &pbproxystate.EndpointRef{ + Id: &pbresource.ID{ + Type: pbcatalog.ServiceEndpointsType, + Name: meshgateways.GatewayName, + Tenancy: proxyTenancy, + }, + MeshPort: meshgateways.LANPortName, + RoutePort: meshgateways.LANPortName, + } + case pbmesh.MeshGatewayMode_MESH_GATEWAY_MODE_REMOTE: + // Use ServiceEndpoints for the MeshGateway in the target service's partition + routeTarget.ServiceEndpointsRef = &pbproxystate.EndpointRef{ + Id: &pbresource.ID{ + Type: pbcatalog.ServiceEndpointsType, + Name: meshgateways.GatewayName, + Tenancy: targetServiceID.Tenancy, + }, + MeshPort: meshgateways.WANPortName, + RoutePort: meshgateways.WANPortName, + } + } + } + } + + dests = append(dests, d) + } + + return dests, nil +} + +func isPartOfService(workloadID *pbresource.ID, svc *types.DecodedService) bool { + if !resource.EqualTenancy(workloadID.GetTenancy(), svc.Resource.Id.GetTenancy()) { + return false + } + sel := svc.Data.Workloads + for _, exact := range sel.GetNames() { + if workloadID.GetName() == exact { + return true + } + } + for _, prefix := range sel.GetPrefixes() { + if strings.HasPrefix(workloadID.GetName(), prefix) { + return true + } + } + return false +} diff --git a/internal/mesh/internal/controllers/sidecarproxy/fetcher/data_fetcher_test.go b/internal/mesh/internal/controllers/sidecarproxy/data_fetcher_test.go similarity index 55% rename from internal/mesh/internal/controllers/sidecarproxy/fetcher/data_fetcher_test.go rename to internal/mesh/internal/controllers/sidecarproxy/data_fetcher_test.go index edf0057ba0..f664cefc52 100644 --- a/internal/mesh/internal/controllers/sidecarproxy/fetcher/data_fetcher_test.go +++ b/internal/mesh/internal/controllers/sidecarproxy/data_fetcher_test.go @@ -1,26 +1,26 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: BUSL-1.1 -package fetcher +package sidecarproxy import ( "context" "fmt" + "slices" "testing" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing" + "github.com/hashicorp/consul/internal/auth" "github.com/hashicorp/consul/internal/catalog" "github.com/hashicorp/consul/internal/controller" "github.com/hashicorp/consul/internal/mesh/internal/controllers/routes/routestest" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/cache" "github.com/hashicorp/consul/internal/mesh/internal/types" "github.com/hashicorp/consul/internal/mesh/internal/types/intermediate" "github.com/hashicorp/consul/internal/resource" "github.com/hashicorp/consul/internal/resource/resourcetest" - pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1/pbproxystate" @@ -32,104 +32,52 @@ import ( type dataFetcherSuite struct { suite.Suite - ctx context.Context - client pbresource.ResourceServiceClient - resourceClient *resourcetest.Client - rt controller.Runtime + ctx context.Context + client *resourcetest.Client + rt controller.Runtime + + ctl *controller.TestController + tenancies []*pbresource.Tenancy api1Service *pbresource.Resource api1ServiceData *pbcatalog.Service api2Service *pbresource.Resource api2ServiceData *pbcatalog.Service - api1ServiceEndpoints *pbresource.Resource - api1ServiceEndpointsData *pbcatalog.ServiceEndpoints - api2ServiceEndpoints *pbresource.Resource - api2ServiceEndpointsData *pbcatalog.ServiceEndpoints - proxyCfg *pbmesh.ComputedProxyConfiguration webComputedDestinationsData *pbmesh.ComputedExplicitDestinations webProxy *pbresource.Resource webWorkload *pbresource.Resource - tenancies []*pbresource.Tenancy } func (suite *dataFetcherSuite) SetupTest() { - suite.ctx = testutil.TestContext(suite.T()) + trustDomainFetcher := func() (string, error) { return "test.consul", nil } + suite.tenancies = resourcetest.TestTenancies() - suite.client = svctest.NewResourceServiceBuilder(). - WithRegisterFns(types.Register, catalog.RegisterTypes). + + suite.ctx = testutil.TestContext(suite.T()) + client := svctest.NewResourceServiceBuilder(). + WithRegisterFns(types.Register, catalog.RegisterTypes, auth.RegisterTypes). WithTenancies(suite.tenancies...). Run(suite.T()) - suite.resourceClient = resourcetest.NewClient(suite.client) - suite.rt = controller.Runtime{ - Client: suite.client, - Logger: testutil.Logger(suite.T()), - } + + suite.ctl = controller.NewTestController(Controller(trustDomainFetcher, "dc1", false), client). + WithLogger(testutil.Logger(suite.T())) + suite.rt = suite.ctl.Runtime() + suite.client = resourcetest.NewClient(suite.rt.Client) } func (suite *dataFetcherSuite) setupWithTenancy(tenancy *pbresource.Tenancy) { - suite.api1ServiceData = &pbcatalog.Service{ - Ports: []*pbcatalog.ServicePort{ + suite.api1Service, suite.api1ServiceData, _ = suite.createService( + "api-1", tenancy, "api1", []*pbcatalog.ServicePort{ {TargetPort: "tcp", VirtualPort: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, {TargetPort: "mesh", VirtualPort: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, - }, - } - suite.api1Service = resourcetest.Resource(pbcatalog.ServiceType, "api-1"). - WithTenancy(tenancy). - WithData(suite.T(), suite.api1ServiceData). - Write(suite.T(), suite.client) + }, nil, []string{"api-1-identity"}, false) - suite.api1ServiceEndpointsData = &pbcatalog.ServiceEndpoints{ - Endpoints: []*pbcatalog.Endpoint{ - { - Addresses: []*pbcatalog.WorkloadAddress{{Host: "10.0.0.1"}}, - Ports: map[string]*pbcatalog.WorkloadPort{ - "tcp": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, - }, - Identity: "api-1-identity", - }, - }, - } - suite.api1ServiceEndpoints = resourcetest.Resource(pbcatalog.ServiceEndpointsType, "api-1"). - WithTenancy(tenancy). - WithData(suite.T(), suite.api1ServiceEndpointsData). - Write(suite.T(), suite.client) - - suite.api2ServiceData = &pbcatalog.Service{ - Ports: []*pbcatalog.ServicePort{ + suite.api2Service, suite.api2ServiceData, _ = suite.createService( + "api-2", tenancy, "api2", []*pbcatalog.ServicePort{ {TargetPort: "tcp1", VirtualPort: 9080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, {TargetPort: "tcp2", VirtualPort: 9081, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, {TargetPort: "mesh", VirtualPort: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, - }, - } - suite.api2Service = resourcetest.Resource(pbcatalog.ServiceType, "api-2"). - WithTenancy(tenancy). - WithData(suite.T(), suite.api2ServiceData). - Write(suite.T(), suite.client) - - suite.api2ServiceEndpointsData = &pbcatalog.ServiceEndpoints{ - Endpoints: []*pbcatalog.Endpoint{ - { - Addresses: []*pbcatalog.WorkloadAddress{{Host: "10.0.0.2"}}, - Ports: map[string]*pbcatalog.WorkloadPort{ - "tcp1": {Port: 9080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - "tcp2": {Port: 9081, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - "mesh": {Port: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, - }, - Identity: "api-2-identity", - }, - }, - } - suite.api2ServiceEndpoints = resourcetest.Resource(pbcatalog.ServiceEndpointsType, "api-2"). - WithTenancy(tenancy). - WithData(suite.T(), suite.api2ServiceEndpointsData). - Write(suite.T(), suite.client) - - suite.proxyCfg = &pbmesh.ComputedProxyConfiguration{ - DynamicConfig: &pbmesh.DynamicConfig{ - MeshGatewayMode: pbmesh.MeshGatewayMode_MESH_GATEWAY_MODE_NONE, - }, - } + }, nil, []string{"api-2-identity"}, false) suite.webComputedDestinationsData = &pbmesh.ComputedExplicitDestinations{ Destinations: []*pbmesh.Destination{ @@ -158,112 +106,25 @@ func (suite *dataFetcherSuite) setupWithTenancy(tenancy *pbresource.Tenancy) { WithData(suite.T(), &pbcatalog.Workload{ Addresses: []*pbcatalog.WorkloadAddress{{Host: "10.0.0.2"}}, Ports: map[string]*pbcatalog.WorkloadPort{"tcp": {Port: 8081, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}}, + Identity: "web-id-abc", }). Write(suite.T(), suite.client) } -func (suite *dataFetcherSuite) TestFetcher_FetchWorkload_WorkloadNotFound() { - suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - identityID := resourcetest.Resource(pbauth.WorkloadIdentityType, "workload-identity-abc"). - WithTenancy(tenancy).ID() - - // Create cache and pre-populate it. - c := cache.New() - - f := Fetcher{ - cache: c, - client: suite.client, - } - - workloadID := resourcetest.Resource(pbcatalog.WorkloadType, "not-found").WithTenancy(tenancy).ID() - - // Track workload with its identity. - workload := resourcetest.Resource(pbcatalog.WorkloadType, workloadID.GetName()). - WithTenancy(tenancy). - WithData(suite.T(), &pbcatalog.Workload{ - Identity: identityID.Name, - }).Build() - - c.TrackWorkload(resourcetest.MustDecode[*pbcatalog.Workload](suite.T(), workload)) - - // Now fetch the workload so that we can check that it's been removed from cache. - _, err := f.FetchWorkload(context.Background(), workloadID) - require.NoError(suite.T(), err) - require.Nil(suite.T(), c.WorkloadsByWorkloadIdentity(identityID)) - }) -} - -func (suite *dataFetcherSuite) TestFetcher_FetchWorkload_WorkloadFound() { - suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - identityID := resourcetest.Resource(pbauth.WorkloadIdentityType, "workload-identity-abc"). - WithTenancy(tenancy).ID() - - // Create cache and pre-populate it. - c := cache.New() - - f := Fetcher{ - cache: c, - client: suite.client, - } - - workload := resourcetest.Resource(pbcatalog.WorkloadType, "service-workload-abc"). - WithTenancy(tenancy). - WithData(suite.T(), &pbcatalog.Workload{ - Identity: identityID.Name, - Ports: map[string]*pbcatalog.WorkloadPort{ - "foo": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_HTTP}, - }, - Addresses: []*pbcatalog.WorkloadAddress{ - { - Host: "10.0.0.1", - Ports: []string{"foo"}, - }, - }, - }).Write(suite.T(), suite.client) - - // This call should track the workload's identity - _, err := f.FetchWorkload(context.Background(), workload.Id) - require.NoError(suite.T(), err) - - // Check that the workload is tracked - workload.Id.Uid = "" - prototest.AssertElementsMatch(suite.T(), []*pbresource.ID{workload.Id}, c.WorkloadsByWorkloadIdentity(identityID)) - }) -} - func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { + const mgwMode = pbmesh.MeshGatewayMode_MESH_GATEWAY_MODE_NONE + suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - c := cache.New() api1ServiceRef := resource.Reference(suite.api1Service.Id, "") - f := Fetcher{ - cache: c, - client: suite.client, - } + webWrk := resourcetest.MustDecode[*pbcatalog.Workload](suite.T(), suite.webWorkload) testutil.RunStep(suite.T(), "computed destinations not found", func(t *testing.T) { - // First add computed destination to cache so we can check if it's untracked later. - compDest := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, suite.webProxy.Id.Name). - WithData(t, &pbmesh.ComputedExplicitDestinations{ - Destinations: []*pbmesh.Destination{ - { - DestinationRef: api1ServiceRef, - DestinationPort: "tcp1", - }, - }, - }). - WithTenancy(tenancy). - Build() - c.TrackComputedDestinations(resourcetest.MustDecode[*pbmesh.ComputedExplicitDestinations](t, compDest)) - // We will try to fetch explicit destinations for a proxy that doesn't have one. - destinations, err := f.FetchComputedExplicitDestinationsData(suite.ctx, suite.webProxy.Id, suite.proxyCfg) + destinations, err := fetchComputedExplicitDestinationsData(suite.rt, webWrk, mgwMode) require.NoError(t, err) require.Nil(t, destinations) - - // Check that cache no longer has this destination. - require.Nil(t, c.ComputedDestinationsByService(resource.IDFromReference(api1ServiceRef))) }) testutil.RunStep(suite.T(), "invalid destinations: service not found", func(t *testing.T) { @@ -271,7 +132,7 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { WithTenancy(tenancy). ReferenceNoSection() - compDest := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, suite.webProxy.Id.Name). + resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, suite.webProxy.Id.Name). WithData(t, &pbmesh.ComputedExplicitDestinations{ Destinations: []*pbmesh.Destination{ { @@ -283,12 +144,9 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { WithTenancy(tenancy). Write(t, suite.client) - destinations, err := f.FetchComputedExplicitDestinationsData(suite.ctx, suite.webProxy.Id, suite.proxyCfg) + destinations, err := fetchComputedExplicitDestinationsData(suite.rt, webWrk, mgwMode) require.NoError(t, err) require.Nil(t, destinations) - cachedCompDestIDs := c.ComputedDestinationsByService(resource.IDFromReference(notFoundServiceRef)) - compDest.Id.Uid = "" - prototest.AssertElementsMatch(t, []*pbresource.ID{compDest.Id}, cachedCompDestIDs) }) testutil.RunStep(suite.T(), "invalid destinations: service not on mesh", func(t *testing.T) { @@ -301,7 +159,7 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { WithTenancy(tenancy). WithData(t, apiNonMeshServiceData). Write(t, suite.client) - compDest := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, suite.webProxy.Id.Name). + resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, suite.webProxy.Id.Name). WithData(t, &pbmesh.ComputedExplicitDestinations{ Destinations: []*pbmesh.Destination{ { @@ -313,25 +171,18 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { WithTenancy(tenancy). Write(t, suite.client) - destinations, err := f.FetchComputedExplicitDestinationsData(suite.ctx, suite.webProxy.Id, suite.proxyCfg) + destinations, err := fetchComputedExplicitDestinationsData(suite.rt, webWrk, mgwMode) require.NoError(t, err) require.Nil(t, destinations) - cachedCompDestIDs := c.ComputedDestinationsByService(resource.IDFromReference(api1ServiceRef)) - compDest.Id.Uid = "" - prototest.AssertElementsMatch(t, []*pbresource.ID{compDest.Id}, cachedCompDestIDs) }) testutil.RunStep(suite.T(), "invalid destinations: destination port not found", func(t *testing.T) { - resourcetest.ResourceID(suite.api1Service.Id). - WithData(t, &pbcatalog.Service{ - Ports: []*pbcatalog.ServicePort{ - {TargetPort: "some-other-port", Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - {TargetPort: "mesh", Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, - }, - }). - WithTenancy(tenancy). - Write(t, suite.client) - compDest := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, suite.webProxy.Id.Name). + suite.api1Service, _, _ = suite.createService( + "api-1", tenancy, "api1", []*pbcatalog.ServicePort{ + {TargetPort: "some-other-port", Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + {TargetPort: "mesh", Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, nil, []string{"api-1-identity"}, false) + resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, suite.webProxy.Id.Name). WithData(t, &pbmesh.ComputedExplicitDestinations{ Destinations: []*pbmesh.Destination{ { @@ -343,12 +194,9 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { WithTenancy(tenancy). Write(t, suite.client) - destinations, err := f.FetchComputedExplicitDestinationsData(suite.ctx, suite.webProxy.Id, suite.proxyCfg) + destinations, err := fetchComputedExplicitDestinationsData(suite.rt, webWrk, mgwMode) require.NoError(t, err) require.Nil(t, destinations) - cachedCompDestIDs := c.ComputedDestinationsByService(resource.IDFromReference(api1ServiceRef)) - compDest.Id.Uid = "" - prototest.AssertElementsMatch(t, []*pbresource.ID{compDest.Id}, cachedCompDestIDs) }) suite.api1Service = resourcetest.ResourceID(suite.api1Service.Id). @@ -363,7 +211,7 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { testutil.RunStep(suite.T(), "invalid destinations: destination is pointing to a mesh port", func(t *testing.T) { // Create a computed destinations resource pointing to the mesh port. - compDest := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, suite.webProxy.Id.Name). + resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, suite.webProxy.Id.Name). WithData(t, &pbmesh.ComputedExplicitDestinations{ Destinations: []*pbmesh.Destination{ { @@ -375,16 +223,12 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { WithTenancy(tenancy). Write(t, suite.client) - destinations, err := f.FetchComputedExplicitDestinationsData(suite.ctx, suite.webProxy.Id, suite.proxyCfg) + destinations, err := fetchComputedExplicitDestinationsData(suite.rt, webWrk, mgwMode) require.NoError(t, err) require.Empty(t, destinations) - - cachedCompDestIDs := c.ComputedDestinationsByService(resource.IDFromReference(api1ServiceRef)) - compDest.Id.Uid = "" - prototest.AssertElementsMatch(t, []*pbresource.ID{compDest.Id}, cachedCompDestIDs) }) - compDest := resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, suite.webProxy.Id.Name). + resourcetest.Resource(pbmesh.ComputedExplicitDestinationsType, suite.webProxy.Id.Name). WithData(suite.T(), suite.webComputedDestinationsData). WithTenancy(tenancy). Write(suite.T(), suite.client) @@ -408,17 +252,11 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { require.NotNil(suite.T(), api1ComputedRoutes) // This destination points to TCP, but the computed routes is stale and only knows about HTTP. - destinations, err := f.FetchComputedExplicitDestinationsData(suite.ctx, suite.webProxy.Id, suite.proxyCfg) + destinations, err := fetchComputedExplicitDestinationsData(suite.rt, webWrk, mgwMode) require.NoError(t, err) // Check that we didn't return any destinations. require.Nil(t, destinations) - - // Check that destination service is still in cache because it's still referenced from the pbmesh.Destinations - // resource. - cachedCompDestIDs := c.ComputedDestinationsByService(resource.IDFromReference(api1ServiceRef)) - compDest.Id.Uid = "" - prototest.AssertElementsMatch(t, []*pbresource.ID{compDest.Id}, cachedCompDestIDs) }) testutil.RunStep(suite.T(), "happy path", func(t *testing.T) { @@ -436,8 +274,6 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { ) require.NotNil(suite.T(), api2ComputedRoutes) - resourcetest.ResourceID(suite.api1Service.Id) - expectedDestinations := []*intermediate.Destination{ { Explicit: suite.webComputedDestinationsData.Destinations[0], @@ -445,13 +281,11 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { ComputedPortRoutes: routestest.MutateTargets(suite.T(), api1ComputedRoutes.Data, "tcp", func(t *testing.T, details *pbmesh.BackendTargetDetails) { switch { case resource.ReferenceOrIDMatch(suite.api1Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp": - se := resourcetest.MustDecode[*pbcatalog.ServiceEndpoints](suite.T(), suite.api1ServiceEndpoints) details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: se.Resource.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, suite.api1Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = se.Data details.IdentityRefs = []*pbresource.Reference{{ Name: "api-1-identity", Tenancy: suite.api1Service.Id.Tenancy, @@ -465,13 +299,11 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { ComputedPortRoutes: routestest.MutateTargets(suite.T(), api2ComputedRoutes.Data, "tcp1", func(t *testing.T, details *pbmesh.BackendTargetDetails) { switch { case resource.ReferenceOrIDMatch(suite.api2Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp1": - se := resourcetest.MustDecode[*pbcatalog.ServiceEndpoints](suite.T(), suite.api2ServiceEndpoints) details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: se.Resource.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, suite.api2Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = se.Data details.IdentityRefs = []*pbresource.Reference{{ Name: "api-2-identity", Tenancy: suite.api2Service.Id.Tenancy, @@ -485,13 +317,11 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { ComputedPortRoutes: routestest.MutateTargets(suite.T(), api2ComputedRoutes.Data, "tcp2", func(t *testing.T, details *pbmesh.BackendTargetDetails) { switch { case resource.ReferenceOrIDMatch(suite.api2Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp2": - se := resourcetest.MustDecode[*pbcatalog.ServiceEndpoints](suite.T(), suite.api2ServiceEndpoints) details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: se.Resource.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, suite.api2Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = se.Data details.IdentityRefs = []*pbresource.Reference{{ Name: "api-2-identity", Tenancy: suite.api2Service.Id.Tenancy, @@ -501,7 +331,7 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { }, } - actualDestinations, err := f.FetchComputedExplicitDestinationsData(suite.ctx, suite.webProxy.Id, suite.proxyCfg) + actualDestinations, err := fetchComputedExplicitDestinationsData(suite.rt, webWrk, mgwMode) require.NoError(t, err) // Check that we've computed expanded destinations correctly. @@ -511,40 +341,17 @@ func (suite *dataFetcherSuite) TestFetcher_FetchExplicitDestinationsData() { } func (suite *dataFetcherSuite) TestFetcher_FetchImplicitDestinationsData() { - suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { - // Create a few other services to be implicit upstreams. - api3Service := resourcetest.Resource(pbcatalog.ServiceType, "api-3"). - WithData(suite.T(), &pbcatalog.Service{ - VirtualIps: []string{"192.1.1.1"}, - Ports: []*pbcatalog.ServicePort{ - {TargetPort: "tcp", VirtualPort: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - {TargetPort: "mesh", VirtualPort: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, - }, - }). - WithTenancy(tenancy). - Write(suite.T(), suite.client) + const mgwMode = pbmesh.MeshGatewayMode_MESH_GATEWAY_MODE_NONE - api3ServiceEndpointsData := &pbcatalog.ServiceEndpoints{ - Endpoints: []*pbcatalog.Endpoint{ - { - TargetRef: &pbresource.ID{ - Name: "api-3-abc", - Tenancy: api3Service.Id.Tenancy, - Type: pbcatalog.WorkloadType, - }, - Addresses: []*pbcatalog.WorkloadAddress{{Host: "10.0.0.1"}}, - Ports: map[string]*pbcatalog.WorkloadPort{ - "tcp": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, - "mesh": {Port: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, - }, - Identity: "api-3-identity", - }, - }, - } - api3ServiceEndpoints := resourcetest.Resource(pbcatalog.ServiceEndpointsType, "api-3"). - WithTenancy(tenancy). - WithData(suite.T(), api3ServiceEndpointsData). - Write(suite.T(), suite.client) + suite.runTestCaseWithTenancies(func(tenancy *pbresource.Tenancy) { + webWrk := resourcetest.MustDecode[*pbcatalog.Workload](suite.T(), suite.webWorkload) + + // Create a few other services to be implicit upstreams. + api3Service, _, _ := suite.createService( + "api-3", tenancy, "api3", []*pbcatalog.ServicePort{ + {TargetPort: "tcp", VirtualPort: 8080, Protocol: pbcatalog.Protocol_PROTOCOL_TCP}, + {TargetPort: "mesh", VirtualPort: 20000, Protocol: pbcatalog.Protocol_PROTOCOL_MESH}, + }, []string{"192.1.1.1"}, []string{"api-3-identity"}, false) // Write a default ComputedRoutes for api1, api2, and api3. var ( @@ -565,6 +372,25 @@ func (suite *dataFetcherSuite) TestFetcher_FetchImplicitDestinationsData() { ) require.NotNil(suite.T(), api3ComputedRoutes) + cidID := &pbresource.ID{ + Type: pbmesh.ComputedImplicitDestinationsType, + Tenancy: webWrk.Id.Tenancy, + Name: webWrk.Data.Identity, + } + + // Write a CID that grants web-id-abc access to api-3-identity + resourcetest.ResourceID(cidID). + WithTenancy(tenancy). + WithData(suite.T(), &pbmesh.ComputedImplicitDestinations{ + Destinations: []*pbmesh.ImplicitDestination{ + { + DestinationRef: resource.Reference(api3Service.Id, ""), + DestinationPorts: []string{"tcp"}, + }, + }, + }). + Write(suite.T(), suite.client) + existingDestinations := []*intermediate.Destination{ { Explicit: suite.webComputedDestinationsData.Destinations[0], @@ -572,13 +398,11 @@ func (suite *dataFetcherSuite) TestFetcher_FetchImplicitDestinationsData() { ComputedPortRoutes: routestest.MutateTargets(suite.T(), api1ComputedRoutes.Data, "tcp", func(t *testing.T, details *pbmesh.BackendTargetDetails) { switch { case resource.ReferenceOrIDMatch(suite.api1Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp": - se := resourcetest.MustDecode[*pbcatalog.ServiceEndpoints](suite.T(), suite.api1ServiceEndpoints) details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: se.Resource.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, suite.api1Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = se.Data details.IdentityRefs = []*pbresource.Reference{{ Name: "api-1-identity", Tenancy: suite.api1Service.Id.Tenancy, @@ -592,13 +416,11 @@ func (suite *dataFetcherSuite) TestFetcher_FetchImplicitDestinationsData() { ComputedPortRoutes: routestest.MutateTargets(suite.T(), api2ComputedRoutes.Data, "tcp1", func(t *testing.T, details *pbmesh.BackendTargetDetails) { switch { case resource.ReferenceOrIDMatch(suite.api2Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp1": - se := resourcetest.MustDecode[*pbcatalog.ServiceEndpoints](suite.T(), suite.api2ServiceEndpoints) details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: se.Resource.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, suite.api2Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = se.Data details.IdentityRefs = []*pbresource.Reference{{ Name: "api-2-identity", Tenancy: suite.api1Service.Id.Tenancy, @@ -612,13 +434,11 @@ func (suite *dataFetcherSuite) TestFetcher_FetchImplicitDestinationsData() { ComputedPortRoutes: routestest.MutateTargets(suite.T(), api2ComputedRoutes.Data, "tcp2", func(t *testing.T, details *pbmesh.BackendTargetDetails) { switch { case resource.ReferenceOrIDMatch(suite.api2Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp2": - se := resourcetest.MustDecode[*pbcatalog.ServiceEndpoints](suite.T(), suite.api2ServiceEndpoints) details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: se.Resource.Id, + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, suite.api2Service.Id), MeshPort: details.MeshPort, RoutePort: details.BackendRef.Port, } - details.ServiceEndpoints = se.Data details.IdentityRefs = []*pbresource.Reference{{ Name: "api-2-identity", Tenancy: suite.api1Service.Id.Tenancy, @@ -626,36 +446,32 @@ func (suite *dataFetcherSuite) TestFetcher_FetchImplicitDestinationsData() { } }), }, - { - // implicit - Service: resourcetest.MustDecode[*pbcatalog.Service](suite.T(), api3Service), - ComputedPortRoutes: routestest.MutateTargets(suite.T(), api3ComputedRoutes.Data, "tcp", func(t *testing.T, details *pbmesh.BackendTargetDetails) { - switch { - case resource.ReferenceOrIDMatch(api3Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp": - se := resourcetest.MustDecode[*pbcatalog.ServiceEndpoints](suite.T(), api3ServiceEndpoints) - details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: se.Resource.Id, - MeshPort: details.MeshPort, - RoutePort: details.BackendRef.Port, - } - details.ServiceEndpoints = se.Data - details.IdentityRefs = []*pbresource.Reference{{ - Name: "api-3-identity", - Tenancy: suite.api1Service.Id.Tenancy, - }} - } - }), - VirtualIPs: []string{"192.1.1.1"}, - }, } - f := Fetcher{ - client: suite.client, - } - - actualDestinations, err := f.FetchImplicitDestinationsData(context.Background(), suite.webProxy.Id, existingDestinations) + actualDestinations, err := fetchComputedImplicitDestinationsData( + suite.rt, webWrk, mgwMode, slices.Clone(existingDestinations), + ) require.NoError(suite.T(), err) + existingDestinations = append(existingDestinations, &intermediate.Destination{ + // implicit + Service: resourcetest.MustDecode[*pbcatalog.Service](suite.T(), api3Service), + ComputedPortRoutes: routestest.MutateTargets(suite.T(), api3ComputedRoutes.Data, "tcp", func(t *testing.T, details *pbmesh.BackendTargetDetails) { + switch { + case resource.ReferenceOrIDMatch(api3Service.Id, details.BackendRef.Ref) && details.BackendRef.Port == "tcp": + details.ServiceEndpointsRef = &pbproxystate.EndpointRef{ + Id: resource.ReplaceType(pbcatalog.ServiceEndpointsType, api3Service.Id), + MeshPort: details.MeshPort, + RoutePort: details.BackendRef.Port, + } + details.IdentityRefs = []*pbresource.Reference{{ + Name: "api-3-identity", + Tenancy: suite.api1Service.Id.Tenancy, + }} + } + }), + VirtualIPs: []string{"192.1.1.1"}, + }) prototest.AssertElementsMatch(suite.T(), existingDestinations, actualDestinations) }) } @@ -669,12 +485,10 @@ func (suite *dataFetcherSuite) appendTenancyInfo(tenancy *pbresource.Tenancy) st } func (suite *dataFetcherSuite) cleanUpNodes() { - suite.resourceClient.MustDelete(suite.T(), suite.api1Service.Id) - suite.resourceClient.MustDelete(suite.T(), suite.api1ServiceEndpoints.Id) - suite.resourceClient.MustDelete(suite.T(), suite.api2Service.Id) - suite.resourceClient.MustDelete(suite.T(), suite.api2ServiceEndpoints.Id) - suite.resourceClient.MustDelete(suite.T(), suite.webProxy.Id) - suite.resourceClient.MustDelete(suite.T(), suite.webWorkload.Id) + suite.client.MustDelete(suite.T(), suite.api1Service.Id) + suite.client.MustDelete(suite.T(), suite.api2Service.Id) + suite.client.MustDelete(suite.T(), suite.webProxy.Id) + suite.client.MustDelete(suite.T(), suite.webWorkload.Id) } func (suite *dataFetcherSuite) runTestCaseWithTenancies(t func(*pbresource.Tenancy)) { @@ -688,3 +502,15 @@ func (suite *dataFetcherSuite) runTestCaseWithTenancies(t func(*pbresource.Tenan }) } } + +func (suite *dataFetcherSuite) createService( + name string, + tenancy *pbresource.Tenancy, + exactSelector string, + ports []*pbcatalog.ServicePort, + vips []string, + workloadIdentities []string, + deferStatusUpdate bool, +) (*pbresource.Resource, *pbcatalog.Service, func() *pbresource.Resource) { + return createService(suite.T(), suite.client, name, tenancy, exactSelector, ports, vips, workloadIdentities, deferStatusUpdate) +} diff --git a/internal/mesh/internal/controllers/sidecarproxy/fetcher/data_fetcher.go b/internal/mesh/internal/controllers/sidecarproxy/fetcher/data_fetcher.go deleted file mode 100644 index 71422e33fb..0000000000 --- a/internal/mesh/internal/controllers/sidecarproxy/fetcher/data_fetcher.go +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: BUSL-1.1 - -package fetcher - -import ( - "context" - "fmt" - "strings" - - "google.golang.org/protobuf/proto" - - "github.com/hashicorp/consul/internal/mesh/internal/controllers/meshgateways" - "github.com/hashicorp/consul/internal/mesh/internal/controllers/sidecarproxy/cache" - "github.com/hashicorp/consul/internal/mesh/internal/types" - intermediateTypes "github.com/hashicorp/consul/internal/mesh/internal/types/intermediate" - "github.com/hashicorp/consul/internal/resource" - "github.com/hashicorp/consul/internal/storage" - pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" - pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" - pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" - "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1/pbproxystate" - "github.com/hashicorp/consul/proto-public/pbresource" -) - -type Fetcher struct { - client pbresource.ResourceServiceClient - cache *cache.Cache -} - -func New(client pbresource.ResourceServiceClient, cache *cache.Cache) *Fetcher { - return &Fetcher{ - client: client, - cache: cache, - } -} - -// FetchWorkload fetches a service resource from the resource service. -// This will panic if the type field in the ID argument is not a Workload type. -func (f *Fetcher) FetchWorkload(ctx context.Context, id *pbresource.ID) (*types.DecodedWorkload, error) { - assertResourceType(pbcatalog.WorkloadType, id.Type) - dec, err := resource.GetDecodedResource[*pbcatalog.Workload](ctx, f.client, id) - if err != nil { - return nil, err - } else if dec == nil { - // We also need to make sure to delete the associated proxy from cache. - f.cache.UntrackWorkload(id) - return nil, nil - } - - f.cache.TrackWorkload(dec) - - return dec, err -} - -// FetchProxyStateTemplate fetches a service resource from the resource service. -// This will panic if the type field in the ID argument is not a ProxyStateTemplate type. -func (f *Fetcher) FetchProxyStateTemplate(ctx context.Context, id *pbresource.ID) (*types.DecodedProxyStateTemplate, error) { - assertResourceType(pbmesh.ProxyStateTemplateType, id.Type) - return resource.GetDecodedResource[*pbmesh.ProxyStateTemplate](ctx, f.client, id) -} - -// FetchComputedTrafficPermissions fetches a service resource from the resource service. -// This will panic if the type field in the ID argument is not a ComputedTrafficPermissons type. -func (f *Fetcher) FetchComputedTrafficPermissions(ctx context.Context, id *pbresource.ID) (*types.DecodedComputedTrafficPermissions, error) { - assertResourceType(pbauth.ComputedTrafficPermissionsType, id.Type) - return resource.GetDecodedResource[*pbauth.ComputedTrafficPermissions](ctx, f.client, id) -} - -// FetchServiceEndpoints fetches a service resource from the resource service. -// This will panic if the type field in the ID argument is not a ServiceEndpoints type. -func (f *Fetcher) FetchServiceEndpoints(ctx context.Context, id *pbresource.ID) (*types.DecodedServiceEndpoints, error) { - assertResourceType(pbcatalog.ServiceEndpointsType, id.Type) - return resource.GetDecodedResource[*pbcatalog.ServiceEndpoints](ctx, f.client, id) -} - -// FetchService fetches a service resource from the resource service. -// This will panic if the type field in the ID argument is not a Service type. -func (f *Fetcher) FetchService(ctx context.Context, id *pbresource.ID) (*types.DecodedService, error) { - assertResourceType(pbcatalog.ServiceType, id.Type) - return resource.GetDecodedResource[*pbcatalog.Service](ctx, f.client, id) -} - -// FetchDestinations fetches a service resource from the resource service. -// This will panic if the type field in the ID argument is not a Destinations type. -func (f *Fetcher) FetchDestinations(ctx context.Context, id *pbresource.ID) (*types.DecodedDestinations, error) { - assertResourceType(pbmesh.DestinationsType, id.Type) - return resource.GetDecodedResource[*pbmesh.Destinations](ctx, f.client, id) -} - -// FetchComputedRoutes fetches a service resource from the resource service. -// This will panic if the type field in the ID argument is not a ComputedRoutes type. -func (f *Fetcher) FetchComputedRoutes(ctx context.Context, id *pbresource.ID) (*types.DecodedComputedRoutes, error) { - assertResourceType(pbmesh.ComputedRoutesType, id.Type) - if !types.IsComputedRoutesType(id.Type) { - return nil, fmt.Errorf("id must be a ComputedRoutes type") - } - - dec, err := resource.GetDecodedResource[*pbmesh.ComputedRoutes](ctx, f.client, id) - if err != nil { - return nil, err - } else if dec == nil { - f.cache.UntrackComputedRoutes(id) - } - - return dec, err -} - -func (f *Fetcher) FetchComputedExplicitDestinationsData( - ctx context.Context, - proxyID *pbresource.ID, - proxyCfg *pbmesh.ComputedProxyConfiguration, -) ([]*intermediateTypes.Destination, error) { - var destinations []*intermediateTypes.Destination - - // Fetch computed explicit destinations first. - cdID := resource.ReplaceType(pbmesh.ComputedExplicitDestinationsType, proxyID) - cd, err := resource.GetDecodedResource[*pbmesh.ComputedExplicitDestinations](ctx, f.client, cdID) - if err != nil { - return nil, err - } - if cd == nil { - f.cache.UntrackComputedDestinations(cdID) - return nil, nil - } - - // Otherwise, track this resource in the destinations cache. - f.cache.TrackComputedDestinations(cd) - - for _, dest := range cd.GetData().GetDestinations() { - d := &intermediateTypes.Destination{} - - serviceID := resource.IDFromReference(dest.DestinationRef) - - // Fetch Service - svc, err := f.FetchService(ctx, serviceID) - if err != nil { - return nil, err - } - - if svc == nil { - // If the Service resource is not found, skip this destination. - continue - } - - d.Service = svc - - // Check if this service is mesh-enabled. If not, update the status. - if !svc.GetData().IsMeshEnabled() { - // This error should not cause the execution to stop, as we want to make sure that this non-mesh destination - // service gets removed from the proxy state. - continue - } - - // Check if the desired port exists on the service and skip it doesn't. - if svc.GetData().FindPortByID(dest.DestinationPort) == nil { - continue - } - - // No destination port should point to a port with "mesh" protocol, - // so check if destination port has the mesh protocol and skip it if it does. - if svc.GetData().FindPortByID(dest.DestinationPort).GetProtocol() == pbcatalog.Protocol_PROTOCOL_MESH { - continue - } - - // Fetch ComputedRoutes. - cr, err := f.FetchComputedRoutes(ctx, resource.ReplaceType(pbmesh.ComputedRoutesType, serviceID)) - if err != nil { - return nil, err - } else if cr == nil { - // This is required, so wait until it exists. - continue - } - - portConfig, ok := cr.Data.PortedConfigs[dest.DestinationPort] - if !ok { - // This is required, so wait until it exists. - continue - } - - // Copy this so we can mutate the targets. - d.ComputedPortRoutes = proto.Clone(portConfig).(*pbmesh.ComputedPortRoutes) - - // As Destinations resource contains a list of destinations, - // we need to find the one that references our service and port. - d.Explicit = dest - - // NOTE: we collect both DIRECT and INDIRECT target information here. - for _, routeTarget := range d.ComputedPortRoutes.Targets { - targetServiceID := resource.IDFromReference(routeTarget.BackendRef.Ref) - - // Fetch ServiceEndpoints. - serviceEndpointID := resource.ReplaceType(pbcatalog.ServiceEndpointsType, targetServiceID) - se, err := f.FetchServiceEndpoints(ctx, serviceEndpointID) - if err != nil { - return nil, err - } - - if se != nil { - routeTarget.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: se.Id, - MeshPort: routeTarget.MeshPort, - RoutePort: routeTarget.BackendRef.Port, - } - routeTarget.ServiceEndpoints = se.Data - // Gather all identities. - var identities []*pbresource.Reference - for _, identity := range se.GetData().GetIdentities() { - identities = append(identities, &pbresource.Reference{ - Name: identity, - Tenancy: se.Resource.Id.Tenancy, - }) - } - routeTarget.IdentityRefs = identities - } - - // If the target service is in a different partition and the mesh gateway mode is - // "local" or "remote", use the ServiceEndpoints for the corresponding MeshGateway - // instead of the ServiceEndpoints for the target service. The IdentityRefs on the - // target will remain the same for TCP targets. - // - // TODO(nathancoleman) Consider cross-datacenter case as well - if routeTarget.BackendRef.Ref.Tenancy.Partition != proxyID.Tenancy.Partition { - mode := pbmesh.MeshGatewayMode_MESH_GATEWAY_MODE_NONE - if proxyCfg != nil && proxyCfg.DynamicConfig != nil { - mode = proxyCfg.GetDynamicConfig().GetMeshGatewayMode() - } - - switch mode { - case pbmesh.MeshGatewayMode_MESH_GATEWAY_MODE_LOCAL: - // Use ServiceEndpoints for the MeshGateway in the source service's partition - routeTarget.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: &pbresource.ID{ - Type: pbcatalog.ServiceEndpointsType, - Name: meshgateways.GatewayName, - Tenancy: proxyID.Tenancy, - }, - MeshPort: meshgateways.LANPortName, - RoutePort: meshgateways.LANPortName, - } - - se, err := f.FetchServiceEndpoints(ctx, routeTarget.ServiceEndpointsRef.Id) - if err != nil { - return nil, err - } else if se != nil { - routeTarget.ServiceEndpoints = se.GetData() - } - case pbmesh.MeshGatewayMode_MESH_GATEWAY_MODE_REMOTE: - // Use ServiceEndpoints for the MeshGateway in the target service's partition - routeTarget.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: &pbresource.ID{ - Type: pbcatalog.ServiceEndpointsType, - Name: meshgateways.GatewayName, - Tenancy: targetServiceID.Tenancy, - }, - MeshPort: meshgateways.WANPortName, - RoutePort: meshgateways.WANPortName, - } - - se, err := f.FetchServiceEndpoints(ctx, routeTarget.ServiceEndpointsRef.Id) - if err != nil { - return nil, err - } else if se != nil { - routeTarget.ServiceEndpoints = se.GetData() - } - } - } - } - - destinations = append(destinations, d) - } - - return destinations, nil -} - -type PortReferenceKey struct { - resource.ReferenceKey - Port string -} - -// FetchImplicitDestinationsData fetches all implicit destinations and adds them to existing destinations. -// If the implicit destination is already in addToDestinations, it will be skipped. -// todo (ishustava): this function will eventually need to fetch implicit destinations from the ImplicitDestinations resource instead. -func (f *Fetcher) FetchImplicitDestinationsData( - ctx context.Context, - proxyID *pbresource.ID, - addToDestinations []*intermediateTypes.Destination, -) ([]*intermediateTypes.Destination, error) { - // First, convert existing destinations to a map so we can de-dup. - // - // This is keyed by the serviceID+port of the upstream, which is effectively - // the same as the id of the computed routes for the service. - destinations := make(map[PortReferenceKey]*intermediateTypes.Destination) - for _, d := range addToDestinations { - prk := PortReferenceKey{ - ReferenceKey: resource.NewReferenceKey(d.Service.Resource.Id), - Port: d.ComputedPortRoutes.ParentRef.Port, - } - destinations[prk] = d - } - - // For now we need to look up all computed routes within a partition. - rsp, err := f.client.List(ctx, &pbresource.ListRequest{ - Type: pbmesh.ComputedRoutesType, - Tenancy: &pbresource.Tenancy{ - Namespace: storage.Wildcard, - Partition: proxyID.Tenancy.Partition, - }, - }) - if err != nil { - return nil, err - } - - for _, r := range rsp.Resources { - svcID := resource.ReplaceType(pbcatalog.ServiceType, r.Id) - computedRoutes, err := resource.Decode[*pbmesh.ComputedRoutes](r) - if err != nil { - return nil, err - } - - if computedRoutes == nil { - // the routes-controller doesn't deem this worthy of the mesh - continue - } - - // Fetch the service. - // todo (ishustava): this should eventually grab virtual IPs resource. - svc, err := f.FetchService(ctx, resource.ReplaceType(pbcatalog.ServiceType, r.Id)) - if err != nil { - return nil, err - } - if svc == nil { - // If service no longer exists, skip. - continue - } - - // If this proxy is a part of this service, ignore it. - if isPartOfService(resource.ReplaceType(pbcatalog.WorkloadType, proxyID), svc) { - continue - } - - inMesh := false - for _, port := range svc.Data.Ports { - if port.Protocol == pbcatalog.Protocol_PROTOCOL_MESH { - inMesh = true - break - } - } - - if !inMesh { - // If a service is no longer in the mesh, skip. - continue - } - - // Fetch the resources that may show up duplicated. - // - // NOTE: we collect both DIRECT and INDIRECT target information here. - endpointsMap := make(map[resource.ReferenceKey]*types.DecodedServiceEndpoints) - for _, portConfig := range computedRoutes.Data.PortedConfigs { - for _, routeTarget := range portConfig.Targets { - targetServiceID := resource.IDFromReference(routeTarget.BackendRef.Ref) - - seID := resource.ReplaceType(pbcatalog.ServiceEndpointsType, targetServiceID) - seRK := resource.NewReferenceKey(seID) - - if _, ok := endpointsMap[seRK]; !ok { - se, err := f.FetchServiceEndpoints(ctx, seID) - if err != nil { - return nil, err - } - // We only add the endpoint to the map if it's not nil. If it's missing on lookup now, the - // controller should get triggered when the endpoint exists again since it watches service - // endpoints. - if se != nil { - endpointsMap[seRK] = se - } - } - } - } - - for portName, portConfig := range computedRoutes.Data.PortedConfigs { - // If it's already in destinations, ignore it. - prk := PortReferenceKey{ - ReferenceKey: resource.NewReferenceKey(svcID), - Port: portName, - } - if _, ok := destinations[prk]; ok { - continue - } - - // Copy this so we can mutate the targets. - portConfig = proto.Clone(portConfig).(*pbmesh.ComputedPortRoutes) - - d := &intermediateTypes.Destination{ - Service: svc, - ComputedPortRoutes: portConfig, - VirtualIPs: svc.Data.VirtualIps, - } - for _, routeTarget := range portConfig.Targets { - targetServiceID := resource.IDFromReference(routeTarget.BackendRef.Ref) - seID := resource.ReplaceType(pbcatalog.ServiceEndpointsType, targetServiceID) - - // Fetch ServiceEndpoints. - se, ok := endpointsMap[resource.NewReferenceKey(seID)] - if ok { - routeTarget.ServiceEndpointsRef = &pbproxystate.EndpointRef{ - Id: se.Resource.Id, - MeshPort: routeTarget.MeshPort, - RoutePort: routeTarget.BackendRef.Port, - } - routeTarget.ServiceEndpoints = se.Data - - // Gather all identities. - var identities []*pbresource.Reference - for _, ep := range se.Data.Endpoints { - identities = append(identities, &pbresource.Reference{ - Name: ep.Identity, - Tenancy: se.Resource.Id.Tenancy, - }) - } - routeTarget.IdentityRefs = identities - } - } - addToDestinations = append(addToDestinations, d) - } - } - return addToDestinations, err -} - -// FetchComputedProxyConfiguration fetches proxy configurations for the proxy state template provided by id -// and merges them into one object. -func (f *Fetcher) FetchComputedProxyConfiguration(ctx context.Context, id *pbresource.ID) (*types.DecodedComputedProxyConfiguration, error) { - compProxyCfgID := resource.ReplaceType(pbmesh.ComputedProxyConfigurationType, id) - - return resource.GetDecodedResource[*pbmesh.ComputedProxyConfiguration](ctx, f.client, compProxyCfgID) -} - -func isPartOfService(workloadID *pbresource.ID, svc *types.DecodedService) bool { - if !resource.EqualTenancy(workloadID.GetTenancy(), svc.Resource.Id.GetTenancy()) { - return false - } - sel := svc.Data.Workloads - for _, exact := range sel.GetNames() { - if workloadID.GetName() == exact { - return true - } - } - for _, prefix := range sel.GetPrefixes() { - if strings.HasPrefix(workloadID.GetName(), prefix) { - return true - } - } - return false -} - -func assertResourceType(expected, actual *pbresource.Type) { - if !proto.Equal(expected, actual) { - // this is always a programmer error so safe to panic - panic(fmt.Sprintf("expected a query for a type of %q, you provided a type of %q", expected, actual)) - } -} diff --git a/internal/mesh/internal/controllers/sidecarproxy/helper_test.go b/internal/mesh/internal/controllers/sidecarproxy/helper_test.go new file mode 100644 index 0000000000..fe61d0d632 --- /dev/null +++ b/internal/mesh/internal/controllers/sidecarproxy/helper_test.go @@ -0,0 +1,87 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package sidecarproxy + +import ( + "strings" + "testing" + + "github.com/stretchr/testify/require" + + "github.com/hashicorp/consul/internal/catalog" + "github.com/hashicorp/consul/internal/resource/resourcetest" + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/hashicorp/consul/sdk/testutil" +) + +func createService( + t *testing.T, + client *resourcetest.Client, + name string, + tenancy *pbresource.Tenancy, + exactSelector string, + ports []*pbcatalog.ServicePort, + vips []string, + workloadIdentities []string, + deferStatusUpdate bool, +) (*pbresource.Resource, *pbcatalog.Service, func() *pbresource.Resource) { + data := &pbcatalog.Service{ + Workloads: &pbcatalog.WorkloadSelector{ + Names: []string{exactSelector}, + }, + Ports: ports, + VirtualIps: vips, + } + + var status *pbresource.Status + if deferStatusUpdate { + status = &pbresource.Status{ + Conditions: []*pbresource.Condition{{ + Type: catalog.StatusConditionBoundIdentities, + State: pbresource.Condition_STATE_TRUE, + Message: "", + }}, + } + } else { + status = &pbresource.Status{ + Conditions: []*pbresource.Condition{{ + Type: catalog.StatusConditionBoundIdentities, + State: pbresource.Condition_STATE_TRUE, + Message: strings.Join(workloadIdentities, ","), + }}, + } + } + + res := resourcetest.Resource(pbcatalog.ServiceType, name). + WithTenancy(tenancy). + WithData(t, data). + WithStatus(catalog.EndpointsStatusKey, status). + Write(t, client) + + var statusUpdate = func() *pbresource.Resource { return res } + if deferStatusUpdate { + statusUpdate = func() *pbresource.Resource { + ctx := testutil.TestContext(t) + + status := &pbresource.Status{ + ObservedGeneration: res.Generation, + Conditions: []*pbresource.Condition{{ + Type: catalog.StatusConditionBoundIdentities, + State: pbresource.Condition_STATE_TRUE, + Message: strings.Join(workloadIdentities, ","), + }}, + } + resp, err := client.WriteStatus(ctx, &pbresource.WriteStatusRequest{ + Id: res.Id, + Key: catalog.EndpointsStatusKey, + Status: status, + }) + require.NoError(t, err) + return resp.Resource + } + } + + return res, data, statusUpdate +} diff --git a/internal/mesh/internal/controllers/sidecarproxy/mapper.go b/internal/mesh/internal/controllers/sidecarproxy/mapper.go new file mode 100644 index 0000000000..2ffc085822 --- /dev/null +++ b/internal/mesh/internal/controllers/sidecarproxy/mapper.go @@ -0,0 +1,210 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package sidecarproxy + +import ( + "context" + "fmt" + + "google.golang.org/protobuf/proto" + + "github.com/hashicorp/consul/internal/controller" + "github.com/hashicorp/consul/internal/controller/cache" + "github.com/hashicorp/consul/internal/controller/cache/indexers" + "github.com/hashicorp/consul/internal/mesh/internal/meshindexes" + "github.com/hashicorp/consul/internal/mesh/internal/types" + "github.com/hashicorp/consul/internal/resource" + pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" + pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +const ( + selectedWorkloadsIndexName = "selected-workloads" +) + +// Cache: reverse CED => Service(destination) +var computedExplicitDestinationsByServiceIndex = indexers.RefOrIDIndex( + "computed-explicit-destinations-by-service", + func(ced *types.DecodedComputedExplicitDestinations) []*pbresource.Reference { + if len(ced.Data.Destinations) == 0 { + return nil + } + + out := make([]*pbresource.Reference, 0, len(ced.Data.Destinations)) + for _, dest := range ced.Data.Destinations { + if resource.EqualType(pbcatalog.ServiceType, dest.DestinationRef.Type) { + out = append(out, dest.DestinationRef) + } + } + return out + }, +) + +// Cache: reverse CID => Service(destination) +var computedImplicitDestinationsByServiceIndex = indexers.RefOrIDIndex( + "computed-implicit-destinations-by-service", + func(ced *types.DecodedComputedImplicitDestinations) []*pbresource.Reference { + if len(ced.Data.Destinations) == 0 { + return nil + } + + out := make([]*pbresource.Reference, 0, len(ced.Data.Destinations)) + for _, dest := range ced.Data.Destinations { + if resource.EqualType(pbcatalog.ServiceType, dest.DestinationRef.Type) { + out = append(out, dest.DestinationRef) + } + } + return out + }, +) + +// Cache: reverse Workload => WorkloadIdentity +var workloadByWorkloadIdentityIndex = indexers.RefOrIDIndex( + "workload-by-workload-identity", + func(wrk *types.DecodedWorkload) []*pbresource.Reference { + if wrk.Data.Identity == "" { + return nil + } + wid := &pbresource.Reference{ + Type: pbauth.WorkloadIdentityType, + Tenancy: wrk.GetId().GetTenancy(), + Name: wrk.Data.Identity, + } + return []*pbresource.Reference{wid} + }, +) + +// Cache: reverse CR => SVC[backend] +var computedRoutesByBackendServiceIndex = meshindexes.ComputedRoutesByBackendServiceIndex() + +// Cache: reverse SVC[*] => WI[*] +var serviceByWorkloadIdentityIndex = meshindexes.ServiceByWorkloadIdentityIndex() + +func MapComputedImplicitDestinations(ctx context.Context, rt controller.Runtime, res *pbresource.Resource) ([]controller.Request, error) { + assertResourceType(pbmesh.ComputedImplicitDestinationsType, res.Id.Type) + + wiID := resource.ReplaceType(pbauth.WorkloadIdentityType, res.Id) + + workloads, err := rt.Cache.List(pbcatalog.WorkloadType, workloadByWorkloadIdentityIndex.Name(), wiID) + if err != nil { + return nil, err + } + + return controller.MakeRequestsFromResources(pbmesh.ProxyStateTemplateType, workloads), nil +} + +func MapComputedTrafficPermissions(ctx context.Context, rt controller.Runtime, res *pbresource.Resource) ([]controller.Request, error) { + assertResourceType(pbauth.ComputedTrafficPermissionsType, res.Id.Type) + + wiID := resource.ReplaceType(pbauth.WorkloadIdentityType, res.Id) + + workloads, err := rt.Cache.List(pbcatalog.WorkloadType, workloadByWorkloadIdentityIndex.Name(), wiID) + if err != nil { + return nil, err + } + + return controller.MakeRequestsFromResources(pbmesh.ProxyStateTemplateType, workloads), nil +} + +func MapComputedRoutes(ctx context.Context, rt controller.Runtime, res *pbresource.Resource) ([]controller.Request, error) { + assertResourceType(pbmesh.ComputedRoutesType, res.Id.Type) + + svcID := resource.ReplaceType(pbcatalog.ServiceType, res.Id) + + return mapServiceThroughDestinations(rt.Cache, svcID) +} + +func MapService(ctx context.Context, rt controller.Runtime, res *pbresource.Resource) ([]controller.Request, error) { + assertResourceType(pbcatalog.ServiceType, res.Id.Type) + + pstIDs, err := mapServiceThroughDestinations(rt.Cache, res.Id) + if err != nil { + return nil, err + } + + // Now walk the mesh configuration information backwards because + // we need to find any PST that needs to DISCOVER endpoints for this + // service as a part of mesh configuration and traffic routing. + + // Find all ComputedRoutes that reference this service. + computedRoutes, err := rt.Cache.List( + pbmesh.ComputedRoutesType, + computedRoutesByBackendServiceIndex.Name(), + res.Id, + ) + if err != nil { + return nil, err + } + + for _, cr := range computedRoutes { + // Find all Upstreams that reference a Service aligned with this + // ComputedRoutes. Afterwards, find all Workloads selected by the + // Upstreams, and align a PST with those. + + ids, err := MapComputedRoutes(ctx, rt, cr) + if err != nil { + return nil, err + } + pstIDs = append(pstIDs, ids...) + } + + return pstIDs, nil +} + +func mapServiceThroughDestinations(cache cache.ReadOnlyCache, svcID *pbresource.ID) ([]controller.Request, error) { + explicitDests, err := cache.List( + pbmesh.ComputedExplicitDestinationsType, + computedExplicitDestinationsByServiceIndex.Name(), + svcID, + ) + if err != nil { + return nil, err + } + + implicitDests, err := cache.List( + pbmesh.ComputedImplicitDestinationsType, + computedImplicitDestinationsByServiceIndex.Name(), + svcID, + ) + if err != nil { + return nil, err + } + + // NOTE: ComputedExplicitDestinations are name-aligned with ProxyStateTemplates. + // This is different for implicit dests, as ComputedImplicitDestinations is name-aligned with WorkloadIdentity + reqs := make([]controller.Request, 0, len(explicitDests)+len(implicitDests)) + reqs = append(reqs, controller.MakeRequestsFromResources( + pbmesh.ProxyStateTemplateType, + explicitDests, + )...) + + for _, dest := range implicitDests { + wiID := resource.ReplaceType(pbauth.WorkloadIdentityType, dest.Id) + + workloads, err := cache.List( + pbcatalog.WorkloadType, + workloadByWorkloadIdentityIndex.Name(), + wiID, + ) + if err != nil { + return nil, err + } + + reqs = append(reqs, controller.MakeRequestsFromResources( + pbmesh.ProxyStateTemplateType, + workloads, + )...) + } + + return reqs, nil +} + +func assertResourceType(expected, actual *pbresource.Type) { + if !proto.Equal(expected, actual) { + // this is always a programmer error so safe to panic + panic(fmt.Sprintf("expected a query for a type of %q, you provided a type of %q", expected, actual)) + } +} diff --git a/internal/mesh/internal/meshindexes/computed_routes.go b/internal/mesh/internal/meshindexes/computed_routes.go new file mode 100644 index 0000000000..47f034095c --- /dev/null +++ b/internal/mesh/internal/meshindexes/computed_routes.go @@ -0,0 +1,66 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package meshindexes + +import ( + "github.com/hashicorp/consul/internal/catalog" + "github.com/hashicorp/consul/internal/controller/cache/index" + "github.com/hashicorp/consul/internal/controller/cache/indexers" + "github.com/hashicorp/consul/internal/mesh/internal/types" + "github.com/hashicorp/consul/internal/resource" + pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" + "github.com/hashicorp/consul/proto-public/pbresource" +) + +// Cache: reverse CR => SVC[backend] +func ComputedRoutesByBackendServiceIndex() *index.Index { + return indexers.RefOrIDIndex( + "computed-routes-by-backend-service", + func(cr *types.DecodedComputedRoutes) []*pbresource.Reference { + return GetBackendServiceRefsFromComputedRoutes(cr) + }, + ) +} + +func GetBackendServiceRefsFromComputedRoutes(cr *types.DecodedComputedRoutes) []*pbresource.Reference { + var ( + out []*pbresource.Reference + seen = make(map[resource.ReferenceKey]struct{}) + ) + for _, pc := range cr.Data.PortedConfigs { + for _, target := range pc.Targets { + ref := target.BackendRef.Ref + rk := resource.NewReferenceKey(ref) + if _, ok := seen[rk]; !ok { + out = append(out, ref) + seen[rk] = struct{}{} + } + } + } + return out +} + +// Cache: reverse SVC[*] => WI[*] +func ServiceByWorkloadIdentityIndex() *index.Index { + return indexers.RefOrIDIndex( + "service-by-workload-identity", + func(svc *types.DecodedService) []*pbresource.Reference { + return GetWorkloadIdentitiesFromService(svc.Resource) + }, + ) +} + +func GetWorkloadIdentitiesFromService(svc *pbresource.Resource) []*pbresource.Reference { + ids := catalog.GetBoundIdentities(svc) + + out := make([]*pbresource.Reference, 0, len(ids)) + for _, id := range ids { + out = append(out, &pbresource.Reference{ + Type: pbauth.WorkloadIdentityType, + Name: id, + Tenancy: svc.Id.Tenancy, + }) + } + return out +} diff --git a/internal/mesh/internal/meshindexes/computed_routes_test.go b/internal/mesh/internal/meshindexes/computed_routes_test.go new file mode 100644 index 0000000000..685d219129 --- /dev/null +++ b/internal/mesh/internal/meshindexes/computed_routes_test.go @@ -0,0 +1,169 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: BUSL-1.1 + +package meshindexes + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/hashicorp/consul/internal/catalog" + "github.com/hashicorp/consul/internal/mesh/internal/types" + "github.com/hashicorp/consul/internal/resource" + "github.com/hashicorp/consul/internal/resource/resourcetest" + rtest "github.com/hashicorp/consul/internal/resource/resourcetest" + pbauth "github.com/hashicorp/consul/proto-public/pbauth/v2beta1" + pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" + pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" + "github.com/hashicorp/consul/proto-public/pbresource" + "github.com/hashicorp/consul/proto/private/prototest" +) + +func TestGetWorkloadIdentitiesFromService(t *testing.T) { + tenancy := resource.DefaultNamespacedTenancy() + + build := func(conds ...*pbresource.Condition) *pbresource.Resource { + b := rtest.Resource(pbcatalog.ServiceType, "web"). + WithTenancy(tenancy). + WithData(t, &pbcatalog.Service{}) + if len(conds) > 0 { + b.WithStatus(catalog.EndpointsStatusKey, &pbresource.Status{ + Conditions: conds, + }) + } + return b.Build() + } + + fooRef := &pbresource.Reference{ + Type: pbauth.WorkloadIdentityType, + Tenancy: tenancy, + Name: "foo", + } + barRef := &pbresource.Reference{ + Type: pbauth.WorkloadIdentityType, + Tenancy: tenancy, + Name: "bar", + } + + makeRefs := func(refs ...*pbresource.Reference) []*pbresource.Reference { + return refs + } + + run := GetWorkloadIdentitiesFromService + + require.Empty(t, run(build(nil))) + require.Empty(t, run(build(&pbresource.Condition{ + Type: catalog.StatusConditionBoundIdentities, + State: pbresource.Condition_STATE_TRUE, + Message: "", + }))) + prototest.AssertDeepEqual(t, makeRefs(fooRef), run(build(&pbresource.Condition{ + Type: catalog.StatusConditionBoundIdentities, + State: pbresource.Condition_STATE_TRUE, + Message: "foo", + }))) + require.Empty(t, run(build(&pbresource.Condition{ + Type: catalog.StatusConditionBoundIdentities, + State: pbresource.Condition_STATE_FALSE, + Message: "foo", + }))) + prototest.AssertDeepEqual(t, makeRefs(barRef, fooRef), run(build(&pbresource.Condition{ + Type: catalog.StatusConditionBoundIdentities, + State: pbresource.Condition_STATE_TRUE, + Message: "bar,foo", // proper order + }))) + prototest.AssertDeepEqual(t, makeRefs(barRef, fooRef), run(build(&pbresource.Condition{ + Type: catalog.StatusConditionBoundIdentities, + State: pbresource.Condition_STATE_TRUE, + Message: "foo,bar", // incorrect order gets fixed + }))) +} + +func TestGetBackendServiceRefsFromComputedRoutes(t *testing.T) { + type testcase struct { + cr *types.DecodedComputedRoutes + expect []*pbresource.Reference + } + + run := func(t *testing.T, tc testcase) { + got := GetBackendServiceRefsFromComputedRoutes(tc.cr) + prototest.AssertElementsMatch(t, tc.expect, got) + } + + tenancy := resource.DefaultNamespacedTenancy() + + newRef := func(name string) *pbresource.Reference { + return &pbresource.Reference{ + Type: pbcatalog.ServiceType, + Tenancy: tenancy, + Name: name, + } + } + + cr1 := resourcetest.Resource(pbmesh.ComputedRoutesType, "cr1"). + WithTenancy(tenancy). + WithData(t, &pbmesh.ComputedRoutes{ + PortedConfigs: map[string]*pbmesh.ComputedPortRoutes{ + "http": { + Targets: map[string]*pbmesh.BackendTargetDetails{ + "opaque1": { + BackendRef: &pbmesh.BackendReference{Ref: newRef("aaa")}, + }, + }, + }, + }, + }). + Build() + + cr2 := resourcetest.Resource(pbmesh.ComputedRoutesType, "cr2"). + WithTenancy(tenancy). + WithData(t, &pbmesh.ComputedRoutes{ + PortedConfigs: map[string]*pbmesh.ComputedPortRoutes{ + "http": { + Targets: map[string]*pbmesh.BackendTargetDetails{ + "opaque1": { + BackendRef: &pbmesh.BackendReference{Ref: newRef("aaa")}, + }, + "opaque2": { + BackendRef: &pbmesh.BackendReference{Ref: newRef("bbb")}, + }, + }, + }, + "grpc": { + Targets: map[string]*pbmesh.BackendTargetDetails{ + "opaque2": { + BackendRef: &pbmesh.BackendReference{Ref: newRef("bbb")}, + }, + "opaque3": { + BackendRef: &pbmesh.BackendReference{Ref: newRef("ccc")}, + }, + }, + }, + }, + }). + Build() + + cases := map[string]testcase{ + "one": { + cr: resourcetest.MustDecode[*pbmesh.ComputedRoutes](t, cr1), + expect: []*pbresource.Reference{ + newRef("aaa"), + }, + }, + "two": { + cr: resourcetest.MustDecode[*pbmesh.ComputedRoutes](t, cr2), + expect: []*pbresource.Reference{ + newRef("aaa"), + newRef("bbb"), + newRef("ccc"), + }, + }, + } + + for name, tc := range cases { + t.Run(name, func(t *testing.T) { + run(t, tc) + }) + } +} diff --git a/internal/mesh/internal/types/computed_explicit_destinations.go b/internal/mesh/internal/types/computed_explicit_destinations.go index ac6bbe7779..48d6e1db81 100644 --- a/internal/mesh/internal/types/computed_explicit_destinations.go +++ b/internal/mesh/internal/types/computed_explicit_destinations.go @@ -8,6 +8,8 @@ import ( pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" ) +type DecodedComputedExplicitDestinations = resource.DecodedResource[*pbmesh.ComputedExplicitDestinations] + func RegisterComputedExplicitDestinations(r resource.Registry) { r.Register(resource.Registration{ Type: pbmesh.ComputedExplicitDestinationsType, diff --git a/internal/mesh/internal/types/computed_routes.go b/internal/mesh/internal/types/computed_routes.go index 86280b7856..d9d13b5566 100644 --- a/internal/mesh/internal/types/computed_routes.go +++ b/internal/mesh/internal/types/computed_routes.go @@ -136,12 +136,6 @@ func validateComputedRoutes(res *DecodedComputedRoutes) error { Wrapped: fmt.Errorf("field should be empty"), })) } - if target.ServiceEndpoints != nil { - merr = multierror.Append(merr, wrapTargetErr(resource.ErrInvalidField{ - Name: "service_endpoints", - Wrapped: fmt.Errorf("field should be empty"), - })) - } if len(target.IdentityRefs) > 0 { merr = multierror.Append(merr, wrapTargetErr(resource.ErrInvalidField{ Name: "identity_refs", diff --git a/internal/mesh/internal/types/computed_routes_test.go b/internal/mesh/internal/types/computed_routes_test.go index 7345387f75..c61d28378e 100644 --- a/internal/mesh/internal/types/computed_routes_test.go +++ b/internal/mesh/internal/types/computed_routes_test.go @@ -11,7 +11,6 @@ import ( "google.golang.org/protobuf/types/known/durationpb" "github.com/hashicorp/consul/internal/resource/resourcetest" - pbcatalog "github.com/hashicorp/consul/proto-public/pbcatalog/v2beta1" pbmesh "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1" "github.com/hashicorp/consul/proto-public/pbmesh/v2beta1/pbproxystate" "github.com/hashicorp/consul/proto-public/pbresource" @@ -149,25 +148,6 @@ func TestValidateComputedRoutes(t *testing.T) { }, expectErr: `invalid value of key "http" within ported_configs: invalid value of key "foo" within targets: invalid "service_endpoint_ref" field: field should be empty`, }, - "target/should not have service endpoints": { - routes: &pbmesh.ComputedRoutes{ - PortedConfigs: map[string]*pbmesh.ComputedPortRoutes{ - "http": { - Config: &pbmesh.ComputedPortRoutes_Tcp{ - Tcp: &pbmesh.ComputedTCPRoute{}, - }, - Targets: map[string]*pbmesh.BackendTargetDetails{ - "foo": { - Type: pbmesh.BackendTargetDetailsType_BACKEND_TARGET_DETAILS_TYPE_DIRECT, - MeshPort: "mesh", - ServiceEndpoints: &pbcatalog.ServiceEndpoints{}, - }, - }, - }, - }, - }, - expectErr: `invalid value of key "http" within ported_configs: invalid value of key "foo" within targets: invalid "service_endpoints" field: field should be empty`, - }, "target/should not have identity refs": { routes: &pbmesh.ComputedRoutes{ PortedConfigs: map[string]*pbmesh.ComputedPortRoutes{ diff --git a/proto-public/pbmesh/v2beta1/computed_routes.pb.go b/proto-public/pbmesh/v2beta1/computed_routes.pb.go index 61d757ad48..c90991d2e4 100644 --- a/proto-public/pbmesh/v2beta1/computed_routes.pb.go +++ b/proto-public/pbmesh/v2beta1/computed_routes.pb.go @@ -838,9 +838,6 @@ type BackendTargetDetails struct { DestinationConfig *DestinationConfig `protobuf:"bytes,5,opt,name=destination_config,json=destinationConfig,proto3" json:"destination_config,omitempty"` // ServiceEndpointsRef is not populated naturally and the field exists only for downstream consumers. ServiceEndpointsRef *pbproxystate.EndpointRef `protobuf:"bytes,24,opt,name=service_endpoints_ref,json=serviceEndpointsRef,proto3" json:"service_endpoints_ref,omitempty"` - // ServiceEndpoints is not populated naturally and the field exists only for - // downstream consumers. - ServiceEndpoints *v2beta1.ServiceEndpoints `protobuf:"bytes,22,opt,name=service_endpoints,json=serviceEndpoints,proto3" json:"service_endpoints,omitempty"` // IdentityRefs are not populated naturally and the field exists only for // downstream consumers. IdentityRefs []*pbresource.Reference `protobuf:"bytes,23,rep,name=identity_refs,json=identityRefs,proto3" json:"identity_refs,omitempty"` @@ -920,13 +917,6 @@ func (x *BackendTargetDetails) GetServiceEndpointsRef() *pbproxystate.EndpointRe return nil } -func (x *BackendTargetDetails) GetServiceEndpoints() *v2beta1.ServiceEndpoints { - if x != nil { - return x.ServiceEndpoints - } - return nil -} - func (x *BackendTargetDetails) GetIdentityRefs() []*pbresource.Reference { if x != nil { return x.IdentityRefs @@ -1066,112 +1056,152 @@ var file_pbmesh_v2beta1_computed_routes_proto_rawDesc = []byte{ 0x72, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x70, 0x62, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x1a, 0x29, 0x70, 0x62, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x2f, 0x76, 0x32, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x70, - 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x70, 0x62, 0x6d, - 0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x63, 0x6f, 0x6d, 0x6d, - 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x27, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, - 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x1a, 0x1f, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x1a, 0x1f, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, - 0x61, 0x31, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x2e, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x1a, 0x27, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x72, - 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x28, 0x70, 0x62, - 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x68, 0x74, 0x74, - 0x70, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x73, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2c, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, - 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x2f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x2e, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x70, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, - 0x74, 0x6f, 0x1a, 0x19, 0x70, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc7, 0x02, - 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, - 0x12, 0x67, 0x0a, 0x0e, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, - 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, - 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, - 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x50, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x70, 0x6f, 0x72, 0x74, - 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x4f, 0x0a, 0x10, 0x62, 0x6f, 0x75, - 0x6e, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, - 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, - 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0f, 0x62, 0x6f, 0x75, 0x6e, 0x64, - 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x1a, 0x73, 0x0a, 0x12, 0x50, 0x6f, - 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, - 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, - 0x65, 0x79, 0x12, 0x47, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x31, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, - 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, - 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x3a, - 0x06, 0xa2, 0x93, 0x04, 0x02, 0x08, 0x03, 0x22, 0x87, 0x05, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x70, - 0x75, 0x74, 0x65, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x46, - 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, - 0x70, 0x75, 0x74, 0x65, 0x64, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x00, - 0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x12, 0x46, 0x0a, 0x04, 0x67, 0x72, 0x70, 0x63, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, - 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x47, 0x52, 0x50, - 0x43, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x67, 0x72, 0x70, 0x63, 0x12, 0x43, - 0x0a, 0x03, 0x74, 0x63, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x68, 0x61, - 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, - 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, - 0x75, 0x74, 0x65, 0x64, 0x54, 0x43, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x00, 0x52, 0x03, - 0x74, 0x63, 0x70, 0x12, 0x30, 0x0a, 0x14, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x5f, 0x64, 0x65, 0x66, - 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x12, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4d, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, - 0x72, 0x65, 0x66, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x68, 0x61, 0x73, 0x68, - 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, - 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x61, 0x72, 0x65, 0x6e, 0x74, - 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x09, 0x70, 0x61, 0x72, 0x65, 0x6e, - 0x74, 0x52, 0x65, 0x66, 0x12, 0x46, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, - 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, - 0x67, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x63, - 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x12, 0x58, 0x0a, 0x07, - 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3e, 0x2e, + 0x1a, 0x1b, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2f, 0x63, 0x6f, 0x6d, 0x6d, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x27, 0x70, + 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x64, 0x65, + 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x70, 0x6f, 0x6c, 0x69, 0x63, 0x79, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, + 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x67, 0x72, 0x70, 0x63, 0x5f, 0x72, 0x6f, 0x75, 0x74, + 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1f, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, + 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x6f, 0x75, + 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x27, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, + 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x6f, + 0x75, 0x74, 0x65, 0x5f, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x1a, 0x28, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2f, 0x68, 0x74, 0x74, 0x70, 0x5f, 0x72, 0x6f, 0x75, 0x74, 0x65, 0x5f, 0x74, 0x69, 0x6d, + 0x65, 0x6f, 0x75, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x2c, 0x70, 0x62, 0x6d, + 0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2f, 0x70, 0x62, 0x70, 0x72, + 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, + 0x63, 0x65, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x70, 0x62, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, + 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x19, 0x70, 0x62, 0x72, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x22, 0xc7, 0x02, 0x0a, 0x0e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x52, + 0x6f, 0x75, 0x74, 0x65, 0x73, 0x12, 0x67, 0x0a, 0x0e, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x5f, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x40, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, - 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, - 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x07, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x1a, 0x6f, 0x0a, 0x0c, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x49, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 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, 0x6d, 0x65, 0x73, 0x68, 0x2e, - 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x52, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x08, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, - 0x67, 0x22, 0x65, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x48, 0x54, 0x54, - 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x4a, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, + 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x50, 0x6f, 0x72, + 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, + 0x0d, 0x70, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, 0x12, 0x4f, + 0x0a, 0x10, 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0f, + 0x62, 0x6f, 0x75, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x1a, + 0x73, 0x0a, 0x12, 0x50, 0x6f, 0x72, 0x74, 0x65, 0x64, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x73, + 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x47, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x31, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, + 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x50, + 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x3a, 0x02, 0x38, 0x01, 0x3a, 0x06, 0xa2, 0x93, 0x04, 0x02, 0x08, 0x03, 0x22, 0x87, 0x05, 0x0a, + 0x12, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x73, 0x12, 0x46, 0x0a, 0x04, 0x68, 0x74, 0x74, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, + 0x75, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x68, 0x74, 0x74, 0x70, 0x12, 0x46, 0x0a, 0x04, 0x67, + 0x72, 0x70, 0x63, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, + 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, + 0x65, 0x64, 0x47, 0x52, 0x50, 0x43, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x67, + 0x72, 0x70, 0x63, 0x12, 0x43, 0x0a, 0x03, 0x74, 0x63, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x2f, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, + 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x54, 0x43, 0x50, 0x52, 0x6f, 0x75, 0x74, + 0x65, 0x48, 0x00, 0x52, 0x03, 0x74, 0x63, 0x70, 0x12, 0x30, 0x0a, 0x14, 0x75, 0x73, 0x69, 0x6e, + 0x67, 0x5f, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x44, 0x65, 0x66, + 0x61, 0x75, 0x6c, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x4d, 0x0a, 0x0a, 0x70, 0x61, + 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2e, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, + 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x09, + 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x52, 0x65, 0x66, 0x12, 0x46, 0x0a, 0x08, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2a, 0x2e, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x63, + 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x50, + 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, 0x6c, 0x52, 0x08, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x63, 0x6f, + 0x6c, 0x12, 0x58, 0x0a, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x18, 0x07, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x3e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x50, 0x6f, 0x72, 0x74, 0x52, + 0x6f, 0x75, 0x74, 0x65, 0x73, 0x2e, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x07, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x1a, 0x6f, 0x0a, 0x0c, 0x54, + 0x61, 0x72, 0x67, 0x65, 0x74, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, + 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x49, 0x0a, + 0x05, 0x76, 0x61, 0x6c, 0x75, 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, + 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x42, 0x61, 0x63, + 0x6b, 0x65, 0x6e, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, + 0x73, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x08, 0x0a, 0x06, + 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x65, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, + 0x65, 0x64, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x4a, 0x0a, 0x05, 0x72, + 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x68, 0x61, 0x73, + 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, + 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, + 0x74, 0x65, 0x64, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, + 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x9d, 0x03, + 0x0a, 0x15, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, + 0x75, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x47, 0x0a, 0x07, 0x6d, 0x61, 0x74, 0x63, 0x68, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, + 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x07, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, + 0x12, 0x48, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x2e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, + 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, + 0x31, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x58, 0x0a, 0x0c, 0x62, 0x61, + 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, + 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, + 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x48, 0x54, 0x54, 0x50, 0x42, 0x61, 0x63, + 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x52, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, + 0x52, 0x65, 0x66, 0x73, 0x12, 0x4c, 0x0a, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x73, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, + 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x73, 0x52, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, + 0x74, 0x73, 0x12, 0x49, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, + 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, + 0x74, 0x61, 0x31, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x74, + 0x72, 0x69, 0x65, 0x73, 0x52, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0xa1, 0x01, + 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x48, 0x54, 0x54, 0x50, 0x42, 0x61, + 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x61, 0x63, 0x6b, + 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0d, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, + 0x16, 0x0a, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, + 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x48, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, + 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, + 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, + 0x74, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, + 0x73, 0x22, 0x65, 0x0a, 0x11, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x47, 0x52, 0x50, + 0x43, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x4a, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x48, 0x54, - 0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x47, 0x52, + 0x50, 0x43, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x22, 0x9d, 0x03, 0x0a, 0x15, 0x43, 0x6f, 0x6d, - 0x70, 0x75, 0x74, 0x65, 0x64, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x75, + 0x70, 0x75, 0x74, 0x65, 0x64, 0x47, 0x52, 0x50, 0x43, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x47, 0x0a, 0x07, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x4d, 0x61, 0x74, + 0x74, 0x61, 0x31, 0x2e, 0x47, 0x52, 0x50, 0x43, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x07, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x48, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x48, 0x54, 0x54, - 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x07, 0x66, 0x69, + 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x52, 0x50, + 0x43, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x12, 0x58, 0x0a, 0x0c, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, - 0x75, 0x74, 0x65, 0x64, 0x48, 0x54, 0x54, 0x50, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, + 0x75, 0x74, 0x65, 0x64, 0x47, 0x52, 0x50, 0x43, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x52, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x73, 0x12, 0x4c, 0x0a, 0x08, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, @@ -1183,7 +1213,7 @@ var file_pbmesh_v2beta1_computed_routes_proto_rawDesc = []byte{ 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x07, 0x72, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x22, 0xa1, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6d, - 0x70, 0x75, 0x74, 0x65, 0x64, 0x48, 0x54, 0x54, 0x50, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, + 0x70, 0x75, 0x74, 0x65, 0x64, 0x47, 0x52, 0x50, 0x43, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x77, 0x65, @@ -1191,161 +1221,112 @@ var file_pbmesh_v2beta1_computed_routes_proto_rawDesc = []byte{ 0x68, 0x74, 0x12, 0x48, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, - 0x74, 0x61, 0x31, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x69, 0x6c, - 0x74, 0x65, 0x72, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22, 0x65, 0x0a, 0x11, - 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x47, 0x52, 0x50, 0x43, 0x52, 0x6f, 0x75, 0x74, - 0x65, 0x12, 0x4a, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, - 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x47, 0x52, 0x50, 0x43, 0x52, 0x6f, 0x75, - 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x4a, 0x04, 0x08, - 0x01, 0x10, 0x02, 0x22, 0x9d, 0x03, 0x0a, 0x15, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, - 0x47, 0x52, 0x50, 0x43, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x47, 0x0a, - 0x07, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2d, - 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, - 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, - 0x52, 0x50, 0x43, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x52, 0x07, 0x6d, - 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x12, 0x48, 0x0a, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, - 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, - 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, 0x52, 0x50, 0x43, 0x52, 0x6f, 0x75, 0x74, - 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, - 0x12, 0x58, 0x0a, 0x0c, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x73, - 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, - 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x47, - 0x52, 0x50, 0x43, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x52, 0x0b, 0x62, - 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x73, 0x12, 0x4c, 0x0a, 0x08, 0x74, 0x69, - 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x48, 0x54, 0x54, - 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x73, 0x52, 0x08, - 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x73, 0x12, 0x49, 0x0a, 0x07, 0x72, 0x65, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x68, 0x61, 0x73, 0x68, + 0x74, 0x61, 0x31, 0x2e, 0x47, 0x52, 0x50, 0x43, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x69, 0x6c, + 0x74, 0x65, 0x72, 0x52, 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22, 0x5d, 0x0a, 0x10, + 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x54, 0x43, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x12, 0x49, 0x0a, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x33, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, + 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x54, 0x43, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, + 0x52, 0x75, 0x6c, 0x65, 0x52, 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x14, 0x43, + 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x54, 0x43, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, + 0x75, 0x6c, 0x65, 0x12, 0x57, 0x0a, 0x0c, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x72, + 0x65, 0x66, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, - 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x48, 0x54, 0x54, 0x50, 0x52, 0x6f, - 0x75, 0x74, 0x65, 0x52, 0x65, 0x74, 0x72, 0x69, 0x65, 0x73, 0x52, 0x07, 0x72, 0x65, 0x74, 0x72, - 0x69, 0x65, 0x73, 0x22, 0xa1, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, - 0x47, 0x52, 0x50, 0x43, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x12, 0x25, - 0x0a, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x54, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x12, 0x48, 0x0a, - 0x07, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2e, - 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, - 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x47, - 0x52, 0x50, 0x43, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x52, 0x07, - 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22, 0x5d, 0x0a, 0x10, 0x43, 0x6f, 0x6d, 0x70, 0x75, - 0x74, 0x65, 0x64, 0x54, 0x43, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x12, 0x49, 0x0a, 0x05, 0x72, - 0x75, 0x6c, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x33, 0x2e, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, - 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, - 0x74, 0x65, 0x64, 0x54, 0x43, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x52, - 0x05, 0x72, 0x75, 0x6c, 0x65, 0x73, 0x22, 0x6f, 0x0a, 0x14, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, - 0x65, 0x64, 0x54, 0x43, 0x50, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x52, 0x75, 0x6c, 0x65, 0x12, 0x57, - 0x0a, 0x0c, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0b, 0x32, 0x34, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, - 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x54, 0x43, 0x50, - 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x52, 0x0b, 0x62, 0x61, 0x63, 0x6b, - 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x73, 0x22, 0x56, 0x0a, 0x15, 0x43, 0x6f, 0x6d, 0x70, 0x75, - 0x74, 0x65, 0x64, 0x54, 0x43, 0x50, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, - 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x72, 0x67, - 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, - 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, - 0xb2, 0x05, 0x0a, 0x14, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, - 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x4b, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, - 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, - 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x54, 0x61, - 0x72, 0x67, 0x65, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x54, 0x79, 0x70, 0x65, 0x52, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, - 0x5f, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2f, 0x2e, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, - 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x65, - 0x6e, 0x64, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0a, 0x62, 0x61, 0x63, - 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x65, 0x73, 0x68, 0x5f, - 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x65, 0x73, 0x68, - 0x50, 0x6f, 0x72, 0x74, 0x12, 0x5e, 0x0a, 0x0f, 0x66, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, - 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x35, 0x2e, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, - 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5f, 0x0a, 0x12, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, - 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, - 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, - 0x69, 0x67, 0x52, 0x11, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, - 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x6b, 0x0a, 0x15, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x18, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, - 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, - 0x65, 0x74, 0x61, 0x31, 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, 0x79, 0x73, 0x74, 0x61, 0x74, - 0x65, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, 0x65, 0x66, 0x52, 0x13, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x52, - 0x65, 0x66, 0x12, 0x5f, 0x0a, 0x11, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x6e, - 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x18, 0x16, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x32, 0x2e, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2e, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, - 0x73, 0x52, 0x10, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, - 0x6e, 0x74, 0x73, 0x12, 0x49, 0x0a, 0x0d, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, - 0x72, 0x65, 0x66, 0x73, 0x18, 0x17, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, 0x2e, 0x68, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x72, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, - 0x52, 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, 0x66, 0x73, 0x4a, 0x04, - 0x08, 0x06, 0x10, 0x15, 0x22, 0xfd, 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, - 0x64, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, - 0x5e, 0x0a, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, - 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, + 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, + 0x65, 0x64, 0x54, 0x43, 0x50, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x52, + 0x0b, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x73, 0x22, 0x56, 0x0a, 0x15, + 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x54, 0x43, 0x50, 0x42, 0x61, 0x63, 0x6b, 0x65, + 0x6e, 0x64, 0x52, 0x65, 0x66, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, + 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x62, + 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x16, 0x0a, 0x06, + 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x06, 0x77, 0x65, + 0x69, 0x67, 0x68, 0x74, 0x22, 0xd7, 0x04, 0x0a, 0x14, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, + 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x12, 0x4b, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x37, 0x2e, 0x68, 0x61, + 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, + 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, + 0x65, 0x6e, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, + 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x50, 0x0a, 0x0b, 0x62, 0x61, + 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x72, 0x65, 0x66, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x2f, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, + 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, + 0x52, 0x0a, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x52, 0x65, 0x66, 0x12, 0x1b, 0x0a, 0x09, + 0x6d, 0x65, 0x73, 0x68, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x08, 0x6d, 0x65, 0x73, 0x68, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x5e, 0x0a, 0x0f, 0x66, 0x61, 0x69, + 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x35, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, + 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, + 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x6f, + 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x0e, 0x66, 0x61, 0x69, 0x6c, 0x6f, + 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5f, 0x0a, 0x12, 0x64, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x30, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, - 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x46, 0x61, - 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x0c, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, - 0x42, 0x0a, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2e, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x67, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, - 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, - 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x25, 0x0a, - 0x0e, 0x73, 0x61, 0x6d, 0x65, 0x6e, 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x61, 0x6d, 0x65, 0x6e, 0x65, 0x73, 0x73, 0x47, - 0x72, 0x6f, 0x75, 0x70, 0x22, 0x44, 0x0a, 0x1b, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, - 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x74, - 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x62, 0x61, 0x63, - 0x6b, 0x65, 0x6e, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x2a, 0x99, 0x01, 0x0a, 0x18, 0x42, - 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x65, 0x74, 0x61, - 0x69, 0x6c, 0x73, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2b, 0x0a, 0x27, 0x42, 0x41, 0x43, 0x4b, 0x45, - 0x4e, 0x44, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, - 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, - 0x45, 0x44, 0x10, 0x00, 0x12, 0x26, 0x0a, 0x22, 0x42, 0x41, 0x43, 0x4b, 0x45, 0x4e, 0x44, 0x5f, - 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x5f, 0x54, - 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x10, 0x01, 0x12, 0x28, 0x0a, 0x24, - 0x42, 0x41, 0x43, 0x4b, 0x45, 0x4e, 0x44, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x5f, 0x44, - 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x44, 0x49, - 0x52, 0x45, 0x43, 0x54, 0x10, 0x02, 0x42, 0x94, 0x02, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x68, - 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, - 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x13, 0x43, 0x6f, - 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, - 0x6f, 0x50, 0x01, 0x5a, 0x43, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, - 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, - 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x6d, 0x65, 0x73, - 0x68, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xa2, 0x02, 0x03, 0x48, 0x43, 0x4d, 0xaa, 0x02, - 0x1d, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, - 0x6c, 0x2e, 0x4d, 0x65, 0x73, 0x68, 0x2e, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, - 0x1d, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, - 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, - 0x29, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, - 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, 0x5c, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, - 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x20, 0x48, 0x61, 0x73, - 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, - 0x4d, 0x65, 0x73, 0x68, 0x3a, 0x3a, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x11, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x6b, 0x0a, 0x15, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x5f, 0x65, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x73, 0x5f, + 0x72, 0x65, 0x66, 0x18, 0x18, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x37, 0x2e, 0x68, 0x61, 0x73, 0x68, + 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, + 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x70, 0x62, 0x70, 0x72, 0x6f, 0x78, + 0x79, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2e, 0x45, 0x6e, 0x64, 0x70, 0x6f, 0x69, 0x6e, 0x74, 0x52, + 0x65, 0x66, 0x52, 0x13, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x45, 0x6e, 0x64, 0x70, 0x6f, + 0x69, 0x6e, 0x74, 0x73, 0x52, 0x65, 0x66, 0x12, 0x49, 0x0a, 0x0d, 0x69, 0x64, 0x65, 0x6e, 0x74, + 0x69, 0x74, 0x79, 0x5f, 0x72, 0x65, 0x66, 0x73, 0x18, 0x17, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x24, + 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, + 0x6c, 0x2e, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x52, 0x65, 0x66, 0x65, 0x72, + 0x65, 0x6e, 0x63, 0x65, 0x52, 0x0c, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x52, 0x65, + 0x66, 0x73, 0x4a, 0x04, 0x08, 0x06, 0x10, 0x15, 0x4a, 0x04, 0x08, 0x16, 0x10, 0x17, 0x22, 0xfd, + 0x01, 0x0a, 0x16, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x6f, + 0x76, 0x65, 0x72, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x5e, 0x0a, 0x0c, 0x64, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x3a, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, + 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, + 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, 0x65, 0x72, + 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0c, 0x64, 0x65, 0x73, + 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x42, 0x0a, 0x04, 0x6d, 0x6f, 0x64, + 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x2e, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x63, 0x61, 0x74, 0x61, 0x6c, + 0x6f, 0x67, 0x2e, 0x76, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x6f, + 0x76, 0x65, 0x72, 0x4d, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x6d, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, + 0x07, 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, + 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x61, 0x6d, 0x65, 0x6e, + 0x65, 0x73, 0x73, 0x5f, 0x67, 0x72, 0x6f, 0x75, 0x70, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0d, 0x73, 0x61, 0x6d, 0x65, 0x6e, 0x65, 0x73, 0x73, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x22, 0x44, + 0x0a, 0x1b, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, 0x46, 0x61, 0x69, 0x6c, 0x6f, 0x76, + 0x65, 0x72, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, + 0x0e, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x61, 0x72, 0x67, 0x65, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x62, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, 0x54, 0x61, + 0x72, 0x67, 0x65, 0x74, 0x2a, 0x99, 0x01, 0x0a, 0x18, 0x42, 0x61, 0x63, 0x6b, 0x65, 0x6e, 0x64, + 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x44, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x54, 0x79, 0x70, + 0x65, 0x12, 0x2b, 0x0a, 0x27, 0x42, 0x41, 0x43, 0x4b, 0x45, 0x4e, 0x44, 0x5f, 0x54, 0x41, 0x52, + 0x47, 0x45, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, + 0x5f, 0x55, 0x4e, 0x53, 0x50, 0x45, 0x43, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x00, 0x12, 0x26, + 0x0a, 0x22, 0x42, 0x41, 0x43, 0x4b, 0x45, 0x4e, 0x44, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, + 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x44, 0x49, + 0x52, 0x45, 0x43, 0x54, 0x10, 0x01, 0x12, 0x28, 0x0a, 0x24, 0x42, 0x41, 0x43, 0x4b, 0x45, 0x4e, + 0x44, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x5f, 0x44, 0x45, 0x54, 0x41, 0x49, 0x4c, 0x53, + 0x5f, 0x54, 0x59, 0x50, 0x45, 0x5f, 0x49, 0x4e, 0x44, 0x49, 0x52, 0x45, 0x43, 0x54, 0x10, 0x02, + 0x42, 0x94, 0x02, 0x0a, 0x21, 0x63, 0x6f, 0x6d, 0x2e, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, + 0x72, 0x70, 0x2e, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x6d, 0x65, 0x73, 0x68, 0x2e, 0x76, + 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x42, 0x13, 0x43, 0x6f, 0x6d, 0x70, 0x75, 0x74, 0x65, 0x64, + 0x52, 0x6f, 0x75, 0x74, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x43, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2d, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x2f, 0x70, 0x62, 0x6d, 0x65, 0x73, 0x68, 0x2f, 0x76, + 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x3b, 0x6d, 0x65, 0x73, 0x68, 0x76, 0x32, 0x62, 0x65, 0x74, + 0x61, 0x31, 0xa2, 0x02, 0x03, 0x48, 0x43, 0x4d, 0xaa, 0x02, 0x1d, 0x48, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x2e, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x2e, 0x4d, 0x65, 0x73, 0x68, + 0x2e, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xca, 0x02, 0x1d, 0x48, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, + 0x5c, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0xe2, 0x02, 0x29, 0x48, 0x61, 0x73, 0x68, 0x69, + 0x63, 0x6f, 0x72, 0x70, 0x5c, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x5c, 0x4d, 0x65, 0x73, 0x68, + 0x5c, 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x20, 0x48, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, + 0x3a, 0x3a, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6c, 0x3a, 0x3a, 0x4d, 0x65, 0x73, 0x68, 0x3a, 0x3a, + 0x56, 0x32, 0x62, 0x65, 0x74, 0x61, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1392,8 +1373,7 @@ var file_pbmesh_v2beta1_computed_routes_proto_goTypes = []interface{}{ (*BackendReference)(nil), // 26: hashicorp.consul.mesh.v2beta1.BackendReference (*DestinationConfig)(nil), // 27: hashicorp.consul.mesh.v2beta1.DestinationConfig (*pbproxystate.EndpointRef)(nil), // 28: hashicorp.consul.mesh.v2beta1.pbproxystate.EndpointRef - (*v2beta1.ServiceEndpoints)(nil), // 29: hashicorp.consul.catalog.v2beta1.ServiceEndpoints - (v2beta1.FailoverMode)(0), // 30: hashicorp.consul.catalog.v2beta1.FailoverMode + (v2beta1.FailoverMode)(0), // 29: hashicorp.consul.catalog.v2beta1.FailoverMode } var file_pbmesh_v2beta1_computed_routes_proto_depIdxs = []int32{ 15, // 0: hashicorp.consul.mesh.v2beta1.ComputedRoutes.ported_configs:type_name -> hashicorp.consul.mesh.v2beta1.ComputedRoutes.PortedConfigsEntry @@ -1425,17 +1405,16 @@ var file_pbmesh_v2beta1_computed_routes_proto_depIdxs = []int32{ 13, // 26: hashicorp.consul.mesh.v2beta1.BackendTargetDetails.failover_config:type_name -> hashicorp.consul.mesh.v2beta1.ComputedFailoverConfig 27, // 27: hashicorp.consul.mesh.v2beta1.BackendTargetDetails.destination_config:type_name -> hashicorp.consul.mesh.v2beta1.DestinationConfig 28, // 28: hashicorp.consul.mesh.v2beta1.BackendTargetDetails.service_endpoints_ref:type_name -> hashicorp.consul.mesh.v2beta1.pbproxystate.EndpointRef - 29, // 29: hashicorp.consul.mesh.v2beta1.BackendTargetDetails.service_endpoints:type_name -> hashicorp.consul.catalog.v2beta1.ServiceEndpoints - 17, // 30: hashicorp.consul.mesh.v2beta1.BackendTargetDetails.identity_refs:type_name -> hashicorp.consul.resource.Reference - 14, // 31: hashicorp.consul.mesh.v2beta1.ComputedFailoverConfig.destinations:type_name -> hashicorp.consul.mesh.v2beta1.ComputedFailoverDestination - 30, // 32: hashicorp.consul.mesh.v2beta1.ComputedFailoverConfig.mode:type_name -> hashicorp.consul.catalog.v2beta1.FailoverMode - 2, // 33: hashicorp.consul.mesh.v2beta1.ComputedRoutes.PortedConfigsEntry.value:type_name -> hashicorp.consul.mesh.v2beta1.ComputedPortRoutes - 12, // 34: hashicorp.consul.mesh.v2beta1.ComputedPortRoutes.TargetsEntry.value:type_name -> hashicorp.consul.mesh.v2beta1.BackendTargetDetails - 35, // [35:35] is the sub-list for method output_type - 35, // [35:35] is the sub-list for method input_type - 35, // [35:35] is the sub-list for extension type_name - 35, // [35:35] is the sub-list for extension extendee - 0, // [0:35] is the sub-list for field type_name + 17, // 29: hashicorp.consul.mesh.v2beta1.BackendTargetDetails.identity_refs:type_name -> hashicorp.consul.resource.Reference + 14, // 30: hashicorp.consul.mesh.v2beta1.ComputedFailoverConfig.destinations:type_name -> hashicorp.consul.mesh.v2beta1.ComputedFailoverDestination + 29, // 31: hashicorp.consul.mesh.v2beta1.ComputedFailoverConfig.mode:type_name -> hashicorp.consul.catalog.v2beta1.FailoverMode + 2, // 32: hashicorp.consul.mesh.v2beta1.ComputedRoutes.PortedConfigsEntry.value:type_name -> hashicorp.consul.mesh.v2beta1.ComputedPortRoutes + 12, // 33: hashicorp.consul.mesh.v2beta1.ComputedPortRoutes.TargetsEntry.value:type_name -> hashicorp.consul.mesh.v2beta1.BackendTargetDetails + 34, // [34:34] is the sub-list for method output_type + 34, // [34:34] is the sub-list for method input_type + 34, // [34:34] is the sub-list for extension type_name + 34, // [34:34] is the sub-list for extension extendee + 0, // [0:34] is the sub-list for field type_name } func init() { file_pbmesh_v2beta1_computed_routes_proto_init() } diff --git a/proto-public/pbmesh/v2beta1/computed_routes.proto b/proto-public/pbmesh/v2beta1/computed_routes.proto index fdf7619601..3bf06c4c84 100644 --- a/proto-public/pbmesh/v2beta1/computed_routes.proto +++ b/proto-public/pbmesh/v2beta1/computed_routes.proto @@ -7,7 +7,6 @@ package hashicorp.consul.mesh.v2beta1; import "pbcatalog/v2beta1/failover_policy.proto"; import "pbcatalog/v2beta1/protocol.proto"; -import "pbcatalog/v2beta1/service_endpoints.proto"; import "pbmesh/v2beta1/common.proto"; import "pbmesh/v2beta1/destination_policy.proto"; import "pbmesh/v2beta1/grpc_route.proto"; @@ -139,9 +138,7 @@ message BackendTargetDetails { // ServiceEndpointsRef is not populated naturally and the field exists only for downstream consumers. pbproxystate.EndpointRef service_endpoints_ref = 24; - // ServiceEndpoints is not populated naturally and the field exists only for - // downstream consumers. - hashicorp.consul.catalog.v2beta1.ServiceEndpoints service_endpoints = 22; + reserved 22; // formerly ServiceEndpoints, never marshaled // IdentityRefs are not populated naturally and the field exists only for // downstream consumers.