2023-09-03 23:38:34 +02:00
|
|
|
from typing import List
|
2023-09-01 13:27:55 +02:00
|
|
|
from unittest import mock
|
|
|
|
|
|
|
|
import responses
|
|
|
|
|
2023-09-03 21:52:19 +02:00
|
|
|
from opnsense_exporter.opnsense_api import OPNSenseAPI, OPNSenseRole
|
2023-09-03 22:08:24 +02:00
|
|
|
from opnsense_exporter.server import OPNSensePrometheusExporter, run
|
2023-09-01 13:27:55 +02:00
|
|
|
|
|
|
|
from .common import (
|
|
|
|
BACKUP_HOST,
|
|
|
|
LOGIN,
|
|
|
|
MAIN_HOST,
|
|
|
|
PASSWORD,
|
|
|
|
generate_diagnostics_traffic_interface_paylaod,
|
|
|
|
generate_get_vip_status_paylaod,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2023-09-01 18:18:09 +02:00
|
|
|
class FakePromMetric:
|
|
|
|
_labels = {}
|
2023-09-03 23:38:34 +02:00
|
|
|
_labels_calls = None
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
self._labels = {}
|
|
|
|
self._labels_calls = []
|
|
|
|
|
|
|
|
@property
|
|
|
|
def count_labels_calls(self) -> int:
|
|
|
|
return len(self._labels_calls)
|
2023-09-01 18:18:09 +02:00
|
|
|
|
|
|
|
def labels(self, *args, **kwargs):
|
|
|
|
self._labels = kwargs
|
2023-09-03 23:38:34 +02:00
|
|
|
self._labels_calls.append(kwargs)
|
2023-09-01 18:18:09 +02:00
|
|
|
return self
|
|
|
|
|
|
|
|
|
|
|
|
class FakePromEnum(FakePromMetric):
|
2023-09-03 23:38:34 +02:00
|
|
|
_state: str = None
|
|
|
|
_state_calls: List[str] = []
|
|
|
|
|
|
|
|
def __init__(self):
|
|
|
|
super().__init__()
|
|
|
|
self._state_calls = []
|
|
|
|
|
|
|
|
@property
|
|
|
|
def count_state_calls(self) -> int:
|
|
|
|
return len(self._state_calls)
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-03 23:38:34 +02:00
|
|
|
def state(self, state: str):
|
2023-09-01 18:18:09 +02:00
|
|
|
self._state = state
|
2023-09-03 23:38:34 +02:00
|
|
|
self._state_calls.append(state)
|
2023-09-01 18:18:09 +02:00
|
|
|
|
|
|
|
|
|
|
|
class FakePromGauge(FakePromMetric):
|
2023-09-03 23:38:34 +02:00
|
|
|
_value: int = None
|
|
|
|
_set_calls: List[int] = []
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-03 23:38:34 +02:00
|
|
|
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)
|
2023-09-01 18:18:09 +02:00
|
|
|
|
|
|
|
|
2023-09-03 22:08:24 +02:00
|
|
|
@mock.patch("opnsense_exporter.server.OPNSensePrometheusExporter.start_server")
|
2023-09-01 13:27:55 +02:00
|
|
|
def test_parser(server_mock):
|
|
|
|
with mock.patch(
|
|
|
|
"sys.argv",
|
|
|
|
[
|
|
|
|
"opnsense-exporter",
|
|
|
|
"-c",
|
|
|
|
"15",
|
|
|
|
"-m",
|
|
|
|
"main.host",
|
|
|
|
"-b",
|
|
|
|
"backup.host",
|
|
|
|
"-u",
|
|
|
|
"user-test",
|
|
|
|
"-p",
|
|
|
|
"pwd-test",
|
2023-09-06 10:39:54 +02:00
|
|
|
"--opnsense-timeout-sec-get-vip-status",
|
|
|
|
"7",
|
|
|
|
"--opnsense-timeout-sec-get-traffic",
|
|
|
|
"9",
|
2023-09-03 23:38:34 +02:00
|
|
|
"-i",
|
|
|
|
"efg,hij",
|
2023-09-01 13:27:55 +02:00
|
|
|
"--prometheus-instance",
|
|
|
|
"server-hostname-instance",
|
|
|
|
],
|
|
|
|
):
|
2023-09-03 22:08:24 +02:00
|
|
|
server = run()
|
2023-09-01 13:27:55 +02:00
|
|
|
server_mock.assert_called_once()
|
2023-09-03 22:08:24 +02:00
|
|
|
|
|
|
|
assert server.main.role == OPNSenseRole.MAIN
|
|
|
|
assert server.main.host == "main.host"
|
|
|
|
assert server.main.login == "user-test"
|
|
|
|
assert server.main.password == "pwd-test"
|
2023-09-06 10:39:54 +02:00
|
|
|
assert server.main.get_vip_status_timeout_sec == 7
|
|
|
|
assert server.main.get_traffic_timeout_sec == 9
|
2023-09-03 22:08:24 +02:00
|
|
|
assert server.backup.role == OPNSenseRole.BACKUP
|
|
|
|
assert server.backup.host == "backup.host"
|
|
|
|
assert server.backup.login == "user-test"
|
|
|
|
assert server.backup.password == "pwd-test"
|
2023-09-06 10:39:54 +02:00
|
|
|
assert server.backup.get_vip_status_timeout_sec == 7
|
|
|
|
assert server.backup.get_traffic_timeout_sec == 9
|
2023-09-03 22:08:24 +02:00
|
|
|
assert server.check_frequency == 15
|
2023-09-03 23:38:34 +02:00
|
|
|
assert server.interfaces == "efg,hij"
|
2023-09-01 13:27:55 +02:00
|
|
|
|
|
|
|
|
|
|
|
@responses.activate
|
|
|
|
def test_process_requests():
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
|
|
|
f"https://{MAIN_HOST}/api/diagnostics/interface/get_vip_status/",
|
|
|
|
body=generate_get_vip_status_paylaod("MASTER", "MASTER", False),
|
|
|
|
)
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
|
|
|
f"https://{BACKUP_HOST}/api/diagnostics/interface/get_vip_status/",
|
|
|
|
body=generate_get_vip_status_paylaod("BACKUP", "BACKUP", False),
|
|
|
|
)
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
2023-09-02 02:16:27 +02:00
|
|
|
f"https://{MAIN_HOST}/api/diagnostics/traffic/top/wan",
|
2023-09-01 13:27:55 +02:00
|
|
|
body=generate_diagnostics_traffic_interface_paylaod(),
|
|
|
|
)
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-04 00:21:56 +02:00
|
|
|
opnsense_server_ha_state_mock = FakePromEnum()
|
2023-09-03 23:38:34 +02:00
|
|
|
opnsense_active_server_traffic_rate_mock = FakePromGauge()
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-04 00:32:02 +02:00
|
|
|
with mock.patch(
|
|
|
|
"opnsense_exporter.server.opnsense_server_ha_state",
|
|
|
|
new=opnsense_server_ha_state_mock,
|
|
|
|
):
|
2023-09-01 13:27:55 +02:00
|
|
|
with mock.patch(
|
2023-09-04 00:32:02 +02:00
|
|
|
"opnsense_exporter.server.opnsense_active_server_traffic_rate",
|
|
|
|
new=opnsense_active_server_traffic_rate_mock,
|
2023-09-01 18:18:09 +02:00
|
|
|
):
|
2023-09-04 00:32:02 +02:00
|
|
|
OPNSensePrometheusExporter(
|
|
|
|
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
|
|
|
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
|
|
|
"wan",
|
|
|
|
).process_requests()
|
2023-09-04 00:21:56 +02:00
|
|
|
|
|
|
|
assert opnsense_server_ha_state_mock.count_state_calls == 2
|
|
|
|
assert opnsense_server_ha_state_mock._labels_calls == [
|
|
|
|
{
|
|
|
|
"instance": "",
|
|
|
|
"host": MAIN_HOST,
|
|
|
|
"role": "main",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"instance": "",
|
|
|
|
"host": BACKUP_HOST,
|
|
|
|
"role": "backup",
|
|
|
|
},
|
|
|
|
]
|
|
|
|
assert opnsense_server_ha_state_mock._state_calls == ["active", "hot_standby"]
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-03 23:38:34 +02:00
|
|
|
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]
|
2023-09-01 13:27:55 +02:00
|
|
|
|
|
|
|
|
|
|
|
@responses.activate
|
2023-09-01 18:18:09 +02:00
|
|
|
def test_process_requests_backup_active():
|
2023-09-01 13:27:55 +02:00
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
|
|
|
f"https://{MAIN_HOST}/api/diagnostics/interface/get_vip_status/",
|
|
|
|
body=generate_get_vip_status_paylaod("MASTER", "MASTER", True),
|
|
|
|
)
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
|
|
|
f"https://{BACKUP_HOST}/api/diagnostics/interface/get_vip_status/",
|
|
|
|
body=generate_get_vip_status_paylaod("MASTER", "MASTER", False),
|
|
|
|
)
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
2023-09-02 02:16:27 +02:00
|
|
|
f"https://{BACKUP_HOST}/api/diagnostics/traffic/top/wan",
|
2023-09-01 13:27:55 +02:00
|
|
|
body=generate_diagnostics_traffic_interface_paylaod(),
|
|
|
|
)
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-04 00:21:56 +02:00
|
|
|
opnsense_server_ha_state_mock = FakePromEnum()
|
2023-09-03 23:38:34 +02:00
|
|
|
opnsense_active_server_traffic_rate_mock = FakePromGauge()
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-04 00:32:02 +02:00
|
|
|
with mock.patch(
|
|
|
|
"opnsense_exporter.server.opnsense_server_ha_state",
|
|
|
|
new=opnsense_server_ha_state_mock,
|
|
|
|
):
|
2023-09-01 13:27:55 +02:00
|
|
|
with mock.patch(
|
2023-09-04 00:32:02 +02:00
|
|
|
"opnsense_exporter.server.opnsense_active_server_traffic_rate",
|
|
|
|
new=opnsense_active_server_traffic_rate_mock,
|
2023-09-01 18:18:09 +02:00
|
|
|
):
|
2023-09-04 00:32:02 +02:00
|
|
|
OPNSensePrometheusExporter(
|
|
|
|
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
|
|
|
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
|
|
|
"wan",
|
|
|
|
).process_requests()
|
2023-09-04 00:21:56 +02:00
|
|
|
|
|
|
|
assert opnsense_server_ha_state_mock.count_state_calls == 2
|
|
|
|
assert opnsense_server_ha_state_mock._labels_calls == [
|
|
|
|
{
|
|
|
|
"instance": "",
|
|
|
|
"host": MAIN_HOST,
|
|
|
|
"role": "main",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"instance": "",
|
|
|
|
"host": BACKUP_HOST,
|
|
|
|
"role": "backup",
|
|
|
|
},
|
|
|
|
]
|
|
|
|
assert opnsense_server_ha_state_mock._state_calls == ["maintenancemode", "active"]
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-03 23:38:34 +02:00
|
|
|
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]
|
2023-09-01 13:27:55 +02:00
|
|
|
|
|
|
|
|
|
|
|
@responses.activate
|
|
|
|
def test_process_no_active():
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
|
|
|
f"https://{MAIN_HOST}/api/diagnostics/interface/get_vip_status/",
|
|
|
|
body=generate_get_vip_status_paylaod("MASTER", "MASTER", True),
|
|
|
|
)
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
|
|
|
f"https://{BACKUP_HOST}/api/diagnostics/interface/get_vip_status/",
|
|
|
|
body=generate_get_vip_status_paylaod("MASTER", "MASTER", True),
|
|
|
|
status=404,
|
|
|
|
)
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
2023-09-02 02:16:27 +02:00
|
|
|
f"https://{BACKUP_HOST}/api/diagnostics/traffic/top/wan",
|
2023-09-01 13:27:55 +02:00
|
|
|
body=generate_diagnostics_traffic_interface_paylaod(),
|
|
|
|
)
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-04 00:21:56 +02:00
|
|
|
opnsense_server_ha_state_mock = FakePromEnum()
|
2023-09-03 23:38:34 +02:00
|
|
|
opnsense_active_server_traffic_rate_mock = FakePromGauge()
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-04 00:32:02 +02:00
|
|
|
with mock.patch(
|
|
|
|
"opnsense_exporter.server.opnsense_server_ha_state",
|
|
|
|
new=opnsense_server_ha_state_mock,
|
|
|
|
):
|
2023-09-01 13:27:55 +02:00
|
|
|
with mock.patch(
|
2023-09-04 00:32:02 +02:00
|
|
|
"opnsense_exporter.server.opnsense_active_server_traffic_rate",
|
|
|
|
new=opnsense_active_server_traffic_rate_mock,
|
2023-09-01 18:18:09 +02:00
|
|
|
):
|
2023-09-04 00:32:02 +02:00
|
|
|
OPNSensePrometheusExporter(
|
|
|
|
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
|
|
|
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
|
|
|
"wan",
|
|
|
|
).process_requests()
|
2023-09-04 00:21:56 +02:00
|
|
|
|
|
|
|
assert opnsense_server_ha_state_mock.count_state_calls == 2
|
|
|
|
assert opnsense_server_ha_state_mock._labels_calls == [
|
|
|
|
{
|
|
|
|
"instance": "",
|
|
|
|
"host": MAIN_HOST,
|
|
|
|
"role": "main",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"instance": "",
|
|
|
|
"host": BACKUP_HOST,
|
|
|
|
"role": "backup",
|
|
|
|
},
|
|
|
|
]
|
|
|
|
assert opnsense_server_ha_state_mock._state_calls == [
|
|
|
|
"maintenancemode",
|
|
|
|
"unavailable",
|
|
|
|
]
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-03 23:38:34 +02:00
|
|
|
assert opnsense_active_server_traffic_rate_mock.count_set_calls == 0
|
2023-09-01 16:23:20 +02:00
|
|
|
|
|
|
|
|
|
|
|
@responses.activate
|
|
|
|
def test_process_with_falsy_value():
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
|
|
|
f"https://{MAIN_HOST}/api/diagnostics/interface/get_vip_status/",
|
|
|
|
body=generate_get_vip_status_paylaod("MASTER", "MASTER", False),
|
|
|
|
)
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
|
|
|
f"https://{BACKUP_HOST}/api/diagnostics/interface/get_vip_status/",
|
|
|
|
body=generate_get_vip_status_paylaod("BACKUP", "BACKUP", False),
|
|
|
|
)
|
|
|
|
responses.add(
|
|
|
|
responses.GET,
|
2023-09-02 02:16:27 +02:00
|
|
|
f"https://{BACKUP_HOST}/api/diagnostics/traffic/top/wan",
|
2023-09-01 16:23:20 +02:00
|
|
|
body=generate_diagnostics_traffic_interface_paylaod(),
|
|
|
|
status=404,
|
|
|
|
)
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-04 00:21:56 +02:00
|
|
|
opnsense_server_ha_state_mock = FakePromEnum()
|
2023-09-03 23:38:34 +02:00
|
|
|
opnsense_active_server_traffic_rate_mock = FakePromGauge()
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-04 00:32:02 +02:00
|
|
|
with mock.patch(
|
|
|
|
"opnsense_exporter.server.opnsense_server_ha_state",
|
|
|
|
new=opnsense_server_ha_state_mock,
|
|
|
|
):
|
2023-09-01 16:23:20 +02:00
|
|
|
with mock.patch(
|
2023-09-04 00:32:02 +02:00
|
|
|
"opnsense_exporter.server.opnsense_active_server_traffic_rate",
|
|
|
|
new=opnsense_active_server_traffic_rate_mock,
|
2023-09-01 18:18:09 +02:00
|
|
|
):
|
2023-09-04 00:32:02 +02:00
|
|
|
OPNSensePrometheusExporter(
|
|
|
|
OPNSenseAPI(OPNSenseRole.MAIN, MAIN_HOST, LOGIN, PASSWORD),
|
|
|
|
OPNSenseAPI(OPNSenseRole.BACKUP, BACKUP_HOST, LOGIN, PASSWORD),
|
|
|
|
"wan",
|
|
|
|
).process_requests()
|
2023-09-04 00:21:56 +02:00
|
|
|
|
|
|
|
assert opnsense_server_ha_state_mock.count_state_calls == 2
|
|
|
|
assert opnsense_server_ha_state_mock._labels_calls == [
|
|
|
|
{
|
|
|
|
"instance": "",
|
|
|
|
"host": MAIN_HOST,
|
|
|
|
"role": "main",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
"instance": "",
|
|
|
|
"host": BACKUP_HOST,
|
|
|
|
"role": "backup",
|
|
|
|
},
|
|
|
|
]
|
|
|
|
assert opnsense_server_ha_state_mock._state_calls == ["active", "hot_standby"]
|
2023-09-01 18:18:09 +02:00
|
|
|
|
2023-09-03 23:38:34 +02:00
|
|
|
assert opnsense_active_server_traffic_rate_mock.count_set_calls == 0
|