Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rule: prevent rule crash from no such host error #3672

Merged
merged 1 commit into from
Jan 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ We use _breaking :warning:_ to mark changes that are not backward compatible (re

- [#3527](https://github.com/thanos-io/thanos/pull/3527) Query Frontend: Fix query_range behavior when start/end times are the same
- [#3560](https://github.com/thanos-io/thanos/pull/3560) query-frontend: Allow separate label cache
- [#3672](https://github.com/thanos-io/thanos/pull/3672) rule: prevent rule crash from no such host error when using `dnssrv+` or `dnssrvnoa+`.

### Changed

Expand Down
25 changes: 25 additions & 0 deletions pkg/discovery/dns/godns/resolver.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) The Thanos Authors.
// Licensed under the Apache License 2.0.

package godns

import (
"net"

"github.com/pkg/errors"
)

// Resolver is a wrapper for net.Resolver.
type Resolver struct {
*net.Resolver
}

// IsNotFound checkout if DNS record is not found.
func (r *Resolver) IsNotFound(err error) bool {
if err == nil {
return false
}
err = errors.Cause(err)
dnsErr, ok := err.(*net.DNSError)
return ok && dnsErr.IsNotFound
}
4 changes: 3 additions & 1 deletion pkg/discovery/dns/miekgdns/lookup.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"github.com/pkg/errors"
)

var ErrNoSuchHost = errors.New("no such host")

// Copied and slightly adjusted from Prometheus DNS SD:
// https://github.com/prometheus/prometheus/blob/be3c082539d85908ce03b6d280f83343e7c930eb/discovery/dns/dns.go#L212

Expand Down Expand Up @@ -68,7 +70,7 @@ func (r *Resolver) lookupWithSearchPath(name string, qtype dns.Type) (*dns.Msg,

if len(errs) == 0 {
// Outcome 2: everyone says NXDOMAIN.
return &dns.Msg{}, nil
return &dns.Msg{}, ErrNoSuchHost
}
// Outcome 3: boned.
return nil, errors.Errorf("could not resolve %q: all servers responded with errors to at least one search domain. Errs %s", name, fmtErrs(errs))
Expand Down
4 changes: 4 additions & 0 deletions pkg/discovery/dns/miekgdns/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,7 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr,
}
return resp, nil
}

func (r *Resolver) IsNotFound(err error) bool {
return errors.Is(errors.Cause(err), ErrNoSuchHost)
}
5 changes: 3 additions & 2 deletions pkg/discovery/dns/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/prometheus/client_golang/prometheus"
"github.com/prometheus/client_golang/prometheus/promauto"

"github.com/thanos-io/thanos/pkg/discovery/dns/godns"
"github.com/thanos-io/thanos/pkg/discovery/dns/miekgdns"
"github.com/thanos-io/thanos/pkg/errutil"
"github.com/thanos-io/thanos/pkg/extprom"
Expand Down Expand Up @@ -43,12 +44,12 @@ func (t ResolverType) ToResolver(logger log.Logger) ipLookupResolver {
var r ipLookupResolver
switch t {
case GolangResolverType:
r = net.DefaultResolver
r = &godns.Resolver{Resolver: net.DefaultResolver}
case MiekgdnsResolverType:
r = &miekgdns.Resolver{ResolvConf: miekgdns.DefaultResolvConfPath}
default:
level.Warn(logger).Log("msg", "no such resolver type, defaulting to golang", "type", t)
r = net.DefaultResolver
r = &godns.Resolver{Resolver: net.DefaultResolver}
}
return r
}
Expand Down
17 changes: 14 additions & 3 deletions pkg/discovery/dns/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ type Resolver interface {
type ipLookupResolver interface {
LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)
LookupSRV(ctx context.Context, service, proto, name string) (cname string, addrs []*net.SRV, err error)
IsNotFound(err error) bool
}

type dnsSD struct {
Expand Down Expand Up @@ -78,7 +79,7 @@ func (s *dnsSD) Resolve(ctx context.Context, name string, qtype QType) ([]string
// We exclude error from std Golang resolver for the case of the domain (e.g `NXDOMAIN`) not being found by DNS
// server. Since `miekg` does not consider this as an error, when the host cannot be found, empty slice will be
// returned.
if dnsErr, ok := err.(*net.DNSError); !ok || !dnsErr.IsNotFound {
if !s.resolver.IsNotFound(err) {
return nil, errors.Wrapf(err, "lookup IP addresses %q", host)
}
if ips == nil {
Expand All @@ -91,7 +92,12 @@ func (s *dnsSD) Resolve(ctx context.Context, name string, qtype QType) ([]string
case SRV, SRVNoA:
_, recs, err := s.resolver.LookupSRV(ctx, "", "", host)
if err != nil {
return nil, errors.Wrapf(err, "lookup SRV records %q", host)
if !s.resolver.IsNotFound(err) {
return nil, errors.Wrapf(err, "lookup SRV records %q", host)
}
if len(recs) == 0 {
level.Error(s.logger).Log("msg", "failed to lookup SRV records", "host", host, "err", err)
}
}

for _, rec := range recs {
Expand All @@ -108,7 +114,12 @@ func (s *dnsSD) Resolve(ctx context.Context, name string, qtype QType) ([]string
// Do A lookup for the domain in SRV answer.
resIPs, err := s.resolver.LookupIPAddr(ctx, rec.Target)
if err != nil {
return nil, errors.Wrapf(err, "look IP addresses %q", rec.Target)
if !s.resolver.IsNotFound(err) {
return nil, errors.Wrapf(err, "lookup IP addresses %q", host)
}
if len(resIPs) == 0 {
level.Error(s.logger).Log("msg", "failed to lookup IP addresses", "host", host, "err", err)
}
}
for _, resIP := range resIPs {
res = append(res, appendScheme(scheme, net.JoinHostPort(resIP.String(), resPort)))
Expand Down
4 changes: 4 additions & 0 deletions pkg/discovery/dns/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ func (m mockHostnameResolver) LookupSRV(ctx context.Context, service, proto, nam
return "", m.resultSRVs[name], nil
}

func (m mockHostnameResolver) IsNotFound(err error) bool {
return false
}

type DNSSDTest struct {
testName string
addr string
Expand Down