diff --git a/lib/vsc/utils/cache.py b/lib/vsc/utils/cache.py index f0c25ae..c5b6025 100644 --- a/lib/vsc/utils/cache.py +++ b/lib/vsc/utils/cache.py @@ -28,18 +28,15 @@ @author: Andy Georges (Ghent University) """ -import gzip -import os +import diskcache as dc import time -import pickle -import jsonpickle -from vsc.utils import fancylogger - -class FileCache: +class FileCache(dc.Cache): """File cache with a timestamp safety. + Wrapper around diskcache to retain the old API until all usage can be replaced. + Stores data (something that can be pickled) into a dictionary indexed by the data.key(). The value stored is a tuple consisting of (the time of addition to the dictionary, the complete @@ -66,52 +63,16 @@ def __init__(self, filename, retain_old=True, raise_unpickable=False): @param filename: (absolute) path to the cache file. """ + del raise_unpickable + + super().__init__(filename) - self.log = fancylogger.getLogger(self.__class__.__name__, fname=False) - self.filename = filename - self.retain_old = retain_old + self.retain_old = retain_old # this is no longer used - self.new_shelf = {} if not retain_old: - self.log.info("Starting with a new empty cache, not retaining previous info if any.") - self.shelf = {} - return - - try: - with open(self.filename, 'rb') as f: - try: - g = gzip.GzipFile(mode='rb', fileobj=f) # no context manager available in python 26 yet - s = g.read() - except (OSError) as _: - self.log.error("Cannot load data from cache file %s as gzipped json", self.filename) - try: - f.seek(0) - self.shelf = pickle.load(f) - except pickle.UnpicklingError as err: - msg = f"Problem loading pickle data from {self.filename} (corrupt data)" - if raise_unpickable: - self.log.raiseException(msg) - else: - self.log.error("%s. Continue with empty shelf: %s", msg, err) - self.shelf = {} - except OSError: - self.log.raiseException("Could not load pickle data from %s", self.filename) - else: - try: - self.shelf = jsonpickle.decode(s) - except ValueError as err: - self.log.error("Cannot decode JSON from %s [%s]", self.filename, err) - self.log.info("Cache in %s starts with an empty shelf", self.filename) - self.shelf = {} - finally: - g.close() - - except (OSError, ValueError, FileNotFoundError) as err: - self.log.warning("Could not access the file cache at %s [%s]", self.filename, err) - self.shelf = {} - self.log.info("Cache in %s starts with an empty shelf", (self.filename,)) - - def update(self, key, data, threshold): + self.clear() + + def update(self, key, data, threshold=None): """Update the given data if the existing data is older than the given threshold. @type key: something that can serve as a dictionary key (and thus can be pickled) @@ -123,18 +84,12 @@ def update(self, key, data, threshold): @param threshold: time in seconds """ now = time.time() - old = self.load(key) - if old: - (ts, _) = old - if now - ts > threshold: - self.new_shelf[key] = (now, data) - return True - else: - self.new_shelf[key] = old - return False + stored = self.set(key=key, value=(now, data), expire=threshold) + + if stored: + return (now, data) else: - self.new_shelf[key] = (now, data) - return True + return (None, None) def load(self, key): """Load the stored data for the given key along with the timestamp it was stored. @@ -143,40 +98,15 @@ def load(self, key): @returns: (timestamp, data) if there is data for the given key, None otherwise. """ - result = None - if self.new_shelf is not None: - result = self.new_shelf.get(key, None) - if result is None and self.shelf is not None: - return self.shelf.get(key, None) - - return result + return self.get(key, default=(None, None)) + @DeprecationWarning def retain(self): """Retain non-updated data on close.""" self.retain_old = True + @DeprecationWarning def discard(self): """Discard non-updated data on close.""" self.retain_old = False - def close(self): - """Close the cache.""" - dirname = os.path.dirname(self.filename) - if not os.path.exists(dirname): - os.makedirs(dirname) - with open(self.filename, 'wb') as fih: - if not fih: - self.log.error('cannot open the file cache at %s for writing', self.filename) - else: - if self.retain_old: - if self.shelf is None: - self.shelf = {} - self.shelf.update(self.new_shelf) - self.new_shelf = self.shelf - - with gzip.GzipFile(mode='wb', fileobj=fih) as zipf: - pickled = jsonpickle.encode(self.new_shelf) - # .encode() is required in Python 3, since we need to pass a bytestring - zipf.write(pickled.encode()) - - self.log.info('closing the file cache at %s', self.filename) diff --git a/lib/vsc/utils/nagios.py b/lib/vsc/utils/nagios.py index 156345d..9ded2d7 100644 --- a/lib/vsc/utils/nagios.py +++ b/lib/vsc/utils/nagios.py @@ -39,6 +39,7 @@ @author: Luis Fernando Muñoz Mejías (Ghent University) """ +import logging import operator import os import pwd @@ -48,12 +49,10 @@ import time from vsc.utils.cache import FileCache -from vsc.utils.fancylogger import getLogger -log = getLogger(__name__) NAGIOS_CACHE_DIR = '/var/cache' -NAGIOS_CACHE_FILENAME_TEMPLATE = '%s.nagios.json.gz' +NAGIOS_CACHE_FILENAME_TEMPLATE = '%s.nagios' NAGIOS_OK = 'OK' NAGIOS_WARNING = 'WARNING' @@ -85,7 +84,7 @@ def _real_exit(message, code, metrics=''): metrics = f'|{message[1]}' if len(msg) > NAGIOS_MAX_MESSAGE_LENGTH: # log long message but print truncated message - log.info("Nagios report %s: %s%s", exit_text, msg, metrics) + logging.info("Nagios report %s: %s%s", exit_text, msg, metrics) msg = msg[:NAGIOS_MAX_MESSAGE_LENGTH-3] + '...' print(f"{exit_text} {msg}{metrics}") @@ -149,20 +148,17 @@ def __init__(self, nrange): @param nrange: nrange in [@][start:][end] format. If it is not a string, it is converted to string and that string should allow conversion to float. """ - self.log = getLogger(self.__class__.__name__, fname=False) - if not isinstance(nrange, str): newnrange = str(nrange) - self.log.debug("nrange %s of type %s, converting to string (%s)", str(nrange), type(nrange), newnrange) + logging.debug("nrange %s of type %s, converting to string (%s)", str(nrange), type(nrange), newnrange) try: float(newnrange) - except ValueError as exc: - msg = ( - f"nrange {str(nrange)} (type {type(nrange)}) is not valid after" - f" conversion to string (newnrange {newnrange})" - ) - self.log.exception(msg) - raise ValueError(msg) from exc + except ValueError: + logging.exception( + "nrange %s (type %s) is not valid after conversion to string (newnrange %s)", + str(nrange), type(nrange), newnrange + ) + raise nrange = newnrange self.range_fn = self.parse(nrange) @@ -175,7 +171,7 @@ def parse(self, nrange): r = reg.search(nrange) if r: res = r.groupdict() - self.log.debug("parse: nrange %s gave %s", nrange, res) + logging.debug("parse: nrange %s gave %s", nrange, res) start_txt = res['start'] if start_txt is None: @@ -185,35 +181,31 @@ def parse(self, nrange): else: try: start = float(start_txt) - except ValueError as exc: - msg = f"Invalid start txt value {start_txt}" - self.log.exception(msg) - raise ValueError(msg) from exc + except ValueError: + logging.exception("Invalid start txt value %s", start_txt) + raise end = res['end'] if end is not None: try: end = float(end) - except ValueError as exc: - msg = f"Invalid end value {end}" - self.log.exception("msg") - raise ValueError(msg) from exc + except ValueError: + logging.exception("Invalid end value %s", end) + raise neg = res['neg'] is not None - self.log.debug("parse: start %s end %s neg %s", start, end, neg) + logging.debug("parse: start %s end %s neg %s", start, end, neg) else: - msg = f"parse: invalid nrange {nrange}." - self.log.Error(msg) - raise ValueError(nrange) + logging.exception('parse: invalid nrange %s.', nrange) + raise def range_fn(test): # test inside nrange? try: test = float(test) - except ValueError as exc: - msg = f"range_fn: can't convert test {test} (type {type(test)}) to float" - self.log.exception(msg) - raise ValueError(msg) from exc + except ValueError: + logging.exception("range_fn: can't convert test %s (type %s) to float", test, type(test)) + raise start_res = True # default: -inf < test if start is not None: @@ -229,7 +221,7 @@ def range_fn(test): if neg: tmp_res = operator.not_(tmp_res) - self.log.debug("range_fn: test %s start_res %s end_res %s result %s (neg %s)", + logging.debug("range_fn: test %s start_res %s end_res %s result %s (neg %s)", test, start_res, end_res, tmp_res, neg) return tmp_res @@ -271,27 +263,27 @@ def __init__(self, header, filename, threshold, nagios_username="nagios", world_ self.nagios_username = nagios_username - self.log = getLogger(self.__class__.__name__, fname=False) - def report_and_exit(self): - """Unzips the cache file and reads the JSON data back in, prints the data and exits accordingly. + """Reads the cache, prints the data and exits accordingly. If the cache data is too old (now - cache timestamp > self.threshold), a critical exit is produced. """ try: - nagios_cache = FileCache(self.filename, True) - except OSError: - self.log.critical("Error opening file %s for reading", self.filename) - unknown_exit(f"{self.header} nagios gzipped JSON file unavailable ({self.filename})") + nagios_cache = FileCache(self.filename) + except (IOError, OSError): + logging.critical("Error opening file %s for reading", self.filename) + unknown_exit("%s nagios cache unavailable (%s)" % (self.header, self.filename)) - (timestamp, ((nagios_exit_code, nagios_exit_string), nagios_message)) = nagios_cache.load('nagios') + (_, nagios_exit_info) = nagios_cache.load('nagios') + + if nagios_exit_info is None: + unknown_exit("%s nagios exit info expired" % self.header) + + ((nagios_exit_code, nagios_exit_string), nagios_message) = nagios_exit_info + + print("%s %s" % (nagios_exit_string, nagios_message)) + sys.exit(nagios_exit_code) - if self.threshold <= 0 or time.time() - timestamp < self.threshold: - self.log.info("Nagios check cache file %s contents delivered: %s", self.filename, nagios_message) - print(f"{nagios_exit_string} {nagios_message}") - sys.exit(nagios_exit_code) - else: - unknown_exit(f"{self.header} gzipped JSON file too old (timestamp = {time.ctime(timestamp)})") def cache(self, nagios_exit, nagios_message): """Store the result in the cache file with a timestamp. @@ -304,32 +296,38 @@ def cache(self, nagios_exit, nagios_message): """ try: nagios_cache = FileCache(self.filename) - nagios_cache.update('nagios', (nagios_exit, nagios_message), 0) # always update + nagios_cache.update('nagios', (nagios_exit, nagios_message), threshold=self.threshold) nagios_cache.close() - self.log.info("Wrote nagios check cache file %s at about %s", self.filename, time.ctime(time.time())) - except OSError as exc: + logging.info("Wrote nagios check cache file %s at about %s", self.filename, time.ctime(time.time())) + except (IOError, OSError): # raising an error is ok, since we usually do this as the very last thing in the script - msg = f"Cannot save to the nagios gzipped JSON file ({self.filename})" - self.log.exception(msg) - raise OSError(msg) from exc + logging.error("Cannot save to the nagios cache (%s)", self.filename) + raise try: p = pwd.getpwnam(self.nagios_username) if self.world_readable: - os.chmod(self.filename, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH) + os.chmod( + self.filename, + stat.S_IRUSR | stat.S_IWUSR | + stat.S_IRGRP | stat.S_IWGRP | stat.S_IROTH | + stat.S_IXUSR | stat.S_IXGRP + ) else: - os.chmod(self.filename, stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP) + os.chmod( + self.filename, + stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IWGRP | stat.S_IXUSR | stat.S_IXGRP + ) # only change owner/group when run as root if os.geteuid() == 0: os.chown(self.filename, p.pw_uid, p.pw_gid) else: - self.log.warning("Not running as root: Cannot chown the nagios check file %s to %s", + logging.warning("Not running as root: Cannot chown the nagios check file %s to %s", self.filename, self.nagios_username) - except (OSError, FileNotFoundError) as exc: - msg = f"Cannot chown the nagios check file {self.filename} to the nagios user" - self.log.exception(msg) - raise(OSError(msg)) from exc + except (OSError, FileNotFoundError): + logging.error("Cannot chown the nagios check file %s to the nagios user", self.filename) + raise return True @@ -454,7 +452,7 @@ def __init__(self, **kwargs): self._final = None self._final_state = None - self._threshold = 0 + self._threshold = None self._report_and_exit = False self._world_readable = False diff --git a/lib/vsc/utils/script_tools.py b/lib/vsc/utils/script_tools.py index d32bd35..62801b5 100644 --- a/lib/vsc/utils/script_tools.py +++ b/lib/vsc/utils/script_tools.py @@ -37,7 +37,6 @@ from copy import deepcopy import logging -from vsc.utils import fancylogger from vsc.utils.availability import proceed_on_ha_service from vsc.utils.generaloption import SimpleOption from vsc.utils.lock import lock_or_bork, release_or_bork, LOCKFILE_DIR, LOCKFILE_FILENAME_TEMPLATE @@ -136,8 +135,6 @@ def __init__(self, options, run_prologue=True, excepthook=None, **kwargs): else: sys.excepthook = excepthook - self.log = fancylogger.getLogger() - def prologue(self): """Checks the options given for settings and takes appropriate action. @@ -159,7 +156,7 @@ def prologue(self): # check for HA host if self.options.ha and not proceed_on_ha_service(self.options.ha): - self.log.warning("Not running on the target host %s in the HA setup. Stopping.", self.options.ha) + logging.warning("Not running on the target host %s in the HA setup. Stopping.", self.options.ha) self.nagios_reporter.ok("Not running on the HA master.") sys.exit(NAGIOS_EXIT_OK) @@ -169,7 +166,7 @@ def prologue(self): ) lock_or_bork(self.lockfile, self.nagios_reporter) - self.log.info("%s has started", _script_name(sys.argv[0])) + logging.info("%s has started", _script_name(sys.argv[0])) def _epilogue(self): if not self.options.disable_locking and not self.options.dry_run: @@ -184,7 +181,7 @@ def epilogue(self, nagios_message, nagios_thresholds=None): nagios_thresholds["message"] = nagios_message self.nagios_reporter._eval_and_exit(**nagios_thresholds) - self.log.info("%s has finished", _script_name(sys.argv[0])) # may not be reached + logging.info("%s has finished", _script_name(sys.argv[0])) # may not be reached def ok(self, nagios_message): """Run at the end of a script and force an OK exit.""" @@ -221,9 +218,9 @@ def critical_exception_handler(self, tp, value, traceback): This function is meant to be used as sys.excepthook """ - self.log.exception("unhandled exception detected: %s - %s", tp, value) - self.log.debug("traceback %s", traceback) - message = f"Script failure: {tp} - {value}" + logging.exception("unhandled exception detected: %s - %s", tp, value) + logging.debug("traceback %s", traceback) + message = "Script failure: %s - %s" % (tp, value) self.critical(message) diff --git a/setup.py b/setup.py index 0d80ea1..9de0e77 100755 --- a/setup.py +++ b/setup.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -## -# Copyright 2012-2020 Ghent University +# +# Copyright 2012-2023 Ghent University # # This file is part of vsc-utils, # originally created by the HPC team of Ghent University (http://ugent.be/hpc/en), @@ -9,7 +9,7 @@ # the Flemish Research Foundation (FWO) (http://www.fwo.be/en) # and the Department of Economy, Science and Innovation (EWI) (http://www.ewi-vlaanderen.be/en). # -# http://github.com/hpcugent/vsc-utils +# https://github.com/hpcugent/vsc-utils # # vsc-utils is free software: you can redistribute it and/or modify # it under the terms of the GNU Library General Public License as @@ -23,7 +23,7 @@ # # You should have received a copy of the GNU Library General Public License # along with vsc-utils. If not, see . -## +# """ vsc-utils base distribution setup.py @@ -38,6 +38,7 @@ 'lockfile >= 0.9.1', 'netifaces', 'jsonpickle', + 'diskcache', ] PACKAGE = { diff --git a/test/cache.py b/test/cache.py index 3d96a10..34779a1 100644 --- a/test/cache.py +++ b/test/cache.py @@ -38,6 +38,7 @@ import random import mock +from pathlib import PurePath from vsc.install.testing import TestCase from vsc.utils.cache import FileCache @@ -61,9 +62,7 @@ def test_contents(self): data, threshold = get_rand_data() # create a tempfilename - (handle, filename) = tempfile.mkstemp(dir='/tmp') - os.unlink(filename) - os.close(handle) + filename = PurePath("/tmp") / next(tempfile._get_candidate_names()) cache = FileCache(filename) for (key, value) in data.items(): cache.update(key, value, threshold) @@ -72,62 +71,31 @@ def test_contents(self): for key, content in data.items(): info = cache.load(key) self.assertFalse(info is None) - (ts, value) = info - self.assertTrue(value == content) + ts, value = info + self.assertTrue(value == data[key]) self.assertTrue(ts <= now) def test_save_and_load(self): """Check if the loaded data is the same as the saved data.""" # test with random data data, threshold = get_rand_data() - tempdir = tempfile.mkdtemp() - # create a tempfilename - (handle, filename) = tempfile.mkstemp(dir=tempdir) - os.close(handle) - shutil.rmtree(tempdir) + + filename = PurePath("/tmp") / next(tempfile._get_candidate_names()) cache = FileCache(filename) + for (key, value) in data.items(): cache.update(key, value, threshold) cache.close() now = time.time() new_cache = FileCache(filename) - for key, content in data.items(): - info = cache.load(key) + for key in data.keys(): + info = new_cache.load(key) self.assertTrue(info is not None) (ts, value) = info self.assertTrue(value == content) self.assertTrue(ts <= now) new_cache.close() - shutil.rmtree(tempdir) - - def test_corrupt_gz_cache(self): - """Test to see if we can handle a corrupt cache file""" - tempdir = tempfile.mkdtemp() - # create a tempfilename - (handle, filename) = tempfile.mkstemp(dir=tempdir) - f = os.fdopen(handle, 'w') - f.write('blabla;not gz') - f.close() - FileCache(filename) - shutil.rmtree(tempdir) - - @mock.patch('vsc.utils.cache.jsonpickle.decode') - def test_value_error(self, mock_decode): - "Test to see that a ValueError upon decoding gets caught correctly" - tempdir = tempfile.mkdtemp() - # create a tempfilename - (handle, filename) = tempfile.mkstemp(dir=tempdir) - f = os.fdopen(handle, 'wb') - g = gzip.GzipFile(mode='wb', fileobj=f) - g.write(b'blabla no json gzip stuffz') - g.close() - - e = ValueError('unable to find valid JSON') - mock_decode.side_effect = e - - fc = FileCache(filename) + shutil.rmtree(filename) - self.assertTrue(fc.shelf == {}) - shutil.rmtree(tempdir) diff --git a/test/nagios.py b/test/nagios.py index 72e573c..8e3e36e 100644 --- a/test/nagios.py +++ b/test/nagios.py @@ -28,15 +28,19 @@ @author: Andy Georges (Ghent University) """ +import logging import os import tempfile import time import sys import random +import shutil import string +import tempfile from pwd import getpwuid from io import StringIO +from pathlib import PurePath from vsc.install.testing import TestCase from vsc.utils.nagios import NagiosReporter, SimpleNagios @@ -64,49 +68,48 @@ def test_eval(self): def test_cache(self): """Test the caching mechanism in the reporter.""" - length = random.randint(1, 30) - exit_code = random.randint(0, 3) - threshold = random.randint(0, 10) + message = "huppeldepup a test string" - message = ''.join(random.choice(string.printable) for x in range(length)) - message = message.rstrip() + threshold = None + filename = PurePath(next(tempfile._get_candidate_names())) - (handle, filename) = tempfile.mkstemp() - os.unlink(filename) - os.close(handle) + logging.info(f"Reporter using file {filename}") reporter = NagiosReporter('test_cache', filename, threshold, self.nagios_user) - nagios_exit = [NAGIOS_EXIT_OK, NAGIOS_EXIT_WARNING, NAGIOS_EXIT_CRITICAL, NAGIOS_EXIT_UNKNOWN][exit_code] + for exit_code in range(0, 4): - reporter.cache(nagios_exit, message) + nagios_exit = [NAGIOS_EXIT_OK, NAGIOS_EXIT_WARNING, NAGIOS_EXIT_CRITICAL, NAGIOS_EXIT_UNKNOWN][exit_code] + logging.info("Caching the exit: %s", nagios_exit) + reporter.cache(nagios_exit, message) - (handle, _) = tempfile.mkstemp() - os.close(handle) - - old_stdout = sys.stdout - try: + old_stdout = sys.stdout buffer = StringIO() sys.stdout = buffer - reporter_test = NagiosReporter('test_cache', filename, threshold, self.nagios_user) - reporter_test.report_and_exit() - except SystemExit as err: - line = buffer.getvalue().rstrip() + + try: + reporter_test = NagiosReporter('test_cache', filename, threshold, self.nagios_user) + reporter_test.report_and_exit() + except SystemExit as err: + line = buffer.getvalue().rstrip() + logging.info("Retrieved buffer value: %s", line) + logging.info("Retrieved exit code: %s", err.code) + logging.info("Expected exit value: %s", nagios_exit) + self.assertTrue(err.code == exit_code) + self.assertTrue(line == "%s %s" % (nagios_exit[1], message)) + sys.stdout = old_stdout buffer.close() - self.assertTrue(err.code == nagios_exit[0]) - self.assertTrue(line == f"{nagios_exit[1]} {message}") - os.unlink(filename) + shutil.rmtree(filename) def test_threshold(self, message="Hello"): """Test the threshold borking mechanism in the reporter.""" message = message.rstrip() - threshold = 1 + threshold = 2 if message == '': return - (handle, filename) = tempfile.mkstemp() - os.unlink(filename) + filename = PurePath(next(tempfile._get_candidate_names())) reporter = NagiosReporter('test_cache', filename, threshold, self.nagios_user) # redirect stdout @@ -116,11 +119,10 @@ def test_threshold(self, message="Hello"): nagios_exit = NAGIOS_EXIT_OK reporter.cache(nagios_exit, message) - os.close(handle) raised_exception = None + reporter_test = NagiosReporter('test_cache', filename, threshold, self.nagios_user) try: - reporter_test = NagiosReporter('test_cache', filename, threshold, self.nagios_user) reporter_test.report_and_exit() except SystemExit as err: raised_exception = err @@ -128,19 +130,13 @@ def test_threshold(self, message="Hello"): "Exit with status when the cached data is recent") # restore stdout buff.close() - sys.stdout = old_stdout - reporter = NagiosReporter('test_cache', filename, threshold, self.nagios_user) - reporter.cache(nagios_exit, message) time.sleep(threshold + 1) - # redirect stdout - old_stdout = sys.stdout buff = StringIO() sys.stdout = buff - raised_exception = None + reporter_test = NagiosReporter('test_cache', filename, threshold, self.nagios_user) try: - reporter_test = NagiosReporter('test_cache', filename, threshold, self.nagios_user) reporter_test.report_and_exit() except SystemExit as err: raised_exception = err @@ -151,6 +147,7 @@ def test_threshold(self, message="Hello"): sys.stdout = old_stdout self.assertEqual(raised_exception.code, NAGIOS_EXIT_UNKNOWN[0], "Too old caches lead to unknown status") - self.assertTrue(line.startswith(f"{NAGIOS_EXIT_UNKNOWN[1]} test_cache gzipped JSON file too old (timestamp =")) + self.assertTrue(line.startswith("%s test_cache nagios exit info expired" % (NAGIOS_EXIT_UNKNOWN[1]))) + + shutil.rmtree(filename) - os.unlink(filename) diff --git a/test/nagios_simple.py b/test/nagios_simple.py index c973d75..bf65a4c 100644 --- a/test/nagios_simple.py +++ b/test/nagios_simple.py @@ -28,12 +28,15 @@ @author: Stijn De Weirdt (Ghent University) """ +import logging import os import tempfile +import shutil import sys import stat from pwd import getpwuid from io import StringIO +from pathlib import PurePath from vsc.install.testing import TestCase @@ -157,31 +160,36 @@ def test_simple_nagios_instance_and_nagios_exit(self): def test_cache(self): """Test the caching""" - (handle, filename) = tempfile.mkstemp() - os.unlink(filename) + message = "huppeldepup a test string" + + threshold = None + filename = PurePath(next(tempfile._get_candidate_names())) - n = SimpleNagios(_cache=filename, _cache_user=self.nagios_user) + logging.info(f"Reporter using file {filename}") + simple_nagios = SimpleNagios(_cache=filename, _cache_user=self.nagios_user) message = "mywarning" - n.warning(message) - os.close(handle) + simple_nagios.warning(message) - self.buffo.seek(0) - self.buffo.truncate(0) + old_stdout = sys.stdout + buffer = StringIO() + sys.stdout = buffer - raised_exception = None + reporter_test = NagiosReporter('test_cache', filename, threshold, self.nagios_user) try: - reporter_test = NagiosReporter('test_cache', filename, -1, self.nagios_user) reporter_test.report_and_exit() except SystemExit as err: - raised_exception = err - bo = self.buffo.getvalue().rstrip() + line = buffer.getvalue().rstrip() + logging.info("Retrieved buffer value: %s", line) + logging.info("Retrieved exit code: %s", err.code) + logging.info("Expected exit value: %s", (NAGIOS_EXIT_WARNING[0], NAGIOS_EXIT_WARNING[1])) + self.assertTrue(err.code == 1) + self.assertTrue(line == "%s %s" % ("WARNING", message)) - self.assertEqual(bo, f"WARNING {message}") - self.assertEqual(raised_exception.code, NAGIOS_EXIT_WARNING[0]) + sys.stdout = old_stdout + buffer.close() - statres = os.stat(filename) + shutil.rmtree(filename) - self.assertFalse(statres.st_mode & stat.S_IROTH) def test_world_readable(self): """Test world readable cache""" diff --git a/test/script_tools.py b/test/script_tools.py index 7bb19ee..aa745e4 100644 --- a/test/script_tools.py +++ b/test/script_tools.py @@ -30,6 +30,7 @@ """ import logging +import os import random import sys import tempfile @@ -107,8 +108,8 @@ def do(self, _): class MyCLI(CLI): TIMESTAMP_MANDATORY = False # mainly for testing, you really should need this in production - TESTFILE = tempfile.mkstemp()[1] - TESTFILE2 = tempfile.mkstemp()[1] + TESTFILE = os.path.join("/tmp", next(tempfile._get_candidate_names())) + TESTFILE2 = os.path.join("/tmp", next(tempfile._get_candidate_names())) CLI_OPTIONS = { 'magic': ('some magic', None, 'store', 'magicdef'), @@ -139,7 +140,7 @@ def test_opts(self, _): 'ignoreconfigfiles': None, 'info': False, 'locking_filename': '/var/lock/setup.lock', - 'nagios_check_filename': '/var/cache/setup.nagios.json.gz', + 'nagios_check_filename': '/var/cache/setup.nagios', 'nagios_check_interval_threshold': 0, 'nagios_report': False, 'nagios_user': 'nrpe',