mirror of https://github.com/status-im/consul.git
feat(v2dns): prepared query ttls (#20563)
This commit is contained in:
parent
7cac918811
commit
24e15cc24e
|
@ -107,11 +107,11 @@ const (
|
||||||
type Result struct {
|
type Result struct {
|
||||||
Service *Location // The name and address of the service.
|
Service *Location // The name and address of the service.
|
||||||
Node *Location // The name and address of the node.
|
Node *Location // The name and address of the node.
|
||||||
Weight uint32 // SRV queries
|
|
||||||
PortName string // Used to generate a fgdn when a specifc port was queried
|
PortName string // Used to generate a fgdn when a specifc port was queried
|
||||||
PortNumber uint32 // SRV queries
|
PortNumber uint32 // SRV queries
|
||||||
Metadata map[string]string // Used to collect metadata into TXT Records
|
Metadata map[string]string // Used to collect metadata into TXT Records
|
||||||
Type ResultType // Used to reconstruct the fqdn name of the resource
|
Type ResultType // Used to reconstruct the fqdn name of the resource
|
||||||
|
DNS DNSConfig // Used for DNS-specific configuration for this result
|
||||||
|
|
||||||
Tenancy ResultTenancy
|
Tenancy ResultTenancy
|
||||||
}
|
}
|
||||||
|
@ -122,6 +122,11 @@ type Location struct {
|
||||||
Address string
|
Address string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DNSConfig struct {
|
||||||
|
TTL *uint32 // deprecated: use for V1 prepared queries only
|
||||||
|
Weight uint32 // SRV queries
|
||||||
|
}
|
||||||
|
|
||||||
// ResultTenancy is used to reconstruct the fqdn name of the resource.
|
// ResultTenancy is used to reconstruct the fqdn name of the resource.
|
||||||
type ResultTenancy struct {
|
type ResultTenancy struct {
|
||||||
Namespace string
|
Namespace string
|
||||||
|
|
|
@ -308,10 +308,6 @@ func (f *V1DataFetcher) FetchPreparedQuery(ctx Context, req *QueryPayload) ([]*R
|
||||||
return nil, ECSNotGlobalError{err}
|
return nil, ECSNotGlobalError{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
// (v2-dns) TODO: (v2-dns) get TTLS working. They come from the database so not having
|
|
||||||
// TTL on the discovery result poses challenges.
|
|
||||||
|
|
||||||
/*
|
|
||||||
// TODO (slackpad) - What's a safe limit we can set here? It seems like
|
// TODO (slackpad) - What's a safe limit we can set here? It seems like
|
||||||
// with dup filtering done at this level we need to get everything to
|
// with dup filtering done at this level we need to get everything to
|
||||||
// match the previous behavior. We can optimize by pushing more filtering
|
// match the previous behavior. We can optimize by pushing more filtering
|
||||||
|
@ -323,20 +319,20 @@ func (f *V1DataFetcher) FetchPreparedQuery(ctx Context, req *QueryPayload) ([]*R
|
||||||
// the query is created, but we check anyway. If the query didn't
|
// the query is created, but we check anyway. If the query didn't
|
||||||
// specify a TTL then we will try to use the agent's service-specific
|
// specify a TTL then we will try to use the agent's service-specific
|
||||||
// TTL configs.
|
// TTL configs.
|
||||||
var ttl time.Duration
|
|
||||||
|
// Check is there is a TTL provided as part of the prepared query
|
||||||
|
var ttlOverride *uint32
|
||||||
if out.DNS.TTL != "" {
|
if out.DNS.TTL != "" {
|
||||||
var err error
|
ttl, err := time.ParseDuration(out.DNS.TTL)
|
||||||
ttl, err = time.ParseDuration(out.DNS.TTL)
|
if err == nil {
|
||||||
if err != nil {
|
ttlSec := uint32(ttl / time.Second)
|
||||||
|
ttlOverride = &ttlSec
|
||||||
|
}
|
||||||
f.logger.Warn("Failed to parse TTL for prepared query , ignoring",
|
f.logger.Warn("Failed to parse TTL for prepared query , ignoring",
|
||||||
"ttl", out.DNS.TTL,
|
"ttl", out.DNS.TTL,
|
||||||
"prepared_query", req.Name,
|
"prepared_query", req.Name,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
ttl, _ = cfg.GetTTLForService(out.Service)
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
// If we have no nodes, return not found!
|
// If we have no nodes, return not found!
|
||||||
if len(out.Nodes) == 0 {
|
if len(out.Nodes) == 0 {
|
||||||
|
@ -345,7 +341,7 @@ func (f *V1DataFetcher) FetchPreparedQuery(ctx Context, req *QueryPayload) ([]*R
|
||||||
|
|
||||||
// Perform a random shuffle
|
// Perform a random shuffle
|
||||||
out.Nodes.Shuffle()
|
out.Nodes.Shuffle()
|
||||||
return f.buildResultsFromServiceNodes(out.Nodes, req), ECSNotGlobalError{}
|
return f.buildResultsFromServiceNodes(out.Nodes, req, ttlOverride), ECSNotGlobalError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// executePreparedQuery is used to execute a PreparedQuery against the Consul catalog.
|
// executePreparedQuery is used to execute a PreparedQuery against the Consul catalog.
|
||||||
|
@ -402,7 +398,7 @@ func (f *V1DataFetcher) ValidateRequest(_ Context, req *QueryPayload) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildResultsFromServiceNodes builds a list of results from a list of nodes.
|
// buildResultsFromServiceNodes builds a list of results from a list of nodes.
|
||||||
func (f *V1DataFetcher) buildResultsFromServiceNodes(nodes []structs.CheckServiceNode, req *QueryPayload) []*Result {
|
func (f *V1DataFetcher) buildResultsFromServiceNodes(nodes []structs.CheckServiceNode, req *QueryPayload, ttlOverride *uint32) []*Result {
|
||||||
// Convert the service endpoints to results up to the limit
|
// Convert the service endpoints to results up to the limit
|
||||||
limit := req.Limit
|
limit := req.Limit
|
||||||
if len(nodes) < limit || limit == 0 {
|
if len(nodes) < limit || limit == 0 {
|
||||||
|
@ -422,7 +418,10 @@ func (f *V1DataFetcher) buildResultsFromServiceNodes(nodes []structs.CheckServic
|
||||||
Address: n.Node.Address,
|
Address: n.Node.Address,
|
||||||
},
|
},
|
||||||
Type: ResultTypeService,
|
Type: ResultTypeService,
|
||||||
|
DNS: DNSConfig{
|
||||||
|
TTL: ttlOverride,
|
||||||
Weight: uint32(findWeight(n)),
|
Weight: uint32(findWeight(n)),
|
||||||
|
},
|
||||||
PortNumber: uint32(f.translateServicePortFunc(n.Node.Datacenter, n.Service.Port, n.Service.TaggedAddresses)),
|
PortNumber: uint32(f.translateServicePortFunc(n.Node.Datacenter, n.Service.Port, n.Service.TaggedAddresses)),
|
||||||
Metadata: n.Node.Meta,
|
Metadata: n.Node.Meta,
|
||||||
Tenancy: ResultTenancy{
|
Tenancy: ResultTenancy{
|
||||||
|
@ -548,7 +547,7 @@ func (f *V1DataFetcher) fetchServiceBasedOnTenancy(ctx Context, req *QueryPayloa
|
||||||
|
|
||||||
// Perform a random shuffle
|
// Perform a random shuffle
|
||||||
out.Nodes.Shuffle()
|
out.Nodes.Shuffle()
|
||||||
return f.buildResultsFromServiceNodes(out.Nodes, req), nil
|
return f.buildResultsFromServiceNodes(out.Nodes, req, nil), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// findWeight returns the weight of a service node.
|
// findWeight returns the weight of a service node.
|
||||||
|
|
|
@ -148,8 +148,10 @@ func Test_FetchEndpoints(t *testing.T) {
|
||||||
Address: "service-address",
|
Address: "service-address",
|
||||||
},
|
},
|
||||||
Type: ResultTypeService,
|
Type: ResultTypeService,
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
logger := testutil.Logger(t)
|
logger := testutil.Logger(t)
|
||||||
|
|
|
@ -116,7 +116,9 @@ func (f *V2DataFetcher) FetchEndpoints(reqContext Context, req *QueryPayload, lo
|
||||||
Namespace: resourceObj.GetId().GetTenancy().GetNamespace(),
|
Namespace: resourceObj.GetId().GetTenancy().GetNamespace(),
|
||||||
Partition: resourceObj.GetId().GetTenancy().GetPartition(),
|
Partition: resourceObj.GetId().GetTenancy().GetPartition(),
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: weight,
|
Weight: weight,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
results = append(results, result)
|
results = append(results, result)
|
||||||
}
|
}
|
||||||
|
|
|
@ -261,10 +261,12 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "FetchEndpoints returns empty result with no endpoints",
|
name: "FetchEndpoints returns empty result with no endpoints",
|
||||||
queryPayload: &QueryPayload{
|
queryPayload: &QueryPayload{
|
||||||
|
@ -360,8 +362,10 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 2,
|
Weight: 2,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Node: &Location{Name: "consul-2", Address: "2.3.4.5"},
|
Node: &Location{Name: "consul-2", Address: "2.3.4.5"},
|
||||||
Type: ResultTypeWorkload,
|
Type: ResultTypeWorkload,
|
||||||
|
@ -369,10 +373,12 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 3,
|
Weight: 3,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "FetchEndpoints filters out warning endpoints when DNSOnlyPassing is true",
|
name: "FetchEndpoints filters out warning endpoints when DNSOnlyPassing is true",
|
||||||
queryPayload: &QueryPayload{
|
queryPayload: &QueryPayload{
|
||||||
|
@ -408,10 +414,12 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 2,
|
Weight: 2,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "FetchEndpoints shuffles the results",
|
name: "FetchEndpoints shuffles the results",
|
||||||
queryPayload: &QueryPayload{
|
queryPayload: &QueryPayload{
|
||||||
|
@ -452,8 +460,10 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Node: &Location{Name: "consul-2", Address: "10.0.0.2"},
|
Node: &Location{Name: "consul-2", Address: "10.0.0.2"},
|
||||||
Type: ResultTypeWorkload,
|
Type: ResultTypeWorkload,
|
||||||
|
@ -461,8 +471,10 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Node: &Location{Name: "consul-3", Address: "10.0.0.3"},
|
Node: &Location{Name: "consul-3", Address: "10.0.0.3"},
|
||||||
Type: ResultTypeWorkload,
|
Type: ResultTypeWorkload,
|
||||||
|
@ -470,8 +482,10 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Node: &Location{Name: "consul-4", Address: "10.0.0.4"},
|
Node: &Location{Name: "consul-4", Address: "10.0.0.4"},
|
||||||
Type: ResultTypeWorkload,
|
Type: ResultTypeWorkload,
|
||||||
|
@ -479,8 +493,10 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Node: &Location{Name: "consul-5", Address: "10.0.0.5"},
|
Node: &Location{Name: "consul-5", Address: "10.0.0.5"},
|
||||||
Type: ResultTypeWorkload,
|
Type: ResultTypeWorkload,
|
||||||
|
@ -488,8 +504,10 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Node: &Location{Name: "consul-6", Address: "10.0.0.6"},
|
Node: &Location{Name: "consul-6", Address: "10.0.0.6"},
|
||||||
Type: ResultTypeWorkload,
|
Type: ResultTypeWorkload,
|
||||||
|
@ -497,8 +515,10 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Node: &Location{Name: "consul-7", Address: "10.0.0.7"},
|
Node: &Location{Name: "consul-7", Address: "10.0.0.7"},
|
||||||
Type: ResultTypeWorkload,
|
Type: ResultTypeWorkload,
|
||||||
|
@ -506,8 +526,10 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Node: &Location{Name: "consul-8", Address: "10.0.0.8"},
|
Node: &Location{Name: "consul-8", Address: "10.0.0.8"},
|
||||||
Type: ResultTypeWorkload,
|
Type: ResultTypeWorkload,
|
||||||
|
@ -515,8 +537,10 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Node: &Location{Name: "consul-9", Address: "10.0.0.9"},
|
Node: &Location{Name: "consul-9", Address: "10.0.0.9"},
|
||||||
Type: ResultTypeWorkload,
|
Type: ResultTypeWorkload,
|
||||||
|
@ -524,8 +548,10 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Node: &Location{Name: "consul-10", Address: "10.0.0.10"},
|
Node: &Location{Name: "consul-10", Address: "10.0.0.10"},
|
||||||
Type: ResultTypeWorkload,
|
Type: ResultTypeWorkload,
|
||||||
|
@ -533,9 +559,11 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
verifyShuffle: true,
|
verifyShuffle: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -572,10 +600,12 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: resource.DefaultNamespaceName,
|
Namespace: resource.DefaultNamespaceName,
|
||||||
Partition: resource.DefaultPartitionName,
|
Partition: resource.DefaultPartitionName,
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "FetchEndpoints returns results with non-default tenancy",
|
name: "FetchEndpoints returns results with non-default tenancy",
|
||||||
queryPayload: &QueryPayload{
|
queryPayload: &QueryPayload{
|
||||||
|
@ -613,10 +643,12 @@ func Test_V2FetchEndpoints(t *testing.T) {
|
||||||
Namespace: "test-namespace",
|
Namespace: "test-namespace",
|
||||||
Partition: "test-partition",
|
Partition: "test-partition",
|
||||||
},
|
},
|
||||||
|
DNS: DNSConfig{
|
||||||
Weight: 1,
|
Weight: 1,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
|
|
|
@ -13,13 +13,12 @@ import (
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/acl"
|
|
||||||
|
|
||||||
"github.com/armon/go-radix"
|
"github.com/armon/go-radix"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
|
|
||||||
"github.com/hashicorp/go-hclog"
|
"github.com/hashicorp/go-hclog"
|
||||||
|
|
||||||
|
"github.com/hashicorp/consul/acl"
|
||||||
"github.com/hashicorp/consul/agent/config"
|
"github.com/hashicorp/consul/agent/config"
|
||||||
"github.com/hashicorp/consul/agent/discovery"
|
"github.com/hashicorp/consul/agent/discovery"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
@ -286,13 +285,18 @@ func (r *Router) trimDomain(questionName string) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// getTTLForResult returns the TTL for a given result.
|
// getTTLForResult returns the TTL for a given result.
|
||||||
func getTTLForResult(name string, query *discovery.Query, cfg *RouterDynamicConfig) uint32 {
|
func getTTLForResult(name string, overrideTTL *uint32, query *discovery.Query, cfg *RouterDynamicConfig) uint32 {
|
||||||
// In the case we are not making a discovery query, such as addr. or arpa. lookups,
|
// In the case we are not making a discovery query, such as addr. or arpa. lookups,
|
||||||
// use the node TTL by convention
|
// use the node TTL by convention
|
||||||
if query == nil {
|
if query == nil {
|
||||||
return uint32(cfg.NodeTTL / time.Second)
|
return uint32(cfg.NodeTTL / time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if overrideTTL != nil {
|
||||||
|
// If a result was provided with an override, use that. This is the case for some prepared queries.
|
||||||
|
return *overrideTTL
|
||||||
|
}
|
||||||
|
|
||||||
switch query.QueryType {
|
switch query.QueryType {
|
||||||
// TODO (v2-dns): currently have to do this related to the results type being changed to node whe
|
// TODO (v2-dns): currently have to do this related to the results type being changed to node whe
|
||||||
// the v1 data fetcher encounters a blank service address and uses the node address instead.
|
// the v1 data fetcher encounters a blank service address and uses the node address instead.
|
||||||
|
@ -301,7 +305,7 @@ func getTTLForResult(name string, query *discovery.Query, cfg *RouterDynamicConf
|
||||||
case discovery.QueryTypeWorkload:
|
case discovery.QueryTypeWorkload:
|
||||||
// TODO (v2-dns): we need to discuss what we want to do for workload TTLs
|
// TODO (v2-dns): we need to discuss what we want to do for workload TTLs
|
||||||
return 0
|
return 0
|
||||||
case discovery.QueryTypeService:
|
case discovery.QueryTypeService, discovery.QueryTypePreparedQuery:
|
||||||
ttl, ok := cfg.getTTLForService(name)
|
ttl, ok := cfg.getTTLForService(name)
|
||||||
if ok {
|
if ok {
|
||||||
return uint32(ttl / time.Second)
|
return uint32(ttl / time.Second)
|
||||||
|
@ -884,7 +888,9 @@ func (r *Router) getAnswerExtraAndNs(result *discovery.Result, req *dns.Msg, req
|
||||||
if query != nil {
|
if query != nil {
|
||||||
ttlLookupName = query.QueryPayload.Name
|
ttlLookupName = query.QueryPayload.Name
|
||||||
}
|
}
|
||||||
ttl := getTTLForResult(ttlLookupName, query, cfg)
|
|
||||||
|
ttl := getTTLForResult(ttlLookupName, result.DNS.TTL, query, cfg)
|
||||||
|
|
||||||
qType := req.Question[0].Qtype
|
qType := req.Question[0].Qtype
|
||||||
|
|
||||||
// TODO (v2-dns): skip records that refer to a workload/node that don't have a valid DNS name.
|
// TODO (v2-dns): skip records that refer to a workload/node that don't have a valid DNS name.
|
||||||
|
@ -1278,7 +1284,7 @@ func makeSRVRecord(name, target string, result *discovery.Result, ttl uint32) *d
|
||||||
Ttl: ttl,
|
Ttl: ttl,
|
||||||
},
|
},
|
||||||
Priority: 1,
|
Priority: 1,
|
||||||
Weight: uint16(result.Weight),
|
Weight: uint16(result.DNS.Weight),
|
||||||
Port: uint16(result.PortNumber),
|
Port: uint16(result.PortNumber),
|
||||||
Target: target,
|
Target: target,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1791,6 +1791,165 @@ func Test_HandleRequest(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// V1 Prepared Queries
|
||||||
|
{
|
||||||
|
name: "v1 prepared query w/ TTL override, ANY query, returns A record",
|
||||||
|
request: &dns.Msg{
|
||||||
|
MsgHdr: dns.MsgHdr{
|
||||||
|
Opcode: dns.OpcodeQuery,
|
||||||
|
},
|
||||||
|
Question: []dns.Question{
|
||||||
|
{
|
||||||
|
Name: "foo.query.consul.",
|
||||||
|
Qtype: dns.TypeA,
|
||||||
|
Qclass: dns.ClassINET,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
agentConfig: &config.RuntimeConfig{
|
||||||
|
DNSDomain: "consul",
|
||||||
|
DNSNodeTTL: 123 * time.Second,
|
||||||
|
DNSSOA: config.RuntimeSOAConfig{
|
||||||
|
Refresh: 1,
|
||||||
|
Retry: 2,
|
||||||
|
Expire: 3,
|
||||||
|
Minttl: 4,
|
||||||
|
},
|
||||||
|
DNSUDPAnswerLimit: maxUDPAnswerLimit,
|
||||||
|
// We shouldn't use this if we have the override defined
|
||||||
|
DNSServiceTTL: map[string]time.Duration{
|
||||||
|
"foo": 1 * time.Second,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configureDataFetcher: func(fetcher discovery.CatalogDataFetcher) {
|
||||||
|
fetcher.(*discovery.MockCatalogDataFetcher).
|
||||||
|
On("FetchPreparedQuery", mock.Anything, mock.Anything).
|
||||||
|
Return([]*discovery.Result{
|
||||||
|
{
|
||||||
|
Service: &discovery.Location{Name: "foo", Address: "1.2.3.4"},
|
||||||
|
Node: &discovery.Location{Name: "bar", Address: "1.2.3.4"},
|
||||||
|
Type: discovery.ResultTypeService,
|
||||||
|
Tenancy: discovery.ResultTenancy{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
},
|
||||||
|
DNS: discovery.DNSConfig{
|
||||||
|
TTL: getUint32Ptr(3),
|
||||||
|
Weight: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil).
|
||||||
|
Run(func(args mock.Arguments) {
|
||||||
|
req := args.Get(1).(*discovery.QueryPayload)
|
||||||
|
require.Equal(t, "foo", req.Name)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
validateAndNormalizeExpected: true,
|
||||||
|
response: &dns.Msg{
|
||||||
|
MsgHdr: dns.MsgHdr{
|
||||||
|
Opcode: dns.OpcodeQuery,
|
||||||
|
Response: true,
|
||||||
|
Authoritative: true,
|
||||||
|
},
|
||||||
|
Compress: true,
|
||||||
|
Question: []dns.Question{
|
||||||
|
{
|
||||||
|
Name: "foo.query.consul.",
|
||||||
|
Qtype: dns.TypeA,
|
||||||
|
Qclass: dns.ClassINET,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Answer: []dns.RR{
|
||||||
|
&dns.A{
|
||||||
|
Hdr: dns.RR_Header{
|
||||||
|
Name: "foo.query.consul.",
|
||||||
|
Rrtype: dns.TypeA,
|
||||||
|
Class: dns.ClassINET,
|
||||||
|
Ttl: 3,
|
||||||
|
},
|
||||||
|
A: net.ParseIP("1.2.3.4"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "v1 prepared query w/ matching service TTL, ANY query, returns A record",
|
||||||
|
request: &dns.Msg{
|
||||||
|
MsgHdr: dns.MsgHdr{
|
||||||
|
Opcode: dns.OpcodeQuery,
|
||||||
|
},
|
||||||
|
Question: []dns.Question{
|
||||||
|
{
|
||||||
|
Name: "foo.query.consul.",
|
||||||
|
Qtype: dns.TypeA,
|
||||||
|
Qclass: dns.ClassINET,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
agentConfig: &config.RuntimeConfig{
|
||||||
|
DNSDomain: "consul",
|
||||||
|
DNSNodeTTL: 123 * time.Second,
|
||||||
|
DNSSOA: config.RuntimeSOAConfig{
|
||||||
|
Refresh: 1,
|
||||||
|
Retry: 2,
|
||||||
|
Expire: 3,
|
||||||
|
Minttl: 4,
|
||||||
|
},
|
||||||
|
DNSUDPAnswerLimit: maxUDPAnswerLimit,
|
||||||
|
// Results should use this as the TTL
|
||||||
|
DNSServiceTTL: map[string]time.Duration{
|
||||||
|
"foo": 1 * time.Second,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
configureDataFetcher: func(fetcher discovery.CatalogDataFetcher) {
|
||||||
|
fetcher.(*discovery.MockCatalogDataFetcher).
|
||||||
|
On("FetchPreparedQuery", mock.Anything, mock.Anything).
|
||||||
|
Return([]*discovery.Result{
|
||||||
|
{
|
||||||
|
Service: &discovery.Location{Name: "foo", Address: "1.2.3.4"},
|
||||||
|
Node: &discovery.Location{Name: "bar", Address: "1.2.3.4"},
|
||||||
|
Type: discovery.ResultTypeService,
|
||||||
|
Tenancy: discovery.ResultTenancy{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
},
|
||||||
|
DNS: discovery.DNSConfig{
|
||||||
|
// Intentionally no TTL here.
|
||||||
|
Weight: 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}, nil).
|
||||||
|
Run(func(args mock.Arguments) {
|
||||||
|
req := args.Get(1).(*discovery.QueryPayload)
|
||||||
|
require.Equal(t, "foo", req.Name)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
validateAndNormalizeExpected: true,
|
||||||
|
response: &dns.Msg{
|
||||||
|
MsgHdr: dns.MsgHdr{
|
||||||
|
Opcode: dns.OpcodeQuery,
|
||||||
|
Response: true,
|
||||||
|
Authoritative: true,
|
||||||
|
},
|
||||||
|
Compress: true,
|
||||||
|
Question: []dns.Question{
|
||||||
|
{
|
||||||
|
Name: "foo.query.consul.",
|
||||||
|
Qtype: dns.TypeA,
|
||||||
|
Qclass: dns.ClassINET,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Answer: []dns.RR{
|
||||||
|
&dns.A{
|
||||||
|
Hdr: dns.RR_Header{
|
||||||
|
Name: "foo.query.consul.",
|
||||||
|
Rrtype: dns.TypeA,
|
||||||
|
Class: dns.ClassINET,
|
||||||
|
Ttl: 1,
|
||||||
|
},
|
||||||
|
A: net.ParseIP("1.2.3.4"),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
testCases = append(testCases, getAdditionalTestCases(t)...)
|
testCases = append(testCases, getAdditionalTestCases(t)...)
|
||||||
|
@ -2174,3 +2333,8 @@ func TestDNS_syncExtra(t *testing.T) {
|
||||||
t.Fatalf("Bad %#v vs. %#v", *resp, *expected)
|
t.Fatalf("Bad %#v vs. %#v", *resp, *expected)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// getUint32Ptr return the pointer of an uint32 literal
|
||||||
|
func getUint32Ptr(i uint32) *uint32 {
|
||||||
|
return &i
|
||||||
|
}
|
||||||
|
|
|
@ -502,6 +502,9 @@ func TestDNS_ServiceLookup(t *testing.T) {
|
||||||
Service: structs.ServiceQuery{
|
Service: structs.ServiceQuery{
|
||||||
Service: "db",
|
Service: "db",
|
||||||
},
|
},
|
||||||
|
DNS: structs.QueryDNSOptions{
|
||||||
|
TTL: "3s",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if err := a.RPC(context.Background(), "PreparedQuery.Apply", args, &id); err != nil {
|
if err := a.RPC(context.Background(), "PreparedQuery.Apply", args, &id); err != nil {
|
||||||
|
@ -538,9 +541,6 @@ func TestDNS_ServiceLookup(t *testing.T) {
|
||||||
if srvRec.Target != "foo.node.dc1.consul." {
|
if srvRec.Target != "foo.node.dc1.consul." {
|
||||||
t.Fatalf("Bad: %#v", srvRec)
|
t.Fatalf("Bad: %#v", srvRec)
|
||||||
}
|
}
|
||||||
if srvRec.Hdr.Ttl != 0 {
|
|
||||||
t.Fatalf("Bad: %#v", in.Answer[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
aRec, ok := in.Extra[0].(*dns.A)
|
aRec, ok := in.Extra[0].(*dns.A)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -552,11 +552,26 @@ func TestDNS_ServiceLookup(t *testing.T) {
|
||||||
if aRec.A.String() != "127.0.0.1" {
|
if aRec.A.String() != "127.0.0.1" {
|
||||||
t.Fatalf("Bad: %#v", in.Extra[0])
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if strings.Contains(question, "query") {
|
||||||
|
// The query should have the TTL associated with the query registration.
|
||||||
|
if srvRec.Hdr.Ttl != 3 {
|
||||||
|
t.Fatalf("Bad: %#v", in.Answer[0])
|
||||||
|
}
|
||||||
|
if aRec.Hdr.Ttl != 3 {
|
||||||
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if srvRec.Hdr.Ttl != 0 {
|
||||||
|
t.Fatalf("Bad: %#v", in.Answer[0])
|
||||||
|
}
|
||||||
if aRec.Hdr.Ttl != 0 {
|
if aRec.Hdr.Ttl != 0 {
|
||||||
t.Fatalf("Bad: %#v", in.Extra[0])
|
t.Fatalf("Bad: %#v", in.Extra[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// Lookup a non-existing service/query, we should receive an SOA.
|
// Lookup a non-existing service/query, we should receive an SOA.
|
||||||
questions = []string{
|
questions = []string{
|
||||||
"nodb.service.consul.",
|
"nodb.service.consul.",
|
||||||
|
|
Loading…
Reference in New Issue