allow to configure OPNSense REST API calls timeout per REST API endpoint

two new paramters available    and
   parameters.
This commit is contained in:
Pierre Verkest 2023-09-06 10:39:54 +02:00
parent f26f0f59ff
commit d04356379e
5 changed files with 108 additions and 9 deletions

View file

@ -80,6 +80,16 @@ optional arguments:
means not calling the traffic diagnostic REST API means not calling the traffic diagnostic REST API
so no `opnsense_active_server_traffic_rate` so no `opnsense_active_server_traffic_rate`
metric. (default: wan,lan) metric. (default: wan,lan)
--opnsense-timeout-sec-get-vip-status GET_VIP_STATUS_TIMEOUT_SEC
Allow to configure timeout while requesting
OPNSense REST API
/api/diagnostics/interface/get_vip_status/
(default: 5)
--opnsense-timeout-sec-get-traffic GET_TRAFFIC_TIMEOUT_SEC
Allow to configure timeout while requesting
OPNSense REST API
/api/diagnostics/traffic/top/[INTERFACES]
(default: 15)
--opnsense-password PASSWORD, -p PASSWORD --opnsense-password PASSWORD, -p PASSWORD
OPNsense password. Expect to be the same on MAIN OPNsense password. Expect to be the same on MAIN
and BACKUP servers and BACKUP servers
@ -98,16 +108,23 @@ You can setup env through `.env` file or environment variables with defined as d
- **OPNSENSE_USERNAME**: default value for `--opnsense-user` param - **OPNSENSE_USERNAME**: default value for `--opnsense-user` param
- **OPNSENSE_PASSWORD**: default value for `--opnsense-password` param - **OPNSENSE_PASSWORD**: default value for `--opnsense-password` param
- **OPNSENSE_INTERFACES**: default value for `--opnsense-interfaces` param - **OPNSENSE_INTERFACES**: default value for `--opnsense-interfaces` param
- **OPNSENSE_TIMEOUT_SEC_GET_VIP_STATUS**: default value for `--opnsense-timeout-sec-get-vip-status` param
- **OPNSENSE_TIMEOUT_SEC_GET_TRAFFIC**: default value for `--opnsense-timeout-sec-get-traffic` param
## Roadmap ## Roadmap
- allow to change the listening port (today it force using `8000`) - allow to change the listening port (today it force using `8000`)
- allow to configure timeouts using environment variables
- improves logging to get a debug mode to understand errors based on unexpected payloads - improves logging to get a debug mode to understand errors based on unexpected payloads
## Changelog ## Changelog
### Version 1.0.0 (UNRELEASED) ### Version 1.1.0 (2023-09-06)
- allow to configure OPNSense REST API calls timeout per REST API endpoint adding
`--opnsense-timeout-sec-get-vip-status` and
`--opnsense-timeout-sec-get-traffic` parameters.
### Version 1.0.0 (2023-09-06)
- remove `opnsense_main_ha_state` and `opnsense_backup_ha_state` - remove `opnsense_main_ha_state` and `opnsense_backup_ha_state`
metrics marked as deprecated on version 0.5.0 and replace metrics marked as deprecated on version 0.5.0 and replace
@ -115,7 +132,6 @@ You can setup env through `.env` file or environment variables with defined as d
- allow empty string interfaces to **not** call diagnostic - allow empty string interfaces to **not** call diagnostic
traffic REST API traffic REST API
### Version 0.5.1 (2023-09-04) ### Version 0.5.1 (2023-09-04)
- FIX `opnsense_server_ha_state` calls were not - FIX `opnsense_server_ha_state` calls were not

View file

