init
This commit is contained in:
5
ipsec_exporter.py
Normal file
5
ipsec_exporter.py
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
from src.app import App
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app = App()
|
||||||
|
app.main()
|
||||||
42
src/app.py
Normal file
42
src/app.py
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
from argparse import *
|
||||||
|
from src.prometheus_metrics_server import *
|
||||||
|
from src.metrics_source import *
|
||||||
|
|
||||||
|
class App:
|
||||||
|
args: Namespace
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
parser = ArgumentParser(description="IPsec Prometheus exporter for Libreswan")
|
||||||
|
parser.add_argument("-a", "--address", dest="address", required=False, type=str, default="0.0.0.0", help="Server IP address")
|
||||||
|
parser.add_argument("-p", "--port", dest="port", required=False, type=int, default=9446, help="Server port")
|
||||||
|
parser.add_argument("-i", "--interval", dest="interval", required=False, type=int, default=1, help="Metrics read interval (in seconds)")
|
||||||
|
self.args = parser.parse_args()
|
||||||
|
|
||||||
|
def main(self):
|
||||||
|
server = PrometheusMetricsServer(self.args.port, "IPsec exporter")
|
||||||
|
server.address = self.args.address
|
||||||
|
server.interval = self.args.interval
|
||||||
|
|
||||||
|
globalstatus_source = CommandMetricsSource("sudo ipsec globalstatus")
|
||||||
|
globalstatus_source.add_metric("ipsec_current_states", r"current\.states\.(?P<type>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_current_states_iketype", r"current\.states\.iketype\.(?P<type>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_current_states_enumerate", r"current\.states\.enumerate\.(?P<type>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_total_ipsec_type", r"total\.ipsec\.type\.(?P<type>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_total_traffic", r"total\.(?P<type>\w+)\.traffic\.(?P<direction>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_total_ike", r"total\.ike\.(?P<version>\w+)\.(?P<status>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_total_ikev2_redirect", r"total\.ike\.ikev2\.redirect\.(?P<status>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_total_pamauth", r"total\.pamauth\.(?P<status>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_total_iketcp", r"total\.iketcp\.(?P<type>\w+)\.(?P<status>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_total_ike_encr", r"total\.(?P<version>\w+)\.encr\.(?P<status>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_total_ike_integ", r"total\.(?P<version>\w+)\.integ\.(?P<status>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_total_ike_group", r"total\.(?P<version>\w+)\.group\.(?P<status>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_total_ike_notifies_error", r"total\.(?P<version>\w+)\.(?P<direction>\w+)\.notifies\.error\.(?P<status>\w+)=(?P<VALUE>\d+)")
|
||||||
|
globalstatus_source.add_metric("ipsec_total_ikev2_notifies_status", r"total\.ikev2\.(?P<direction>\w+)\.notifies\.status\.(?P<status>\w+)=(?P<VALUE>\d+)")
|
||||||
|
server.add_metrics_source(globalstatus_source)
|
||||||
|
|
||||||
|
custom_metrics_source = CustomMetricsSource()
|
||||||
|
custom_metrics_source.add_metric(IPsecTrafficCustomMetric("ipsec_traffic"))
|
||||||
|
server.add_metrics_source(custom_metrics_source)
|
||||||
|
|
||||||
|
server.run()
|
||||||
|
|
||||||
74
src/metric.py
Normal file
74
src/metric.py
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
from abc import abstractmethod
|
||||||
|
from prometheus_client import *
|
||||||
|
from re import Pattern
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class Metric:
|
||||||
|
gauge: Gauge
|
||||||
|
|
||||||
|
def __init__(self, name: str, labels: list[str], description: str = ""):
|
||||||
|
self.gauge = Gauge(
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
labels
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class CommandMetric(Metric):
|
||||||
|
regex: Pattern
|
||||||
|
|
||||||
|
def __init__(self, name: str, regex: str, description: str = ""):
|
||||||
|
self.regex = re.compile(regex)
|
||||||
|
|
||||||
|
labels = list(self.regex.groupindex.keys())
|
||||||
|
labels.remove("VALUE")
|
||||||
|
|
||||||
|
super().__init__(name, labels, description)
|
||||||
|
|
||||||
|
def update(self, command_output: str):
|
||||||
|
self.gauge.clear()
|
||||||
|
|
||||||
|
results = re.finditer(self.regex, command_output)
|
||||||
|
|
||||||
|
for result in results:
|
||||||
|
groups = result.groupdict()
|
||||||
|
value = groups.pop("VALUE")
|
||||||
|
self.gauge.labels(*list(groups.values())).set(int(value))
|
||||||
|
|
||||||
|
|
||||||
|
class CustomMetric(Metric):
|
||||||
|
def __init__(self, name: str, labels: list[str], description: str = ""):
|
||||||
|
super().__init__(name, labels, description)
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def update(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class IPsecTrafficCustomMetric(CustomMetric):
|
||||||
|
def __init__(self, name: str, description: str = ""):
|
||||||
|
labels = [
|
||||||
|
"lease",
|
||||||
|
"connection",
|
||||||
|
"direction"
|
||||||
|
]
|
||||||
|
super().__init__(name, labels, description)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
self.gauge.clear()
|
||||||
|
|
||||||
|
trafficstatus = os.popen("sudo ipsec trafficstatus").read()
|
||||||
|
|
||||||
|
trafficstatus_results = re.finditer(r""""(?P<connection>.+)"\[\d+\] \d+\.\d+\.\d+\.\d+, type=\w+, add_time=\d+, inBytes=(?P<IN_VALUE>\d+), outBytes=(?P<OUT_VALUE>\d+), maxBytes=.+, id='.+', lease=(?P<lease>\d+\.\d+\.\d+\.\d+\/\d+)""", trafficstatus)
|
||||||
|
|
||||||
|
for result in trafficstatus_results:
|
||||||
|
lease = result.groupdict()["lease"]
|
||||||
|
connection = result.groupdict()["connection"]
|
||||||
|
in_value = result.groupdict()["IN_VALUE"]
|
||||||
|
out_value = result.groupdict()["OUT_VALUE"]
|
||||||
|
|
||||||
|
self.gauge.labels(lease, connection, "in").set(int(in_value))
|
||||||
|
self.gauge.labels(lease, connection, "out").set(int(out_value))
|
||||||
43
src/metrics_source.py
Normal file
43
src/metrics_source.py
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
from abc import ABC, abstractmethod
|
||||||
|
from src.metric import *
|
||||||
|
import os
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class MetricsSource:
|
||||||
|
_metrics : list[Metric]
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._metrics = []
|
||||||
|
|
||||||
|
@abstractmethod
|
||||||
|
def update(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class CommandMetricsSource(MetricsSource):
|
||||||
|
command : str
|
||||||
|
|
||||||
|
def __init__(self, command: str):
|
||||||
|
super().__init__()
|
||||||
|
self.command = command
|
||||||
|
|
||||||
|
def add_metric(self, name: str, regex: str, description: str = ""):
|
||||||
|
self._metrics.append(CommandMetric(name, regex, description))
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
output = os.popen(self.command).read()
|
||||||
|
for metric in self._metrics:
|
||||||
|
metric.update(output)
|
||||||
|
|
||||||
|
|
||||||
|
class CustomMetricsSource(MetricsSource):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
def add_metric(self, custom_metric : CustomMetric):
|
||||||
|
self._metrics.append(custom_metric)
|
||||||
|
|
||||||
|
def update(self):
|
||||||
|
for metric in self._metrics:
|
||||||
|
metric.update()
|
||||||
32
src/prometheus_metrics_server.py
Normal file
32
src/prometheus_metrics_server.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import prometheus_client
|
||||||
|
import time
|
||||||
|
from src.metrics_source import *
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class PrometheusMetricsServer:
|
||||||
|
_metrics_sources: list[MetricsSource]
|
||||||
|
|
||||||
|
address: str
|
||||||
|
port: int
|
||||||
|
interval: int
|
||||||
|
server_name: str
|
||||||
|
|
||||||
|
def __init__(self, port: int, server_name: str):
|
||||||
|
self._metrics_sources = []
|
||||||
|
|
||||||
|
self.address = "0.0.0.0"
|
||||||
|
self.port = port
|
||||||
|
self.interval = 1
|
||||||
|
self.server_name = server_name
|
||||||
|
|
||||||
|
def add_metrics_source(self, source: MetricsSource):
|
||||||
|
self._metrics_sources.append(source)
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
prometheus_client.start_http_server(self.port, addr=self.address)
|
||||||
|
print(f"{self.server_name} is running on {self.address}:{self.port}")
|
||||||
|
while True:
|
||||||
|
for source in self._metrics_sources:
|
||||||
|
source.update()
|
||||||
|
time.sleep(self.interval)
|
||||||
Reference in New Issue
Block a user