nagios-check_domain_expirat.../check_domain_expiration_rdap.py
Alarig Le Lay cb96bb23be
Adding timeout to fetch the IANA RDAP JSON, just in case
Signed-off-by: Alarig Le Lay <alelay@scaleway.com>
2024-07-19 12:04:13 +02:00

172 lines
4.7 KiB
Python
Executable file
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python
# Copyright 2024 Alarig Le Lay <alarig@swordarmor.fr>
# Distributed under the terms of the GNU General Public License v3
import argparse
import datetime
import logging
import requests
import nagiosplugin
import pandas
import pyunycode
import requests_cache
_log = logging.getLogger('nagiosplugin')
def expiration(domain):
list2dict = []
session = requests_cache.CachedSession(
'/tmp/iana_rdap_cache',
cache_control=True
)
req = session.get('https://data.iana.org/rdap/dns.json', timeout=120)
for k,v in req.json()['services']:
for x in k:
list2dict.append({'name':x, 'url':v[0]})
df = pandas.DataFrame(list2dict)
domain = pyunycode.convert(domain)
tld = domain.split('.')[-1]
try:
url = df[df.name == (tld)].iloc[0].url
# no rdap on tld
except IndexError:
raise nagiosplugin.CheckError(
f'The TLD {tld} does not have an RDAP server'
)
_log.debug(f'The used RDAP server is {url}')
req_rdap = requests.get(f'{url}domain/{domain}')
match req_rdap.status_code:
case 403:
raise nagiosplugin.CheckError(
f'Got {req_rdap.status_code}, the RDAP server {url} refused to reply'
)
case 404:
raise nagiosplugin.CheckError(
f'Got {req_rdap.status_code}, the domain {domain} has not been found'
)
case 503:
raise nagiosplugin.CheckError(
f'Got {req_rdap.status_code}, the RDAP server {url} seems broken'
)
case _:
pass
_log.debug(f'The used RDAP JSON is {req_rdap.json()}')
raw_expiration = [
event.get('eventDate', False)
for event in req_rdap.json().get('events', {})
if event.get('eventAction', {}) == 'expiration'
]
try:
fecha = raw_expiration[0].split('T')[0]
except IndexError:
raise nagiosplugin.CheckError(
f'The domain JSON for {domain} does not have "eventAction"."expiration" field, run with -vvv or --debug to have the JSON dump'
)
today = datetime.datetime.now()
delta = datetime.datetime.strptime(fecha, '%Y-%m-%d') - today
return delta.days
# data acquisition
class Expiration(nagiosplugin.Resource):
"""Domain model: domain expiration
Get the expiration date from RDAP.
The RDAP server is extracted from https://data.iana.org/rdap/dns.json which
cached to avoid useless fetching; but the JSON from the registry RDAP isnt
cached because we cant presume of the data lifetime.
"""
def __init__(self, domain):
self.domain = domain
def probe(self):
try:
days_to_expiration = expiration(self.domain)
except requests.exceptions.ConnectionError as err:
raise nagiosplugin.CheckError(
f'The connection to the RDAP server failed: {err}'
)
return [nagiosplugin.Metric(
'daystoexpiration',
days_to_expiration,
uom='d'
)]
# data presentation
class ExpirationSummary(nagiosplugin.Summary):
"""Status line conveying expiration information.
"""
def __init__(self, domain):
self.domain = domain
pass
# runtime environment and data evaluation
@nagiosplugin.guarded
def main():
argp = argparse.ArgumentParser(description=__doc__)
argp.add_argument(
'-w', '--warning', metavar='int', default='30',
help='warning expiration max days. Default=30'
)
argp.add_argument(
'-c', '--critical', metavar='range', default='15',
help='critical expiration max days. Default=15'
)
argp.add_argument(
'-v', '--verbose', action='count', default=0, help='be more verbose'
)
argp.add_argument(
'-d', '--debug', action='count', default=0,
help='debug logging to /tmp/nagios-check_domain_expiration_rdap.log'
)
argp.add_argument('domain')
args = argp.parse_args()
wrange = f'@{args.critical}:{args.warning}'
crange = f'@~:{args.critical}'
fmetric = '{value} days until domain expires'
if (args.debug):
logging.basicConfig(
filename='/tmp/nagios-check_domain_expiration_rdap.log',
encoding='utf-8',
format='%(asctime)s %(message)s',
level=logging.DEBUG
)
check = nagiosplugin.Check(
Expiration(args.domain),
nagiosplugin.ScalarContext(
'daystoexpiration',
warning=wrange,
critical=crange,
fmt_metric=fmetric
),
ExpirationSummary(args.domain)
)
check.main(verbose=args.verbose)
if __name__ == '__main__':
main()