@ -24,7 +24,12 @@ class OPNSenseTraffic:
metric: OPNSenseTrafficMetric = None metric: OPNSenseTrafficMetric = None
value: int = 0 value: int = 0
def __init__(self, interface: str, metric: OPNSenseTrafficMetric, value: int = 0): def __init__(
self,
interface: str,
metric: OPNSenseTrafficMetric,
value: int = 0,
):
self.value = value self.value = value
self.interface = interface self.interface = interface
self.metric = metric self.metric = metric
@ -55,12 +60,24 @@ class OPNSenseAPI:
login: str = None login: str = None
password: str = None password: str = None
role: OPNSenseRole = None role: OPNSenseRole = None
get_vip_status_timeout_sec: int = 5
get_traffic_timeout_sec: int = 15
def __init__(self, role, host, login, password): def __init__(
self,
role,
host,
login,
password,
get_vip_status_timeout_sec: int = 5,
get_traffic_timeout_sec: int = 5,
):
self.role = role self.role = role
self.host = host self.host = host
self.login = login self.login = login
self.password = password self.password = password
self.get_vip_status_timeout_sec = get_vip_status_timeout_sec
self.get_traffic_timeout_sec = get_traffic_timeout_sec
@property @property
def labels(self): def labels(self):
@ -86,7 +103,10 @@ class OPNSenseAPI:
def get_interface_vip_status(self) -> OPNSenseHAState: def get_interface_vip_status(self) -> OPNSenseHAState:
try: try:
data = self.get("/api/diagnostics/interface/get_vip_status/") data = self.get(
"/api/diagnostics/interface/get_vip_status/",
timeout=self.get_vip_status_timeout_sec,
)
except RequestException as ex: except RequestException as ex:
logger.error( logger.error(
"Get VIP STATUS on %s failed with the following error %r", self.host, ex "Get VIP STATUS on %s failed with the following error %r", self.host, ex
@ -109,7 +129,10 @@ class OPNSenseAPI:
if not interfaces: if not interfaces:
return [] return []
try: try:
data = self.get(f"/api/diagnostics/traffic/top/{interfaces}", timeout=15) data = self.get(
f"/api/diagnostics/traffic/top/{interfaces}",
timeout=self.get_traffic_timeout_sec,
)
except RequestException as ex: except RequestException as ex:
logger.error( logger.error(
"Get diagnostics traffic on %s interface(s) 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",

View file

@ -135,6 +135,20 @@ def run():
"An empty string '' means not calling the traffic diagnostic REST API so no " "An empty string '' means not calling the traffic diagnostic REST API so no "
"`opnsense_active_server_traffic_rate` metric.", "`opnsense_active_server_traffic_rate` metric.",
) )
parser.add_argument(
"--opnsense-timeout-sec-get-vip-status",
type=int,
dest="get_vip_status_timeout_sec",
default=int(os.environ.get("OPNSENSE_TIMEOUT_SEC_GET_VIP_STATUS", 5)),
help="Allow to configure timeout while requesting OPNSense REST API /api/diagnostics/interface/get_vip_status/",
)
parser.add_argument(
"--opnsense-timeout-sec-get-traffic",
type=int,
dest="get_traffic_timeout_sec",
default=int(os.environ.get("OPNSENSE_TIMEOUT_SEC_GET_TRAFFIC", 15)),
help="Allow to configure timeout while requesting OPNSense REST API /api/diagnostics/traffic/top/[INTERFACES]",
)
parser.add_argument( parser.add_argument(
"--opnsense-password", "--opnsense-password",
"-p", "-p",
@ -158,10 +172,20 @@ def run():
server = OPNSensePrometheusExporter( server = OPNSensePrometheusExporter(
OPNSenseAPI( OPNSenseAPI(
OPNSenseRole.MAIN, arguments.main, arguments.user, arguments.password OPNSenseRole.MAIN,
arguments.main,
arguments.user,
arguments.password,
get_vip_status_timeout_sec=arguments.get_vip_status_timeout_sec,
get_traffic_timeout_sec=arguments.get_traffic_timeout_sec,
), ),
OPNSenseAPI( OPNSenseAPI(
OPNSenseRole.BACKUP, arguments.backup, arguments.user, arguments.password OPNSenseRole.BACKUP,
arguments.backup,
arguments.user,
arguments.password,
get_vip_status_timeout_sec=arguments.get_vip_status_timeout_sec,
get_traffic_timeout_sec=arguments.get_traffic_timeout_sec,
), ),
arguments.interfaces, arguments.interfaces,
check_frequency=arguments.frequency, check_frequency=arguments.frequency,

View file

@ -1,3 +1,5 @@
from unittest import mock
import responses import responses
from opnsense_exporter.opnsense_api import ( from opnsense_exporter.opnsense_api import (
@ -17,6 +19,32 @@ from .common import (
) )
def test_get_vip_status_timeout_sec():
with mock.patch("opnsense_exporter.opnsense_api.OPNSenseAPI.get") as get_mock:
OPNSenseAPI(
OPNSenseRole.MAIN,
MAIN_HOST,
LOGIN,
PASSWORD,
get_vip_status_timeout_sec=11,
).get_interface_vip_status()
get_mock.assert_called_once_with(
"/api/diagnostics/interface/get_vip_status/", timeout=11
)
def test_get_traffic_timeout_sec():
with mock.patch("opnsense_exporter.opnsense_api.OPNSenseAPI.get") as get_mock:
OPNSenseAPI(
OPNSenseRole.MAIN,
MAIN_HOST,
LOGIN,
PASSWORD,
get_traffic_timeout_sec=11,
).get_traffic("wan")
get_mock.assert_called_once_with("/api/diagnostics/traffic/top/wan", timeout=11)
@responses.activate @responses.activate
def test_get_interface_vip_status_active(): def test_get_interface_vip_status_active():
responses.add( responses.add(

View file

@ -84,6 +84,10 @@ def test_parser(server_mock):
"user-test", "user-test",
"-p", "-p",
"pwd-test", "pwd-test",
"--opnsense-timeout-sec-get-vip-status",
"7",
"--opnsense-timeout-sec-get-traffic",
"9",
"-i", "-i",
"efg,hij", "efg,hij",
"--prometheus-instance", "--prometheus-instance",
@ -97,10 +101,14 @@ def test_parser(server_mock):
assert server.main.host == "main.host" assert server.main.host == "main.host"
assert server.main.login == "user-test" assert server.main.login == "user-test"
assert server.main.password == "pwd-test" assert server.main.password == "pwd-test"
assert server.main.get_vip_status_timeout_sec == 7
assert server.main.get_traffic_timeout_sec == 9
assert server.backup.role == OPNSenseRole.BACKUP assert server.backup.role == OPNSenseRole.BACKUP
assert server.backup.host == "backup.host" assert server.backup.host == "backup.host"
assert server.backup.login == "user-test" assert server.backup.login == "user-test"
assert server.backup.password == "pwd-test" assert server.backup.password == "pwd-test"
assert server.backup.get_vip_status_timeout_sec == 7
assert server.backup.get_traffic_timeout_sec == 9
assert server.check_frequency == 15 assert server.check_frequency == 15
assert server.interfaces == "efg,hij" assert server.interfaces == "efg,hij"