forked from bortzmeyer/check_expire
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
ff901cfc06 | ||
|
014fe9fec5 | ||
|
60a6410941 | ||
|
4e17d48adb | ||
|
f7e355702f | ||
|
6d6f054a26 | ||
|
30d4678e03 | ||
|
9dc05e9c7b | ||
3af8b31034 | |||
0b10e8d563 |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
__pycache__/
|
10
README.md
10
README.md
@ -19,6 +19,8 @@ You need Python 3 and [Requests](http://python-requests.org/). You can install R
|
||||
|
||||
Then, copy the script `check_expire` and the file `ianardap.py`to the directory of local plugins.
|
||||
|
||||
The use of a cache directory is not mandatory, but highly recommended. It can be either `$XDG_CACHE_HOME/ianardap` or `$HOME/.ianardapcaches` depending on the environment variables set.
|
||||
|
||||
## Icinga configuration
|
||||
|
||||
If you use Icinga, here is a possible definition of the command:
|
||||
@ -35,6 +37,7 @@ object CheckCommand "expiration" {
|
||||
"-v" = { set_if = "$expiration_verbose$" }
|
||||
}
|
||||
|
||||
env.XDG_CACHE_HOME = "/var/cache/nagios"
|
||||
}
|
||||
|
||||
apply Service "expiration" {
|
||||
@ -60,6 +63,13 @@ object Host "bortzmeyer-org" {
|
||||
}
|
||||
```
|
||||
|
||||
If needed, create the cache directory accordingly:
|
||||
|
||||
```
|
||||
mkdir /var/cache/nagios
|
||||
chown nagios: /var/cache/nagios
|
||||
```
|
||||
|
||||
## Zabbix configuration
|
||||
|
||||
For monitoring systems that do not rely on exit codes but on calculation mechanism based on the metric they receive you can use the `-u` option that will only return the expiration date in unixtime format.
|
||||
|
@ -45,6 +45,9 @@ warning_t = datetime.timedelta(days=7)
|
||||
unixtime = False
|
||||
timeout = 20 # Seconds
|
||||
|
||||
# Cannot be changed on the command-line (yet)
|
||||
server = None
|
||||
|
||||
def usage(msg=None):
|
||||
print("Usage: %s -H domain-name [-c critical -w warning -u -t timeout]" % sys.argv[0], end="")
|
||||
if msg is not None and msg != "":
|
||||
@ -53,6 +56,8 @@ def usage(msg=None):
|
||||
print("")
|
||||
|
||||
def details():
|
||||
if database and not database.cachefile:
|
||||
print(" (WARNING: no cache directory used, please set environement variable XDG_CACHE_HOME or HOME.)", end="")
|
||||
if verbose:
|
||||
print(" RDAP database \"%s\", version %s published on %s, retrieved on %s, RDAP server is %s" % \
|
||||
(database.description, database.version, database.publication, database.retrieved, server))
|
||||
@ -101,7 +106,7 @@ try:
|
||||
elif option == "--hostname" or option == "-H":
|
||||
domain = value
|
||||
elif option == "--timeout" or option == "-t":
|
||||
timeout = int(value)
|
||||
timeout = float(value)
|
||||
elif option == "--unixtime" or option == "-u":
|
||||
unixtime = True
|
||||
elif option == "--verbose" or option == "-v":
|
||||
@ -142,6 +147,7 @@ for server in servers:
|
||||
response = requests.get("%s/domain/%s" % (server, domain), timeout=timeout)
|
||||
except requests.exceptions.Timeout:
|
||||
unknowns += "Timeout when trying to reach %s " % server
|
||||
continue
|
||||
if response.status_code != 200:
|
||||
errors += "Invalid RDAP return code at %s: %s " % \
|
||||
(server, response.status_code)
|
||||
|
57
ianardap.py
57
ianardap.py
@ -21,7 +21,8 @@ IANABASES = {"domains": "https://data.iana.org/rdap/dns.json",
|
||||
"v6prefixes": "https://data.iana.org/rdap/ipv6.json",
|
||||
"as": "https://data.iana.org/rdap/asn.json",
|
||||
"objects": "https://data.iana.org/rdap/object-tags.json"}
|
||||
CACHE = os.environ["HOME"] + "/.ianardapcaches"
|
||||
CACHE = os.environ["XDG_CACHE_HOME"] + "/ianardap" if "XDG_CACHE_HOME" in os.environ else \
|
||||
(os.environ["HOME"] + "/.ianardapcaches" if "HOME" in os.environ else None)
|
||||
MAXAGE = 24 # Hours. Used only if the server no longer gives the information.
|
||||
IANATIMEOUT = 10 # Seconds
|
||||
MAXTESTS = 3 # Maximum attempts to get the database
|
||||
@ -60,28 +61,33 @@ file (see the documentation of the module).
|
||||
"""
|
||||
|
||||
cache_valid = False
|
||||
if not os.path.exists(cachedir):
|
||||
os.mkdir(cachedir)
|
||||
self.category = category
|
||||
cachefile = os.path.join(cachedir, category)
|
||||
if pickleformat:
|
||||
self.cachefile = cachefile + ".pickle"
|
||||
else:
|
||||
self.cachefile = cachefile + ".json"
|
||||
self.lockname = self.cachefile + ".lock"
|
||||
self.expirationfile = self.cachefile + ".expires"
|
||||
self.cachefile = None
|
||||
self.lockname = None
|
||||
self.expirationfile = None
|
||||
if cachedir:
|
||||
if not os.path.exists(cachedir):
|
||||
os.mkdir(cachedir)
|
||||
cachefile = os.path.join(cachedir, category)
|
||||
if pickleformat:
|
||||
self.cachefile = cachefile + ".pickle"
|
||||
else:
|
||||
self.cachefile = cachefile + ".json"
|
||||
self.lockname = self.cachefile + ".lock"
|
||||
self.expirationfile = self.cachefile + ".expires"
|
||||
if maxage is not None:
|
||||
with open(self.expirationfile, 'w'):
|
||||
self.expirationtime = time.mktime((datetime.datetime.now() + \
|
||||
datetime.timedelta(hours=maxage)).timetuple())
|
||||
os.utime(self.expirationfile,
|
||||
times = (self.expirationtime, self.expirationtime))
|
||||
self.expirationtime = time.mktime((datetime.datetime.now() + \
|
||||
datetime.timedelta(hours=maxage)).timetuple())
|
||||
if self.expirationfile:
|
||||
with open(self.expirationfile, 'w'):
|
||||
os.utime(self.expirationfile,
|
||||
times = (self.expirationtime, self.expirationtime))
|
||||
loaded = False
|
||||
tests = 0
|
||||
errmsg = "No error"
|
||||
while not loaded and tests < MAXTESTS:
|
||||
self.lock()
|
||||
if os.path.exists(self.cachefile) and \
|
||||
if self.cachefile and os.path.exists(self.cachefile) and \
|
||||
(pathlib.Path(self.expirationfile).exists() and \
|
||||
datetime.datetime.fromtimestamp(os.path.getmtime(self.expirationfile)) > \
|
||||
datetime.datetime.now()):
|
||||
@ -139,9 +145,10 @@ file (see the documentation of the module).
|
||||
try:
|
||||
content = response.content
|
||||
database = json.loads(content)
|
||||
with open(self.expirationfile, 'w'):
|
||||
os.utime(self.expirationfile,
|
||||
times = (self.expirationtime, self.expirationtime))
|
||||
if self.expirationfile:
|
||||
with open(self.expirationfile, 'w'):
|
||||
os.utime(self.expirationfile,
|
||||
times = (self.expirationtime, self.expirationtime))
|
||||
except json.decoder.JSONDecodeError:
|
||||
tests += 1
|
||||
errmsg = "Invalid JSON retrieved from %s" % IANABASE
|
||||
@ -173,7 +180,7 @@ file (see the documentation of the module).
|
||||
else: # IP addresses will be complicated, because of the
|
||||
# longest prefix rule.
|
||||
raise Exception("Unsupported category %s" % self.category)
|
||||
if not cache_valid:
|
||||
if self.cachefile and not cache_valid:
|
||||
self.lock()
|
||||
cache = open(self.cachefile, "wb")
|
||||
if pickleformat:
|
||||
@ -184,12 +191,14 @@ file (see the documentation of the module).
|
||||
self.unlock()
|
||||
|
||||
def lock(self):
|
||||
self.lockhandle = open(self.lockname, 'w')
|
||||
fcntl.lockf(self.lockhandle, fcntl.LOCK_EX)
|
||||
if self.lockname:
|
||||
self.lockhandle = open(self.lockname, 'w')
|
||||
fcntl.lockf(self.lockhandle, fcntl.LOCK_EX)
|
||||
|
||||
def unlock(self):
|
||||
fcntl.lockf(self.lockhandle, fcntl.LOCK_UN)
|
||||
self.lockhandle.close()
|
||||
if self.lockname:
|
||||
fcntl.lockf(self.lockhandle, fcntl.LOCK_UN)
|
||||
self.lockhandle.close()
|
||||
|
||||
def find(self, id):
|
||||
"""Get the RDAP server(s), as an array, for a given identifier. None
|
||||
|
@ -29,8 +29,9 @@ def test_refresh():
|
||||
# Force a resfresh
|
||||
database = ianardap.IanaRDAPDatabase(maxage=0)
|
||||
assert (database.retrieved > (datetime.datetime.now() - datetime.timedelta(minutes=1))) and \
|
||||
((not database.cachefile) or \
|
||||
(datetime.datetime.fromtimestamp(os.path.getmtime(database.cachefile)) > \
|
||||
(datetime.datetime.now() - datetime.timedelta(minutes=1)))
|
||||
(datetime.datetime.now() - datetime.timedelta(minutes=1))))
|
||||
|
||||
def test_find_exists():
|
||||
database = ianardap.IanaRDAPDatabase()
|
||||
|
26
tests.yaml
26
tests.yaml
@ -28,11 +28,11 @@ tests:
|
||||
retcode: 1
|
||||
partstderr: 'ValueError'
|
||||
|
||||
# 2021-07-05: no RDAP server for this TLD
|
||||
# No RDAP server for this TLD
|
||||
- exe: './check_expire'
|
||||
args:
|
||||
- '-H'
|
||||
- 'bie.re'
|
||||
- 'welcome.this-is-not-a-tld'
|
||||
retcode: 3
|
||||
partstdout: 'No RDAP server'
|
||||
|
||||
@ -45,13 +45,13 @@ tests:
|
||||
retcode: 2
|
||||
partstdout: 'No expiration found'
|
||||
|
||||
# Far away and slow, timeout is expected
|
||||
# With a timeout of 1µs, a timeout is expected
|
||||
- exe: './check_expire'
|
||||
args:
|
||||
- '-t'
|
||||
- '1'
|
||||
- '0.000001'
|
||||
- '-H'
|
||||
- 'nic.ar'
|
||||
- 'bortzmeyer.org'
|
||||
retcode: 3
|
||||
partstdout: 'Timeout'
|
||||
|
||||
@ -143,14 +143,14 @@ tests:
|
||||
retcode: 0
|
||||
stderr: ''
|
||||
|
||||
# Iran, expiration date in the past
|
||||
- exe: './check_expire'
|
||||
args:
|
||||
- '-H'
|
||||
- 'nic.pars'
|
||||
retcode: 2
|
||||
partstdout: "already expired"
|
||||
stderr: ''
|
||||
# Iran, expiration date in the past. But down (2024-06-16)
|
||||
#- exe: './check_expire'
|
||||
# args:
|
||||
# - '-H'
|
||||
# - 'nic.pars'
|
||||
# retcode: 2
|
||||
# partstdout: "already expired"
|
||||
# stderr: ''
|
||||
|
||||
# Brazil
|
||||
- exe: './check_expire'
|
||||
|
Loading…
Reference in New Issue
Block a user