diff options
Diffstat (limited to 'src/go/collectors/go.d.plugin/modules/powerdns')
12 files changed, 2235 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/powerdns/README.md b/src/go/collectors/go.d.plugin/modules/powerdns/README.md new file mode 120000 index 0000000000..3e5989715e --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/powerdns/README.md @@ -0,0 +1 @@ +integrations/powerdns_authoritative_server.md
\ No newline at end of file diff --git a/src/go/collectors/go.d.plugin/modules/powerdns/authoritativens.go b/src/go/collectors/go.d.plugin/modules/powerdns/authoritativens.go new file mode 100644 index 0000000000..07b7fdbcfe --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/powerdns/authoritativens.go @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package powerdns + +import ( + _ "embed" + "net/http" + "time" + + "github.com/netdata/go.d.plugin/agent/module" + "github.com/netdata/go.d.plugin/pkg/web" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("powerdns", module.Creator{ + JobConfigSchema: configSchema, + Create: func() module.Module { return New() }, + }) +} + +func New() *AuthoritativeNS { + return &AuthoritativeNS{ + Config: Config{ + HTTP: web.HTTP{ + Request: web.Request{ + URL: "http://127.0.0.1:8081", + }, + Client: web.Client{ + Timeout: web.Duration{Duration: time.Second}, + }, + }, + }, + } +} + +type Config struct { + web.HTTP `yaml:",inline"` +} + +type AuthoritativeNS struct { + module.Base + Config `yaml:",inline"` + + httpClient *http.Client + charts *module.Charts +} + +func (ns *AuthoritativeNS) Init() bool { + err := ns.validateConfig() + if err != nil { + ns.Errorf("config validation: %v", err) + return false + } + + client, err := ns.initHTTPClient() + if err != nil { + ns.Errorf("init HTTP client: %v", err) + return false + } + ns.httpClient = client + + cs, err := ns.initCharts() + if err != nil { + ns.Errorf("init charts: %v", err) + return false + } + ns.charts = cs + + return true +} + +func (ns *AuthoritativeNS) Check() bool { + return len(ns.Collect()) > 0 +} + +func (ns *AuthoritativeNS) Charts() *module.Charts { + return ns.charts +} + +func (ns *AuthoritativeNS) Collect() map[string]int64 { + ms, err := ns.collect() + if err != nil { + ns.Error(err) + } + + if len(ms) == 0 { + return nil + } + return ms +} + +func (ns *AuthoritativeNS) Cleanup() { + if ns.httpClient == nil { + return + } + ns.httpClient.CloseIdleConnections() +} diff --git a/src/go/collectors/go.d.plugin/modules/powerdns/authoritativens_test.go b/src/go/collectors/go.d.plugin/modules/powerdns/authoritativens_test.go new file mode 100644 index 0000000000..71e5c6dc4d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/powerdns/authoritativens_test.go @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package powerdns + +import ( + "net/http" + "net/http/httptest" + "os" + "testing" + + "github.com/netdata/go.d.plugin/pkg/tlscfg" + "github.com/netdata/go.d.plugin/pkg/web" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + v430statistics, _ = os.ReadFile("testdata/v4.3.0/statistics.json") + recursorStatistics, _ = os.ReadFile("testdata/recursor/statistics.json") +) + +func Test_testDataIsCorrectlyReadAndValid(t *testing.T) { + for name, data := range map[string][]byte{ + "v430statistics": v430statistics, + "recursorStatistics": recursorStatistics, + } { + require.NotNilf(t, data, name) + } +} + +func TestNew(t *testing.T) { + assert.IsType(t, (*AuthoritativeNS)(nil), New()) +} + +func TestRecursor_Init(t *testing.T) { + tests := map[string]struct { + config Config + wantFail bool + }{ + "success on default config": { + config: New().Config, + }, + "fails on unset URL": { + wantFail: true, + config: Config{ + HTTP: web.HTTP{ + Request: web.Request{URL: ""}, + }, + }, + }, + "fails on invalid TLSCA": { + wantFail: true, + config: Config{ + HTTP: web.HTTP{ + Request: web.Request{ + URL: "http://127.0.0.1:38001", + }, + Client: web.Client{ + TLSConfig: tlscfg.TLSConfig{TLSCA: "testdata/tls"}, + }, + }, + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + ns := New() + ns.Config = test.config + + if test.wantFail { + assert.False(t, ns.Init()) + } else { + assert.True(t, ns.Init()) + } + }) + } +} + +func TestRecursor_Check(t *testing.T) { + tests := map[string]struct { + prepare func() (p *AuthoritativeNS, cleanup func()) + wantFail bool + }{ + "success on valid response v4.3.0": { + prepare: preparePowerDNSAuthoritativeNSV430, + }, + "fails on response from PowerDNS Recursor": { + wantFail: true, + prepare: preparePowerDNSAuthoritativeNSRecursorData, + }, + "fails on 404 response": { + wantFail: true, + prepare: preparePowerDNSAuthoritativeNS404, + }, + "fails on connection refused": { + wantFail: true, + prepare: preparePowerDNSAuthoritativeNSConnectionRefused, + }, + "fails on response with invalid data": { + wantFail: true, + prepare: preparePowerDNSAuthoritativeNSInvalidData, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + recursor, cleanup := test.prepare() + defer cleanup() + require.True(t, recursor.Init()) + + if test.wantFail { + assert.False(t, recursor.Check()) + } else { + assert.True(t, recursor.Check()) + } + }) + } +} + +func TestRecursor_Charts(t *testing.T) { + recursor := New() + require.True(t, recursor.Init()) + assert.NotNil(t, recursor.Charts()) +} + +func TestRecursor_Cleanup(t *testing.T) { + assert.NotPanics(t, New().Cleanup) +} + +func TestRecursor_Collect(t *testing.T) { + tests := map[string]struct { + prepare func() (p *AuthoritativeNS, cleanup func()) + wantCollected map[string]int64 + }{ + "success on valid response v4.3.0": { + prepare: preparePowerDNSAuthoritativeNSV430, + wantCollected: map[string]int64{ + "corrupt-packets": 1, + "cpu-iowait": 513, + "cpu-steal": 1, + "deferred-cache-inserts": 1, + "deferred-cache-lookup": 1, + "deferred-packetcache-inserts": 1, + "deferred-packetcache-lookup": 1, + "dnsupdate-answers": 1, + "dnsupdate-changes": 1, + "dnsupdate-queries": 1, + "dnsupdate-refused": 1, + "fd-usage": 23, + "incoming-notifications": 1, + "key-cache-size": 1, + "latency": 1, + "meta-cache-size": 1, + "open-tcp-connections": 1, + "overload-drops": 1, + "packetcache-hit": 1, + "packetcache-miss": 1, + "packetcache-size": 1, + "qsize-q": 1, + "query-cache-hit": 1, + "query-cache-miss": 1, + "query-cache-size": 1, + "rd-queries": 1, + "real-memory-usage": 164507648, + "recursing-answers": 1, + "recursing-questions": 1, + "recursion-unanswered": 1, + "ring-logmessages-capacity": 10000, + "ring-logmessages-size": 10, + "ring-noerror-queries-capacity": 10000, + "ring-noerror-queries-size": 1, + "ring-nxdomain-queries-capacity": 10000, + "ring-nxdomain-queries-size": 1, + "ring-queries-capacity": 10000, + "ring-queries-size": 1, + "ring-remotes-capacity": 10000, + "ring-remotes-corrupt-capacity": 10000, + "ring-remotes-corrupt-size": 1, + "ring-remotes-size": 1, + "ring-remotes-unauth-capacity": 10000, + "ring-remotes-unauth-size": 1, + "ring-servfail-queries-capacity": 10000, + "ring-servfail-queries-size": 1, + "ring-unauth-queries-capacity": 10000, + "ring-unauth-queries-size": 1, + "security-status": 1, + "servfail-packets": 1, + "signature-cache-size": 1, + "signatures": 1, + "sys-msec": 128, + "tcp-answers": 1, + "tcp-answers-bytes": 1, + "tcp-queries": 1, + "tcp4-answers": 1, + "tcp4-answers-bytes": 1, + "tcp4-queries": 1, + "tcp6-answers": 1, + "tcp6-answers-bytes": 1, + "tcp6-queries": 1, + "timedout-packets": 1, + "udp-answers": 1, + "udp-answers-bytes": 1, + "udp-do-queries": 1, + "udp-in-errors": 1, + "udp-noport-errors": 1, + "udp-queries": 1, + "udp-recvbuf-errors": 1, + "udp-sndbuf-errors": 1, + "udp4-answers": 1, + "udp4-answers-bytes": 1, + "udp4-queries": 1, + "udp6-answers": 1, + "udp6-answers-bytes": 1, + "udp6-queries": 1, + "uptime": 207, + "user-msec": 56, + }, + }, + "fails on response from PowerDNS Recursor": { + prepare: preparePowerDNSAuthoritativeNSRecursorData, + }, + "fails on 404 response": { + prepare: preparePowerDNSAuthoritativeNS404, + }, + "fails on connection refused": { + prepare: preparePowerDNSAuthoritativeNSConnectionRefused, + }, + "fails on response with invalid data": { + prepare: preparePowerDNSAuthoritativeNSInvalidData, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + ns, cleanup := test.prepare() + defer cleanup() + require.True(t, ns.Init()) + + collected := ns.Collect() + + assert.Equal(t, test.wantCollected, collected) + if len(test.wantCollected) > 0 { + ensureCollectedHasAllChartsDimsVarsIDs(t, ns, collected) + } + }) + } +} + +func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, ns *AuthoritativeNS, collected map[string]int64) { + for _, chart := range *ns.Charts() { + if chart.Obsolete { + continue + } + for _, dim := range chart.Dims { + _, ok := collected[dim.ID] + assert.Truef(t, ok, "chart '%s' dim '%s': no dim in collected", dim.ID, chart.ID) + } + for _, v := range chart.Vars { + _, ok := collected[v.ID] + assert.Truef(t, ok, "chart '%s' dim '%s': no dim in collected", v.ID, chart.ID) + } + } +} + +func preparePowerDNSAuthoritativeNSV430() (*AuthoritativeNS, func()) { + srv := preparePowerDNSAuthoritativeNSEndpoint() + ns := New() + ns.URL = srv.URL + + return ns, srv.Close +} + +func preparePowerDNSAuthoritativeNSRecursorData() (*AuthoritativeNS, func()) { + srv := preparePowerDNSRecursorEndpoint() + ns := New() + ns.URL = srv.URL + + return ns, srv.Close +} + +func preparePowerDNSAuthoritativeNSInvalidData() (*AuthoritativeNS, func()) { + srv := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + _, _ = w.Write([]byte("hello and\n goodbye")) + })) + ns := New() + ns.URL = srv.URL + + return ns, srv.Close +} + +func preparePowerDNSAuthoritativeNS404() (*AuthoritativeNS, func()) { + srv := httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusNotFound) + })) + ns := New() + ns.URL = srv.URL + + return ns, srv.Close +} + +func preparePowerDNSAuthoritativeNSConnectionRefused() (*AuthoritativeNS, func()) { + ns := New() + ns.URL = "http://127.0.0.1:38001" + + return ns, func() {} +} + +func preparePowerDNSAuthoritativeNSEndpoint() *httptest.Server { + return httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case urlPathLocalStatistics: + _, _ = w.Write(v430statistics) + default: + w.WriteHeader(http.StatusNotFound) + } + })) +} + +func preparePowerDNSRecursorEndpoint() *httptest.Server { + return httptest.NewServer(http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case urlPathLocalStatistics: + _, _ = w.Write(recursorStatistics) + default: + w.WriteHeader(http.StatusNotFound) + } + })) +} diff --git a/src/go/collectors/go.d.plugin/modules/powerdns/charts.go b/src/go/collectors/go.d.plugin/modules/powerdns/charts.go new file mode 100644 index 0000000000..aa61149e69 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/powerdns/charts.go @@ -0,0 +1,66 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package powerdns + +import "github.com/netdata/go.d.plugin/agent/module" + +var charts = module.Charts{ + { + ID: "questions_in", + Title: "Incoming questions", + Units: "questions/s", + Fam: "questions", + Ctx: "powerdns.questions_in", + Dims: module.Dims{ + {ID: "udp-queries", Name: "udp", Algo: module.Incremental}, + {ID: "tcp-queries", Name: "tcp", Algo: module.Incremental}, + }, + }, + { + ID: "questions_out", + Title: "Outgoing questions", + Units: "questions/s", + Fam: "questions", + Ctx: "powerdns.questions_out", + Dims: module.Dims{ + {ID: "udp-answers", Name: "udp", Algo: module.Incremental}, + {ID: "tcp-answers", Name: "tcp", Algo: module.Incremental}, + }, + }, + { + ID: "cache_usage", + Title: "Cache Usage", + Units: "events/s", + Fam: "cache", + Ctx: "powerdns.cache_usage", + Dims: module.Dims{ + {ID: "query-cache-hit", Algo: module.Incremental}, + {ID: "query-cache-miss", Algo: module.Incremental}, + {ID: "packetcache-hit", Name: "packet-cache-hit", Algo: module.Incremental}, + {ID: "packetcache-miss", Name: "packet-cache-miss", Algo: module.Incremental}, + }, + }, + { + ID: "cache_size", + Title: "Cache Size", + Units: "entries", + Fam: "cache", + Ctx: "powerdns.cache_size", + Dims: module.Dims{ + {ID: "query-cache-size", Name: "query-cache"}, + {ID: "packetcache-size", Name: "packet-cache"}, + {ID: "key-cache-size", Name: "key-cache"}, + {ID: "meta-cache-size", Name: "meta-cache"}, + }, + }, + { + ID: "latency", + Title: "Answer latency", + Units: "microseconds", + Fam: "latency", + Ctx: "powerdns.latency", + Dims: module.Dims{ + {ID: "latency"}, + }, + }, +} diff --git a/src/go/collectors/go.d.plugin/modules/powerdns/collect.go b/src/go/collectors/go.d.plugin/modules/powerdns/collect.go new file mode 100644 index 0000000000..7a184d9160 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/powerdns/collect.go @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package powerdns + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "net/http" + "strconv" + + "github.com/netdata/go.d.plugin/pkg/web" +) + +const ( + urlPathLocalStatistics = "/api/v1/servers/localhost/statistics" +) + +func (ns *AuthoritativeNS) collect() (map[string]int64, error) { + statistics, err := ns.scrapeStatistics() + if err != nil { + return nil, err + } + + collected := make(map[string]int64) + + ns.collectStatistics(collected, statistics) + + if !isPowerDNSAuthoritativeNSMetrics(collected) { + return nil, errors.New("returned metrics aren't PowerDNS Authoritative Server metrics") + } + + return collected, nil +} + +func isPowerDNSAuthoritativeNSMetrics(collected map[string]int64) bool { + // PowerDNS Recursor has same endpoint and returns data in the same format. + _, ok1 := collected["over-capacity-drops"] + _, ok2 := collected["tcp-questions"] + return !ok1 && !ok2 +} + +func (ns *AuthoritativeNS) collectStatistics(collected map[string]int64, statistics statisticMetrics) { + for _, s := range statistics { + // https://doc.powerdns.com/authoritative/http-api/statistics.html#statisticitem + if s.Type != "StatisticItem" { + continue + } + + value, ok := s.Value.(string) + if !ok { + ns.Debugf("%s value (%v) unexpected type: want=string, got=%T.", s.Name, s.Value, s.Value) + continue + } + + v, err := strconv.ParseInt(value, 10, 64) + if err != nil { + ns.Debugf("%s value (%v) parse error: %v", s.Name, s.Value, err) + continue + } + + collected[s.Name] = v + } +} + +func (ns *AuthoritativeNS) scrapeStatistics() ([]statisticMetric, error) { + req, _ := web.NewHTTPRequest(ns.Request) + req.URL.Path = urlPathLocalStatistics + + var statistics statisticMetrics + if err := ns.doOKDecode(req, &statistics); err != nil { + return nil, err + } + + return statistics, nil +} + +func (ns *AuthoritativeNS) doOKDecode(req *http.Request, in interface{}) error { + resp, err := ns.httpClient.Do(req) + if err != nil { + return fmt.Errorf("error on HTTP request '%s': %v", req.URL, err) + } + defer closeBody(resp) + + if resp.StatusCode != http.StatusOK { + return fmt.Errorf("'%s' returned HTTP status code: %d", req.URL, resp.StatusCode) + } + + if err := json.NewDecoder(resp.Body).Decode(in); err != nil { + return fmt.Errorf("error on decoding response from '%s': %v", req.URL, err) + } + return nil +} + +func closeBody(resp *http.Response) { + if resp != nil && resp.Body != nil { + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + } +} diff --git a/src/go/collectors/go.d.plugin/modules/powerdns/config_schema.json b/src/go/collectors/go.d.plugin/modules/powerdns/config_schema.json new file mode 100644 index 0000000000..93f8e72a2a --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/powerdns/config_schema.json @@ -0,0 +1,59 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "go.d/powerdns job configuration schema.", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "url": { + "type": "string" + }, + "timeout": { + "type": [ + "string", + "integer" + ] + }, + "username": { + "type": "string" + }, + "password": { + "type": "string" + }, + "proxy_url": { + "type": "string" + }, + "proxy_username": { + "type": "string" + }, + "proxy_password": { + "type": "string" + }, + "headers": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "not_follow_redirects": { + "type": "boolean" + }, + "tls_ca": { + "type": "string" + }, + "tls_cert": { + "type": "string" + }, + "tls_key": { + "type": "string" + }, + "insecure_skip_verify": { + "type": "boolean" + } + }, + "required": [ + "name", + "url" + ] +} diff --git a/src/go/collectors/go.d.plugin/modules/powerdns/init.go b/src/go/collectors/go.d.plugin/modules/powerdns/init.go new file mode 100644 index 0000000000..a577db7732 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/powerdns/init.go @@ -0,0 +1,29 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package powerdns + +import ( + "errors" + "net/http" + + "github.com/netdata/go.d.plugin/agent/module" + "github.com/netdata/go.d.plugin/pkg/web" +) + +func (ns AuthoritativeNS) validateConfig() error { + if ns.URL == "" { + return errors.New("URL not set") + } + if _, err := web.NewHTTPRequest(ns.Request); err != nil { + return err + } + return nil +} + +func (ns AuthoritativeNS) initHTTPClient() (*http.Client, error) { + return web.NewHTTPClient(ns.Client) +} + +func (ns AuthoritativeNS) initCharts() (*module.Charts, error) { + return charts.Copy(), nil +} diff --git a/src/go/collectors/go.d.plugin/modules/powerdns/integrations/powerdns_authoritative_server.md b/src/go/collectors/go.d.plugin/modules/powerdns/integrations/powerdns_authoritative_server.md new file mode 100644 index 0000000000..4c776193a5 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/powerdns/integrations/powerdns_authoritative_server.md @@ -0,0 +1,223 @@ +<!--startmeta +custom_edit_url: "https://github.com/netdata/go.d.plugin/edit/master/modules/powerdns/README.md" +meta_yaml: "https://github.com/netdata/go.d.plugin/edit/master/modules/powerdns/metadata.yaml" +sidebar_label: "PowerDNS Authoritative Server" +learn_status: "Published" +learn_rel_path: "Data Collection/DNS and DHCP Servers" +most_popular: False +message: "DO NOT EDIT THIS FILE DIRECTLY, IT IS GENERATED BY THE COLLECTOR'S metadata.yaml FILE" +endmeta--> + +# PowerDNS Authoritative Server + + +<img src="https://netdata.cloud/img/powerdns.svg" width="150"/> + + +Plugin: go.d.plugin +Module: powerdns + +<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" /> + +## Overview + +This collector monitors PowerDNS Authoritative Server instances. +It collects metrics from [the internal webserver](https://doc.powerdns.com/authoritative/http-api/index.html#webserver). + +Used endpoints: + +- [`/api/v1/servers/localhost/statistics`](https://doc.powerdns.com/authoritative/http-api/statistics.html) + + + + +This collector is supported on all platforms. + +This collector supports collecting metrics from multiple instances of this integration, including remote instances. + + +### Default Behavior + +#### Auto-Detection + +This integration doesn't support auto-detection. + +#### Limits + +The default configuration for this integration does not impose any limits on data collection. + +#### Performance Impact + +The default configuration for this integration is not expected to impose a significant performance impact on the system. + + +## Metrics + +Metrics grouped by *scope*. + +The scope defines the instance that the metric belongs to. An instance is uniquely identified by a set of labels. + + + +### Per PowerDNS Authoritative Server instance + +These metrics refer to the entire monitored application. + +This scope has no labels. + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| powerdns.questions_in | udp, tcp | questions/s | +| powerdns.questions_out | udp, tcp | questions/s | +| powerdns.cache_usage | query-cache-hit, query-cache-miss, packetcache-hit, packetcache-miss | events/s | +| powerdns.cache_size | query-cache, packet-cache, key-cache, meta-cache | entries | +| powerdns.latency | latency | microseconds | + + + +## Alerts + +There are no alerts configured by default for this integration. + + +## Setup + +### Prerequisites + +#### Enable webserver + +Follow [webserver](https://doc.powerdns.com/authoritative/http-api/index.html#webserver) documentation. + + +#### Enable HTTP API + +Follow [HTTP API](https://doc.powerdns.com/authoritative/http-api/index.html#enabling-the-api) documentation. + + + +### Configuration + +#### File + +The configuration file name for this integration is `go.d/powerdns.conf`. + + +You can edit the configuration file using the `edit-config` script from the +Netdata [config directory](https://github.com/netdata/netdata/blob/master/docs/configure/nodes.md#the-netdata-config-directory). + +```bash +cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata +sudo ./edit-config go.d/powerdns.conf +``` +#### Options + +The following options can be defined globally: update_every, autodetection_retry. + + +<details><summary>Config options</summary> + +| Name | Description | Default | Required | +|:----|:-----------|:-------|:--------:| +| update_every | Data collection frequency. | 1 | no | +| autodetection_retry | Recheck interval in seconds. Zero means no recheck will be scheduled. | 0 | no | +| url | Server URL. | http://127.0.0.1:8081 | yes | +| timeout | HTTP request timeout. | 1 | no | +| username | Username for basic HTTP authentication. | | no | +| password | Password for basic HTTP authentication. | | no | +| proxy_url | Proxy URL. | | no | +| proxy_username | Username for proxy basic HTTP authentication. | | no | +| proxy_password | Password for proxy basic HTTP authentication. | | no | +| method | HTTP request method. | GET | no | +| body | HTTP request body. | | no | +| headers | HTTP request headers. | | no | +| not_follow_redirects | Redirect handling policy. Controls whether the client follows redirects. | no | no | +| tls_skip_verify | Server certificate chain and hostname validation policy. Controls whether the client performs this check. | no | no | +| tls_ca | Certification authority that the client uses when verifying the server's certificates. | | no | +| tls_cert | Client TLS certificate. | | no | +| tls_key | Client TLS key. | | no | + +</details> + +#### Examples + +##### Basic + +An example configuration. + +<details><summary>Config</summary> + +```yaml +jobs: + - name: local + url: http://127.0.0.1:8081 + +``` +</details> + +##### HTTP authentication + +Basic HTTP authentication. + +<details><summary>Config</summary> + +```yaml +jobs: + - name: local + url: http://127.0.0.1:8081 + username: admin + password: password + +``` +</details> + +##### Multi-instance + +> **Note**: When you define multiple jobs, their names must be unique. + +Local and remote instances. + + +<details><summary>Config</summary> + +```yaml +jobs: + - name: local + url: http://127.0.0.1:8081 + + - name: remote + url: http://203.0.113.0:8081 + +``` +</details> + + + +## Troubleshooting + +### Debug Mode + +To troubleshoot issues with the `powerdns` collector, run the `go.d.plugin` with the debug option enabled. The output +should give you clues as to why the collector isn't working. + +- Navigate to the `plugins.d` directory, usually at `/usr/libexec/netdata/plugins.d/`. If that's not the case on + your system, open `netdata.conf` and look for the `plugins` setting under `[directories]`. + + ```bash + cd /usr/libexec/netdata/plugins.d/ + ``` + +- Switch to the `netdata` user. + + ```bash + sudo -u netdata -s + ``` + +- Run the `go.d.plugin` to debug the collector: + + ```bash + ./go.d.plugin -d -m powerdns + ``` + + diff --git a/src/go/collectors/go.d.plugin/modules/powerdns/metadata.yaml b/src/go/collectors/go.d.plugin/modules/powerdns/metadata.yaml new file mode 100644 index 0000000000..ea4dec0b53 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/powerdns/metadata.yaml @@ -0,0 +1,215 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-powerdns + plugin_name: go.d.plugin + module_name: powerdns + monitored_instance: + name: PowerDNS Authoritative Server + link: https://doc.powerdns.com/authoritative/ + icon_filename: powerdns.svg + categories: + - data-collection.dns-and-dhcp-servers + keywords: + - powerdns + - dns + related_resources: + integrations: + list: [] + info_provided_to_referring_integrations: + description: "" + most_popular: false + overview: + data_collection: + metrics_description: | + This collector monitors PowerDNS Authoritative Server instances. + It collects metrics from [the internal webserver](https://doc.powerdns.com/authoritative/http-api/index.html#webserver). + + Used endpoints: + + - [`/api/v1/servers/localhost/statistics`](https://doc.powerdns.com/authoritative/http-api/statistics.html) + |