From ed559c5a69560ce9a45d37f8c29d55ea23a9e6cd Mon Sep 17 00:00:00 2001 From: Tomy Guichard Date: Wed, 3 May 2023 21:17:27 +0200 Subject: [PATCH 1/4] Add deviceinfo metrics --- README.md | 26 ++++---- internal/collector/deviceinfo.go | 101 +++++++++++++++++++++++++++++++ main.go | 3 + 3 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 internal/collector/deviceinfo.go diff --git a/README.md b/README.md index 2494f96..2f93b8b 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,21 @@ FTTH subscription. This exporter currently exposes the following metrics: -| Name | Type | Description | Labels | Experimental | -| ---------------------------------- | ----- | ------------------------------------------------- | --------- | ------------ | -| livebox_interface_rx_mbits | gauge | Received Mbits per second | interface | No | -| livebox_interface_tx_mbits | gauge | Transmitted Mbits per second | interface | No | -| livebox_devices_total | gauge | The total number of active devices | type | No | -| livebox_interface_homelan_rx_mbits | gauge | Received Mbits per second | interface | Yes | -| livebox_interface_homelan_tx_mbits | gauge | Transmitted Mbits per second | interface | Yes | -| livebox_interface_netdev_rx_mbits | gauge | Received Mbits per second | interface | Yes | -| livebox_interface_netdev_tx_mbits | gauge | Transmitted Mbits per second | interface | Yes | -| livebox_wan_rx_mbits | gauge | Received Mbits per second on the WAN interface | | Yes | -| livebox_wan_tx_mbits | gauge | Transmitted Mbits per second on the WAN interface | | Yes | +| Name | Type | Description | Labels | Experimental | +| --------------------------------------- | ----- | ------------------------------------------------- | --------- | ------------ | +| livebox_interface_rx_mbits | gauge | Received Mbits per second | interface | No | +| livebox_interface_tx_mbits | gauge | Transmitted Mbits per second | interface | No | +| livebox_devices_total | gauge | The total number of active devices | type | No | +| livebox_deviceinfo_reboots_total | gauge | Number of Livebox reboots | | No | +| livebox_deviceinfo_uptime_seconds_total | gauge | Livebox current uptime | | No | +| livebox_deviceinfo_memory_total_mbytes | gauge | Livebox system total memory | | No | +| livebox_deviceinfo_memory_usage_mbytes | gauge | Livebox system used memory | | No | +| livebox_interface_homelan_rx_mbits | gauge | Received Mbits per second | interface | Yes | +| livebox_interface_homelan_tx_mbits | gauge | Transmitted Mbits per second | interface | Yes | +| livebox_interface_netdev_rx_mbits | gauge | Received Mbits per second | interface | Yes | +| livebox_interface_netdev_tx_mbits | gauge | Transmitted Mbits per second | interface | Yes | +| livebox_wan_rx_mbits | gauge | Received Mbits per second on the WAN interface | | Yes | +| livebox_wan_tx_mbits | gauge | Transmitted Mbits per second on the WAN interface | | Yes | Experimental metrics are not enabled by default, use the `-experimental` command-line option to enable them. diff --git a/internal/collector/deviceinfo.go b/internal/collector/deviceinfo.go new file mode 100644 index 0000000..3f990d8 --- /dev/null +++ b/internal/collector/deviceinfo.go @@ -0,0 +1,101 @@ +package collector + +import ( + "context" + "log" + "sync" + + "github.com/Tomy2e/livebox-api-client" + "github.com/Tomy2e/livebox-api-client/api/request" + "github.com/prometheus/client_golang/prometheus" +) + +var _ prometheus.Collector = &DeviceInfo{} + +// DeviceInfo implements a prometheus Collector that returns Livebox specific metrics. +type DeviceInfo struct { + client livebox.Client + numberOfRebootsMetric *prometheus.Desc + uptimeMetric *prometheus.Desc + memoryTotalMetric *prometheus.Desc + memoryUsageMetric *prometheus.Desc +} + +// NewDeviceInfo returns a new DeviceInfo collector using the specified client. +func NewDeviceInfo(client livebox.Client) *DeviceInfo { + return &DeviceInfo{ + client: client, + numberOfRebootsMetric: prometheus.NewDesc( + "livebox_deviceinfo_reboots_total", + "Number of Livebox reboots.", + nil, nil, + ), + uptimeMetric: prometheus.NewDesc( + "livebox_deviceinfo_uptime_seconds_total", + "Livebox current uptime.", + nil, nil, + ), + memoryTotalMetric: prometheus.NewDesc( + "livebox_deviceinfo_memory_total_mbytes", + "Livebox system total memory.", + nil, nil, + ), + memoryUsageMetric: prometheus.NewDesc( + "livebox_deviceinfo_memory_usage_mbytes", + "Livebox system used memory.", + nil, nil, + ), + } +} + +// Describe currently does nothing. +func (d *DeviceInfo) Describe(c chan<- *prometheus.Desc) {} + +func (d *DeviceInfo) deviceInfo(c chan<- prometheus.Metric) { + var deviceInfo struct { + Status struct { + NumberOfReboots float64 `json:"NumberOfReboots"` + UpTime float64 `json:"UpTime"` + } `json:"status"` + } + if err := d.client.Request(context.TODO(), request.New("DeviceInfo", "get", nil), &deviceInfo); err != nil { + log.Printf("WARN: DeviceInfo collector failed: %s", err) + return + } + + c <- prometheus.MustNewConstMetric(d.numberOfRebootsMetric, prometheus.GaugeValue, deviceInfo.Status.NumberOfReboots) + c <- prometheus.MustNewConstMetric(d.uptimeMetric, prometheus.GaugeValue, deviceInfo.Status.UpTime) +} + +func (d *DeviceInfo) memoryStatus(c chan<- prometheus.Metric) { + var memoryStatus struct { + Status struct { + Total float64 `json:"Total"` + Free float64 `json:"Free"` + } `json:"status"` + } + if err := d.client.Request(context.TODO(), request.New("DeviceInfo.MemoryStatus", "get", nil), &memoryStatus); err != nil { + log.Printf("WARN: MemoryStatus collector failed: %s", err) + return + } + + c <- prometheus.MustNewConstMetric(d.memoryTotalMetric, prometheus.GaugeValue, memoryStatus.Status.Total) + c <- prometheus.MustNewConstMetric(d.memoryUsageMetric, prometheus.GaugeValue, memoryStatus.Status.Total-memoryStatus.Status.Free) +} + +// Collect collects all DeviceInfo metrics. +func (d *DeviceInfo) Collect(c chan<- prometheus.Metric) { + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + d.deviceInfo(c) + wg.Done() + }() + + wg.Add(1) + go func() { + d.memoryStatus(c) + wg.Done() + }() + wg.Wait() +} diff --git a/main.go b/main.go index fea4ac2..fd4b671 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( "time" "github.com/Tomy2e/livebox-api-client" + "github.com/Tomy2e/livebox-exporter/internal/collector" "github.com/Tomy2e/livebox-exporter/internal/poller" exporterLivebox "github.com/Tomy2e/livebox-exporter/pkg/livebox" "github.com/prometheus/client_golang/prometheus" @@ -130,6 +131,8 @@ func main() { )..., ) + registry.MustRegister(collector.NewDeviceInfo(client)) + go func() { for { if err := pollers.Poll(ctx); err != nil { From 86d6520c62cb3d5e7f8f0999b96e2ee8691ac591 Mon Sep 17 00:00:00 2001 From: Tomy Guichard Date: Wed, 3 May 2023 21:43:49 +0200 Subject: [PATCH 2/4] fix livebox_deviceinfo_memory unit --- README.md | 4 ++-- internal/collector/deviceinfo.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2f93b8b..8464fd9 100644 --- a/README.md +++ b/README.md @@ -14,8 +14,8 @@ This exporter currently exposes the following metrics: | livebox_devices_total | gauge | The total number of active devices | type | No | | livebox_deviceinfo_reboots_total | gauge | Number of Livebox reboots | | No | | livebox_deviceinfo_uptime_seconds_total | gauge | Livebox current uptime | | No | -| livebox_deviceinfo_memory_total_mbytes | gauge | Livebox system total memory | | No | -| livebox_deviceinfo_memory_usage_mbytes | gauge | Livebox system used memory | | No | +| livebox_deviceinfo_memory_total_bytes | gauge | Livebox system total memory | | No | +| livebox_deviceinfo_memory_usage_bytes | gauge | Livebox system used memory | | No | | livebox_interface_homelan_rx_mbits | gauge | Received Mbits per second | interface | Yes | | livebox_interface_homelan_tx_mbits | gauge | Transmitted Mbits per second | interface | Yes | | livebox_interface_netdev_rx_mbits | gauge | Received Mbits per second | interface | Yes | diff --git a/internal/collector/deviceinfo.go b/internal/collector/deviceinfo.go index 3f990d8..e317cfc 100644 --- a/internal/collector/deviceinfo.go +++ b/internal/collector/deviceinfo.go @@ -36,12 +36,12 @@ func NewDeviceInfo(client livebox.Client) *DeviceInfo { nil, nil, ), memoryTotalMetric: prometheus.NewDesc( - "livebox_deviceinfo_memory_total_mbytes", + "livebox_deviceinfo_memory_total_bytes", "Livebox system total memory.", nil, nil, ), memoryUsageMetric: prometheus.NewDesc( - "livebox_deviceinfo_memory_usage_mbytes", + "livebox_deviceinfo_memory_usage_bytes", "Livebox system used memory.", nil, nil, ), @@ -79,8 +79,8 @@ func (d *DeviceInfo) memoryStatus(c chan<- prometheus.Metric) { return } - c <- prometheus.MustNewConstMetric(d.memoryTotalMetric, prometheus.GaugeValue, memoryStatus.Status.Total) - c <- prometheus.MustNewConstMetric(d.memoryUsageMetric, prometheus.GaugeValue, memoryStatus.Status.Total-memoryStatus.Status.Free) + c <- prometheus.MustNewConstMetric(d.memoryTotalMetric, prometheus.GaugeValue, 1000*memoryStatus.Status.Total) + c <- prometheus.MustNewConstMetric(d.memoryUsageMetric, prometheus.GaugeValue, 1000*(memoryStatus.Status.Total-memoryStatus.Status.Free)) } // Collect collects all DeviceInfo metrics. From 5abe206e2794130fbb66146f1b6317e615c30053 Mon Sep 17 00:00:00 2001 From: Tomy Guichard Date: Tue, 23 May 2023 20:55:05 +0200 Subject: [PATCH 3/4] Add deviceinfo metrics (#5) --- README.md | 26 ++++---- internal/collector/deviceinfo.go | 101 +++++++++++++++++++++++++++++++ main.go | 3 + 3 files changed, 119 insertions(+), 11 deletions(-) create mode 100644 internal/collector/deviceinfo.go diff --git a/README.md b/README.md index 2494f96..8464fd9 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,21 @@ FTTH subscription. This exporter currently exposes the following metrics: -| Name | Type | Description | Labels | Experimental | -| ---------------------------------- | ----- | ------------------------------------------------- | --------- | ------------ | -| livebox_interface_rx_mbits | gauge | Received Mbits per second | interface | No | -| livebox_interface_tx_mbits | gauge | Transmitted Mbits per second | interface | No | -| livebox_devices_total | gauge | The total number of active devices | type | No | -| livebox_interface_homelan_rx_mbits | gauge | Received Mbits per second | interface | Yes | -| livebox_interface_homelan_tx_mbits | gauge | Transmitted Mbits per second | interface | Yes | -| livebox_interface_netdev_rx_mbits | gauge | Received Mbits per second | interface | Yes | -| livebox_interface_netdev_tx_mbits | gauge | Transmitted Mbits per second | interface | Yes | -| livebox_wan_rx_mbits | gauge | Received Mbits per second on the WAN interface | | Yes | -| livebox_wan_tx_mbits | gauge | Transmitted Mbits per second on the WAN interface | | Yes | +| Name | Type | Description | Labels | Experimental | +| --------------------------------------- | ----- | ------------------------------------------------- | --------- | ------------ | +| livebox_interface_rx_mbits | gauge | Received Mbits per second | interface | No | +| livebox_interface_tx_mbits | gauge | Transmitted Mbits per second | interface | No | +| livebox_devices_total | gauge | The total number of active devices | type | No | +| livebox_deviceinfo_reboots_total | gauge | Number of Livebox reboots | | No | +| livebox_deviceinfo_uptime_seconds_total | gauge | Livebox current uptime | | No | +| livebox_deviceinfo_memory_total_bytes | gauge | Livebox system total memory | | No | +| livebox_deviceinfo_memory_usage_bytes | gauge | Livebox system used memory | | No | +| livebox_interface_homelan_rx_mbits | gauge | Received Mbits per second | interface | Yes | +| livebox_interface_homelan_tx_mbits | gauge | Transmitted Mbits per second | interface | Yes | +| livebox_interface_netdev_rx_mbits | gauge | Received Mbits per second | interface | Yes | +| livebox_interface_netdev_tx_mbits | gauge | Transmitted Mbits per second | interface | Yes | +| livebox_wan_rx_mbits | gauge | Received Mbits per second on the WAN interface | | Yes | +| livebox_wan_tx_mbits | gauge | Transmitted Mbits per second on the WAN interface | | Yes | Experimental metrics are not enabled by default, use the `-experimental` command-line option to enable them. diff --git a/internal/collector/deviceinfo.go b/internal/collector/deviceinfo.go new file mode 100644 index 0000000..e317cfc --- /dev/null +++ b/internal/collector/deviceinfo.go @@ -0,0 +1,101 @@ +package collector + +import ( + "context" + "log" + "sync" + + "github.com/Tomy2e/livebox-api-client" + "github.com/Tomy2e/livebox-api-client/api/request" + "github.com/prometheus/client_golang/prometheus" +) + +var _ prometheus.Collector = &DeviceInfo{} + +// DeviceInfo implements a prometheus Collector that returns Livebox specific metrics. +type DeviceInfo struct { + client livebox.Client + numberOfRebootsMetric *prometheus.Desc + uptimeMetric *prometheus.Desc + memoryTotalMetric *prometheus.Desc + memoryUsageMetric *prometheus.Desc +} + +// NewDeviceInfo returns a new DeviceInfo collector using the specified client. +func NewDeviceInfo(client livebox.Client) *DeviceInfo { + return &DeviceInfo{ + client: client, + numberOfRebootsMetric: prometheus.NewDesc( + "livebox_deviceinfo_reboots_total", + "Number of Livebox reboots.", + nil, nil, + ), + uptimeMetric: prometheus.NewDesc( + "livebox_deviceinfo_uptime_seconds_total", + "Livebox current uptime.", + nil, nil, + ), + memoryTotalMetric: prometheus.NewDesc( + "livebox_deviceinfo_memory_total_bytes", + "Livebox system total memory.", + nil, nil, + ), + memoryUsageMetric: prometheus.NewDesc( + "livebox_deviceinfo_memory_usage_bytes", + "Livebox system used memory.", + nil, nil, + ), + } +} + +// Describe currently does nothing. +func (d *DeviceInfo) Describe(c chan<- *prometheus.Desc) {} + +func (d *DeviceInfo) deviceInfo(c chan<- prometheus.Metric) { + var deviceInfo struct { + Status struct { + NumberOfReboots float64 `json:"NumberOfReboots"` + UpTime float64 `json:"UpTime"` + } `json:"status"` + } + if err := d.client.Request(context.TODO(), request.New("DeviceInfo", "get", nil), &deviceInfo); err != nil { + log.Printf("WARN: DeviceInfo collector failed: %s", err) + return + } + + c <- prometheus.MustNewConstMetric(d.numberOfRebootsMetric, prometheus.GaugeValue, deviceInfo.Status.NumberOfReboots) + c <- prometheus.MustNewConstMetric(d.uptimeMetric, prometheus.GaugeValue, deviceInfo.Status.UpTime) +} + +func (d *DeviceInfo) memoryStatus(c chan<- prometheus.Metric) { + var memoryStatus struct { + Status struct { + Total float64 `json:"Total"` + Free float64 `json:"Free"` + } `json:"status"` + } + if err := d.client.Request(context.TODO(), request.New("DeviceInfo.MemoryStatus", "get", nil), &memoryStatus); err != nil { + log.Printf("WARN: MemoryStatus collector failed: %s", err) + return + } + + c <- prometheus.MustNewConstMetric(d.memoryTotalMetric, prometheus.GaugeValue, 1000*memoryStatus.Status.Total) + c <- prometheus.MustNewConstMetric(d.memoryUsageMetric, prometheus.GaugeValue, 1000*(memoryStatus.Status.Total-memoryStatus.Status.Free)) +} + +// Collect collects all DeviceInfo metrics. +func (d *DeviceInfo) Collect(c chan<- prometheus.Metric) { + wg := sync.WaitGroup{} + wg.Add(1) + go func() { + d.deviceInfo(c) + wg.Done() + }() + + wg.Add(1) + go func() { + d.memoryStatus(c) + wg.Done() + }() + wg.Wait() +} diff --git a/main.go b/main.go index fea4ac2..fd4b671 100644 --- a/main.go +++ b/main.go @@ -12,6 +12,7 @@ import ( "time" "github.com/Tomy2e/livebox-api-client" + "github.com/Tomy2e/livebox-exporter/internal/collector" "github.com/Tomy2e/livebox-exporter/internal/poller" exporterLivebox "github.com/Tomy2e/livebox-exporter/pkg/livebox" "github.com/prometheus/client_golang/prometheus" @@ -130,6 +131,8 @@ func main() { )..., ) + registry.MustRegister(collector.NewDeviceInfo(client)) + go func() { for { if err := pollers.Poll(ctx); err != nil { From 4a5496d239e0525686eae0d54f86dd0158140057 Mon Sep 17 00:00:00 2001 From: Tomy Guichard Date: Sat, 3 Jun 2023 11:30:01 +0200 Subject: [PATCH 4/4] Allow using a custom livebox address (#7) --- README.md | 8 +- charts/livebox-exporter/Chart.yaml | 4 +- .../livebox-exporter/templates/configmap.yaml | 10 +++ .../templates/deployment.yaml | 25 ++++++- charts/livebox-exporter/templates/secret.yaml | 4 +- charts/livebox-exporter/values.yaml | 21 +++--- go.mod | 2 +- go.sum | 4 +- internal/collector/deviceinfo.go | 4 +- internal/poller/devices.go | 4 +- internal/poller/interface.go | 4 +- internal/poller/interface_homelan.go | 4 +- internal/poller/interface_netdev.go | 4 +- internal/poller/wan.go | 4 +- main.go | 75 ++++++++++++++++++- pkg/livebox/discovery.go | 2 +- 16 files changed, 141 insertions(+), 38 deletions(-) create mode 100644 charts/livebox-exporter/templates/configmap.yaml diff --git a/README.md b/README.md index 8464fd9..fbd7a39 100644 --- a/README.md +++ b/README.md @@ -40,9 +40,11 @@ The exporter accepts the following command-line options: The exporter reads the following environment variables: -| Name | Description | Default value | -| -------------- | --------------------------------------------------------------------------------------------------------- | ------------- | -| ADMIN_PASSWORD | Password of the Livebox "admin" user. The exporter will exit if this environment variable is not defined. | | +| Name | Description | Default value | +| --------------- | --------------------------------------------------------------------------------------------------------- | -------------------- | +| ADMIN_PASSWORD | Password of the Livebox "admin" user. The exporter will exit if this environment variable is not defined. | | +| LIVEBOX_ADDRESS | Address of the Livebox. | `http://192.168.1.1` | +| LIVEBOX_CACERT | Optional path to a PEM-encoded CA certificate file on the local disk. | | ### Docker diff --git a/charts/livebox-exporter/Chart.yaml b/charts/livebox-exporter/Chart.yaml index 171c10a..fe972e1 100644 --- a/charts/livebox-exporter/Chart.yaml +++ b/charts/livebox-exporter/Chart.yaml @@ -2,5 +2,5 @@ apiVersion: v2 name: livebox-exporter description: A prometheus exporter for Livebox type: application -version: 0.2.0 -appVersion: "v0.2.0" +version: 0.3.0 +appVersion: "v0.3.0" diff --git a/charts/livebox-exporter/templates/configmap.yaml b/charts/livebox-exporter/templates/configmap.yaml new file mode 100644 index 0000000..aefe3a2 --- /dev/null +++ b/charts/livebox-exporter/templates/configmap.yaml @@ -0,0 +1,10 @@ +{{- if .Values.livebox.caCert }} +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "livebox-exporter.fullname" . }} + labels: + {{- include "livebox-exporter.labels" . | nindent 4 }} +data: + ca.crt: {{ toYaml .Values.livebox.caCert | indent 2 }} +{{- end }} \ No newline at end of file diff --git a/charts/livebox-exporter/templates/deployment.yaml b/charts/livebox-exporter/templates/deployment.yaml index be2aa8d..e7cb588 100644 --- a/charts/livebox-exporter/templates/deployment.yaml +++ b/charts/livebox-exporter/templates/deployment.yaml @@ -41,13 +41,26 @@ spec: - name: ADMIN_PASSWORD valueFrom: secretKeyRef: - {{- if .Values.adminPassword.secretKeyRef }} - name: {{ .Values.adminPassword.secretKeyRef.name}} - key: {{ .Values.adminPassword.secretKeyRef.key }} + {{- if .Values.livebox.adminPassword.secretKeyRef }} + name: {{ .Values.livebox.adminPassword.secretKeyRef.name}} + key: {{ .Values.livebox.adminPassword.secretKeyRef.key }} {{- else }} name: {{ include "livebox-exporter.fullname" . }}-admin key: password {{- end }} + {{- with .Values.livebox.address }} + - name: LIVEBOX_ADDRESS + value: {{ . }} + {{- end }} + {{- if .Values.livebox.caCert }} + - name: LIVEBOX_CACERT + value: /etc/livebox/certs/ca.crt + {{- end }} + {{- if .Values.livebox.caCert }} + volumeMounts: + - name: livebox-crt + mountPath: /etc/livebox/certs + {{- end }} {{- with .Values.nodeSelector }} nodeSelector: {{- toYaml . | nindent 8 }} @@ -60,3 +73,9 @@ spec: tolerations: {{- toYaml . | nindent 8 }} {{- end }} + {{- if .Values.livebox.caCert }} + volumes: + - name: livebox-crt + configMap: + name: {{ include "livebox-exporter.fullname" . }} + {{- end }} \ No newline at end of file diff --git a/charts/livebox-exporter/templates/secret.yaml b/charts/livebox-exporter/templates/secret.yaml index f2f0c3b..18a30f7 100644 --- a/charts/livebox-exporter/templates/secret.yaml +++ b/charts/livebox-exporter/templates/secret.yaml @@ -1,4 +1,4 @@ -{{- if not .Values.adminPassword.secretKeyRef }} +{{- if not .Values.livebox.adminPassword.secretKeyRef }} apiVersion: v1 kind: Secret metadata: @@ -7,5 +7,5 @@ metadata: {{- include "livebox-exporter.labels" . | nindent 4 }} type: Opaque data: - password: {{ .Values.adminPassword.value | b64enc }} + password: {{ .Values.livebox.adminPassword.value | b64enc }} {{- end }} \ No newline at end of file diff --git a/charts/livebox-exporter/values.yaml b/charts/livebox-exporter/values.yaml index 98120a7..e2a2cee 100644 --- a/charts/livebox-exporter/values.yaml +++ b/charts/livebox-exporter/values.yaml @@ -1,7 +1,3 @@ -# Default values for livebox-exporter. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - replicaCount: 1 image: @@ -10,12 +6,19 @@ image: # Overrides the image tag whose default is the chart appVersion. tag: "" -adminPassword: - secretKeyRef: {} - # name: "" - # key: "" +livebox: + adminPassword: + secretKeyRef: {} + # name: "" + # key: "" - value: "changeme" + value: "changeme" + + # Address of the Livebox. If empty the exporter will use its own default value. + address: "" + + # CA cert of the Livebox. + caCert: "" imagePullSecrets: [] nameOverride: "" diff --git a/go.mod b/go.mod index f497aca..1929fff 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,7 @@ module github.com/Tomy2e/livebox-exporter go 1.18 require ( - github.com/Tomy2e/livebox-api-client v0.0.0-20230304114924-a629a6a185e7 + github.com/Tomy2e/livebox-api-client v0.0.0-20230524112450-31caca47cbd8 github.com/prometheus/client_golang v1.14.0 golang.org/x/exp v0.0.0-20230315142452-642cacee5cc0 golang.org/x/sync v0.1.0 diff --git a/go.sum b/go.sum index acacb92..ada3d6e 100644 --- a/go.sum +++ b/go.sum @@ -33,8 +33,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Tomy2e/livebox-api-client v0.0.0-20230304114924-a629a6a185e7 h1:aX04myQJxWqjP1I1S8jiE8fKyXSu4CHKMBOCUMTwlCI= -github.com/Tomy2e/livebox-api-client v0.0.0-20230304114924-a629a6a185e7/go.mod h1:3uvJQHRP5V3BKPTzWCOmUMxZrPbJNl45Wu7ueX9L8QM= +github.com/Tomy2e/livebox-api-client v0.0.0-20230524112450-31caca47cbd8 h1:rVK1emWX3JW3nNhLdl76M4RJgmMj/hcgQVOJmrh2r9Y= +github.com/Tomy2e/livebox-api-client v0.0.0-20230524112450-31caca47cbd8/go.mod h1:3uvJQHRP5V3BKPTzWCOmUMxZrPbJNl45Wu7ueX9L8QM= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= diff --git a/internal/collector/deviceinfo.go b/internal/collector/deviceinfo.go index e317cfc..37827d8 100644 --- a/internal/collector/deviceinfo.go +++ b/internal/collector/deviceinfo.go @@ -14,7 +14,7 @@ var _ prometheus.Collector = &DeviceInfo{} // DeviceInfo implements a prometheus Collector that returns Livebox specific metrics. type DeviceInfo struct { - client livebox.Client + client *livebox.Client numberOfRebootsMetric *prometheus.Desc uptimeMetric *prometheus.Desc memoryTotalMetric *prometheus.Desc @@ -22,7 +22,7 @@ type DeviceInfo struct { } // NewDeviceInfo returns a new DeviceInfo collector using the specified client. -func NewDeviceInfo(client livebox.Client) *DeviceInfo { +func NewDeviceInfo(client *livebox.Client) *DeviceInfo { return &DeviceInfo{ client: client, numberOfRebootsMetric: prometheus.NewDesc( diff --git a/internal/poller/devices.go b/internal/poller/devices.go index a244969..5794118 100644 --- a/internal/poller/devices.go +++ b/internal/poller/devices.go @@ -13,12 +13,12 @@ var _ Poller = &DevicesTotal{} // DevicesTotal allows to poll the total number of active devices. type DevicesTotal struct { - client livebox.Client + client *livebox.Client devicesTotal *prometheus.GaugeVec } // NewDevicesTotal returns a new DevicesTotal poller. -func NewDevicesTotal(client livebox.Client) *DevicesTotal { +func NewDevicesTotal(client *livebox.Client) *DevicesTotal { return &DevicesTotal{ client: client, devicesTotal: prometheus.NewGaugeVec(prometheus.GaugeOpts{ diff --git a/internal/poller/interface.go b/internal/poller/interface.go index 03c152e..824587a 100644 --- a/internal/poller/interface.go +++ b/internal/poller/interface.go @@ -15,12 +15,12 @@ var _ Poller = &InterfaceMbits{} // InterfaceMbits allows to poll the current bandwidth usage on the Livebox // interfaces. type InterfaceMbits struct { - client livebox.Client + client *livebox.Client txMbits, rxMbits *prometheus.GaugeVec } // NewInterfaceMbits returns a new InterfaceMbits poller. -func NewInterfaceMbits(client livebox.Client) *InterfaceMbits { +func NewInterfaceMbits(client *livebox.Client) *InterfaceMbits { return &InterfaceMbits{ client: client, txMbits: prometheus.NewGaugeVec(prometheus.GaugeOpts{ diff --git a/internal/poller/interface_homelan.go b/internal/poller/interface_homelan.go index 02e882b..368efd9 100644 --- a/internal/poller/interface_homelan.go +++ b/internal/poller/interface_homelan.go @@ -22,14 +22,14 @@ var _ Poller = &InterfaceHomeLanMbits{} // InterfaceHomeLanMbits is an experimental poller to get the current bandwidth // usage on the Livebox interfaces. type InterfaceHomeLanMbits struct { - client livebox.Client + client *livebox.Client interfaces []*exporterLivebox.Interface bitrate *bitrate.Bitrate txMbits, rxMbits *prometheus.GaugeVec } // NewInterfaceHomeLanMbits returns a new InterfaceMbits poller. -func NewInterfaceHomeLanMbits(client livebox.Client, interfaces []*exporterLivebox.Interface) *InterfaceHomeLanMbits { +func NewInterfaceHomeLanMbits(client *livebox.Client, interfaces []*exporterLivebox.Interface) *InterfaceHomeLanMbits { return &InterfaceHomeLanMbits{ client: client, interfaces: interfaces, diff --git a/internal/poller/interface_netdev.go b/internal/poller/interface_netdev.go index 306e91f..94966e3 100644 --- a/internal/poller/interface_netdev.go +++ b/internal/poller/interface_netdev.go @@ -16,14 +16,14 @@ var _ Poller = &InterfaceNetDevMbits{} // InterfaceNetDevMbits is an experimental poller to get the current bandwidth // usage on the Livebox interfaces. type InterfaceNetDevMbits struct { - client livebox.Client + client *livebox.Client interfaces []*exporterLivebox.Interface bitrate *bitrate.Bitrate txMbits, rxMbits *prometheus.GaugeVec } // NewInterfaceNetDevMbits returns a new InterfaceNetDevMbits poller. -func NewInterfaceNetDevMbits(client livebox.Client, interfaces []*exporterLivebox.Interface) *InterfaceNetDevMbits { +func NewInterfaceNetDevMbits(client *livebox.Client, interfaces []*exporterLivebox.Interface) *InterfaceNetDevMbits { return &InterfaceNetDevMbits{ client: client, interfaces: interfaces, diff --git a/internal/poller/wan.go b/internal/poller/wan.go index 90089f0..058fdc6 100644 --- a/internal/poller/wan.go +++ b/internal/poller/wan.go @@ -14,13 +14,13 @@ var _ Poller = &WANMbits{} // WANMbits is an experimental poller to get the current bandwidth usage on the // WAN interface of the Livebox. type WANMbits struct { - client livebox.Client + client *livebox.Client bitrate *bitrate.Bitrate txMbits, rxMbits prometheus.Gauge } // NewWANMbits returns a new WANMbits poller. -func NewWANMbits(client livebox.Client) *WANMbits { +func NewWANMbits(client *livebox.Client) *WANMbits { return &WANMbits{ client: client, bitrate: bitrate.New(InterfaceHomeLanMbitsMinDelay), diff --git a/main.go b/main.go index fd4b671..98b7aca 100644 --- a/main.go +++ b/main.go @@ -2,9 +2,12 @@ package main import ( "context" + "crypto/tls" + "crypto/x509" "errors" "flag" "fmt" + "io/ioutil" "log" "net/http" "os" @@ -37,10 +40,14 @@ var experimentalMetrics = []string{ func parseExperimentalFlag( ctx context.Context, - client livebox.Client, + client *livebox.Client, experimental string, pollingFrequency *uint, ) (pollers []poller.Poller) { + if experimental == "" { + return nil + } + var ( interfaces []*exporterLivebox.Interface err error @@ -96,6 +103,50 @@ func parseExperimentalFlag( return } +func getHTTPClient() (*http.Client, error) { + liveboxCACertPath := os.Getenv("LIVEBOX_CACERT") + + if liveboxCACertPath == "" { + return http.DefaultClient, nil + } + + // Get the SystemCertPool, continue with an empty pool on error. + rootCAs, _ := x509.SystemCertPool() + if rootCAs == nil { + rootCAs = x509.NewCertPool() + } + + certs, err := ioutil.ReadFile(liveboxCACertPath) + if err != nil { + return nil, fmt.Errorf("failed to read livebox CA cert: %w", err) + } + + if ok := rootCAs.AppendCertsFromPEM(certs); !ok { + return nil, errors.New("no livebox CA cert was successfully added") + } + + return &http.Client{ + Transport: &http.Transport{ + TLSClientConfig: &tls.Config{ + RootCAs: rootCAs, + }, + }, + }, nil +} + +func isFatalError(err error) bool { + if errors.Is(err, livebox.ErrInvalidPassword) { + return true + } + + var certError *tls.CertificateVerificationError + if errors.As(err, &certError) { + return true + } + + return false +} + func main() { pollingFrequency := flag.Uint("polling-frequency", defaultPollingFrequency, "Polling frequency") listen := flag.String("listen", ":8080", "Listening address") @@ -110,10 +161,28 @@ func main() { log.Fatal("ADMIN_PASSWORD environment variable must be set") } + liveboxAddress := os.Getenv("LIVEBOX_ADDRESS") + if liveboxAddress == "" { + liveboxAddress = livebox.DefaultAddress + } + + httpClient, err := getHTTPClient() + if err != nil { + log.Fatal(err) + } + + client, err := livebox.NewClient( + adminPassword, + livebox.WithAddress(liveboxAddress), + livebox.WithHTTPClient(httpClient), + ) + if err != nil { + log.Fatalf("Failed to create Livebox client: %v", err) + } + var ( ctx = context.Background() registry = prometheus.NewRegistry() - client = livebox.NewClient(adminPassword) pollers = poller.Pollers{ poller.NewDevicesTotal(client), poller.NewInterfaceMbits(client), @@ -136,7 +205,7 @@ func main() { go func() { for { if err := pollers.Poll(ctx); err != nil { - if errors.Is(err, livebox.ErrInvalidPassword) { + if isFatalError(err) { log.Fatal(err) } diff --git a/pkg/livebox/discovery.go b/pkg/livebox/discovery.go index 6e496f7..0433a92 100644 --- a/pkg/livebox/discovery.go +++ b/pkg/livebox/discovery.go @@ -27,7 +27,7 @@ func (i *Interface) IsWLAN() bool { } // DiscoverInterfaces discovers network interfaces on the Livebox. -func DiscoverInterfaces(ctx context.Context, client livebox.Client) ([]*Interface, error) { +func DiscoverInterfaces(ctx context.Context, client *livebox.Client) ([]*Interface, error) { var mibs struct { Status struct { Base map[string]struct {