Skip to content
Open
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
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,14 @@ devices:
- host: host2.example.com:2233
username: exporter
password: secret
- host: router.*.example.com
# Tell the exporter that this hostname should be used as a pattern when loading
# device-specific configurations. This example would match against a hostname
# like "router1.example.com".
host_pattern: true
username: exporter
password: secret


features:
bgp: true
Expand Down
10 changes: 10 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package config
import (
"io"
"io/ioutil"
"regexp"
"strings"

"gopkg.in/yaml.v2"
Expand Down Expand Up @@ -31,6 +32,8 @@ type DeviceConfig struct {
Timeout *int `yaml:"timeout,omitempty"`
BatchSize *int `yaml:"batch_size,omitempty"`
Features *FeatureConfig `yaml:"features,omitempty"`
IsHostPattern bool `yaml:"host_pattern,omitempty"`
HostPattern *regexp.Regexp
}

// FeatureConfig is the list of collectors enabled or disabled
Expand Down Expand Up @@ -66,6 +69,13 @@ func Load(reader io.Reader) (*Config, error) {
}

for _, d := range c.Devices {
if d.IsHostPattern {
hostPattern, err := regexp.Compile(d.Host)
if err != nil {
return nil, err
}
d.HostPattern = hostPattern
}
if d.Features == nil {
continue
}
Expand Down
17 changes: 11 additions & 6 deletions devices.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,31 @@ import (
)

func devicesForConfig(cfg *config.Config) ([]*connector.Device, error) {
devs := make([]*connector.Device, len(cfg.Devices))
var err error
for i, d := range cfg.Devices {
devs[i], err = deviceFromDeviceConfig(d, cfg)
devs := make([]*connector.Device, 0)
for _, d := range cfg.Devices {
if d.IsHostPattern {
continue
}

dev, err := deviceFromDeviceConfig(d, d.Host, cfg)
if err != nil {
return nil, err
}

devs = append(devs, dev)
}

return devs, nil
}

func deviceFromDeviceConfig(device *config.DeviceConfig, cfg *config.Config) (*connector.Device, error) {
func deviceFromDeviceConfig(device *config.DeviceConfig, hostname string, cfg *config.Config) (*connector.Device, error) {
auth, err := authForDevice(device, cfg)
if err != nil {
return nil, errors.Wrapf(err, "could not initialize config for device %s", device.Host)
}

port := "22"
host := device.Host
host := hostname
if strings.Contains(host, ":") {
d := strings.Split(host, ":")
host = d[0]
Expand Down
39 changes: 38 additions & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,9 +144,16 @@ func startServer() {
}

func handleMetricsRequest(w http.ResponseWriter, r *http.Request) {

reg := prometheus.NewRegistry()

c := newCiscoCollector(devices)
devs, err := devicesForRequest(r)
if err != nil {
http.Error(w, err.Error(), 400)
return
}

c := newCiscoCollector(devs)
reg.MustRegister(c)

l := log.New()
Expand All @@ -156,3 +163,33 @@ func handleMetricsRequest(w http.ResponseWriter, r *http.Request) {
ErrorLog: l,
ErrorHandling: promhttp.ContinueOnError}).ServeHTTP(w, r)
}

func devicesForRequest(r *http.Request) ([]*connector.Device, error) {
reqTarget := r.URL.Query().Get("target")
if reqTarget == "" {
return devices, nil
}

for _, d := range devices {
if d.Host == reqTarget {
return []*connector.Device{d}, nil
}
}

for _, dc := range cfg.Devices {
if !dc.IsHostPattern {
continue
}

if dc.HostPattern.MatchString(reqTarget) {
d, err := deviceFromDeviceConfig(dc, reqTarget, cfg)
if err != nil {
return nil, err
}

return []*connector.Device{d}, nil
}
}

return nil, fmt.Errorf("the target '%s' is not defined in the configuration file", reqTarget)
}