github.com/netdata/go.d.plugin@v0.58.1/modules/isc_dhcpd/collect.go (about) 1 // SPDX-License-Identifier: GPL-3.0-or-later 2 3 package isc_dhcpd 4 5 import ( 6 "os" 7 ) 8 9 /* 10 dhcpd.leases db (file), see details: https://kb.isc.org/docs/en/isc-dhcp-44-manual-pages-dhcpdleases#dhcpdleases 11 12 Every time a lease is acquired, renewed or released, its new value is recorded at the end of the lease file. 13 So if more than one declaration appears for a given lease, the last one in the file is the current one. 14 15 In order to prevent the lease database from growing without bound, the file is rewritten from time to time. 16 First, a temporary lease database is created and all known leases are dumped to it. 17 Then, the old lease database is renamed DBDIR/dhcpd.leases~. 18 Finally, the newly written lease database is moved into place. 19 20 In order to process both DHCPv4 and DHCPv6 messages you will need to run two separate instances of the dhcpd process. 21 Each of these instances will need its own lease file. 22 */ 23 24 func (d *DHCPd) collect() (map[string]int64, error) { 25 fi, err := os.Stat(d.LeasesPath) 26 if err != nil { 27 return nil, err 28 } 29 30 if d.leasesModTime.Equal(fi.ModTime()) { 31 d.Debugf("leases file is not modified, returning cached metrics ('%s')", d.LeasesPath) 32 return d.collected, nil 33 } 34 35 d.leasesModTime = fi.ModTime() 36 37 leases, err := parseDHCPdLeasesFile(d.LeasesPath) 38 if err != nil { 39 return nil, err 40 } 41 42 activeLeases := removeInactiveLeases(leases) 43 d.Debugf("found total/active %d/%d leases ('%s')", len(leases), len(activeLeases), d.LeasesPath) 44 45 for _, pool := range d.pools { 46 collectPool(d.collected, pool, activeLeases) 47 } 48 d.collected["active_leases_total"] = int64(len(activeLeases)) 49 50 return d.collected, nil 51 } 52 53 const precision = 100 54 55 func collectPool(collected map[string]int64, pool ipPool, leases []leaseEntry) { 56 n := calcPoolActiveLeases(pool, leases) 57 collected["pool_"+pool.name+"_active_leases"] = n 58 collected["pool_"+pool.name+"_utilization"] = int64(calcPoolUtilizationPercentage(pool, n) * precision) 59 } 60 61 func calcPoolActiveLeases(pool ipPool, leases []leaseEntry) (num int64) { 62 for _, l := range leases { 63 if pool.addresses.Contains(l.ip) { 64 num++ 65 } 66 } 67 return num 68 } 69 70 func calcPoolUtilizationPercentage(pool ipPool, leases int64) float64 { 71 size := pool.addresses.Size() 72 if leases == 0 || !size.IsInt64() { 73 return 0 74 } 75 if size.Int64() == 0 { 76 return 100 77 } 78 return float64(leases) / float64(size.Int64()) * 100 79 } 80 81 func removeInactiveLeases(leases []leaseEntry) (active []leaseEntry) { 82 active = leases[:0] 83 for _, l := range leases { 84 if l.bindingState == "active" { 85 active = append(active, l) 86 } 87 } 88 return active 89 }