diff options
Diffstat (limited to '')
17 files changed, 2052 insertions, 0 deletions
diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/README.md b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/README.md new file mode 120000 index 000000000..3385a00a4 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/README.md @@ -0,0 +1 @@ +integrations/isc_dhcp.md
\ No newline at end of file diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/charts.go b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/charts.go new file mode 100644 index 000000000..7165bbffb --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/charts.go @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package isc_dhcpd + +import ( + "github.com/netdata/netdata/go/go.d.plugin/agent/module" +) + +const ( + prioLeasesTotal = module.Priority + iota + + prioDHCPPoolUtilization + prioDHCPPoolActiveLeases +) + +var activeLeasesTotalChart = module.Chart{ + ID: "active_leases_total", + Title: "Active Leases Total", + Units: "leases", + Fam: "summary", + Ctx: "isc_dhcpd.active_leases_total", + Priority: prioLeasesTotal, + Dims: module.Dims{ + {ID: "active_leases_total", Name: "active"}, + }, +} + +var dhcpPoolChartsTmpl = module.Charts{ + dhcpPoolActiveLeasesChartTmpl.Copy(), + dhcpPoolUtilizationChartTmpl.Copy(), +} + +var ( + dhcpPoolUtilizationChartTmpl = module.Chart{ + ID: "dhcp_pool_%s_utilization", + Title: "DHCP Pool Utilization", + Units: "percent", + Fam: "pools", + Ctx: "isc_dhcpd.dhcp_pool_utilization", + Priority: prioDHCPPoolUtilization, + Type: module.Area, + Dims: module.Dims{ + {ID: "dhcp_pool_%s_utilization", Name: "utilization"}, + }, + } + dhcpPoolActiveLeasesChartTmpl = module.Chart{ + ID: "dhcp_pool_%s_active_leases", + Title: "DHCP Pool Active Leases", + Units: "leases", + Fam: "pools", + Ctx: "isc_dhcpd.dhcp_pool_active_leases", + Priority: prioDHCPPoolActiveLeases, + Dims: module.Dims{ + {ID: "dhcp_pool_%s_active_leases", Name: "active"}, + }, + } +) diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/collect.go b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/collect.go new file mode 100644 index 000000000..08716a108 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/collect.go @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package isc_dhcpd + +import ( + "os" +) + +/* +dhcpd.leases db (file), see details: https://kb.isc.org/docs/en/isc-dhcp-44-manual-pages-dhcpdleases#dhcpdleases + +Every time a lease is acquired, renewed or released, its new value is recorded at the end of the lease file. +So if more than one declaration appears for a given lease, the last one in the file is the current one. + +In order to prevent the lease database from growing without bound, the file is rewritten from time to time. +First, a temporary lease database is created and all known leases are dumped to it. +Then, the old lease database is renamed DBDIR/dhcpd.leases~. +Finally, the newly written lease database is moved into place. + +In order to process both DHCPv4 and DHCPv6 messages you will need to run two separate instances of the dhcpd process. +Each of these instances will need its own lease file. +*/ + +func (d *DHCPd) collect() (map[string]int64, error) { + fi, err := os.Stat(d.LeasesPath) + if err != nil { + return nil, err + } + + if d.leasesModTime.Equal(fi.ModTime()) { + d.Debugf("leases file is not modified, returning cached metrics ('%s')", d.LeasesPath) + return d.collected, nil + } + + d.leasesModTime = fi.ModTime() + + leases, err := parseDHCPdLeasesFile(d.LeasesPath) + if err != nil { + return nil, err + } + + activeLeases := removeInactiveLeases(leases) + d.Debugf("found total/active %d/%d leases ('%s')", len(leases), len(activeLeases), d.LeasesPath) + + for _, pool := range d.pools { + collectPool(d.collected, pool, activeLeases) + } + d.collected["active_leases_total"] = int64(len(activeLeases)) + + return d.collected, nil +} + +const precision = 100 + +func collectPool(collected map[string]int64, pool ipPool, leases []leaseEntry) { + n := calcPoolActiveLeases(pool, leases) + collected["dhcp_pool_"+pool.name+"_active_leases"] = n + collected["dhcp_pool_"+pool.name+"_utilization"] = int64(calcPoolUtilizationPercentage(pool, n) * precision) +} + +func calcPoolActiveLeases(pool ipPool, leases []leaseEntry) (num int64) { + for _, l := range leases { + if pool.addresses.Contains(l.ip) { + num++ + } + } + return num +} + +func calcPoolUtilizationPercentage(pool ipPool, leases int64) float64 { + size := pool.addresses.Size() + if leases == 0 || !size.IsInt64() { + return 0 + } + if size.Int64() == 0 { + return 100 + } + return float64(leases) / float64(size.Int64()) * 100 +} + +func removeInactiveLeases(leases []leaseEntry) (active []leaseEntry) { + active = leases[:0] + for _, l := range leases { + if l.bindingState == "active" { + active = append(active, l) + } + } + return active +} diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/config_schema.json b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/config_schema.json new file mode 100644 index 000000000..e357fd86d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/config_schema.json @@ -0,0 +1,70 @@ +{ + "jsonSchema": { + "$schema": "http://json-schema.org/draft-07/schema#", + "title": "ISC DHCP collector configuration.", + "type": "object", + "properties": { + "update_every": { + "title": "Update every", + "description": "Data collection interval, measured in seconds.", + "type": "integer", + "minimum": 1, + "default": 1 + }, + "leases_path": { + "title": "Leases file", + "description": "File path to the ISC DHCP server's lease database.", + "type": "string", + "default": "/var/lib/dhcp/dhcpd.leases", + "pattern": "^$|^/" + }, + "pools": { + "title": "IP pools", + "description": "A list of IP pools to monitor. Each pool consists of a descriptive name and corresponding IP ranges.", + "type": [ + "array", + "null" + ], + "items": { + "title": "IP pool", + "type": [ + "object", + "null" + ], + "properties": { + "name": { + "title": "Name", + "description": "A descriptive name for the IP pool.", + "type": "string" + }, + "networks": { + "title": "Networks", + "description": "A space-separated list of [IP ranges](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/pkg/iprange#supported-formats) for the pool.", + "type": "string" + } + }, + "required": [ + "name", + "networks" + ] + }, + "minItems": 1, + "uniqueItems": true, + "additionalItems": false + } + }, + "required": [ + "leases_path", + "pools" + ], + "additionalProperties": false, + "patternProperties": { + "^name$": {} + } + }, + "uiSchema": { + "uiOptions": { + "fullPage": true + } + } +} diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/init.go b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/init.go new file mode 100644 index 000000000..861ded398 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/init.go @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package isc_dhcpd + +import ( + "errors" + "fmt" + "strings" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + "github.com/netdata/netdata/go/go.d.plugin/pkg/iprange" +) + +type ipPool struct { + name string + addresses iprange.Pool +} + +func (d *DHCPd) validateConfig() error { + if d.Config.LeasesPath == "" { + return errors.New("'lease_path' parameter not set") + } + if len(d.Config.Pools) == 0 { + return errors.New("'pools' parameter not set") + } + for i, cfg := range d.Config.Pools { + if cfg.Name == "" { + return fmt.Errorf("'pools[%d]->pool.name' parameter not set", i+1) + } + if cfg.Networks == "" { + return fmt.Errorf("'pools[%d]->pool.networks' parameter not set", i+1) + } + } + return nil +} + +func (d *DHCPd) initPools() ([]ipPool, error) { + var pools []ipPool + + for i, cfg := range d.Pools { + ipRange, err := iprange.ParseRanges(cfg.Networks) + if err != nil { + return nil, fmt.Errorf("parse pools[%d]->pool.networks '%s' ('%s'): %v", i+1, cfg.Name, cfg.Networks, err) + } + if len(ipRange) == 0 { + continue + } + + pool := ipPool{name: cfg.Name, addresses: ipRange} + pools = append(pools, pool) + } + + return pools, nil +} + +func (d *DHCPd) initCharts(pools []ipPool) (*module.Charts, error) { + charts := &module.Charts{} + + if err := charts.Add(activeLeasesTotalChart.Copy()); err != nil { + return nil, err + } + + for _, pool := range pools { + poolCharts := dhcpPoolChartsTmpl.Copy() + + for _, chart := range *poolCharts { + chart.ID = fmt.Sprintf(chart.ID, cleanPoolNameForChart(pool.name)) + chart.Labels = []module.Label{ + {Key: "dhcp_pool_name", Value: pool.name}, + } + for _, dim := range chart.Dims { + dim.ID = fmt.Sprintf(dim.ID, pool.name) + } + } + + if err := charts.Add(*poolCharts...); err != nil { + return nil, err + } + } + + return charts, nil +} + +func cleanPoolNameForChart(name string) string { + name = strings.ReplaceAll(name, " ", "_") + name = strings.ReplaceAll(name, ".", "_") + return name +} diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/integrations/isc_dhcp.md b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/integrations/isc_dhcp.md new file mode 100644 index 000000000..29d657c8d --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/integrations/isc_dhcp.md @@ -0,0 +1,193 @@ +<!--startmeta +custom_edit_url: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/isc_dhcpd/README.md" +meta_yaml: "https://github.com/netdata/netdata/edit/master/src/go/collectors/go.d.plugin/modules/isc_dhcpd/metadata.yaml" +sidebar_label: "ISC DHCP" +learn_status: "Published" +learn_rel_path: "Collecting Metrics/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--> + +# ISC DHCP + + +<img src="https://netdata.cloud/img/isc.png" width="150"/> + + +Plugin: go.d.plugin +Module: isc_dhcpd + +<img src="https://img.shields.io/badge/maintained%20by-Netdata-%2300ab44" /> + +## Overview + +This collector monitors ISC DHCP lease usage by reading the DHCP client lease database (dhcpd.leases). + + + + +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 ISC DHCP instance + +These metrics refer to the entire monitored application. + +This scope has no labels. + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| isc_dhcpd.active_leases_total | active | leases | + +### Per ISC DHCP instance + +These metrics refer to the DHCP pool. + +Labels: + +| Label | Description | +|:-----------|:----------------| +| dhcp_pool_name | The DHCP pool name defined in the collector configuration. | + +Metrics: + +| Metric | Dimensions | Unit | +|:------|:----------|:----| +| isc_dhcpd.dhcp_pool_utilization | utilization | percent | +| isc_dhcpd.dhcp_pool_active_leases | active | leases | + + + +## Alerts + +There are no alerts configured by default for this integration. + + +## Setup + +### Prerequisites + +No action required. + +### Configuration + +#### File + +The configuration file name for this integration is `go.d/isc_dhcpd.conf`. + + +You can edit the configuration file using the `edit-config` script from the +Netdata [config directory](/docs/netdata-agent/configuration/README.md#the-netdata-config-directory). + +```bash +cd /etc/netdata 2>/dev/null || cd /opt/netdata/etc/netdata +sudo ./edit-config go.d/isc_dhcpd.conf +``` +#### Options + +The following options can be defined globally: update_every, autodetection_retry. + + +<details open><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 | +| leases_path | Path to DHCP client lease database. | /var/lib/dhcp/dhcpd.leases | no | +| pools | List of IP pools to monitor. | | yes | + +##### pools + +List of IP pools to monitor. + +- IP range syntax: see [supported formats](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/pkg/iprange#supported-formats). +- Syntax: + +```yaml +pools: + - name: "POOL_NAME1" + networks: "SPACE SEPARATED LIST OF IP RANGES" + - name: "POOL_NAME2" + networks: "SPACE SEPARATED LIST OF IP RANGES" +``` + + +</details> + +#### Examples + +##### Basic + +A basic example configuration. + +<details open><summary>Config</summary> + +```yaml +jobs: + - name: local + pools: + - name: lan + networks: "192.168.0.0/24 192.168.1.0/24 192.168.2.0/24" + - name: wifi + networks: "10.0.0.0/24" + +``` +</details> + + + +## Troubleshooting + +### Debug Mode + +To troubleshoot issues with the `isc_dhcpd` 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 isc_dhcpd + ``` + + diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/isc_dhcpd.go b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/isc_dhcpd.go new file mode 100644 index 000000000..c51abc75b --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/isc_dhcpd.go @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package isc_dhcpd + +import ( + _ "embed" + "errors" + "time" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" +) + +//go:embed "config_schema.json" +var configSchema string + +func init() { + module.Register("isc_dhcpd", module.Creator{ + JobConfigSchema: configSchema, + Defaults: module.Defaults{ + UpdateEvery: 1, + }, + Create: func() module.Module { return New() }, + Config: func() any { return &Config{} }, + }) +} + +func New() *DHCPd { + return &DHCPd{ + Config: Config{ + LeasesPath: "/var/lib/dhcp/dhcpd.leases", + }, + + collected: make(map[string]int64), + } +} + +type ( + Config struct { + UpdateEvery int `yaml:"update_every,omitempty" json:"update_every"` + LeasesPath string `yaml:"leases_path" json:"leases_path"` + // TODO: parse config file to extract configured pool + Pools []PoolConfig `yaml:"pools" json:"pools"` + } + PoolConfig struct { + Name string `yaml:"name" json:"name"` + Networks string `yaml:"networks" json:"networks"` + } +) + +type DHCPd struct { + module.Base + Config `yaml:",inline" json:""` + + charts *module.Charts + + pools []ipPool + leasesModTime time.Time + collected map[string]int64 +} + +func (d *DHCPd) Configuration() any { + return d.Config +} + +func (d *DHCPd) Init() error { + err := d.validateConfig() + if err != nil { + d.Errorf("config validation: %v", err) + return err + } + + pools, err := d.initPools() + if err != nil { + d.Errorf("ip pools init: %v", err) + return err + } + d.pools = pools + + charts, err := d.initCharts(pools) + if err != nil { + d.Errorf("charts init: %v", err) + return err + } + d.charts = charts + + d.Debugf("monitoring leases file: %v", d.Config.LeasesPath) + d.Debugf("monitoring ip pools: %v", d.Config.Pools) + + return nil +} + +func (d *DHCPd) Check() error { + mx, err := d.collect() + if err != nil { + d.Error(err) + return err + } + if len(mx) == 0 { + return errors.New("no metrics collected") + } + return nil +} + +func (d *DHCPd) Charts() *module.Charts { + return d.charts +} + +func (d *DHCPd) Collect() map[string]int64 { + mx, err := d.collect() + if err != nil { + d.Error(err) + } + + if len(mx) == 0 { + return nil + } + + return mx +} + +func (d *DHCPd) Cleanup() {} diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/isc_dhcpd_test.go b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/isc_dhcpd_test.go new file mode 100644 index 000000000..d91dfca15 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/isc_dhcpd_test.go @@ -0,0 +1,345 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package isc_dhcpd + +import ( + "os" + "testing" + + "github.com/netdata/netdata/go/go.d.plugin/agent/module" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +var ( + dataConfigJSON, _ = os.ReadFile("testdata/config.json") + dataConfigYAML, _ = os.ReadFile("testdata/config.yaml") +) + +func Test_testDataIsValid(t *testing.T) { + for name, data := range map[string][]byte{ + "dataConfigJSON": dataConfigJSON, + "dataConfigYAML": dataConfigYAML, + } { + require.NotNil(t, data, name) + } +} + +func TestDHCPd_ConfigurationSerialize(t *testing.T) { + module.TestConfigurationSerialize(t, &DHCPd{}, dataConfigJSON, dataConfigYAML) +} + +func TestDHCPd_Cleanup(t *testing.T) { + assert.NotPanics(t, New().Cleanup) +} + +func TestDHCPd_Init(t *testing.T) { + tests := map[string]struct { + config Config + wantFail bool + }{ + "default": { + wantFail: true, + config: New().Config, + }, + "'leases_path' not set": { + wantFail: true, + config: Config{ + LeasesPath: "", + Pools: []PoolConfig{ + {Name: "test", Networks: "10.220.252.0/24"}, + }, + }, + }, + "'pools' not set": { + wantFail: true, + config: Config{ + LeasesPath: "testdata/dhcpd.leases_ipv4", + }, + }, + "'pools->pool.networks' invalid syntax": { + wantFail: true, + config: Config{ + LeasesPath: "testdata/dhcpd.leases_ipv4", + Pools: []PoolConfig{ + {Name: "test", Networks: "10.220.252./24"}, + }, + }}, + "ok config ('leases_path' and 'pools' are set)": { + config: Config{ + LeasesPath: "testdata/dhcpd.leases_ipv4", + Pools: []PoolConfig{ + {Name: "test", Networks: "10.220.252.0/24"}, + }, + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + dhcpd := New() + dhcpd.Config = test.config + + if test.wantFail { + assert.Error(t, dhcpd.Init()) + } else { + assert.NoError(t, dhcpd.Init()) + } + }) + } +} + +func TestDHCPd_Check(t *testing.T) { + tests := map[string]struct { + prepare func() *DHCPd + wantFail bool + }{ + "lease db not exists": {prepare: prepareDHCPdLeasesNotExists, wantFail: true}, + "lease db is an empty file": {prepare: prepareDHCPdLeasesEmpty}, + "lease db ipv4": {prepare: prepareDHCPdLeasesIPv4}, + "lease db ipv4 with only inactive leases": {prepare: prepareDHCPdLeasesIPv4Inactive}, + "lease db ipv4 with backup leases": {prepare: prepareDHCPdLeasesIPv4Backup}, + "lease db ipv6": {prepare: prepareDHCPdLeasesIPv6}, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + dhcpd := test.prepare() + require.NoError(t, dhcpd.Init()) + + if test.wantFail { + assert.Error(t, dhcpd.Check()) + } else { + assert.NoError(t, dhcpd.Check()) + } + }) + } +} + +func TestDHCPd_Charts(t *testing.T) { + dhcpd := New() + dhcpd.LeasesPath = "leases_path" + dhcpd.Pools = []PoolConfig{ + {Name: "name", Networks: "192.0.2.0/24"}, + } + require.NoError(t, dhcpd.Init()) + + assert.NotNil(t, dhcpd.Charts()) +} + +func TestDHCPd_Collect(t *testing.T) { + tests := map[string]struct { + prepare func() *DHCPd + wantCollected map[string]int64 + }{ + "lease db not exists": { + prepare: prepareDHCPdLeasesNotExists, + wantCollected: nil, + }, + "lease db is an empty file": { + prepare: prepareDHCPdLeasesEmpty, + wantCollected: map[string]int64{ + "active_leases_total": 0, + "dhcp_pool_net1_active_leases": 0, + "dhcp_pool_net1_utilization": 0, + "dhcp_pool_net2_active_leases": 0, + "dhcp_pool_net2_utilization": 0, + "dhcp_pool_net3_active_leases": 0, + "dhcp_pool_net3_utilization": 0, + "dhcp_pool_net4_active_leases": 0, + "dhcp_pool_net4_utilization": 0, + "dhcp_pool_net5_active_leases": 0, + "dhcp_pool_net5_utilization": 0, + "dhcp_pool_net6_active_leases": 0, + "dhcp_pool_net6_utilization": 0, + }, + }, + "lease db ipv4": { + prepare: prepareDHCPdLeasesIPv4, + wantCollected: map[string]int64{ + "active_leases_total": 5, + "dhcp_pool_net1_active_leases": 2, + "dhcp_pool_net1_utilization": 158, + "dhcp_pool_net2_active_leases": 1, + "dhcp_pool_net2_utilization": 39, + "dhcp_pool_net3_active_leases": 0, + "dhcp_pool_net3_utilization": 0, + "dhcp_pool_net4_active_leases": 1, + "dhcp_pool_net4_utilization": 79, + "dhcp_pool_net5_active_leases": 0, + "dhcp_pool_net5_utilization": 0, + "dhcp_pool_net6_active_leases": 1, + "dhcp_pool_net6_utilization": 39, + }, + }, + "lease db ipv4 with only inactive leases": { + prepare: prepareDHCPdLeasesIPv4Inactive, + wantCollected: map[string]int64{ + "active_leases_total": 0, + "dhcp_pool_net1_active_leases": 0, + "dhcp_pool_net1_utilization": 0, + "dhcp_pool_net2_active_leases": 0, + "dhcp_pool_net2_utilization": 0, + "dhcp_pool_net3_active_leases": 0, + "dhcp_pool_net3_utilization": 0, + "dhcp_pool_net4_active_leases": 0, + "dhcp_pool_net4_utilization": 0, + "dhcp_pool_net5_active_leases": 0, + "dhcp_pool_net5_utilization": 0, + "dhcp_pool_net6_active_leases": 0, + "dhcp_pool_net6_utilization": 0, + }, + }, + "lease db ipv4 with backup leases": { + prepare: prepareDHCPdLeasesIPv4Backup, + wantCollected: map[string]int64{ + "active_leases_total": 2, + "dhcp_pool_net1_active_leases": 1, + "dhcp_pool_net1_utilization": 79, + "dhcp_pool_net2_active_leases": 0, + "dhcp_pool_net2_utilization": 0, + "dhcp_pool_net3_active_leases": 0, + "dhcp_pool_net3_utilization": 0, + "dhcp_pool_net4_active_leases": 1, + "dhcp_pool_net4_utilization": 79, + "dhcp_pool_net5_active_leases": 0, + "dhcp_pool_net5_utilization": 0, + "dhcp_pool_net6_active_leases": 0, + "dhcp_pool_net6_utilization": 0, + }, + }, + "lease db ipv6": { + prepare: prepareDHCPdLeasesIPv6, + wantCollected: map[string]int64{ + "active_leases_total": 6, + "dhcp_pool_net1_active_leases": 6, + "dhcp_pool_net1_utilization": 5454, + "dhcp_pool_net2_active_leases": 0, + "dhcp_pool_net2_utilization": 0, + }, + }, + } + + for name, test := range tests { + t.Run(name, func(t *testing.T) { + dhcpd := test.prepare() + require.NoError(t, dhcpd.Init()) + + collected := dhcpd.Collect() + + assert.Equal(t, test.wantCollected, collected) + if len(collected) > 0 { + ensureCollectedHasAllChartsDimsVarsIDs(t, dhcpd, collected) + } + }) + } +} + +func ensureCollectedHasAllChartsDimsVarsIDs(t *testing.T, dhcpd *DHCPd, collected map[string]int64) { + for _, chart := range *dhcpd.Charts() { + if chart.Obsolete { + continue + } + for _, dim := range chart.Dims { + _, ok := collected[dim.ID] + assert.Truef(t, ok, "collected metrics has no data for dim '%s' chart '%s'", dim.ID, chart.ID) + } + for _, v := range chart.Vars { + _, ok := collected[v.ID] + assert.Truef(t, ok, "collected metrics has no data for var '%s' chart '%s'", v.ID, chart.ID) + } + } +} + +func prepareDHCPdLeasesNotExists() *DHCPd { + dhcpd := New() + dhcpd.Config = Config{ + LeasesPath: "testdata/dhcpd.leases_not_exists", + Pools: []PoolConfig{ + {Name: "net1", Networks: "192.168.3.0/25"}, + {Name: "net2", Networks: "10.254.251.0/24"}, + {Name: "net3", Networks: "10.254.252.0/24"}, + {Name: "net4", Networks: "10.254.253.0/25"}, + {Name: "net5", Networks: "10.254.254.0/25"}, + {Name: "net6", Networks: "10.254.255.0/24"}, + }, + } + return dhcpd +} + +func prepareDHCPdLeasesEmpty() *DHCPd { + dhcpd := New() + dhcpd.Config = Config{ + LeasesPath: "testdata/dhcpd.leases_empty", + Pools: []PoolConfig{ + {Name: "net1", Networks: "192.168.3.0/25"}, + {Name: "net2", Networks: "10.254.251.0/24"}, + {Name: "net3", Networks: "10.254.252.0/24"}, + {Name: "net4", Networks: "10.254.253.0/25"}, + {Name: "net5", Networks: "10.254.254.0/25"}, + {Name: "net6", Networks: "10.254.255.0/24"}, + }, + } + return dhcpd +} + +func prepareDHCPdLeasesIPv4() *DHCPd { + dhcpd := New() + dhcpd.Config = Config{ + LeasesPath: "testdata/dhcpd.leases_ipv4", + Pools: []PoolConfig{ + {Name: "net1", Networks: "192.168.3.0/25"}, + {Name: "net2", Networks: "10.254.251.0/24"}, + {Name: "net3", Networks: "10.254.252.0/24"}, + {Name: "net4", Networks: "10.254.253.0/25"}, + {Name: "net5", Networks: "10.254.254.0/25"}, + {Name: "net6", Networks: "10.254.255.0/24"}, + }, + } + return dhcpd +} + +func prepareDHCPdLeasesIPv4Backup() *DHCPd { + dhcpd := New() + dhcpd.Config = Config{ + LeasesPath: "testdata/dhcpd.leases_ipv4_backup", + Pools: []PoolConfig{ + {Name: "net1", Networks: "192.168.3.0/25"}, + {Name: "net2", Networks: "10.254.251.0/24"}, + {Name: "net3", Networks: "10.254.252.0/24"}, + {Name: "net4", Networks: "10.254.253.0/25"}, + {Name: "net5", Networks: "10.254.254.0/25"}, + {Name: "net6", Networks: "10.254.255.0/24"}, + }, + } + return dhcpd +} + +func prepareDHCPdLeasesIPv4Inactive() *DHCPd { + dhcpd := New() + dhcpd.Config = Config{ + LeasesPath: "testdata/dhcpd.leases_ipv4_inactive", + Pools: []PoolConfig{ + {Name: "net1", Networks: "192.168.3.0/25"}, + {Name: "net2", Networks: "10.254.251.0/24"}, + {Name: "net3", Networks: "10.254.252.0/24"}, + {Name: "net4", Networks: "10.254.253.0/25"}, + {Name: "net5", Networks: "10.254.254.0/25"}, + {Name: "net6", Networks: "10.254.255.0/24"}, + }, + } + return dhcpd +} + +func prepareDHCPdLeasesIPv6() *DHCPd { + dhcpd := New() + dhcpd.Config = Config{ + LeasesPath: "testdata/dhcpd.leases_ipv6", + Pools: []PoolConfig{ + {Name: "net1", Networks: "2001:db8::-2001:db8::a"}, + {Name: "net2", Networks: "2001:db8:0:1::-2001:db8:0:1::a"}, + }, + } + return dhcpd +} diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/metadata.yaml b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/metadata.yaml new file mode 100644 index 000000000..e6e11d72e --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/metadata.yaml @@ -0,0 +1,135 @@ +plugin_name: go.d.plugin +modules: + - meta: + id: collector-go.d.plugin-isc_dhcpd + plugin_name: go.d.plugin + module_name: isc_dhcpd + monitored_instance: + name: ISC DHCP + link: https://www.isc.org/dhcp/ + categories: + - data-collection.dns-and-dhcp-servers + icon_filename: isc.png + keywords: + - dhcpd + - dhcp + most_popular: false + info_provided_to_referring_integrations: + description: "" + related_resources: + integrations: + list: [] + overview: + data_collection: + metrics_description: | + This collector monitors ISC DHCP lease usage by reading the DHCP client lease database (dhcpd.leases). + method_description: "" + default_behavior: + auto_detection: + description: "" + limits: + description: "" + performance_impact: + description: "" + additional_permissions: + description: "" + multi_instance: true + supported_platforms: + include: [] + exclude: [] + setup: + prerequisites: + list: [] + configuration: + file: + name: go.d/isc_dhcpd.conf + options: + description: | + The following options can be defined globally: update_every, autodetection_retry. + folding: + title: Config options + enabled: true + list: + - name: update_every + description: Data collection frequency. + default_value: 1 + required: false + - name: autodetection_retry + description: Recheck interval in seconds. Zero means no recheck will be scheduled. + default_value: 0 + required: false + - name: leases_path + description: Path to DHCP client lease database. + default_value: /var/lib/dhcp/dhcpd.leases + required: false + - name: pools + description: List of IP pools to monitor. + default_value: "" + required: true + detailed_description: | + List of IP pools to monitor. + + - IP range syntax: see [supported formats](https://github.com/netdata/netdata/tree/master/src/go/collectors/go.d.plugin/pkg/iprange#supported-formats). + - Syntax: + + ```yaml + pools: + - name: "POOL_NAME1" + networks: "SPACE SEPARATED LIST OF IP RANGES" + - name: "POOL_NAME2" + networks: "SPACE SEPARATED LIST OF IP RANGES" + ``` + examples: + folding: + title: Config + enabled: true + list: + - name: Basic + description: A basic example configuration. + config: | + jobs: + - name: local + pools: + - name: lan + networks: "192.168.0.0/24 192.168.1.0/24 192.168.2.0/24" + - name: wifi + networks: "10.0.0.0/24" + troubleshooting: + problems: + list: [] + alerts: [] + metrics: + folding: + title: Metrics + enabled: false + description: "" + availability: [] + scopes: + - name: global + description: These metrics refer to the entire monitored application. + labels: [] + metrics: + - name: isc_dhcpd.active_leases_total + description: Active Leases Total + unit: leases + chart_type: line + dimensions: + - name: active + - name: global + description: These metrics refer to the DHCP pool. + labels: + - name: dhcp_pool_name + description: The DHCP pool name defined in the collector configuration. + metrics: + - name: isc_dhcpd.dhcp_pool_utilization + description: DHCP Pool Utilization + unit: percent + chart_type: area + dimensions: + - name: utilization + - name: isc_dhcpd.dhcp_pool_active_leases + description: Active Leases Total + unit: leases + chart_type: line + dimensions: + - name: active diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/parse.go b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/parse.go new file mode 100644 index 000000000..cb4161745 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/parse.go @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +package isc_dhcpd + +import ( + "bufio" + "bytes" + "net" + "os" +) + +/* +Documentation (v4.4): https://kb.isc.org/docs/en/isc-dhcp-44-manual-pages-dhcpdleases + +DHCPv4 prepare declaration: + prepare ip-address { + statements... + } + +DHCPv6 prepare declaration: + ia_ta IAID_DUID { + cltt date; + iaaddr ipv6-address { + statements... + } + } + ia_na IAID_DUID { + cltt date; + iaaddr ipv6-address { + statements... + } + } + ia_pd IAID_DUID { + cltt date; + iaprefix ipv6-address/prefix-length { + statements... + } + } +*/ + +type leaseEntry struct { + ip net.IP + bindingState string +} + +func (l leaseEntry) hasIP() bool { return l.ip != nil } +func (l leaseEntry) hasBindingState() bool { return l.bindingState != "" } + +func parseDHCPdLeasesFile(filepath string) ([]leaseEntry, error) { + f, err := os.Open(filepath) + if err != nil { + return nil, err + } + defer func() { _ = f.Close() }() + + leasesSet := make(map[string]leaseEntry) + l := leaseEntry{} + sc := bufio.NewScanner(f) + + for sc.Scan() { + bs := bytes.TrimSpace(sc.Bytes()) + switch { + case !l.hasIP() && bytes.HasPrefix(bs, []byte("lease")): + // "lease 192.168.0.1 {" => "192.168.0.1" + s := string(bs) + l.ip = net.ParseIP(s[6 : len(s)-2]) + case !l.hasIP() && bytes.HasPrefix(bs, []byte("iaaddr")): + // "iaaddr 1985:470:1f0b:c9a::001 {" => "1985:470:1f0b:c9a::001" + s := string(bs) + l.ip = net.ParseIP(s[7 : len(s)-2]) + case l.hasIP() && !l.hasBindingState() && bytes.HasPrefix(bs, []byte("binding state")): + // "binding state active;" => "active" + s := string(bs) + l.bindingState = s[14 : len(s)-1] + case bytes.HasPrefix(bs, []byte("}")): + if l.hasIP() && l.hasBindingState() { + leasesSet[l.ip.String()] = l + } + l = leaseEntry{} + } + } + + if len(leasesSet) == 0 { + return nil, nil + } + + leases := make([]leaseEntry, 0, len(leasesSet)) + for _, l := range leasesSet { + leases = append(leases, l) + } + return leases, nil +} diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/config.json b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/config.json new file mode 100644 index 000000000..945f8865e --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/config.json @@ -0,0 +1,10 @@ +{ + "update_every": 123, + "leases_path": "ok", + "pools": [ + { + "name": "ok", + "networks": "ok" + } + ] +} diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/config.yaml b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/config.yaml new file mode 100644 index 000000000..a33defc55 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/config.yaml @@ -0,0 +1,5 @@ +update_every: 123 +leases_path: "ok" +pools: + - name: "ok" + networks: "ok" diff --git a/fluent-bit/lib/jansson-e23f558/test/suites/invalid/empty/input b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_empty index e69de29bb..e69de29bb 100644 --- a/fluent-bit/lib/jansson-e23f558/test/suites/invalid/empty/input +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_empty diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv4 b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv4 new file mode 100644 index 000000000..08e0e3f20 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv4 @@ -0,0 +1,370 @@ +# The format of this file is documented in the dhcpd.leases(5) manual page. +# This lease file was written by isc-dhcp-4.3.1 + +lease 10.254.252.2 { + starts 3 2014/07/23 07:32:16; + ends 3 2014/07/23 09:12:16; + tstp 3 2014/07/23 09:12:16; + cltt 3 2014/07/23 07:32:16; + binding state free; + hardware ethernet f0:de:f1:89:24:1f; + uid "\001\360\336\361\211$\037"; +} +lease 10.254.252.3 { + starts 5 2014/11/28 05:49:01; + ends 5 2014/11/28 07:29:01; + tstp 5 2014/11/28 07:29:01; + cltt 5 2014/11/28 05:49:01; + binding state free; + hardware ethernet c0:4a:00:00:f5:fa; + uid "\001\300J\000\000\365\372"; +} +lease 10.254.252.4 { + starts 5 2016/03/11 01:03:59; + ends 5 2016/03/11 02:33:20; + tstp 5 2016/03/11 02:33:20; + cltt 5 2016/03/11 01:12:33; + binding state free; + hardware ethernet 00:1c:c0:7a:38:3f; + uid "\001\000\034\300z8?"; + set vendor-class-identifier = "MSFT 5.0"; +} +lease 10.254.252.5 { + starts 1 2016/09/05 23:53:19; + ends 2 2016/09/06 01:33:19; + tstp 2 2016/09/06 01:33:19; + cltt 1 2016/09/05 23:53:19; + binding state free; + hardware ethernet 28:28:5d:65:30:ef; + uid "\001((]e0\357"; +} +lease 10.254.252.6 { + starts 4 2016/09/29 01:41:23; + ends 4 2016/09/29 03:21:23; + tstp 4 2016/09/29 03:21:23; + cltt 4 2016/09/29 01:41:23; + binding state free; + hardware ethernet 04:bf:6d:94:1b:0d; + uid "\001\004\277m\224\033\015"; +} +lease 10.254.252.7 { + starts 1 2016/10/03 08:23:14; + ends 1 2016/10/03 10:03:14; + tstp 1 2016/10/03 10:03:14; + cltt 1 2016/10/03 08:23:14; + binding state free; + hardware ethernet ec:22:80:f7:3f:44; + uid "\001\354\"\200\367?D"; +} +lease 10.254.252.8 { + starts 5 2016/10/07 05:43:11; + ends 5 2016/10/07 05:58:31; + tstp 5 2016/10/07 05:58:31; + cltt 5 2016/10/07 05:43:11; + binding state free; + hardware ethernet 70:62:b8:bf:b5:b3; + uid "\001pb\270\277\265\263"; +} +lease 192.168.3.15 { + starts 2 2019/01/08 06:29:58; + ends 2 2019/01/08 08:09:58; + tstp 2 2019/01/08 08:09:58; + cltt 2 2019/01/08 06:29:58; + binding state free; + hardware ethernet a8:f9:4b:20:99:9c; + uid "\001\250\371K \231\234"; +} +lease 192.168.3.18 { + starts 2 2020/03/10 01:46:07; + ends 2 2020/03/10 03:22:21; + tstp 2 2020/03/10 03:22:21; + cltt 2 2020/03/10 01:46:08; + binding state free; + hardware ethernet 04:bf:6d:0d:e2:35; + uid "\001\004\277m\015\3425"; + set vendor-class-identifier = "ndhcpc"; +} +lease 192.168.3.11 { + starts 6 2020/10/03 07:52:36; + ends 6 2020/10/03 09:32:36; + cltt 6 2020/10/03 07:52:36; + binding state active; + next binding state free; + rewind binding state free; + hardware ethernet 60:a4:4c:3f:6e:78; + uid "\001`\244L?nx"; +} +lease 192.168.3.10 { + starts 6 2020/10/03 08:18:50; + ends 6 2020/10/03 09:58:50; + cltt 6 2020/10/03 08:18:50; + binding state active; + next binding state free; + rewind binding state free; + hardware ethernet 70:62:b8:bf:b5:b3; + uid "\001pb\270\277\265\263"; + set vendor-class-identifier = "dslforum.org"; +} +lease 10.254.251.101 { + starts 0 2017/03/12 22:11:59; + ends 0 2017/03/12 23:51:58; + tstp 0 2017/03/12 23:51:58; + cltt 0 2017/03/12 22:11:59; + binding state free; + hardware ethernet b4:ce:f6:01:83:73; + set vendor-class-identifier = "dhcpcd-5.5.6"; +} +lease 10.254.251.102 { + starts 5 2017/05/19 06:07:39; + ends 5 2017/05/19 07:47:39; + tstp 5 2017/05/19 07:47:39; + cltt 5 2017/05/19 06:07:39; + binding state free; + hardware ethernet 34:51:c9:4c:40:c9; + uid "\0014Q\311L@\311"; +} +lease 10.254.251.103 { + starts 2 2018/04/24 13:18:00; + ends 2 2018/04/24 14:58:00; + tstp 2 2018/04/24 14:58:00; + cltt 2 2018/04/24 13:18:00; + binding state free; + hardware ethernet 70:8a:09:da:74:d0; + set vendor-class-identifier = "dhcpcd-5.5.6"; +} +lease 10.254.251.104 { + starts 2 2018/04/24 12:54:27; + ends 3 2018/04/25 06:47:20; + tstp 3 2018/04/25 06:47:20; + cltt 2 2018/04/24 12:54:28; + binding state free; + hardware ethernet 78:a3:e4:e8:12:1f; + uid "\001x\243\344\350\022\037"; +} +lease 10.254.251.100 { + starts 6 2020/10/03 07:58:45; + ends 6 2020/10/03 09:38:45; + cltt 6 2020/10/03 07:58:45; + binding state active; + next binding state free; + rewind binding state free; + hardware ethernet 74:ea:3a:a6:a9:c7; + uid "\001t\352:\246\251\307"; + set vendor-class-identifier = "MSFT 5.0"; + client-hostname "TL-WR741N"; +} +lease 10.254.255.104 { + starts 1 2017/07/10 09:35:24; + ends 1 2017/07/10 09:37:24; + tstp 1 2017/07/10 09:37:24; + cltt 1 2017/07/10 09:35:24; + binding state free; + hardware ethernet 50:85:69:11:b6:ff; + uid "\001P\205i\021\266\377"; +} +lease 10.254.255.102 { + starts 3 2017/08/16 22:01:09; + ends 3 2017/08/16 23:41:09; + tstp 3 2017/08/16 23:41:09; + cltt 3 2017/08/16 22:01:09; + binding state free; + hardware ethernet c8:d3:a3:54:31:3a; + uid "\001\310\323\243T1:"; +} +lease 10.254.255.103 { + starts 0 2018/12/16 00:54:07; + ends 0 2018/12/16 02:34:07; + tstp 0 2018/12/16 02:34:07; + cltt 0 2018/12/16 00:54:07; + binding state free; + hardware ethernet 08:c6:b3:01:e8:18; + uid "\001\010\306\263\001\350\030"; + set vendor-class-identifier = "QTCH-QBR1041WUV2"; +} +lease 10.254.255.100 { + starts 2 2018/12/18 09:21:24; + ends 2 2018/12/18 10:32:36; + tstp 2 2018/12/18 10:32:36; + cltt 2 2018/12/18 09:21:30; + binding state free; + hardware ethernet 70:62:b8:c3:51:a3; + uid "\001pb\270\303Q\243"; +} +lease 10.254.255.105 { + starts 5 2019/03/22 07:42:55; + ends 5 2019/03/22 09:22:55; + tstp 5 2019/03/22 09:22:55; + cltt 5 2019/03/22 07:42:55; + binding state free; + hardware ethernet 58:d5:6e:95:88:30; + uid "\001X\325n\225\2100"; + set vendor-class-identifier = "dslforum.org"; +} +lease 10.254.255.101 { + starts 6 2020/10/03 07:29:24; + ends 6 2020/10/03 09:09:24; + cltt 6 2020/10/03 07:29:24; + binding state active; + next binding state free; + rewind binding state free; + hardware ethernet 28:3b:82:58:f4:58; + uid "\001(;\202X\364X"; + set vendor-class-identifier = "dslforum.org"; +} +lease 10.254.253.104 { + starts 4 2018/03/15 12:01:12; + ends 4 2018/03/15 12:34:35; + tstp 4 2018/03/15 12:34:35; + cltt 4 2018/03/15 12:02:58; + binding state free; + hardware ethernet 50:64:2b:4f:fd:3d; + uid "\001Pd+O\375="; + set vendor-class-identifier = "udhcp 1.19.4"; +} +lease 10.254.253.105 { + starts 4 2018/03/15 12:39:46; + ends 4 2018/03/15 14:17:39; + tstp 4 2018/03/15 14:17:39; + cltt 4 2018/03/15 12:39:47; + binding state free; + hardware ethernet 50:64:2b:4f:fd:3d; + set vendor-class-identifier = "udhcp 1.19.4"; +} +lease 10.254.253.101 { + starts 5 2018/03/16 11:00:43; + ends 5 2018/03/16 12:40:15; + tstp 5 2018/03/16 12:40:15; + cltt 5 2018/03/16 11:00:43; + binding state free; + hardware ethernet d0:66:7b:8b:e5:ff; + uid "\001\320f{\213\345\377"; + set vendor-class-identifier = "udhcp 1.14.3-VD Linux VDLinux.1.2.1.x"; +} +lease 10.254.253.102 { + starts 5 2018/03/16 11:26:21; + ends 5 2018/03/16 13:06:21; + tstp 5 2018/03/16 13:06:21; + cltt 5 2018/03/16 11:26:21; + binding state free; + hardware ethernet 50:64:2b:4f:fd:3f; + uid "\001Pd+O\375?"; +} +lease 10.254.253.100 { + starts 2 2018/08/21 05:48:43; + ends 2 2018/08/21 07:23:13; + tstp 2 2018/08/21 07:23:13; + cltt 2 2018/08/21 05:48:44; + binding state free; + hardware ethernet 20:cf:30:ef:8e:a4; + uid "\001 \3170\357\216\244"; + set vendor-class-identifier = "udhcp 0.9.8-asus"; +} +lease 10.254.253.103 { + starts 6 2020/10/03 08:07:02; + ends 6 2020/10/03 09:47:02; + cltt 6 2020/10/03 08:07:02; + binding state active; + next binding state free; + rewind binding state free; + hardware ethernet 34:ce:00:03:08:57; + uid "\0014\316\000\003\010W"; + set vendor-class-identifier = "udhcp 1.24.2"; +} +lease 10.254.254.103 { + starts 3 2015/11/11 09:03:11; + ends 3 2015/11/11 09:05:11; + tstp 3 2015/11/11 09:05:11; + cltt 3 2015/11/11 09:03:11; + binding state free; + hardware ethernet 74:d0:2b:0e:9b:d6; +} +lease 10.254.254.104 { + starts 0 2017/12/03 15:57:29; + ends 0 2017/12/03 17:37:29; + tstp 0 2017/12/03 17:37:29; + cltt 0 2017/12/03 15:57:29; + binding state free; + hardware ethernet ac:22:0b:78:00:78; + uid "\377\3139\012\307\000\002\000\000\253\021(CC\252e\021\000\017"; +} +lease 10.254.254.105 { + starts 2 2018/06/26 12:30:04; + ends 2 2018/06/26 13:09:10; + tstp 2 2018/06/26 13:09:10; + cltt 2 2018/06/26 12:30:04; + binding state free; + hardware ethernet cc:2d:e0:3f:bc:5c; + uid "\001\314-\340?\274\\"; +} +lease 10.254.254.101 { + starts 3 2018/07/25 09:33:10; + ends 3 2018/07/25 11:13:10; + tstp 3 2018/07/25 11:13:10; + cltt 3 2018/07/25 09:33:10; + binding state free; + hardware ethernet 74:d0:2b:0e:9b:d6; + uid "\001t\320+\016\233\326"; + set vendor-class-identifier = "MSFT 5.0"; +} +lease 10.254.254.100 { + starts 2 2020/09/22 11:19:29; + ends 2 2020/09/22 11:21:29; + cltt 2 2020/09/22 11:19:29; + binding state free; + hardware ethernet 30:45:96:6a:f3:de; + uid "\0010E\226j\363\336"; + client-hostname "Honor_7C-bb23201389a3c44"; +} +lease 10.254.254.102 { + starts 2 2020/09/22 11:25:14; + ends 2 2020/09/22 11:27:14; + cltt 2 2020/09/22 11:25:14; + binding state free; + hardware ethernet c8:3d:dc:be:d2:cf; + uid "\001\310=\334\276\322\317"; + client-hostname "Redmi7A-Redmi"; +} +lease 10.254.255.101 { + starts 6 2020/10/03 08:19:24; + ends 6 2020/10/03 09:59:24; + cltt 6 2020/10/03 08:19:24; + binding state active; + next binding state free; + rewind binding state free; + hardware ethernet 28:3b:82:58:f4:58; + uid "\001(;\202X\364X"; + set vendor-class-identifier = "dslforum.org"; +} +lease 10.254.251.100 { + starts 6 2020/10/03 08:48:45; + ends 6 2020/10/03 10:28:45; + cltt 6 2020/10/03 08:48:45; + binding state active; + next binding state free; + rewind binding state free; + hardware ethernet 74:ea:3a:a6:a9:c7; + uid "\001t\352:\246\251\307"; + set vendor-class-identifier = "MSFT 5.0"; + client-hostname "TL-WR741N"; +} +lease 10.254.253.103 { + starts 6 2020/10/03 08:57:02; + ends 6 2020/10/03 10:37:02; + cltt 6 2020/10/03 08:57:02; + binding state active; + next binding state free; + rewind binding state free; + hardware ethernet 34:ce:00:03:08:57; + uid "\0014\316\000\003\010W"; + set vendor-class-identifier = "udhcp 1.24.2"; +} +lease 192.168.3.11 { + starts 6 2020/10/03 09:01:22; + ends 6 2020/10/03 10:41:22; + cltt 6 2020/10/03 09:01:22; + binding state active; + next binding state free; + rewind binding state free; + hardware ethernet 60:a4:4c:3f:6e:78; + uid "\001`\244L?nx"; +} diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv4_backup b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv4_backup new file mode 100644 index 000000000..e822ca846 --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv4_backup @@ -0,0 +1,39 @@ +# The format of this file is documented in the dhcpd.leases(5) manual page. +# This lease file was written by isc-dhcp-4.4.2 + +# authoring-byte-order entry is generated, DO NOT DELETE +authoring-byte-order little-endian; + +lease 10.254.253.103 { + starts 6 2020/10/03 08:57:02; + ends 6 2020/10/03 10:37:02; + cltt 6 2020/10/03 08:57:02; + binding state active; + next binding state free; + rewind binding state free; + hardware ethernet 34:ce:00:03:08:57; + uid "\0014\316\000\003\010W"; + set vendor-class-identifier = "udhcp 1.24.2"; +} +lease 192.168.3.1 { + starts 6 2018/02/17 01:13:21; + tsfp 6 2018/02/17 01:13:21; + atsfp 6 2018/02/17 01:13:21; + binding state backup; +} +lease 192.168.3.11 { + starts 6 2020/10/03 09:01:22; + ends 6 2020/10/03 10:41:22; + cltt 6 2020/10/03 09:01:22; + binding state active; + next binding state free; + rewind binding state free; + hardware ethernet 60:a4:4c:3f:6e:78; + uid "\001`\244L?nx"; +} +lease 192.168.3.2 { + starts 6 2018/02/17 01:13:21; + tsfp 6 2018/02/17 01:13:21; + atsfp 6 2018/02/17 01:13:21; + binding state backup; +} diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv4_inactive b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv4_inactive new file mode 100644 index 000000000..c5aed080f --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv4_inactive @@ -0,0 +1,370 @@ +# The format of this file is documented in the dhcpd.leases(5) manual page. +# This lease file was written by isc-dhcp-4.3.1 + +lease 10.254.252.2 { + starts 3 2014/07/23 07:32:16; + ends 3 2014/07/23 09:12:16; + tstp 3 2014/07/23 09:12:16; + cltt 3 2014/07/23 07:32:16; + binding state free; + hardware ethernet f0:de:f1:89:24:1f; + uid "\001\360\336\361\211$\037"; +} +lease 10.254.252.3 { + starts 5 2014/11/28 05:49:01; + ends 5 2014/11/28 07:29:01; + tstp 5 2014/11/28 07:29:01; + cltt 5 2014/11/28 05:49:01; + binding state free; + hardware ethernet c0:4a:00:00:f5:fa; + uid "\001\300J\000\000\365\372"; +} +lease 10.254.252.4 { + starts 5 2016/03/11 01:03:59; + ends 5 2016/03/11 02:33:20; + tstp 5 2016/03/11 02:33:20; + cltt 5 2016/03/11 01:12:33; + binding state free; + hardware ethernet 00:1c:c0:7a:38:3f; + uid "\001\000\034\300z8?"; + set vendor-class-identifier = "MSFT 5.0"; +} +lease 10.254.252.5 { + starts 1 2016/09/05 23:53:19; + ends 2 2016/09/06 01:33:19; + tstp 2 2016/09/06 01:33:19; + cltt 1 2016/09/05 23:53:19; + binding state free; + hardware ethernet 28:28:5d:65:30:ef; + uid "\001((]e0\357"; +} +lease 10.254.252.6 { + starts 4 2016/09/29 01:41:23; + ends 4 2016/09/29 03:21:23; + tstp 4 2016/09/29 03:21:23; + cltt 4 2016/09/29 01:41:23; + binding state free; + hardware ethernet 04:bf:6d:94:1b:0d; + uid "\001\004\277m\224\033\015"; +} +lease 10.254.252.7 { + starts 1 2016/10/03 08:23:14; + ends 1 2016/10/03 10:03:14; + tstp 1 2016/10/03 10:03:14; + cltt 1 2016/10/03 08:23:14; + binding state free; + hardware ethernet ec:22:80:f7:3f:44; + uid "\001\354\"\200\367?D"; +} +lease 10.254.252.8 { + starts 5 2016/10/07 05:43:11; + ends 5 2016/10/07 05:58:31; + tstp 5 2016/10/07 05:58:31; + cltt 5 2016/10/07 05:43:11; + binding state free; + hardware ethernet 70:62:b8:bf:b5:b3; + uid "\001pb\270\277\265\263"; +} +lease 192.168.3.15 { + starts 2 2019/01/08 06:29:58; + ends 2 2019/01/08 08:09:58; + tstp 2 2019/01/08 08:09:58; + cltt 2 2019/01/08 06:29:58; + binding state free; + hardware ethernet a8:f9:4b:20:99:9c; + uid "\001\250\371K \231\234"; +} +lease 192.168.3.18 { + starts 2 2020/03/10 01:46:07; + ends 2 2020/03/10 03:22:21; + tstp 2 2020/03/10 03:22:21; + cltt 2 2020/03/10 01:46:08; + binding state free; + hardware ethernet 04:bf:6d:0d:e2:35; + uid "\001\004\277m\015\3425"; + set vendor-class-identifier = "ndhcpc"; +} +lease 192.168.3.11 { + starts 6 2020/10/03 07:52:36; + ends 6 2020/10/03 09:32:36; + cltt 6 2020/10/03 07:52:36; + binding state free; + next binding state free; + rewind binding state free; + hardware ethernet 60:a4:4c:3f:6e:78; + uid "\001`\244L?nx"; +} +lease 192.168.3.10 { + starts 6 2020/10/03 08:18:50; + ends 6 2020/10/03 09:58:50; + cltt 6 2020/10/03 08:18:50; + binding state free; + next binding state free; + rewind binding state free; + hardware ethernet 70:62:b8:bf:b5:b3; + uid "\001pb\270\277\265\263"; + set vendor-class-identifier = "dslforum.org"; +} +lease 10.254.251.101 { + starts 0 2017/03/12 22:11:59; + ends 0 2017/03/12 23:51:58; + tstp 0 2017/03/12 23:51:58; + cltt 0 2017/03/12 22:11:59; + binding state free; + hardware ethernet b4:ce:f6:01:83:73; + set vendor-class-identifier = "dhcpcd-5.5.6"; +} +lease 10.254.251.102 { + starts 5 2017/05/19 06:07:39; + ends 5 2017/05/19 07:47:39; + tstp 5 2017/05/19 07:47:39; + cltt 5 2017/05/19 06:07:39; + binding state free; + hardware ethernet 34:51:c9:4c:40:c9; + uid "\0014Q\311L@\311"; +} +lease 10.254.251.103 { + starts 2 2018/04/24 13:18:00; + ends 2 2018/04/24 14:58:00; + tstp 2 2018/04/24 14:58:00; + cltt 2 2018/04/24 13:18:00; + binding state free; + hardware ethernet 70:8a:09:da:74:d0; + set vendor-class-identifier = "dhcpcd-5.5.6"; +} +lease 10.254.251.104 { + starts 2 2018/04/24 12:54:27; + ends 3 2018/04/25 06:47:20; + tstp 3 2018/04/25 06:47:20; + cltt 2 2018/04/24 12:54:28; + binding state free; + hardware ethernet 78:a3:e4:e8:12:1f; + uid "\001x\243\344\350\022\037"; +} +lease 10.254.251.100 { + starts 6 2020/10/03 07:58:45; + ends 6 2020/10/03 09:38:45; + cltt 6 2020/10/03 07:58:45; + binding state free; + next binding state free; + rewind binding state free; + hardware ethernet 74:ea:3a:a6:a9:c7; + uid "\001t\352:\246\251\307"; + set vendor-class-identifier = "MSFT 5.0"; + client-hostname "TL-WR741N"; +} +lease 10.254.255.104 { + starts 1 2017/07/10 09:35:24; + ends 1 2017/07/10 09:37:24; + tstp 1 2017/07/10 09:37:24; + cltt 1 2017/07/10 09:35:24; + binding state free; + hardware ethernet 50:85:69:11:b6:ff; + uid "\001P\205i\021\266\377"; +} +lease 10.254.255.102 { + starts 3 2017/08/16 22:01:09; + ends 3 2017/08/16 23:41:09; + tstp 3 2017/08/16 23:41:09; + cltt 3 2017/08/16 22:01:09; + binding state free; + hardware ethernet c8:d3:a3:54:31:3a; + uid "\001\310\323\243T1:"; +} +lease 10.254.255.103 { + starts 0 2018/12/16 00:54:07; + ends 0 2018/12/16 02:34:07; + tstp 0 2018/12/16 02:34:07; + cltt 0 2018/12/16 00:54:07; + binding state free; + hardware ethernet 08:c6:b3:01:e8:18; + uid "\001\010\306\263\001\350\030"; + set vendor-class-identifier = "QTCH-QBR1041WUV2"; +} +lease 10.254.255.100 { + starts 2 2018/12/18 09:21:24; + ends 2 2018/12/18 10:32:36; + tstp 2 2018/12/18 10:32:36; + cltt 2 2018/12/18 09:21:30; + binding state free; + hardware ethernet 70:62:b8:c3:51:a3; + uid "\001pb\270\303Q\243"; +} +lease 10.254.255.105 { + starts 5 2019/03/22 07:42:55; + ends 5 2019/03/22 09:22:55; + tstp 5 2019/03/22 09:22:55; + cltt 5 2019/03/22 07:42:55; + binding state free; + hardware ethernet 58:d5:6e:95:88:30; + uid "\001X\325n\225\2100"; + set vendor-class-identifier = "dslforum.org"; +} +lease 10.254.255.101 { + starts 6 2020/10/03 07:29:24; + ends 6 2020/10/03 09:09:24; + cltt 6 2020/10/03 07:29:24; + binding state free; + next binding state free; + rewind binding state free; + hardware ethernet 28:3b:82:58:f4:58; + uid "\001(;\202X\364X"; + set vendor-class-identifier = "dslforum.org"; +} +lease 10.254.253.104 { + starts 4 2018/03/15 12:01:12; + ends 4 2018/03/15 12:34:35; + tstp 4 2018/03/15 12:34:35; + cltt 4 2018/03/15 12:02:58; + binding state free; + hardware ethernet 50:64:2b:4f:fd:3d; + uid "\001Pd+O\375="; + set vendor-class-identifier = "udhcp 1.19.4"; +} +lease 10.254.253.105 { + starts 4 2018/03/15 12:39:46; + ends 4 2018/03/15 14:17:39; + tstp 4 2018/03/15 14:17:39; + cltt 4 2018/03/15 12:39:47; + binding state free; + hardware ethernet 50:64:2b:4f:fd:3d; + set vendor-class-identifier = "udhcp 1.19.4"; +} +lease 10.254.253.101 { + starts 5 2018/03/16 11:00:43; + ends 5 2018/03/16 12:40:15; + tstp 5 2018/03/16 12:40:15; + cltt 5 2018/03/16 11:00:43; + binding state free; + hardware ethernet d0:66:7b:8b:e5:ff; + uid "\001\320f{\213\345\377"; + set vendor-class-identifier = "udhcp 1.14.3-VD Linux VDLinux.1.2.1.x"; +} +lease 10.254.253.102 { + starts 5 2018/03/16 11:26:21; + ends 5 2018/03/16 13:06:21; + tstp 5 2018/03/16 13:06:21; + cltt 5 2018/03/16 11:26:21; + binding state free; + hardware ethernet 50:64:2b:4f:fd:3f; + uid "\001Pd+O\375?"; +} +lease 10.254.253.100 { + starts 2 2018/08/21 05:48:43; + ends 2 2018/08/21 07:23:13; + tstp 2 2018/08/21 07:23:13; + cltt 2 2018/08/21 05:48:44; + binding state free; + hardware ethernet 20:cf:30:ef:8e:a4; + uid "\001 \3170\357\216\244"; + set vendor-class-identifier = "udhcp 0.9.8-asus"; +} +lease 10.254.253.103 { + starts 6 2020/10/03 08:07:02; + ends 6 2020/10/03 09:47:02; + cltt 6 2020/10/03 08:07:02; + binding state free; + next binding state free; + rewind binding state free; + hardware ethernet 34:ce:00:03:08:57; + uid "\0014\316\000\003\010W"; + set vendor-class-identifier = "udhcp 1.24.2"; +} +lease 10.254.254.103 { + starts 3 2015/11/11 09:03:11; + ends 3 2015/11/11 09:05:11; + tstp 3 2015/11/11 09:05:11; + cltt 3 2015/11/11 09:03:11; + binding state free; + hardware ethernet 74:d0:2b:0e:9b:d6; +} +lease 10.254.254.104 { + starts 0 2017/12/03 15:57:29; + ends 0 2017/12/03 17:37:29; + tstp 0 2017/12/03 17:37:29; + cltt 0 2017/12/03 15:57:29; + binding state free; + hardware ethernet ac:22:0b:78:00:78; + uid "\377\3139\012\307\000\002\000\000\253\021(CC\252e\021\000\017"; +} +lease 10.254.254.105 { + starts 2 2018/06/26 12:30:04; + ends 2 2018/06/26 13:09:10; + tstp 2 2018/06/26 13:09:10; + cltt 2 2018/06/26 12:30:04; + binding state free; + hardware ethernet cc:2d:e0:3f:bc:5c; + uid "\001\314-\340?\274\\"; +} +lease 10.254.254.101 { + starts 3 2018/07/25 09:33:10; + ends 3 2018/07/25 11:13:10; + tstp 3 2018/07/25 11:13:10; + cltt 3 2018/07/25 09:33:10; + binding state free; + hardware ethernet 74:d0:2b:0e:9b:d6; + uid "\001t\320+\016\233\326"; + set vendor-class-identifier = "MSFT 5.0"; +} +lease 10.254.254.100 { + starts 2 2020/09/22 11:19:29; + ends 2 2020/09/22 11:21:29; + cltt 2 2020/09/22 11:19:29; + binding state free; + hardware ethernet 30:45:96:6a:f3:de; + uid "\0010E\226j\363\336"; + client-hostname "Honor_7C-bb23201389a3c44"; +} +lease 10.254.254.102 { + starts 2 2020/09/22 11:25:14; + ends 2 2020/09/22 11:27:14; + cltt 2 2020/09/22 11:25:14; + binding state free; + hardware ethernet c8:3d:dc:be:d2:cf; + uid "\001\310=\334\276\322\317"; + client-hostname "Redmi7A-Redmi"; +} +lease 10.254.255.101 { + starts 6 2020/10/03 08:19:24; + ends 6 2020/10/03 09:59:24; + cltt 6 2020/10/03 08:19:24; + binding state free; + next binding state free; + rewind binding state free; + hardware ethernet 28:3b:82:58:f4:58; + uid "\001(;\202X\364X"; + set vendor-class-identifier = "dslforum.org"; +} +lease 10.254.251.100 { + starts 6 2020/10/03 08:48:45; + ends 6 2020/10/03 10:28:45; + cltt 6 2020/10/03 08:48:45; + binding state free; + next binding state free; + rewind binding state free; + hardware ethernet 74:ea:3a:a6:a9:c7; + uid "\001t\352:\246\251\307"; + set vendor-class-identifier = "MSFT 5.0"; + client-hostname "TL-WR741N"; +} +lease 10.254.253.103 { + starts 6 2020/10/03 08:57:02; + ends 6 2020/10/03 10:37:02; + cltt 6 2020/10/03 08:57:02; + binding state free; + next binding state free; + rewind binding state free; + hardware ethernet 34:ce:00:03:08:57; + uid "\0014\316\000\003\010W"; + set vendor-class-identifier = "udhcp 1.24.2"; +} +lease 192.168.3.11 { + starts 6 2020/10/03 09:01:22; + ends 6 2020/10/03 10:41:22; + cltt 6 2020/10/03 09:01:22; + binding state free; + next binding state free; + rewind binding state free; + hardware ethernet 60:a4:4c:3f:6e:78; + uid "\001`\244L?nx"; +} diff --git a/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv6 b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv6 new file mode 100644 index 000000000..3a4f1520e --- /dev/null +++ b/src/go/collectors/go.d.plugin/modules/isc_dhcpd/testdata/dhcpd.leases_ipv6 @@ -0,0 +1,67 @@ +# The format of this file is documented in the dhcpd.leases(5) manual page. +# This lease file was written by isc-dhcp-4.3.6b1 + +# authoring-byte-order entry is generated, DO NOT DELETE +authoring-byte-order little-endian; + +server-duid "\000\001\002\003!\004\005\006\007\008)^6\257"; + +ia-na "'\000\010\016\000\001\000\001!\320\263\003\010\000'\327\337\354" { + cltt 0 2017/12/24 10:53:29; + iaaddr 2001:db8:: { + binding state active; + preferred-life 604800; + max-life 2592000; + ends 2 2020/09/30 10:53:29; + } +} + +ia-na "#\2340\000\000\000\000\000!\300\021]0\234#e\212\261" { + cltt 6 2017/12/23 23:59:58; + iaaddr 2001:db8::1 { + binding state active; + preferred-life 604800; + max-life 2592000; + ends 2 2020/09/30 23:59:58; + } +} + +ia-na "\000\000\000\000\000\001\000\000 \000\301\267xOCl\313\310" { + cltt 0 2017/12/24 02:11:08; + iaaddr 2001:db8::2 { + binding state active; + preferred-life 604800; + max-life 2592000; + ends 2 2020/09/30 02:11:08; + } +} + +ia-na "'\000\000\000\000\000\000\001\027.\010\225\010\000'C8\353" { + cltt 0 2017/12/24 00:48:39; + iaaddr 2001:db8::3 { + binding state active; + preferred-life 604800; + max-life 2592000; + ends 2 2020/09/30 18:48:39; + } +} + +ia-na "\000\000\000\000\000\000\000\265H\006n\305F\351\270i\014\326q\023J\347" { + cltt 0 2017/12/24 01:53:15; + iaaddr 2001:db8::4 { + binding state active; + preferred-life 604800; + max-life 2592000; + ends 2 2020/09/30 14:53:15; + } +} + +ia-na "\000\000\000\000\000\000\000\000 \010\351\267xOCl\313\310" { + cltt 0 2017/12/24 11:33:17; + iaaddr 2001:db8::5 { + binding state active; + preferred-life 604800; + max-life 2592000; + ends 2 2020/09/30 11:33:17; + } +} |