mesh: use ComputedImplicitDestinations resource in the sidecar controller (#20553)

Wire the ComputedImplicitDestinations resource into the sidecar controller, replacing the inline version already present.

Also:

- Rewrite the controller to use the controller cache
- Rewrite it to no longer depend on ServiceEndpoints
- Remove the fetcher and (local) cache abstraction
This commit is contained in:
R.B. Boyer 2024-02-12 14:10:33 -06:00 committed by GitHub
parent 7e8f2e5f08
commit 671c436415
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 1568 additions and 2455 deletions

View File

@ -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
}

View File

@ -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())

View File

@ -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)

View File

@ -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,
}
}

View File

@ -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,
}

View File

@ -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,

View File

@ -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 (

View File

@ -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)
})
}
}

View File

@ -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 {

View File

@ -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())

View File

@ -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
}
}),

View File

@ -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}
}
}),

View File

@ -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
}

View File

@ -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
}

View File

@ -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 <align> PST
ComputedDestinations <align> PST(==Workload)
ComputedDestinations <contain> Service(destinations)
ComputedProxyConfiguration <align> PST(==Workload)
ComputedRoutes <align> Service(upstream)
ComputedRoutes <contain> Service(disco)
ComputedTrafficPermissions <align> WorkloadIdentity
Workload <contain> WorkloadIdentity
Workload <align> PST
ComputedExplicitDestinations <align> PST(==Workload)
ComputedExplicitDestinations <contain> Service(destinations)
ComputedProxyConfiguration <align> PST(==Workload)
ComputedRoutes <align> Service(upstream)
ComputedRoutes <contain> Service(disco)
ComputedTrafficPermissions <align> WorkloadIdentity
Workload <contain> WorkloadIdentity
ComputedImplicitDestinations <align> WorkloadIdentity
ComputedImplicitDestinations <contain> 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.
<EXPLICIT-for-each>
<EXPLICIT_OR_IMPLICIT-for-each>
fetcher: read Service(Destination)
fetcher: read ComputedRoutes
<TARGET-for-each>
fetcher: read ServiceEndpoints
fetcher: read Service
</TARGET-for-each>
</EXPLICIT-for-each>
<IMPLICIT>
fetcher: list ALL ComputedRoutes
<CR-for-each>
fetcher: read Service(upstream)
<TARGET-for-each>
fetcher: read ServiceEndpoints
</TARGET-for-each>
</CR-for-each>
</IMPLICIT>
</EXPLICIT_OR_IMPLICIT-for-each>
*/
/*
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,
}
}

View File

@ -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)
}

View File

@ -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
}

View File

@ -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)
}

View File

@ -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))
}
}

View File

@ -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
}

View File

@ -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))
}
}

View File

@ -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
}

View File

@ -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)
})
}
}

View File

@ -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,

View File

@ -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",

View File

@ -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{

View File

@ -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() }

View File

@ -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.