Allow a specific cache directory or no cache
If the env var XDG_CACHE_HOME is set, the cache directory is "$XDG_CACHE_HOME/ianardap", else if HOME is set, it is "$HOME/.ianardapcaches", else no cache is used but a loud warning is displayed at the end of the result to encourage users to set a cache directory. Adapted pytest tests, no change needed on test_exe_matrix. They are obviously slower with no cache. NB: two tests now fail independently of this change. Issue: #4
This commit is contained in:
parent
b3709c64e9
commit
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.
|
||||
|
@ -53,6 +53,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))
|
||||
|
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()
|
||||
|
Loading…
Reference in New Issue
Block a user