Allow to monitor multiple interfaces
This commit is contained in:
parent
334be5b4c2
commit
7501a0d9b8
6 changed files with 548 additions and 236 deletions
39
README.md
39
README.md
|
@ -26,7 +26,7 @@ This exporter gives following metrics, all metrics received following labels:
|
|||
|
||||
- `instance`: by default this is set with the hostname where is running this exporter service
|
||||
- `host`: the host of the OPNSense
|
||||
- `role`: `main` or `backup`
|
||||
- `role`: `main` or `backup` to determine the OPNSense server role.
|
||||
|
||||
### Enums
|
||||
|
||||
|
@ -35,8 +35,10 @@ This exporter gives following metrics, all metrics received following labels:
|
|||
|
||||
### Gauges
|
||||
|
||||
- `opnsense_active_server_bytes_received`: Active OPNSense server bytes received on WAN interface
|
||||
- `opnsense_active_server_bytes_transmitted`: Active OPNSense server bytes transmitted on WAN interface
|
||||
- `opnsense_active_server_traffic_rate`: Active OPNSense server traffic rate per interfaces bits/s
|
||||
add following labels:
|
||||
- **interface**: the interface to export (values given using `--opnsense-interfaces`)
|
||||
- **metric**: the metric name (as today one of `rate_bits_in`, `rate_bits_in`)
|
||||
|
||||
## Usage
|
||||
|
||||
|
@ -47,6 +49,7 @@ opnsense-exporter --help
|
|||
usage: opnsense-exporter [-h] [--check-frequency-seconds FREQUENCY]
|
||||
[--main-host MAIN] [--backup-host BACKUP]
|
||||
[--opnsense-user USER]
|
||||
[--opnsense-interfaces INTERFACES]
|
||||
[--opnsense-password PASSWORD]
|
||||
[--prometheus-instance PROM_INSTANCE]
|
||||
|
||||
|
@ -61,17 +64,21 @@ optional arguments:
|
|||
MAIN OPNsense server that should be in `active`
|
||||
state in normal configuration.
|
||||
--backup-host BACKUP, -b BACKUP
|
||||
BACKUP OPNsense server that should be
|
||||
`hot_standby` state in normal configuration.
|
||||
BACKUP OPNsense server that should be `hot_standby`
|
||||
state in normal configuration.
|
||||
--opnsense-user USER, -u USER
|
||||
OPNsense user. Expect to be the same on MAIN and
|
||||
BACKUP servers
|
||||
--opnsense-interfaces INTERFACES, -i INTERFACES
|
||||
OPNsense interfaces (coma separated) list to export
|
||||
trafic rates (bytes/s) (default: wan,lan)
|
||||
--opnsense-password PASSWORD, -p PASSWORD
|
||||
OPNsense password. Expect to be the same on MAIN
|
||||
and BACKUP servers
|
||||
--prometheus-instance PROM_INSTANCE
|
||||
Exporter Instance name, default value computed
|
||||
with hostname where the server is running. Use to
|
||||
Exporter Instance name, default value computed with
|
||||
hostname where the server is running. Use to set
|
||||
the instance label. (default: my-opnsense-prom-exporter-server)
|
||||
```
|
||||
|
||||
You can setup env through `.env` file or environment variables with defined as default values
|
||||
|
@ -86,8 +93,6 @@ You can setup env through `.env` file or environment variables with defined as d
|
|||
|
||||
## Roadmap
|
||||
|
||||
- merge `opnsense_active_server_bytes_received` and `opnsense_active_server_bytes_transmitted`
|
||||
metrics adding labels to distinguish rates transmitted and rate received
|
||||
- allow to configure interfaces to get traffic rates for lan,wan and/or other names
|
||||
- refactor server in a class to avoid transmitted params over methods
|
||||
- allow to change the listening port (today it force using `8000`)
|
||||
|
@ -96,22 +101,26 @@ You can setup env through `.env` file or environment variables with defined as d
|
|||
|
||||
## Changelog
|
||||
|
||||
### Version 0.0.5 (UNRELEASED)
|
||||
### Version 0.5.0 (UNRELEASED)
|
||||
|
||||
* add role label in metrics
|
||||
- add role label in metrics
|
||||
- all to configure supervised interfaces using `--opnsense-interfaces`
|
||||
- replace `active_server_bytes_received` and
|
||||
`active_server_bytes_transmitted` by
|
||||
`opnsense_active_server_traffic_rate`
|
||||
|
||||
### Version 0.4.0 (2023-09-02)
|
||||
|
||||
* Higher timeout while getting WAN traffic info
|
||||
- Higher timeout while getting WAN traffic info
|
||||
|
||||
### Version 0.3.0 (2023-09-02)
|
||||
|
||||
* Use proper method to compute WAN traffic
|
||||
- Use proper method to compute WAN traffic
|
||||
|
||||
### Version 0.2.0 (2023-09-01)
|
||||
|
||||
* Setup automatic release from gitlab while pushing new tag
|
||||
- Setup automatic release from gitlab while pushing new tag
|
||||
|
||||
### Version 0.1.0 (2023-09-01)
|
||||
|
||||
* Initial version
|
||||
- Initial version
|
||||
|
|
|
@ -7,6 +7,37 @@ from requests import RequestException
|
|||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class OPNSenseTrafficMetric(Enum):
|
||||
IN = "rate_bits_in"
|
||||
OUT = "rate_bits_out"
|
||||
|
||||
|
||||
class OPNSenseTraffic:
|
||||
interface: str = None
|
||||
metric: OPNSenseTrafficMetric = None
|
||||
value: int = 0
|
||||
|
||||
def __init__(self, interface: str, metric: OPNSenseTrafficMetric, value: int = 0):
|
||||
self.value = value
|
||||
self.interface = interface
|
||||
self.metric = metric
|
||||
|
||||
@property
|
||||
def labels(self):
|
||||
return {"metric": self.metric.value, "interface": self.interface}
|
||||
|
||||
def __eq__(self, opn_traffic):
|
||||
"""Used by unittest to assert expected values"""
|
||||
return (
|
||||
self.interface == opn_traffic.interface
|
||||
and self.metric == opn_traffic.metric
|
||||
and self.value == opn_traffic.value
|
||||
)
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.interface} - {self.metric} = {self.value}"
|
||||
|
||||
|
||||
class OPNSenseRole(Enum):
|
||||
MAIN = "main"
|
||||
BACKUP = "backup"
|
||||
|
@ -67,20 +98,23 @@ class OPNSenseAPI:
|
|||
)
|
||||
return "unavailable"
|
||||
|
||||
def get_wan_trafic(self):
|
||||
def get_traffic(self, interfaces):
|
||||
try:
|
||||
data = self.get("/api/diagnostics/traffic/top/wan", timeout=15)
|
||||
data = self.get(f"/api/diagnostics/traffic/top/{interfaces}", timeout=15)
|
||||
except RequestException as ex:
|
||||
logger.error(
|
||||
"Get diagnostics traffic on WAN interface for %s host failed with the following error %r",
|
||||
"Get diagnostics traffic on %s interface(s) for %s host failed with the following error %r",
|
||||
interfaces,
|
||||
self.host,
|
||||
ex,
|
||||
)
|
||||
return None, None
|
||||
|
||||
received = 0
|
||||
transmitted = 0
|
||||
for record in data.get("wan", []).get("records", []):
|
||||
received += record.get("rate_bits_in", 0)
|
||||
transmitted += record.get("rate_bits_out", 0)
|
||||
return received, transmitted
|
||||
return []
|
||||
traffics = []
|
||||
for interface in interfaces.split(","):
|
||||
traffic_in = OPNSenseTraffic(interface, OPNSenseTrafficMetric.IN)
|
||||
traffic_out = OPNSenseTraffic(interface, OPNSenseTrafficMetric.OUT)
|
||||
for record in data.get(interface, []).get("records", []):
|
||||
traffic_in.value += record.get(OPNSenseTrafficMetric.IN.value, 0)
|
||||
traffic_out.value += record.get(OPNSenseTrafficMetric.OUT.value, 0)
|
||||
traffics.extend([traffic_in, traffic_out])
|
||||
return traffics
|
||||
|
|
|
@ -31,22 +31,15 @@ backup_ha_state = Enum(
|
|||
],
|
||||
states=HA_STATES,
|
||||
)
|
||||
active_server_bytes_received = Gauge(
|
||||
"opnsense_active_server_bytes_received",
|
||||
"Active OPNSense server bytes received on WAN interface",
|
||||
[
|
||||
"instance",
|
||||
"host",
|
||||
"role",
|
||||
],
|
||||
)
|
||||
active_server_bytes_transmitted = Gauge(
|
||||
"opnsense_active_server_bytes_transmitted",
|
||||
"Active OPNSense server bytes transmitted on WAN interface",
|
||||
opnsense_active_server_traffic_rate = Gauge(
|
||||
"opnsense_active_server_traffic_rate",
|
||||
"Active OPNSense server bytes in/out per interface",
|
||||
[
|
||||
"instance",
|
||||
"host",
|
||||
"role",
|
||||
"interface",
|
||||
"metric",
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -56,11 +49,13 @@ class OPNSensePrometheusExporter:
|
|||
self,
|
||||
main: OPNSenseAPI,
|
||||
backup: OPNSenseAPI,
|
||||
interfaces,
|
||||
exporter_instance: str = "",
|
||||
check_frequency: int = 1,
|
||||
):
|
||||
self.main = main
|
||||
self.backup = backup
|
||||
self.interfaces = interfaces
|
||||
self.exporter_instance = exporter_instance
|
||||
self.check_frequency = check_frequency
|
||||
|
||||
|
@ -80,15 +75,13 @@ class OPNSensePrometheusExporter:
|
|||
if backup_sate == "active":
|
||||
active_opnsense = self.backup
|
||||
if active_opnsense:
|
||||
bytes_received, bytes_transmitted = active_opnsense.get_wan_trafic()
|
||||
if bytes_received or bytes_received == 0:
|
||||
active_server_bytes_received.labels(
|
||||
instance=self.exporter_instance, **active_opnsense.labels
|
||||
).set(bytes_received)
|
||||
if bytes_transmitted or bytes_transmitted == 0:
|
||||
active_server_bytes_transmitted.labels(
|
||||
instance=self.exporter_instance, **active_opnsense.labels
|
||||
).set(bytes_transmitted)
|
||||
for traffic in active_opnsense.get_traffic(self.interfaces):
|
||||
if traffic.value:
|
||||
opnsense_active_server_traffic_rate.labels(
|
||||
instance=self.exporter_instance,
|
||||
**active_opnsense.labels,
|
||||
**traffic.labels
|
||||
).set(traffic.value)
|
||||
|
||||
def start_server(self):
|
||||
# Start up the server to expose the metrics.
|
||||
|
@ -136,6 +129,14 @@ def run():
|
|||
default=os.environ.get("OPNSENSE_USERNAME", None),
|
||||
help="OPNsense user. Expect to be the same on MAIN and BACKUP servers",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--opnsense-interfaces",
|
||||
"-i",
|
||||
type=str,
|
||||
dest="interfaces",
|
||||
default=os.environ.get("OPNSENSE_INTERFACES", "wan,lan"),
|
||||
help="OPNsense interfaces (coma separated) list to export trafic rates (bytes/s)",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--opnsense-password",
|
||||
"-p",
|
||||
|
@ -164,6 +165,7 @@ def run():
|
|||
OPNSenseAPI(
|
||||
OPNSenseRole.BACKUP, arguments.backup, arguments.user, arguments.password
|
||||
),
|
||||
arguments.interfaces,
|
||||
check_frequency=arguments.frequency,
|
||||
exporter_instance=arguments.prom_instance,
|
||||
)
|
||||
|
|
404
tests/common.py
404
tests/common.py
|
@ -47,126 +47,131 @@ def generate_get_vip_status_paylaod(state_wan, state_lan, maintenance_mode):
|
|||
|
||||
|
||||
def generate_diagnostics_traffic_interface_paylaod():
|
||||
# wan - rate_bits_in: 101026
|
||||
# wan - rate_bits_out: 86020
|
||||
# lan - rate_bits_in: 188490
|
||||
# lan - rate_bits_out: 952
|
||||
|
||||
return json.dumps(
|
||||
{
|
||||
"wan": {
|
||||
"records": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 15300,
|
||||
"rate_bits_out": 1720,
|
||||
"rate_bits": 17020,
|
||||
"cumulative_bytes_in": 3830,
|
||||
"cumulative_bytes_out": 441,
|
||||
"cumulative_bytes": 4271,
|
||||
"rate_bits_in": 62300,
|
||||
"rate_bits_out": 66100,
|
||||
"rate_bits": 128400,
|
||||
"cumulative_bytes_in": 15600,
|
||||
"cumulative_bytes_out": 16500,
|
||||
"cumulative_bytes": 32100,
|
||||
"tags": [],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "15.3Kb",
|
||||
"rate_bits": 15300,
|
||||
"cumulative": "3.83KB",
|
||||
"cumulative_bytes": 3830,
|
||||
"rate": "62.3Kb",
|
||||
"rate_bits": 62300,
|
||||
"cumulative": "15.6KB",
|
||||
"cumulative_bytes": 15600,
|
||||
"tags": ["local"],
|
||||
}
|
||||
],
|
||||
"rname": "fake value",
|
||||
"rate_in": "15.3 kb",
|
||||
"rate_out": "1.72 kb",
|
||||
"rate": "17.02 kb",
|
||||
"cumulative_in": "3.83 kb",
|
||||
"cumulative_out": "441.0 b",
|
||||
"cumulative": "4.27 kb",
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "62.3 kb",
|
||||
"rate_out": "66.1 kb",
|
||||
"rate": "128.4 kb",
|
||||
"cumulative_in": "15.6 kb",
|
||||
"cumulative_out": "16.5 kb",
|
||||
"cumulative": "32.1 kb",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 4470,
|
||||
"rate_bits_out": 7290,
|
||||
"rate_bits": 11760,
|
||||
"cumulative_bytes_in": 1120,
|
||||
"cumulative_bytes_out": 1820,
|
||||
"cumulative_bytes": 2940,
|
||||
"rate_bits_in": 36200,
|
||||
"rate_bits_out": 16100,
|
||||
"rate_bits": 52300,
|
||||
"cumulative_bytes_in": 9060,
|
||||
"cumulative_bytes_out": 4020,
|
||||
"cumulative_bytes": 13080,
|
||||
"tags": [],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "4.47Kb",
|
||||
"rate_bits": 4470,
|
||||
"cumulative": "1.12KB",
|
||||
"cumulative_bytes": 1120,
|
||||
"rate": "36.2Kb",
|
||||
"rate_bits": 36200,
|
||||
"cumulative": "9.06KB",
|
||||
"cumulative_bytes": 9060,
|
||||
"tags": ["local"],
|
||||
}
|
||||
],
|
||||
"rname": "fake value",
|
||||
"rate_in": "4.47 kb",
|
||||
"rate_out": "7.29 kb",
|
||||
"rate": "11.76 kb",
|
||||
"cumulative_in": "1.12 kb",
|
||||
"cumulative_out": "1.82 kb",
|
||||
"cumulative": "2.94 kb",
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "36.2 kb",
|
||||
"rate_out": "16.1 kb",
|
||||
"rate": "52.3 kb",
|
||||
"cumulative_in": "9.06 kb",
|
||||
"cumulative_out": "4.02 kb",
|
||||
"cumulative": "13.08 kb",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 272,
|
||||
"rate_bits_out": 272,
|
||||
"rate_bits": 544,
|
||||
"cumulative_bytes_in": 68,
|
||||
"cumulative_bytes_out": 68,
|
||||
"cumulative_bytes": 136,
|
||||
"rate_bits_in": 1790,
|
||||
"rate_bits_out": 1520,
|
||||
"rate_bits": 3310,
|
||||
"cumulative_bytes_in": 459,
|
||||
"cumulative_bytes_out": 389,
|
||||
"cumulative_bytes": 848,
|
||||
"tags": [],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "272b",
|
||||
"rate_bits": 272,
|
||||
"cumulative": "68B",
|
||||
"cumulative_bytes": 68,
|
||||
"rate": "1.79Kb",
|
||||
"rate_bits": 1790,
|
||||
"cumulative": "459B",
|
||||
"cumulative_bytes": 459,
|
||||
"tags": ["local"],
|
||||
}
|
||||
],
|
||||
"rname": "fake value",
|
||||
"rate_in": "272.0 b",
|
||||
"rate_out": "272.0 b",
|
||||
"rate": "544.0 b",
|
||||
"cumulative_in": "68.0 b",
|
||||
"cumulative_out": "68.0 b",
|
||||
"cumulative": "136.0 b",
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "1.79 kb",
|
||||
"rate_out": "1.52 kb",
|
||||
"rate": "3.31 kb",
|
||||
"cumulative_in": "459.0 b",
|
||||
"cumulative_out": "389.0 b",
|
||||
"cumulative": "848.0 b",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 272,
|
||||
"rate_bits_out": 272,
|
||||
"rate_bits": 544,
|
||||
"cumulative_bytes_in": 68,
|
||||
"cumulative_bytes_out": 68,
|
||||
"cumulative_bytes": 136,
|
||||
"rate_bits_in": 512,
|
||||
"rate_bits_out": 1580,
|
||||
"rate_bits": 2092,
|
||||
"cumulative_bytes_in": 128,
|
||||
"cumulative_bytes_out": 405,
|
||||
"cumulative_bytes": 533,
|
||||
"tags": [],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "272b",
|
||||
"rate_bits": 272,
|
||||
"cumulative": "68B",
|
||||
"cumulative_bytes": 68,
|
||||
"rate": "512b",
|
||||
"rate_bits": 512,
|
||||
"cumulative": "128B",
|
||||
"cumulative_bytes": 128,
|
||||
"tags": ["local"],
|
||||
}
|
||||
],
|
||||
"rname": "fake value",
|
||||
"rate_in": "272.0 b",
|
||||
"rate_out": "272.0 b",
|
||||
"rate": "544.0 b",
|
||||
"cumulative_in": "68.0 b",
|
||||
"cumulative_out": "68.0 b",
|
||||
"cumulative": "136.0 b",
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "512.0 b",
|
||||
"rate_out": "1.58 kb",
|
||||
"rate": "2.09 kb",
|
||||
"cumulative_in": "128.0 b",
|
||||
"cumulative_out": "405.0 b",
|
||||
"cumulative": "533.0 b",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 0,
|
||||
"rate_bits_out": 480,
|
||||
"rate_bits": 480,
|
||||
"rate_bits_out": 448,
|
||||
"rate_bits": 448,
|
||||
"cumulative_bytes_in": 0,
|
||||
"cumulative_bytes_out": 120,
|
||||
"cumulative_bytes": 120,
|
||||
"cumulative_bytes_out": 112,
|
||||
"cumulative_bytes": 112,
|
||||
"tags": [],
|
||||
"details": [
|
||||
{
|
||||
|
@ -176,7 +181,26 @@ def generate_diagnostics_traffic_interface_paylaod():
|
|||
"cumulative": "0B",
|
||||
"cumulative_bytes": 0,
|
||||
"tags": ["local"],
|
||||
},
|
||||
}
|
||||
],
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "0.0 b",
|
||||
"rate_out": "448.0 b",
|
||||
"rate": "448.0 b",
|
||||
"cumulative_in": "0.0 b",
|
||||
"cumulative_out": "112.0 b",
|
||||
"cumulative": "112.0 b",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 0,
|
||||
"rate_bits_out": 272,
|
||||
"rate_bits": 272,
|
||||
"cumulative_bytes_in": 0,
|
||||
"cumulative_bytes_out": 68,
|
||||
"cumulative_bytes": 68,
|
||||
"tags": [],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "0b",
|
||||
|
@ -184,15 +208,15 @@ def generate_diagnostics_traffic_interface_paylaod():
|
|||
"cumulative": "0B",
|
||||
"cumulative_bytes": 0,
|
||||
"tags": ["local"],
|
||||
},
|
||||
}
|
||||
],
|
||||
"rname": "fake value",
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "0.0 b",
|
||||
"rate_out": "480.0 b",
|
||||
"rate": "480.0 b",
|
||||
"rate_out": "272.0 b",
|
||||
"rate": "272.0 b",
|
||||
"cumulative_in": "0.0 b",
|
||||
"cumulative_out": "120.0 b",
|
||||
"cumulative": "120.0 b",
|
||||
"cumulative_out": "68.0 b",
|
||||
"cumulative": "68.0 b",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
|
@ -213,7 +237,7 @@ def generate_diagnostics_traffic_interface_paylaod():
|
|||
"tags": ["local"],
|
||||
}
|
||||
],
|
||||
"rname": "fake value",
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "224.0 b",
|
||||
"rate_out": "0.0 b",
|
||||
"rate": "224.0 b",
|
||||
|
@ -223,6 +247,224 @@ def generate_diagnostics_traffic_interface_paylaod():
|
|||
},
|
||||
],
|
||||
"status": "ok",
|
||||
}
|
||||
},
|
||||
"lan": {
|
||||
"records": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 65200,
|
||||
"rate_bits_out": 0,
|
||||
"rate_bits": 65200,
|
||||
"cumulative_bytes_in": 16270,
|
||||
"cumulative_bytes_out": 0,
|
||||
"cumulative_bytes": 16270,
|
||||
"tags": [],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "45.3Kb",
|
||||
"rate_bits": 45300,
|
||||
"cumulative": "11.3KB",
|
||||
"cumulative_bytes": 11300,
|
||||
"tags": ["private"],
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "19.9Kb",
|
||||
"rate_bits": 19900,
|
||||
"cumulative": "4.97KB",
|
||||
"cumulative_bytes": 4970,
|
||||
"tags": ["private"],
|
||||
},
|
||||
],
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "65.2 kb",
|
||||
"rate_out": "0.0 b",
|
||||
"rate": "65.2 kb",
|
||||
"cumulative_in": "16.27 kb",
|
||||
"cumulative_out": "0.0 b",
|
||||
"cumulative": "16.27 kb",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 47900,
|
||||
"rate_bits_out": 0,
|
||||
"rate_bits": 47900,
|
||||
"cumulative_bytes_in": 12000,
|
||||
"cumulative_bytes_out": 0,
|
||||
"cumulative_bytes": 12000,
|
||||
"tags": ["private"],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "47.9Kb",
|
||||
"rate_bits": 47900,
|
||||
"cumulative": "12.0KB",
|
||||
"cumulative_bytes": 12000,
|
||||
"tags": [],
|
||||
}
|
||||
],
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "47.9 kb",
|
||||
"rate_out": "0.0 b",
|
||||
"rate": "47.9 kb",
|
||||
"cumulative_in": "12.0 kb",
|
||||
"cumulative_out": "0.0 b",
|
||||
"cumulative": "12.0 kb",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 36200,
|
||||
"rate_bits_out": 0,
|
||||
"rate_bits": 36200,
|
||||
"cumulative_bytes_in": 9060,
|
||||
"cumulative_bytes_out": 0,
|
||||
"cumulative_bytes": 9060,
|
||||
"tags": [],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "36.2Kb",
|
||||
"rate_bits": 36200,
|
||||
"cumulative": "9.06KB",
|
||||
"cumulative_bytes": 9060,
|
||||
"tags": ["private"],
|
||||
}
|
||||
],
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "36.2 kb",
|
||||
"rate_out": "0.0 b",
|
||||
"rate": "36.2 kb",
|
||||
"cumulative_in": "9.06 kb",
|
||||
"cumulative_out": "0.0 b",
|
||||
"cumulative": "9.06 kb",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 19200,
|
||||
"rate_bits_out": 0,
|
||||
"rate_bits": 19200,
|
||||
"cumulative_bytes_in": 4814,
|
||||
"cumulative_bytes_out": 0,
|
||||
"cumulative_bytes": 4814,
|
||||
"tags": ["private"],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "16.1Kb",
|
||||
"rate_bits": 16100,
|
||||
"cumulative": "4.02KB",
|
||||
"cumulative_bytes": 4020,
|
||||
"tags": [],
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "1.58Kb",
|
||||
"rate_bits": 1580,
|
||||
"cumulative": "405B",
|
||||
"cumulative_bytes": 405,
|
||||
"tags": [],
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "1.52Kb",
|
||||
"rate_bits": 1520,
|
||||
"cumulative": "389B",
|
||||
"cumulative_bytes": 389,
|
||||
"tags": [],
|
||||
},
|
||||
],
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "19.2 kb",
|
||||
"rate_out": "0.0 b",
|
||||
"rate": "19.2 kb",
|
||||
"cumulative_in": "4.81 kb",
|
||||
"cumulative_out": "0.0 b",
|
||||
"cumulative": "4.81 kb",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 18200,
|
||||
"rate_bits_out": 0,
|
||||
"rate_bits": 18200,
|
||||
"cumulative_bytes_in": 4550,
|
||||
"cumulative_bytes_out": 0,
|
||||
"cumulative_bytes": 4550,
|
||||
"tags": ["private"],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "18.2Kb",
|
||||
"rate_bits": 18200,
|
||||
"cumulative": "4.55KB",
|
||||
"cumulative_bytes": 4550,
|
||||
"tags": [],
|
||||
}
|
||||
],
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "18.2 kb",
|
||||
"rate_out": "0.0 b",
|
||||
"rate": "18.2 kb",
|
||||
"cumulative_in": "4.55 kb",
|
||||
"cumulative_out": "0.0 b",
|
||||
"cumulative": "4.55 kb",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 1790,
|
||||
"rate_bits_out": 0,
|
||||
"rate_bits": 1790,
|
||||
"cumulative_bytes_in": 459,
|
||||
"cumulative_bytes_out": 0,
|
||||
"cumulative_bytes": 459,
|
||||
"tags": [],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "1.79Kb",
|
||||
"rate_bits": 1790,
|
||||
"cumulative": "459B",
|
||||
"cumulative_bytes": 459,
|
||||
"tags": ["private"],
|
||||
}
|
||||
],
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "1.79 kb",
|
||||
"rate_out": "0.0 b",
|
||||
"rate": "1.79 kb",
|
||||
"cumulative_in": "459.0 b",
|
||||
"cumulative_out": "0.0 b",
|
||||
"cumulative": "459.0 b",
|
||||
},
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate_bits_in": 0,
|
||||
"rate_bits_out": 952,
|
||||
"rate_bits": 952,
|
||||
"cumulative_bytes_in": 0,
|
||||
"cumulative_bytes_out": 238,
|
||||
"cumulative_bytes": 238,
|
||||
"tags": ["private"],
|
||||
"details": [
|
||||
{
|
||||
"address": "0.1.2.3",
|
||||
"rate": "0b",
|
||||
"rate_bits": 0,
|
||||
"cumulative": "0B",
|
||||
"cumulative_bytes": 0,
|
||||
"tags": ["private"],
|
||||
}
|
||||
],
|
||||
"rname": "fake rname value",
|
||||
"rate_in": "0.0 b",
|
||||
"rate_out": "952.0 b",
|
||||
"rate": "952.0 b",
|
||||
"cumulative_in": "0.0 b",
|
||||
"cumulative_out": "238.0 b",
|
||||
"cumulative": "238.0 b",
|
||||
},
|
||||
],
|
||||
"status": "ok",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import responses
|
||||
|
||||
from opnsense_exporter.opnsense_api import OPNSenseAPI, OPNSenseRole
|
||||
from opnsense_exporter.opnsense_api import (
|
||||
OPNSenseAPI,
|
||||
OPNSenseRole,
|
||||
OPNSenseTraffic,
|
||||
OPNSenseTrafficMetric,
|
||||
)
|
||||
|
||||
from .common import (
|
||||
BACKUP_HOST,
|
||||
|
@ -92,33 +97,35 @@ def test_get_interface_vip_status_unavailable_rest_api_error():
|
|||
|
||||
|
||||
@responses.activate
|
||||
def test_get_wan_traffic():
|
||||
def test_get_traffic():
|
||||
responses.add(
|
||||
responses.GET,
|
||||
f"https://{MAIN_HOST}/api/diagnostics/traffic/top/wan",
|
||||
f"https://{MAIN_HOST}/api/diagnostics/traffic/top/wan,lan",
|
||||
body=generate_diagnostics_traffic_interface_paylaod(),
|
||||
)
|
||||
assert OPNSenseAPI(
|
||||
OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD
|
||||
).get_wan_trafic() == (
|
||||
20538,
|
||||
10034,
|
||||
)
|
||||
assert OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD).get_traffic(
|
||||
"wan,lan"
|
||||
) == [
|
||||
OPNSenseTraffic("wan", OPNSenseTrafficMetric.IN, value=101026),
|
||||
OPNSenseTraffic("wan", OPNSenseTrafficMetric.OUT, value=86020),
|
||||
OPNSenseTraffic("lan", OPNSenseTrafficMetric.IN, value=188490),
|
||||
OPNSenseTraffic("lan", OPNSenseTrafficMetric.OUT, value=952),
|
||||
]
|
||||
|
||||
|
||||
@responses.activate
|
||||
def test_get_wan_traffic_none():
|
||||
def test_get_traffic_none():
|
||||
responses.add(
|
||||
responses.GET,
|
||||
f"https://{MAIN_HOST}/api/diagnostics/traffic/top/wan",
|
||||
f"https://{MAIN_HOST}/api/diagnostics/traffic/top/test-not-found",
|
||||
json={"error": "not found"},
|
||||
status=404,
|
||||
)
|
||||
assert OPNSenseAPI(
|
||||
OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD
|
||||
).get_wan_trafic() == (
|
||||
None,
|
||||
None,
|
||||
assert (
|
||||
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD).get_traffic(
|
||||
"test-not-found"
|
||||
)
|
||||
== []
|
||||
)
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
from typing import List
|
||||
from unittest import mock
|
||||
|
||||
import responses
|
||||
|
@ -17,28 +18,54 @@ from .common import (
|
|||
|
||||
class FakePromMetric:
|
||||
_labels = {}
|
||||
_labels_calls = None
|
||||
|
||||
def __init__(self):
|
||||
self._labels = {}
|
||||
self._labels_calls = []
|
||||
|
||||
@property
|
||||
def count_labels_calls(self) -> int:
|
||||
return len(self._labels_calls)
|
||||
|
||||
def labels(self, *args, **kwargs):
|
||||
self._labels = kwargs
|
||||
self._labels_calls.append(kwargs)
|
||||
return self
|
||||
|
||||
|
||||
class FakePromEnum(FakePromMetric):
|
||||
_state = None
|
||||
count_state_calls = 0
|
||||
_state: str = None
|
||||
_state_calls: List[str] = []
|
||||
|
||||
def state(self, state):
|
||||
self.count_state_calls += 1
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._state_calls = []
|
||||
|
||||
@property
|
||||
def count_state_calls(self) -> int:
|
||||
return len(self._state_calls)
|
||||
|
||||
def state(self, state: str):
|
||||
self._state = state
|
||||
self._state_calls.append(state)
|
||||
|
||||
|
||||
class FakePromGauge(FakePromMetric):
|
||||
value = None
|
||||
count_set_calls = 0
|
||||
_value: int = None
|
||||
_set_calls: List[int] = []
|
||||
|
||||
def set(self, value):
|
||||
self.count_set_calls += 1
|
||||
self.value = value
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._set_calls = []
|
||||
|
||||
@property
|
||||
def count_set_calls(self) -> int:
|
||||
return len(self._set_calls)
|
||||
|
||||
def set(self, value: int):
|
||||
self._value = value
|
||||
self._set_calls.append(value)
|
||||
|
||||
|
||||
@mock.patch("opnsense_exporter.server.OPNSensePrometheusExporter.start_server")
|
||||
|
@ -57,6 +84,8 @@ def test_parser(server_mock):
|
|||
"user-test",
|
||||
"-p",
|
||||
"pwd-test",
|
||||
"-i",
|
||||
"efg,hij",
|
||||
"--prometheus-instance",
|
||||
"server-hostname-instance",
|
||||
],
|
||||
|
@ -73,6 +102,7 @@ def test_parser(server_mock):
|
|||
assert server.backup.login == "user-test"
|
||||
assert server.backup.password == "pwd-test"
|
||||
assert server.check_frequency == 15
|
||||
assert server.interfaces == "efg,hij"
|
||||
|
||||
|
||||
@responses.activate
|
||||
|
@ -95,28 +125,24 @@ def test_process_requests():
|
|||
|
||||
main_ha_state_mock = FakePromEnum()
|
||||
backup_ha_state_mock = FakePromEnum()
|
||||
active_server_bytes_received_mock = FakePromGauge()
|
||||
active_server_bytes_transmitted_mock = FakePromGauge()
|
||||
opnsense_active_server_traffic_rate_mock = FakePromGauge()
|
||||
|
||||
with mock.patch("opnsense_exporter.server.main_ha_state", new=main_ha_state_mock):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.backup_ha_state", new=backup_ha_state_mock
|
||||
):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.active_server_bytes_received",
|
||||
new=active_server_bytes_received_mock,
|
||||
"opnsense_exporter.server.opnsense_active_server_traffic_rate",
|
||||
new=opnsense_active_server_traffic_rate_mock,
|
||||
):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.active_server_bytes_transmitted",
|
||||
new=active_server_bytes_transmitted_mock,
|
||||
):
|
||||
OPNSensePrometheusExporter(
|
||||
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
||||
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
||||
).process_requests()
|
||||
OPNSensePrometheusExporter(
|
||||
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
||||
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
||||
"wan",
|
||||
).process_requests()
|
||||
|
||||
assert main_ha_state_mock._state == "active"
|
||||
assert main_ha_state_mock.count_state_calls == 1
|
||||
assert main_ha_state_mock.count_state_calls == 1, main_ha_state_mock._state_calls
|
||||
assert main_ha_state_mock._labels == {
|
||||
"instance": "",
|
||||
"host": MAIN_HOST,
|
||||
|
@ -131,21 +157,24 @@ def test_process_requests():
|
|||
"role": "backup",
|
||||
}
|
||||
|
||||
assert active_server_bytes_received_mock.value == 20538
|
||||
assert active_server_bytes_received_mock.count_set_calls == 1
|
||||
assert active_server_bytes_received_mock._labels == {
|
||||
"instance": "",
|
||||
"host": MAIN_HOST,
|
||||
"role": "main",
|
||||
}
|
||||
|
||||
assert active_server_bytes_transmitted_mock.value == 10034
|
||||
assert active_server_bytes_transmitted_mock.count_set_calls == 1
|
||||
assert active_server_bytes_transmitted_mock._labels == {
|
||||
"instance": "",
|
||||
"host": MAIN_HOST,
|
||||
"role": "main",
|
||||
}
|
||||
assert opnsense_active_server_traffic_rate_mock.count_set_calls == 2
|
||||
assert opnsense_active_server_traffic_rate_mock._labels_calls == [
|
||||
{
|
||||
"instance": "",
|
||||
"host": MAIN_HOST,
|
||||
"role": "main",
|
||||
"interface": "wan",
|
||||
"metric": "rate_bits_in",
|
||||
},
|
||||
{
|
||||
"instance": "",
|
||||
"host": MAIN_HOST,
|
||||
"role": "main",
|
||||
"interface": "wan",
|
||||
"metric": "rate_bits_out",
|
||||
},
|
||||
]
|
||||
assert opnsense_active_server_traffic_rate_mock._set_calls == [101026, 86020]
|
||||
|
||||
|
||||
@responses.activate
|
||||
|
@ -168,25 +197,21 @@ def test_process_requests_backup_active():
|
|||
|
||||
main_ha_state_mock = FakePromEnum()
|
||||
backup_ha_state_mock = FakePromEnum()
|
||||
active_server_bytes_received_mock = FakePromGauge()
|
||||
active_server_bytes_transmitted_mock = FakePromGauge()
|
||||
opnsense_active_server_traffic_rate_mock = FakePromGauge()
|
||||
|
||||
with mock.patch("opnsense_exporter.server.main_ha_state", new=main_ha_state_mock):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.backup_ha_state", new=backup_ha_state_mock
|
||||
):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.active_server_bytes_received",
|
||||
new=active_server_bytes_received_mock,
|
||||
"opnsense_exporter.server.opnsense_active_server_traffic_rate",
|
||||
new=opnsense_active_server_traffic_rate_mock,
|
||||
):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.active_server_bytes_transmitted",
|
||||
new=active_server_bytes_transmitted_mock,
|
||||
):
|
||||
OPNSensePrometheusExporter(
|
||||
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
||||
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
||||
).process_requests()
|
||||
OPNSensePrometheusExporter(
|
||||
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
||||
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
||||
"wan",
|
||||
).process_requests()
|
||||
assert main_ha_state_mock._state == "maintenancemode"
|
||||
assert main_ha_state_mock.count_state_calls == 1
|
||||
assert main_ha_state_mock._labels == {
|
||||
|
@ -203,21 +228,24 @@ def test_process_requests_backup_active():
|
|||
"role": "backup",
|
||||
}
|
||||
|
||||
assert active_server_bytes_received_mock.value == 20538
|
||||
assert active_server_bytes_received_mock.count_set_calls == 1
|
||||
assert active_server_bytes_received_mock._labels == {
|
||||
"instance": "",
|
||||
"host": BACKUP_HOST,
|
||||
"role": "backup",
|
||||
}
|
||||
|
||||
assert active_server_bytes_transmitted_mock.value == 10034
|
||||
assert active_server_bytes_transmitted_mock.count_set_calls == 1
|
||||
assert active_server_bytes_transmitted_mock._labels == {
|
||||
"instance": "",
|
||||
"host": BACKUP_HOST,
|
||||
"role": "backup",
|
||||
}
|
||||
assert opnsense_active_server_traffic_rate_mock.count_set_calls == 2
|
||||
opnsense_active_server_traffic_rate_mock._labels_calls == [
|
||||
{
|
||||
"instance": "",
|
||||
"host": BACKUP_HOST,
|
||||
"role": "backup",
|
||||
"interface": "wan",
|
||||
"metric": "rate_bits_in",
|
||||
},
|
||||
{
|
||||
"instance": "",
|
||||
"host": BACKUP_HOST,
|
||||
"role": "backup",
|
||||
"interface": "wan",
|
||||
"metric": "rate_bits_out",
|
||||
},
|
||||
]
|
||||
assert opnsense_active_server_traffic_rate_mock._set_calls == [101026, 86020]
|
||||
|
||||
|
||||
@responses.activate
|
||||
|
@ -241,25 +269,21 @@ def test_process_no_active():
|
|||
|
||||
main_ha_state_mock = FakePromEnum()
|
||||
backup_ha_state_mock = FakePromEnum()
|
||||
active_server_bytes_received_mock = FakePromGauge()
|
||||
active_server_bytes_transmitted_mock = FakePromGauge()
|
||||
opnsense_active_server_traffic_rate_mock = FakePromGauge()
|
||||
|
||||
with mock.patch("opnsense_exporter.server.main_ha_state", new=main_ha_state_mock):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.backup_ha_state", new=backup_ha_state_mock
|
||||
):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.active_server_bytes_received",
|
||||
new=active_server_bytes_received_mock,
|
||||
"opnsense_exporter.server.opnsense_active_server_traffic_rate",
|
||||
new=opnsense_active_server_traffic_rate_mock,
|
||||
):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.active_server_bytes_transmitted",
|
||||
new=active_server_bytes_transmitted_mock,
|
||||
):
|
||||
OPNSensePrometheusExporter(
|
||||
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
||||
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
||||
).process_requests()
|
||||
OPNSensePrometheusExporter(
|
||||
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
||||
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
||||
"wan",
|
||||
).process_requests()
|
||||
|
||||
assert main_ha_state_mock._state == "maintenancemode"
|
||||
assert main_ha_state_mock.count_state_calls == 1
|
||||
|
@ -277,8 +301,7 @@ def test_process_no_active():
|
|||
"role": "backup",
|
||||
}
|
||||
|
||||
assert active_server_bytes_received_mock.count_set_calls == 0
|
||||
assert active_server_bytes_transmitted_mock.count_set_calls == 0
|
||||
assert opnsense_active_server_traffic_rate_mock.count_set_calls == 0
|
||||
|
||||
|
||||
@responses.activate
|
||||
|
@ -302,25 +325,21 @@ def test_process_with_falsy_value():
|
|||
|
||||
main_ha_state_mock = FakePromEnum()
|
||||
backup_ha_state_mock = FakePromEnum()
|
||||
active_server_bytes_received_mock = FakePromGauge()
|
||||
active_server_bytes_transmitted_mock = FakePromGauge()
|
||||
opnsense_active_server_traffic_rate_mock = FakePromGauge()
|
||||
|
||||
with mock.patch("opnsense_exporter.server.main_ha_state", new=main_ha_state_mock):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.backup_ha_state", new=backup_ha_state_mock
|
||||
):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.active_server_bytes_received",
|
||||
new=active_server_bytes_received_mock,
|
||||
"opnsense_exporter.server.opnsense_active_server_traffic_rate",
|
||||
new=opnsense_active_server_traffic_rate_mock,
|
||||
):
|
||||
with mock.patch(
|
||||
"opnsense_exporter.server.active_server_bytes_transmitted",
|
||||
new=active_server_bytes_transmitted_mock,
|
||||
):
|
||||
OPNSensePrometheusExporter(
|
||||
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
||||
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
||||
).process_requests()
|
||||
OPNSensePrometheusExporter(
|
||||
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
||||
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
||||
"wan",
|
||||
).process_requests()
|
||||
assert main_ha_state_mock._state == "active"
|
||||
assert main_ha_state_mock.count_state_calls == 1
|
||||
assert main_ha_state_mock._labels == {
|
||||
|
@ -337,5 +356,4 @@ def test_process_with_falsy_value():
|
|||
"role": "backup",
|
||||
}
|
||||
|
||||
assert active_server_bytes_received_mock.count_set_calls == 0
|
||||
assert active_server_bytes_transmitted_mock.count_set_calls == 0
|
||||
assert opnsense_active_server_traffic_rate_mock.count_set_calls == 0
|
||||
|
|
Loading…
Reference in a new issue