diff --git a/internal/mesh/internal/controllers/gatewayproxy/builder/builder.go b/internal/mesh/internal/controllers/gatewayproxy/builder/builder.go index 36b088952f..cac48d0d6e 100644 --- a/internal/mesh/internal/controllers/gatewayproxy/builder/builder.go +++ b/internal/mesh/internal/controllers/gatewayproxy/builder/builder.go @@ -6,8 +6,10 @@ package builder import ( "context" "fmt" + "time" "github.com/hashicorp/go-hclog" + "google.golang.org/protobuf/types/known/durationpb" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/envoyextensions/xdscommon" @@ -22,16 +24,18 @@ import ( "github.com/hashicorp/consul/proto-public/pbresource" ) +const nullRouteClusterName = "null_route_cluster" + type proxyStateTemplateBuilder struct { workload *types.DecodedWorkload dataFetcher *fetcher.Fetcher dc string - exportedServices *types.DecodedComputedExportedServices + exportedServices []*pbmulticluster.ComputedExportedService logger hclog.Logger trustDomain string } -func NewProxyStateTemplateBuilder(workload *types.DecodedWorkload, exportedServices *types.DecodedComputedExportedServices, logger hclog.Logger, dataFetcher *fetcher.Fetcher, dc, trustDomain string) *proxyStateTemplateBuilder { +func NewProxyStateTemplateBuilder(workload *types.DecodedWorkload, exportedServices []*pbmulticluster.ComputedExportedService, logger hclog.Logger, dataFetcher *fetcher.Fetcher, dc, trustDomain string) *proxyStateTemplateBuilder { return &proxyStateTemplateBuilder{ workload: workload, dataFetcher: dataFetcher, @@ -100,7 +104,7 @@ func (b *proxyStateTemplateBuilder) buildListener(address *pbcatalog.WorkloadAdd L4: &pbproxystate.L4Destination{ Destination: &pbproxystate.L4Destination_Cluster{ Cluster: &pbproxystate.DestinationCluster{ - Name: "", + Name: nullRouteClusterName, }, }, StatPrefix: "prefix", @@ -117,11 +121,7 @@ func (b *proxyStateTemplateBuilder) buildListener(address *pbcatalog.WorkloadAdd func (b *proxyStateTemplateBuilder) routers() []*pbproxystate.Router { var routers []*pbproxystate.Router - if b.exportedServices == nil { - return routers - } - - for _, exportedService := range b.exportedServices.Data.Services { + for _, exportedService := range b.exportedServices { serviceID := resource.IDFromReference(exportedService.TargetRef) service, err := b.dataFetcher.FetchService(context.Background(), serviceID) if err != nil { @@ -160,11 +160,7 @@ func (b *proxyStateTemplateBuilder) routers() []*pbproxystate.Router { func (b *proxyStateTemplateBuilder) clusters() map[string]*pbproxystate.Cluster { clusters := map[string]*pbproxystate.Cluster{} - if b.exportedServices == nil { - return clusters - } - - for _, exportedService := range b.exportedServices.Data.Services { + for _, exportedService := range b.exportedServices { serviceID := resource.IDFromReference(exportedService.TargetRef) service, err := b.dataFetcher.FetchService(context.Background(), serviceID) if err != nil { @@ -192,6 +188,23 @@ func (b *proxyStateTemplateBuilder) clusters() map[string]*pbproxystate.Cluster } } + // Add null route cluster for any unmatched traffic + clusters[nullRouteClusterName] = &pbproxystate.Cluster{ + Name: nullRouteClusterName, + Group: &pbproxystate.Cluster_EndpointGroup{ + EndpointGroup: &pbproxystate.EndpointGroup{ + Group: &pbproxystate.EndpointGroup_Static{ + Static: &pbproxystate.StaticEndpointGroup{ + Config: &pbproxystate.StaticEndpointGroupConfig{ + ConnectTimeout: durationpb.New(10 * time.Second), + }, + }, + }, + }, + }, + Protocol: pbproxystate.Protocol_PROTOCOL_TCP, + } + return clusters } @@ -219,11 +232,7 @@ func (b *proxyStateTemplateBuilder) Build() *meshv2beta1.ProxyStateTemplate { func (b *proxyStateTemplateBuilder) requiredEndpoints() map[string]*pbproxystate.EndpointRef { requiredEndpoints := make(map[string]*pbproxystate.EndpointRef) - if b.exportedServices == nil { - return requiredEndpoints - } - - for _, exportedService := range b.exportedServices.Data.Services { + for _, exportedService := range b.exportedServices { serviceID := resource.IDFromReference(exportedService.TargetRef) service, err := b.dataFetcher.FetchService(context.Background(), serviceID) if err != nil { diff --git a/internal/mesh/internal/controllers/gatewayproxy/builder/builder_test.go b/internal/mesh/internal/controllers/gatewayproxy/builder/builder_test.go index 1828cc1043..357813b1cd 100644 --- a/internal/mesh/internal/controllers/gatewayproxy/builder/builder_test.go +++ b/internal/mesh/internal/controllers/gatewayproxy/builder/builder_test.go @@ -7,9 +7,11 @@ import ( "context" "fmt" "testing" + "time" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" + "google.golang.org/protobuf/types/known/durationpb" "github.com/hashicorp/consul/agent/connect" svctest "github.com/hashicorp/consul/agent/grpc-external/services/resource/testing" @@ -197,7 +199,7 @@ func (suite *proxyStateTemplateBuilderSuite) TestProxyStateTemplateBuilder_Build "without address ports": suite.workloadWithOutAddressPorts, } { testutil.RunStep(suite.T(), name, func(t *testing.T) { - builder := NewProxyStateTemplateBuilder(workload, suite.exportedServicesPeerData, logger, f, dc, trustDomain) + builder := NewProxyStateTemplateBuilder(workload, suite.exportedServicesPeerData.Data.Services, logger, f, dc, trustDomain) expectedProxyStateTemplate := &pbmesh.ProxyStateTemplate{ ProxyState: &pbmesh.ProxyState{ Identity: &pbresource.Reference{ @@ -223,7 +225,7 @@ func (suite *proxyStateTemplateBuilderSuite) TestProxyStateTemplateBuilder_Build L4: &pbproxystate.L4Destination{ Destination: &pbproxystate.L4Destination_Cluster{ Cluster: &pbproxystate.DestinationCluster{ - Name: "", + Name: nullRouteClusterName, }, }, StatPrefix: "prefix", @@ -267,6 +269,21 @@ func (suite *proxyStateTemplateBuilderSuite) TestProxyStateTemplateBuilder_Build }, }, Clusters: map[string]*pbproxystate.Cluster{ + nullRouteClusterName: { + Name: nullRouteClusterName, + Group: &pbproxystate.Cluster_EndpointGroup{ + EndpointGroup: &pbproxystate.EndpointGroup{ + Group: &pbproxystate.EndpointGroup_Static{ + Static: &pbproxystate.StaticEndpointGroup{ + Config: &pbproxystate.StaticEndpointGroupConfig{ + ConnectTimeout: durationpb.New(10 * time.Second), + }, + }, + }, + }, + }, + Protocol: pbproxystate.Protocol_PROTOCOL_TCP, + }, fmt.Sprintf("mesh.%s", connect.PeeredServiceSNI("api-1", tenancy.Namespace, tenancy.Partition, "api-1", "trustDomain")): { Name: fmt.Sprintf("mesh.%s", connect.PeeredServiceSNI("api-1", tenancy.Namespace, tenancy.Partition, "api-1", "trustDomain")), Group: &pbproxystate.Cluster_EndpointGroup{ diff --git a/internal/mesh/internal/controllers/gatewayproxy/controller.go b/internal/mesh/internal/controllers/gatewayproxy/controller.go index 9f5b2bd3e0..3e9a4b45c5 100644 --- a/internal/mesh/internal/controllers/gatewayproxy/controller.go +++ b/internal/mesh/internal/controllers/gatewayproxy/controller.go @@ -119,15 +119,14 @@ func (r *reconciler) Reconcile(ctx context.Context, rt controller.Runtime, req c Type: pbmulticluster.ComputedExportedServicesType, } - exportedServices, err := dataFetcher.FetchExportedServices(ctx, exportedServicesID) - if err != nil || exportedServices == nil { - if err != nil { - rt.Logger.Error("error reading the associated exported services", "error", err) - } - - if exportedServices == nil { - rt.Logger.Error("exported services was nil") - } + var exportedServices []*pbmulticluster.ComputedExportedService + dec, err := dataFetcher.FetchExportedServices(ctx, exportedServicesID) + if err != nil { + rt.Logger.Error("error reading the associated exported services", "error", err) + } else if dec == nil { + rt.Logger.Error("exported services was nil") + } else { + exportedServices = dec.Data.Services } trustDomain, err := r.getTrustDomain()