opnsense-prom-exporter/opnsense_exporter/server.py

198 lines
6.3 KiB
Python
Raw Normal View History

2023-09-01 13:27:55 +02:00
import argparse
import logging
2023-09-01 13:27:55 +02:00
import os
import socket
import time
from dotenv import load_dotenv
from prometheus_client import Enum, Gauge, start_http_server
from opnsense_exporter.opnsense_api import OPNSenseAPI, OPNSenseHAState, OPNSenseRole
2023-09-01 13:27:55 +02:00
logger = logging.getLogger(__name__)
2023-09-01 13:27:55 +02:00
load_dotenv()
HA_STATES = [enum.value for enum in list(OPNSenseHAState)]
opnsense_server_ha_state = Enum(
"opnsense_server_ha_state",
"OPNSense server HA state",
[
"instance",
"host",
"role",
],
states=HA_STATES,
)
2023-09-03 23:38:34 +02:00
opnsense_active_server_traffic_rate = Gauge(
"opnsense_active_server_traffic_rate",
"Active OPNSense server bytes in/out per interface",
2023-09-01 16:23:20 +02:00
[
"instance",
"host",
"role",
2023-09-03 23:38:34 +02:00
"interface",
"metric",
2023-09-01 16:23:20 +02:00
],
2023-09-01 13:27:55 +02:00
)
class OPNSensePrometheusExporter:
def __init__(
self,
main: OPNSenseAPI,
backup: OPNSenseAPI,
2023-09-03 23:38:34 +02:00
interfaces,
exporter_instance: str = "",
check_frequency: int = 1,
):
self.main = main
self.backup = backup
2023-09-03 23:38:34 +02:00
self.interfaces = interfaces
self.exporter_instance = exporter_instance
self.check_frequency = check_frequency
2023-09-01 13:27:55 +02:00
def process_requests(self):
"""A dummy function that takes some time."""
main_state = self.main.get_interface_vip_status()
backup_sate = self.backup.get_interface_vip_status()
opnsense_server_ha_state.labels(
instance=self.exporter_instance, **self.main.labels
).state(main_state.value)
opnsense_server_ha_state.labels(
instance=self.exporter_instance, **self.backup.labels
).state(backup_sate.value)
active_opnsense = None
if main_state == OPNSenseHAState.ACTIVE:
active_opnsense = self.main
if backup_sate == OPNSenseHAState.ACTIVE:
active_opnsense = self.backup
if active_opnsense:
2023-09-03 23:38:34 +02:00
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)
2023-09-01 13:27:55 +02:00
def start_server(self, port=8000):
# Start up the server to expose the metrics.
start_http_server(port)
logger.info("listen port %s", port)
# Generate some requests.
while True:
self.process_requests()
time.sleep(self.check_frequency)
2023-09-01 13:27:55 +02:00
def run():
parser = argparse.ArgumentParser(
description="OPNSense prometheus exporter",
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
parser.add_argument(
"--check-frequency-seconds",
"-c",
type=int,
dest="frequency",
default=int(os.environ.get("CHECK_FREQUENCY_SECONDS", 2)),
help="How often (in seconds) this server requests OPNSense servers",
)
parser.add_argument(
"--main-host",
"-m",
type=str,
dest="main",
default=os.environ.get("OPNSENSE_MAIN_HOST", None),
help="MAIN OPNsense server that should be in `active` state in normal configuration.",
)
parser.add_argument(
"--backup-host",
"-b",
type=str,
dest="backup",
default=os.environ.get("OPNSENSE_BACKUP_HOST", None),
help="BACKUP OPNsense server that should be `hot_standby` state in normal configuration.",
)
parser.add_argument(
"--opnsense-user",
"-u",
type=str,
dest="user",
default=os.environ.get("OPNSENSE_USERNAME", None),
help="OPNsense user. Expect to be the same on MAIN and BACKUP servers",
)
2023-09-03 23:38:34 +02:00
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). "
"An empty string '' means not calling the traffic diagnostic REST API so no "
"`opnsense_active_server_traffic_rate` metric.",
2023-09-03 23:38:34 +02:00
)
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]",
)
2023-09-01 13:27:55 +02:00
parser.add_argument(
"--opnsense-password",
"-p",
type=str,
dest="password",
default=os.environ.get("OPNSENSE_PASSWORD", None),
help="OPNsense password. Expect to be the same on MAIN and BACKUP servers",
)
parser.add_argument(
"--prometheus-instance",
dest="prom_instance",
type=str,
default=socket.gethostname(),
help=(
2023-09-01 16:23:20 +02:00
"Exporter Instance name, default value computed with hostname "
2023-09-01 13:27:55 +02:00
"where the server is running. Use to set the instance label."
),
)
arguments = parser.parse_args()
server = OPNSensePrometheusExporter(
OPNSenseAPI(
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(
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,
),
2023-09-03 23:38:34 +02:00
arguments.interfaces,
2023-09-01 13:27:55 +02:00
check_frequency=arguments.frequency,
2023-09-01 16:23:20 +02:00
exporter_instance=arguments.prom_instance,
2023-09-01 13:27:55 +02:00
)
server.start_server()
# return the server instance mainly for test purpose
return server