Compare commits

..

No commits in common. "master" and "master" have entirely different histories.

6 changed files with 39 additions and 66 deletions

1
.gitignore vendored
View File

@ -1 +0,0 @@
__pycache__/

View File

@ -19,8 +19,6 @@ 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:
@ -37,7 +35,6 @@ object CheckCommand "expiration" {
"-v" = { set_if = "$expiration_verbose$" }
}
env.XDG_CACHE_HOME = "/var/cache/nagios"
}
apply Service "expiration" {
@ -63,13 +60,6 @@ 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.

View File

@ -45,9 +45,6 @@ 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 != "":
@ -56,8 +53,6 @@ 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))
@ -106,7 +101,7 @@ try:
elif option == "--hostname" or option == "-H":
domain = value
elif option == "--timeout" or option == "-t":
timeout = float(value)
timeout = int(value)
elif option == "--unixtime" or option == "-u":
unixtime = True
elif option == "--verbose" or option == "-v":
@ -147,7 +142,6 @@ 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)

View File

@ -21,8 +21,7 @@ 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["XDG_CACHE_HOME"] + "/ianardap" if "XDG_CACHE_HOME" in os.environ else \
(os.environ["HOME"] + "/.ianardapcaches" if "HOME" in os.environ else None)
CACHE = os.environ["HOME"] + "/.ianardapcaches"
MAXAGE = 24 # Hours. Used only if the server no longer gives the information.
IANATIMEOUT = 10 # Seconds
MAXTESTS = 3 # Maximum attempts to get the database
@ -61,33 +60,28 @@ file (see the documentation of the module).
"""
cache_valid = False
if not os.path.exists(cachedir):
os.mkdir(cachedir)
self.category = category
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"
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:
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))
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))
loaded = False
tests = 0
errmsg = "No error"
while not loaded and tests < MAXTESTS:
self.lock()
if self.cachefile and os.path.exists(self.cachefile) and \
if os.path.exists(self.cachefile) and \
(pathlib.Path(self.expirationfile).exists() and \
datetime.datetime.fromtimestamp(os.path.getmtime(self.expirationfile)) > \
datetime.datetime.now()):
@ -145,10 +139,9 @@ file (see the documentation of the module).
try:
content = response.content
database = json.loads(content)
if self.expirationfile:
with open(self.expirationfile, 'w'):
os.utime(self.expirationfile,
times = (self.expirationtime, self.expirationtime))
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
@ -180,7 +173,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 self.cachefile and not cache_valid:
if not cache_valid:
self.lock()
cache = open(self.cachefile, "wb")
if pickleformat:
@ -191,14 +184,12 @@ file (see the documentation of the module).
self.unlock()
def lock(self):
if self.lockname:
self.lockhandle = open(self.lockname, 'w')
fcntl.lockf(self.lockhandle, fcntl.LOCK_EX)
self.lockhandle = open(self.lockname, 'w')
fcntl.lockf(self.lockhandle, fcntl.LOCK_EX)
def unlock(self):
if self.lockname:
fcntl.lockf(self.lockhandle, fcntl.LOCK_UN)
self.lockhandle.close()
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

View File

@ -29,9 +29,8 @@ 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()

View File

@ -28,11 +28,11 @@ tests:
retcode: 1
partstderr: 'ValueError'
# No RDAP server for this TLD
# 2021-07-05: no RDAP server for this TLD
- exe: './check_expire'
args:
- '-H'
- 'welcome.this-is-not-a-tld'
- 'bie.re'
retcode: 3
partstdout: 'No RDAP server'
@ -45,13 +45,13 @@ tests:
retcode: 2
partstdout: 'No expiration found'
# With a timeout of 1µs, a timeout is expected
# Far away and slow, timeout is expected
- exe: './check_expire'
args:
- '-t'
- '0.000001'
- '1'
- '-H'
- 'bortzmeyer.org'
- 'nic.ar'
retcode: 3
partstdout: 'Timeout'
@ -143,14 +143,14 @@ tests:
retcode: 0
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: ''
# Iran, expiration date in the past
- exe: './check_expire'
args:
- '-H'
- 'nic.pars'
retcode: 2
partstdout: "already expired"
stderr: ''
# Brazil
- exe: './check_expire'