Skip to content

Commit

Permalink
dns: implements prefix lookups for DNS TTL (#4605)
Browse files Browse the repository at this point in the history
This will fix #4509 and allow forinstance lb-* to match services lb-001 or lb-service-007.
  • Loading branch information
pierresouchay authored and pearkes committed Oct 19, 2018
1 parent c4d6d19 commit fab55be
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 240 deletions.
1 change: 1 addition & 0 deletions agent/catalog_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,7 @@ func TestCatalogServices(t *testing.T) {
t.Parallel()
a := NewTestAgent(t.Name(), "")
defer a.Shutdown()
testrpc.WaitForTestAgent(t, a.RPC, "dc1")

// Register node
args := &structs.RegisterRequest{
Expand Down
2 changes: 1 addition & 1 deletion agent/consul/catalog_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1340,7 +1340,7 @@ func TestCatalog_ListServices_NodeMetaFilter(t *testing.T) {
codec := rpcClient(t, s1)
defer codec.Close()

testrpc.WaitForLeader(t, s1.RPC, "dc1")
testrpc.WaitForTestAgent(t, s1.RPC, "dc1")

// Add a new node with the right meta k/v pair
node := &structs.Node{Node: "foo", Address: "127.0.0.1", Meta: map[string]string{"somekey": "somevalue"}}
Expand Down
1 change: 1 addition & 0 deletions agent/consul/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -450,6 +450,7 @@ func TestClient_SnapshotRPC(t *testing.T) {

// Try to join.
joinLAN(t, c1, s1)
testrpc.WaitForLeader(t, c1.RPC, "dc1")

// Wait until we've got a healthy server.
retry.Run(t, func(r *retry.R) {
Expand Down
49 changes: 36 additions & 13 deletions agent/dns.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"regexp"

"github.com/armon/go-metrics"
"github.com/armon/go-radix"
"github.com/coredns/coredns/plugin/pkg/dnsutil"
"github.com/hashicorp/consul/agent/config"
"github.com/hashicorp/consul/agent/consul"
Expand Down Expand Up @@ -72,6 +73,9 @@ type DNSServer struct {
domain string
recursors []string
logger *log.Logger
// Those are handling prefix lookups
ttlRadix *radix.Tree
ttlStrict map[string]time.Duration

// disableCompression is the config.DisableCompression flag that can
// be safely changed at runtime. It always contains a bool and is
Expand Down Expand Up @@ -99,7 +103,21 @@ func NewDNSServer(a *Agent) (*DNSServer, error) {
domain: domain,
logger: a.logger,
recursors: recursors,
ttlRadix: radix.New(),
ttlStrict: make(map[string]time.Duration),
}
if dnscfg.ServiceTTL != nil {
for key, ttl := range dnscfg.ServiceTTL {
// All suffix with '*' are put in radix
// This include '*' that will match anything
if strings.HasSuffix(key, "*") {
srv.ttlRadix.Insert(key[:len(key)-1], ttl)
} else {
srv.ttlStrict[key] = ttl
}
}
}

srv.disableCompression.Store(a.config.DNSDisableCompression)

return srv, nil
Expand Down Expand Up @@ -130,6 +148,22 @@ func GetDNSConfig(conf *config.RuntimeConfig) *dnsConfig {
}
}

// GetTTLForService Find the TTL for a given service.
// return ttl, true if found, 0, false otherwise
func (d *DNSServer) GetTTLForService(service string) (time.Duration, bool) {
if d.config.ServiceTTL != nil {
ttl, ok := d.ttlStrict[service]
if ok {
return ttl, true
}
_, ttlRaw, ok := d.ttlRadix.LongestPrefix(service)
if ok {
return ttlRaw.(time.Duration), true
}
}
return time.Duration(0), false
}

func (d *DNSServer) ListenAndServe(network, addr string, notif func()) error {
mux := dns.NewServeMux()
mux.HandleFunc("arpa.", d.handlePtr)
Expand Down Expand Up @@ -1027,14 +1061,7 @@ func (d *DNSServer) serviceLookup(network, datacenter, service, tag string, conn
out.Nodes.Shuffle()

// Determine the TTL
var ttl time.Duration
if d.config.ServiceTTL != nil {
var ok bool
ttl, ok = d.config.ServiceTTL[service]
if !ok {
ttl = d.config.ServiceTTL["*"]
}
}
ttl, _ := d.GetTTLForService(service)

// Add various responses depending on the request
qType := req.Question[0].Qtype
Expand Down Expand Up @@ -1155,11 +1182,7 @@ RPC:
d.logger.Printf("[WARN] dns: Failed to parse TTL '%s' for prepared query '%s', ignoring", out.DNS.TTL, query)
}
} else if d.config.ServiceTTL != nil {
var ok bool
ttl, ok = d.config.ServiceTTL[out.Service]
if !ok {
ttl = d.config.ServiceTTL["*"]
}
ttl, _ = d.GetTTLForService(out.Service)
}

// If we have no nodes, return not found!
Expand Down
Loading

0 comments on commit fab55be

Please sign in to comment.