diff --git a/agent/consul/prepared_query_endpoint.go b/agent/consul/prepared_query_endpoint.go index 9343685bfb65..7877ed1ae732 100644 --- a/agent/consul/prepared_query_endpoint.go +++ b/agent/consul/prepared_query_endpoint.go @@ -578,9 +578,11 @@ func (p *PreparedQuery) execute(query *structs.PreparedQuery, // Filter out any unhealthy nodes. filterType := structs.HealthFilterExcludeCritical - if query.Service.OnlyPassing { - filterType = structs.HealthFilterIncludeOnlyPassing + if query.Service.IncludeAll { + filterType = structs.HealthFilterIncludeAll + } else if query.Service.OnlyPassing { + filterType = structs.HealthFilterIncludeOnlyPassing } nodes = nodes.Filter(structs.CheckServiceNodeFilterOptions{FilterType: filterType, diff --git a/agent/consul/prepared_query_endpoint_test.go b/agent/consul/prepared_query_endpoint_test.go index 9a14d96404a8..dba70af07618 100644 --- a/agent/consul/prepared_query_endpoint_test.go +++ b/agent/consul/prepared_query_endpoint_test.go @@ -2178,6 +2178,33 @@ func TestPreparedQuery_Execute(t *testing.T) { expectNodes(t, &query, &reply, 0) }) + // Critical nodes should also be returned + query.Query.Service.IncludeAll = true + // remove tags filtering + query.Query.Service.Tags = nil + setHealth(t, es.server.codec, "dc1", 1, api.HealthPassing) + setHealth(t, es.server.codec, "dc1", 2, api.HealthPassing) + setHealth(t, es.server.codec, "dc1", 4, api.HealthWarning) + require.NoError(t, msgpackrpc.CallWithCodec(es.server.codec, "PreparedQuery.Apply", &query, &query.Query.ID)) + t.Run("see 10 nodes despite all nodes being critical", func(t *testing.T) { + req := structs.PreparedQueryExecuteRequest{ + Datacenter: "dc1", + QueryIDOrName: query.Query.ID, + QueryOptions: structs.QueryOptions{Token: es.execToken}, + } + + var reply structs.PreparedQueryExecuteResponse + require.NoError(t, msgpackrpc.CallWithCodec(es.server.codec, "PreparedQuery.Execute", &req, &reply)) + + expectNodes(t, &query, &reply, 10) + }) + // Undo that so all the following tests aren't broken! + query.Query.Service.IncludeAll = false + query.Query.Service.Tags = []string{"!tag3"} + setHealth(t, es.server.codec, "dc1", 1, api.HealthCritical) + setHealth(t, es.server.codec, "dc1", 2, api.HealthCritical) + require.NoError(t, msgpackrpc.CallWithCodec(es.server.codec, "PreparedQuery.Apply", &query, &query.Query.ID)) + // Modify the query to have it fail over to a bogus DC and then dc2. query.Query.Service.Failover.Datacenters = []string{"bogus", "dc2"} require.NoError(t, msgpackrpc.CallWithCodec(es.server.codec, "PreparedQuery.Apply", &query, &query.Query.ID)) diff --git a/agent/structs/prepared_query.go b/agent/structs/prepared_query.go index 8d596a76d0c1..c0f59578f51c 100644 --- a/agent/structs/prepared_query.go +++ b/agent/structs/prepared_query.go @@ -86,6 +86,10 @@ type ServiceQuery struct { // local datacenter. Failover QueryFailoverOptions + // If IncludeAll is true then we will only include all nodes + // whatever the health checks + IncludeAll bool + // If OnlyPassing is true then we will only include nodes with passing // health checks (critical AND warning checks will cause a node to be // discarded)