diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f539813 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +venv +ovh.conf +__pycache__ diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 0000000..e010821 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,16 @@ +--- +repos: + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.2.0 + hooks: + - id: check-executables-have-shebangs + - id: check-merge-conflict + - id: end-of-file-fixer + - id: fix-encoding-pragma + args: ['--remove'] + - id: requirements-txt-fixer + - id: trailing-whitespace + - repo: https://github.com/psf/black + rev: 22.3.0 + hooks: + - id: black diff --git a/README.md b/README.md new file mode 100644 index 0000000..9c8aafa --- /dev/null +++ b/README.md @@ -0,0 +1,36 @@ +# OVHcloud Nagios collection + +Nagios checks for [OVHcloud](https://www.ovhcloud.com) services. + +# Installation + +Using pip: + +``` +python3 -m venv venv +. ./venv/bin/activate +pip install -r requirements.txt +``` + +Create OVHcloud API tokens following [this guide](https://github.com/ovh/python-ovh). + +# check_voip + +For each VoIP lines associated to the account, detect the last registration time: + +``` +./check_voip --help +``` + +Example of configuration: + +``` +command[check_voip]=/opt/check_ovhcloud/check_voip -w 7200 -c 86400 +``` + +# Contributing + +``` +pip install pre-commit +pre-commit run --files check_* +``` diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..3eefcb9 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +1.0.0 diff --git a/check_voip b/check_voip new file mode 100755 index 0000000..4c346b6 --- /dev/null +++ b/check_voip @@ -0,0 +1,139 @@ +#!/usr/bin/env python3 + +import argparse +import logging +import sys +import ovh +from datetime import datetime, timezone + +from lib import setup_logging, show_version + +from nagiosplugin import ( + Check, + Metric, + Resource, + ScalarContext, + Summary, +) +from nagiosplugin.state import Critical, Ok, Unknown, Warn + +logger = logging.getLogger(__name__) + + +def parse_arguments(): + parser = argparse.ArgumentParser() + parser.add_argument( + "-v", + "--verbose", + dest="loglevel", + action="store_const", + const=logging.INFO, + help="Print more output", + ) + parser.add_argument( + "-d", + "--debug", + dest="loglevel", + action="store_const", + const=logging.DEBUG, + default=logging.WARNING, + help="Print even more output", + ) + + parser.add_argument( + "--version", + dest="show_version", + action="store_true", + help="Print version and exit", + ) + + parser.add_argument( + "--registration-warning", + "-w", + dest="registration_warning", + type=int, + default=7200, + help="Raise warning if last line registration time is higher than this threshold (in seconds)", + ) + + parser.add_argument( + "--registration-critical", + "-c", + dest="registration_critical", + type=int, + default=86400, + help="Raise critical if last line registration time is higher than this threshold (in seconds)", + ) + + args = parser.parse_args() + return args + + +class Voip(Resource): + def __init__(self, client): + self.client = client + + def probe(self): + metrics = [] + billing_accounts = self.client.get(f"/telephony") + for billing_account in billing_accounts: + service_names = self.client.get(f"/telephony/{billing_account}/line") + for service_name in service_names: + last_registration = self.client.get( + f"/telephony/{billing_account}/line/{service_name}/lastRegistrations" + )[0] + last_registration_delta = int( + ( + datetime.now(tz=timezone.utc) + - datetime.fromisoformat(last_registration["datetime"]) + ).total_seconds() + ) + metrics.append( + Metric( + f"{service_name} last registration", + last_registration_delta, + context="last_registration", + uom="s", + ) + ) + return metrics + + +class VoipSummary(Summary): + def problem(self, results): + return ", ".join( + [ + f"{result.metric.name} {result.state}: {result.hint}" + for result in results + if str(result.state) != "ok" + ] + ) + + +def main(): + args = parse_arguments() + setup_logging(args) + + if args.show_version: + show_version() + return + + try: + check = Check( + Voip(client=ovh.Client()), + ScalarContext( + "last_registration", + warning=args.registration_warning, + critical=args.registration_critical, + ), + VoipSummary(), + ) + check.main() + except Exception as err: + print(f"Failed to execute check: {str(err)}") + logger.debug(err, exc_info=True) + sys.exit(Unknown.code) + + +if __name__ == "__main__": + main() diff --git a/lib/__init__.py b/lib/__init__.py new file mode 100644 index 0000000..384feb9 --- /dev/null +++ b/lib/__init__.py @@ -0,0 +1,13 @@ +import logging +import os + + +def show_version(): + with open( + os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "VERSION"), "r" + ) as fd: + print(fd.read().strip()) + + +def setup_logging(args): + logging.basicConfig(format="%(levelname)s: %(message)s", level=args.loglevel) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..6b2e766 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,7 @@ +certifi==2023.7.22 +charset-normalizer==3.2.0 +idna==3.4 +nagiosplugin==1.3.3 +ovh==1.1.0 +requests==2.31.0 +urllib3==2.0.5