Added support to auto discovery with SRV DNS registry (#60)

* Added support to auto discovery witih SRV

The yaml configuration has been modified to suport srv parameters.
Now the name is taken form the router identity to allow dynamic
discovery of devices based on SRV registry.

* Corrected format

* feat(collector): Added support to use custom DNS

* feat(collector): get default dns server from resolv.conf

* Remove getIdentity on the static config devices
This commit is contained in:
wolmi
2020-02-04 04:03:45 +01:00
committed by GitHub
parent 75b5f8be36
commit d723fdfe38
5 changed files with 121 additions and 5 deletions

View File

@@ -8,11 +8,15 @@ import (
"fmt"
"io"
"net"
"os"
"strconv"
"strings"
"sync"
"time"
"mikrotik-exporter/config"
"github.com/miekg/dns"
"github.com/prometheus/client_golang/prometheus"
log "github.com/sirupsen/logrus"
routeros "gopkg.in/routeros.v2"
@@ -22,6 +26,7 @@ const (
namespace = "mikrotik"
apiPort = "8728"
apiPortTLS = "8729"
dnsPort = 53
// DefaultTimeout defines the default timeout when connecting to a router
DefaultTimeout = 5 * time.Second
@@ -194,9 +199,52 @@ func (c *collector) Describe(ch chan<- *prometheus.Desc) {
// Collect implements the prometheus.Collector interface.
func (c *collector) Collect(ch chan<- prometheus.Metric) {
wg := sync.WaitGroup{}
wg.Add(len(c.devices))
var realDevices []config.Device
for _, dev := range c.devices {
if (config.SrvRecord{}) != dev.Srv {
log.WithFields(log.Fields{
"SRV": dev.Srv.Record,
}).Info("SRV configuration detected")
conf, _ := dns.ClientConfigFromFile("/etc/resolv.conf")
dnsServer := net.JoinHostPort(conf.Servers[0], strconv.Itoa(dnsPort))
if (config.DnsServer{}) != dev.Srv.Dns {
dnsServer = net.JoinHostPort(dev.Srv.Dns.Address, strconv.Itoa(dev.Srv.Dns.Port))
log.WithFields(log.Fields{
"DnsServer": dnsServer,
}).Info("Custom DNS config detected")
}
dnsMsg := new(dns.Msg)
dnsCli := new(dns.Client)
dnsMsg.RecursionDesired = true
dnsMsg.SetQuestion(dns.Fqdn(dev.Srv.Record), dns.TypeSRV)
r, _, err := dnsCli.Exchange(dnsMsg, dnsServer)
if err != nil {
os.Exit(1)
}
for _, k := range r.Answer {
if s, ok := k.(*dns.SRV); ok {
d := config.Device{}
d.Name = strings.TrimRight(s.Target, ".")
d.Address = strings.TrimRight(s.Target, ".")
d.User = dev.User
d.Password = dev.Password
c.getIdentity(&d)
realDevices = append(realDevices, d)
}
}
} else {
realDevices = append(realDevices, dev)
}
}
wg.Add(len(realDevices))
for _, dev := range realDevices {
go func(d config.Device) {
c.collectForDevice(d, ch)
wg.Done()
@@ -206,6 +254,30 @@ func (c *collector) Collect(ch chan<- prometheus.Metric) {
wg.Wait()
}
func (c *collector) getIdentity(d *config.Device) error {
cl, err := c.connect(d)
if err != nil {
log.WithFields(log.Fields{
"device": d.Name,
"error": err,
}).Error("error dialing device")
return err
}
defer cl.Close()
reply, err := cl.Run("/system/identity/print")
if err != nil {
log.WithFields(log.Fields{
"device": d.Name,
"error": err,
}).Error("error fetching ethernet interfaces")
return err
}
for _, id := range reply.Re {
d.Name = id.Map["name"]
}
return nil
}
func (c *collector) collectForDevice(d config.Device, ch chan<- prometheus.Metric) {
begin := time.Now()