diff --git a/agent/proxycfg/snapshot.go b/agent/proxycfg/snapshot.go index bd8671183b..5f6ac693ea 100644 --- a/agent/proxycfg/snapshot.go +++ b/agent/proxycfg/snapshot.go @@ -83,7 +83,7 @@ func (s *ConfigSnapshot) Valid() bool { case structs.ServiceKindConnectProxy: return s.Roots != nil && s.ConnectProxy.Leaf != nil case structs.ServiceKindMeshGateway: - return s.Roots != nil && (s.MeshGateway.WatchedServicesSet || len(s.MeshGateway.WatchedServices) > 0) + return s.Roots != nil && (s.MeshGateway.WatchedServicesSet || len(s.MeshGateway.ServiceGroups) > 0) default: return false } diff --git a/agent/xds/server.go b/agent/xds/server.go index cf51cd3dfc..a375ec5d09 100644 --- a/agent/xds/server.go +++ b/agent/xds/server.go @@ -215,6 +215,10 @@ func (s *Server) process(stream ADSStream, reqCh <-chan *envoy.DiscoveryRequest) typeURL: ClusterType, resources: s.clustersFromSnapshot, stream: stream, + allowEmptyFn: func(cfgSnap *proxycfg.ConfigSnapshot) bool { + // Mesh gateways are allowed to inform CDS of no clusters. + return cfgSnap.Kind == structs.ServiceKindMeshGateway + }, }, RouteType: &xDSType{ typeURL: RouteType, @@ -370,8 +374,9 @@ type xDSType struct { // previous request we already responded to and 2) if the proxy rejected the // last version we sent with a Nack then req.VersionInfo will be the older // version it's hanging on to. - lastVersion uint64 - resources func(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) + lastVersion uint64 + resources func(cfgSnap *proxycfg.ConfigSnapshot, token string) ([]proto.Message, error) + allowEmptyFn func(cfgSnap *proxycfg.ConfigSnapshot) bool } func (t *xDSType) Recv(req *envoy.DiscoveryRequest) { @@ -392,13 +397,16 @@ func (t *xDSType) SendIfNew(cfgSnap *proxycfg.ConfigSnapshot, version uint64, no if err != nil { return err } + + allowEmpty := t.allowEmptyFn != nil && t.allowEmptyFn(cfgSnap) + // Zero length resource responses should be ignored and are the result of no // data yet. Notice that this caused a bug originally where we had zero // healthy endpoints for an upstream that would cause Envoy to hang waiting // for the EDS response. This is fixed though by ensuring we send an explicit // empty LoadAssignment resource for the cluster rather than allowing junky // empty resources. - if len(resources) == 0 { + if len(resources) == 0 && !allowEmpty { // Nothing to send yet return nil } diff --git a/test/integration/connect/envoy/case-gateway-without-services/bind.hcl b/test/integration/connect/envoy/case-gateway-without-services/bind.hcl new file mode 100644 index 0000000000..f54393f03e --- /dev/null +++ b/test/integration/connect/envoy/case-gateway-without-services/bind.hcl @@ -0,0 +1,2 @@ +bind_addr = "0.0.0.0" +advertise_addr = "{{ GetInterfaceIP \"eth0\" }}" \ No newline at end of file diff --git a/test/integration/connect/envoy/case-gateway-without-services/gateway.hcl b/test/integration/connect/envoy/case-gateway-without-services/gateway.hcl new file mode 100644 index 0000000000..7bdbfd6dc1 --- /dev/null +++ b/test/integration/connect/envoy/case-gateway-without-services/gateway.hcl @@ -0,0 +1,5 @@ +services { + name = "mesh-gateway" + kind = "mesh-gateway" + port = 4431 +} \ No newline at end of file diff --git a/test/integration/connect/envoy/case-gateway-without-services/s1.hcl b/test/integration/connect/envoy/case-gateway-without-services/s1.hcl new file mode 100644 index 0000000000..f9c223cfec --- /dev/null +++ b/test/integration/connect/envoy/case-gateway-without-services/s1.hcl @@ -0,0 +1 @@ +# We don't want an s1 service diff --git a/test/integration/connect/envoy/case-gateway-without-services/s2.hcl b/test/integration/connect/envoy/case-gateway-without-services/s2.hcl new file mode 100644 index 0000000000..89311191b3 --- /dev/null +++ b/test/integration/connect/envoy/case-gateway-without-services/s2.hcl @@ -0,0 +1 @@ +# We don't want an s2 service diff --git a/test/integration/connect/envoy/case-gateway-without-services/setup.sh b/test/integration/connect/envoy/case-gateway-without-services/setup.sh new file mode 100644 index 0000000000..3ffc060511 --- /dev/null +++ b/test/integration/connect/envoy/case-gateway-without-services/setup.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -eEuo pipefail + +gen_envoy_bootstrap mesh-gateway 19000 primary true diff --git a/test/integration/connect/envoy/case-gateway-without-services/vars.sh b/test/integration/connect/envoy/case-gateway-without-services/vars.sh new file mode 100644 index 0000000000..b9f520fae3 --- /dev/null +++ b/test/integration/connect/envoy/case-gateway-without-services/vars.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +export REQUIRED_SERVICES="gateway-primary" diff --git a/test/integration/connect/envoy/case-gateway-without-services/verify.bats b/test/integration/connect/envoy/case-gateway-without-services/verify.bats new file mode 100644 index 0000000000..289a688d42 --- /dev/null +++ b/test/integration/connect/envoy/case-gateway-without-services/verify.bats @@ -0,0 +1,11 @@ +#!/usr/bin/env bats + +load helpers + +@test "gateway-primary proxy admin is up on :19000" { + retry_default curl -f -s localhost:19000/stats -o /dev/null +} + +@test "gateway-primary listener is up on :4431" { + retry_default nc -z localhost:4431 +}