Merge pull request #946 from prometheus/add-sd-dns-a
Add support for A record based DNS SD
This commit is contained in:
commit
6e7d743cd4
|
@ -80,6 +80,7 @@ var (
|
||||||
// The default DNS SD configuration.
|
// The default DNS SD configuration.
|
||||||
DefaultDNSSDConfig = DNSSDConfig{
|
DefaultDNSSDConfig = DNSSDConfig{
|
||||||
RefreshInterval: Duration(30 * time.Second),
|
RefreshInterval: Duration(30 * time.Second),
|
||||||
|
Type: "SRV",
|
||||||
}
|
}
|
||||||
|
|
||||||
// The default file SD configuration.
|
// The default file SD configuration.
|
||||||
|
@ -362,7 +363,8 @@ func (tg *TargetGroup) UnmarshalJSON(b []byte) error {
|
||||||
type DNSSDConfig struct {
|
type DNSSDConfig struct {
|
||||||
Names []string `yaml:"names"`
|
Names []string `yaml:"names"`
|
||||||
RefreshInterval Duration `yaml:"refresh_interval,omitempty"`
|
RefreshInterval Duration `yaml:"refresh_interval,omitempty"`
|
||||||
|
Type string `yaml:"type"`
|
||||||
|
Port int `yaml:"port"` // Ignored for SRV records
|
||||||
// Catches all undefined fields and must be empty after parsing.
|
// Catches all undefined fields and must be empty after parsing.
|
||||||
XXX map[string]interface{} `yaml:",inline"`
|
XXX map[string]interface{} `yaml:",inline"`
|
||||||
}
|
}
|
||||||
|
@ -378,6 +380,15 @@ func (c *DNSSDConfig) UnmarshalYAML(unmarshal func(interface{}) error) error {
|
||||||
if len(c.Names) == 0 {
|
if len(c.Names) == 0 {
|
||||||
return fmt.Errorf("DNS-SD config must contain at least one SRV record name")
|
return fmt.Errorf("DNS-SD config must contain at least one SRV record name")
|
||||||
}
|
}
|
||||||
|
switch strings.ToUpper(c.Type) {
|
||||||
|
case "SRV":
|
||||||
|
case "A", "AAAA":
|
||||||
|
if c.Port == 0 {
|
||||||
|
return fmt.Errorf("a port is required in DNS-SD configs for all record types except SRV")
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("invalid DNS-SD records type %s", c.Type)
|
||||||
|
}
|
||||||
return checkOverflow(c.XXX, "dns_sd_config")
|
return checkOverflow(c.XXX, "dns_sd_config")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,12 +98,14 @@ var expectedConf = &Config{
|
||||||
"second.dns.address.domain.com",
|
"second.dns.address.domain.com",
|
||||||
},
|
},
|
||||||
RefreshInterval: Duration(15 * time.Second),
|
RefreshInterval: Duration(15 * time.Second),
|
||||||
|
Type: "SRV",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Names: []string{
|
Names: []string{
|
||||||
"first.dns.address.domain.com",
|
"first.dns.address.domain.com",
|
||||||
},
|
},
|
||||||
RefreshInterval: Duration(30 * time.Second),
|
RefreshInterval: Duration(30 * time.Second),
|
||||||
|
Type: "SRV",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -68,14 +68,27 @@ type DNSDiscovery struct {
|
||||||
done chan struct{}
|
done chan struct{}
|
||||||
ticker *time.Ticker
|
ticker *time.Ticker
|
||||||
m sync.RWMutex
|
m sync.RWMutex
|
||||||
|
port int
|
||||||
|
qtype uint16
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewDNSDiscovery returns a new DNSDiscovery which periodically refreshes its targets.
|
// NewDNSDiscovery returns a new DNSDiscovery which periodically refreshes its targets.
|
||||||
func NewDNSDiscovery(conf *config.DNSSDConfig) *DNSDiscovery {
|
func NewDNSDiscovery(conf *config.DNSSDConfig) *DNSDiscovery {
|
||||||
|
qtype := dns.TypeSRV
|
||||||
|
switch strings.ToUpper(conf.Type) {
|
||||||
|
case "A":
|
||||||
|
qtype = dns.TypeA
|
||||||
|
case "AAAA":
|
||||||
|
qtype = dns.TypeAAAA
|
||||||
|
case "SRV":
|
||||||
|
qtype = dns.TypeSRV
|
||||||
|
}
|
||||||
return &DNSDiscovery{
|
return &DNSDiscovery{
|
||||||
names: conf.Names,
|
names: conf.Names,
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
ticker: time.NewTicker(time.Duration(conf.RefreshInterval)),
|
ticker: time.NewTicker(time.Duration(conf.RefreshInterval)),
|
||||||
|
qtype: qtype,
|
||||||
|
port: conf.Port,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +143,7 @@ func (dd *DNSDiscovery) refreshAll(ch chan<- *config.TargetGroup) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (dd *DNSDiscovery) refresh(name string, ch chan<- *config.TargetGroup) error {
|
func (dd *DNSDiscovery) refresh(name string, ch chan<- *config.TargetGroup) error {
|
||||||
response, err := lookupSRV(name)
|
response, err := lookupAll(name, dd.qtype)
|
||||||
dnsSDLookupsCount.Inc()
|
dnsSDLookupsCount.Inc()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
dnsSDLookupFailuresCount.Inc()
|
dnsSDLookupFailuresCount.Inc()
|
||||||
|
@ -139,15 +152,22 @@ func (dd *DNSDiscovery) refresh(name string, ch chan<- *config.TargetGroup) erro
|
||||||
|
|
||||||
tg := &config.TargetGroup{}
|
tg := &config.TargetGroup{}
|
||||||
for _, record := range response.Answer {
|
for _, record := range response.Answer {
|
||||||
addr, ok := record.(*dns.SRV)
|
target := clientmodel.LabelValue("")
|
||||||
if !ok {
|
switch addr := record.(type) {
|
||||||
|
case *dns.SRV:
|
||||||
|
// Remove the final dot from rooted DNS names to make them look more usual.
|
||||||
|
addr.Target = strings.TrimRight(addr.Target, ".")
|
||||||
|
|
||||||
|
target = clientmodel.LabelValue(fmt.Sprintf("%s:%d", addr.Target, addr.Port))
|
||||||
|
case *dns.A:
|
||||||
|
target = clientmodel.LabelValue(fmt.Sprintf("%s:%d", addr.A, dd.port))
|
||||||
|
case *dns.AAAA:
|
||||||
|
target = clientmodel.LabelValue(fmt.Sprintf("%s:%d", addr.AAAA, dd.port))
|
||||||
|
default:
|
||||||
log.Warnf("%q is not a valid SRV record", record)
|
log.Warnf("%q is not a valid SRV record", record)
|
||||||
continue
|
continue
|
||||||
}
|
|
||||||
// Remove the final dot from rooted DNS names to make them look more usual.
|
|
||||||
addr.Target = strings.TrimRight(addr.Target, ".")
|
|
||||||
|
|
||||||
target := clientmodel.LabelValue(fmt.Sprintf("%s:%d", addr.Target, addr.Port))
|
}
|
||||||
tg.Targets = append(tg.Targets, clientmodel.LabelSet{
|
tg.Targets = append(tg.Targets, clientmodel.LabelSet{
|
||||||
clientmodel.AddressLabel: target,
|
clientmodel.AddressLabel: target,
|
||||||
DNSNameLabel: clientmodel.LabelValue(name),
|
DNSNameLabel: clientmodel.LabelValue(name),
|
||||||
|
@ -160,7 +180,7 @@ func (dd *DNSDiscovery) refresh(name string, ch chan<- *config.TargetGroup) erro
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookupSRV(name string) (*dns.Msg, error) {
|
func lookupAll(name string, qtype uint16) (*dns.Msg, error) {
|
||||||
conf, err := dns.ClientConfigFromFile(resolvConf)
|
conf, err := dns.ClientConfigFromFile(resolvConf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not load resolv.conf: %s", err)
|
return nil, fmt.Errorf("could not load resolv.conf: %s", err)
|
||||||
|
@ -172,7 +192,7 @@ func lookupSRV(name string) (*dns.Msg, error) {
|
||||||
for _, server := range conf.Servers {
|
for _, server := range conf.Servers {
|
||||||
servAddr := net.JoinHostPort(server, conf.Port)
|
servAddr := net.JoinHostPort(server, conf.Port)
|
||||||
for _, suffix := range conf.Search {
|
for _, suffix := range conf.Search {
|
||||||
response, err = lookup(name, dns.TypeSRV, client, servAddr, suffix, false)
|
response, err = lookup(name, qtype, client, servAddr, suffix, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Warnf("resolving %s.%s failed: %s", name, suffix, err)
|
log.Warnf("resolving %s.%s failed: %s", name, suffix, err)
|
||||||
continue
|
continue
|
||||||
|
@ -181,7 +201,7 @@ func lookupSRV(name string) (*dns.Msg, error) {
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response, err = lookup(name, dns.TypeSRV, client, servAddr, "", false)
|
response, err = lookup(name, qtype, client, servAddr, "", false)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return response, nil
|
return response, nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue