From 0fec85c4a8724cc523aad2e63662864f68bd4d13 Mon Sep 17 00:00:00 2001 From: Tristan Michelet Date: Wed, 17 Feb 2016 23:48:36 +0000 Subject: [PATCH] [Config] Update config logic to look for checks in 3rd-party directory - add tests on the config logic - refactor the logic - add some logic to add for checks in 3rd-party folder -- We are starting to install checks in the 3rd-party folder. Let the agent use these checks. Priority should be: - /etc/dd-agent/checks.d/ - /opt/datadog-agent/3rd-party/ - /opt/datadog-agent/agent/checks.d/ --- config.py | 285 ++++++++++-------- tests/core/fixtures/checks/__init__.py | 0 tests/core/fixtures/checks/invalid_check_1.py | 2 + tests/core/fixtures/checks/invalid_check_2.py | 4 + tests/core/fixtures/checks/invalid_conf.yaml | 1 + tests/core/fixtures/checks/valid_check_1.py | 8 + tests/core/fixtures/checks/valid_check_2.py | 8 + tests/core/fixtures/checks/valid_conf.yaml | 4 + tests/core/fixtures/checks/valid_conf_2.yaml | 5 + tests/core/fixtures/checks/valid_sub_check.py | 8 + tests/core/test_config.py | 160 +++++++++- 11 files changed, 359 insertions(+), 126 deletions(-) create mode 100644 tests/core/fixtures/checks/__init__.py create mode 100644 tests/core/fixtures/checks/invalid_check_1.py create mode 100644 tests/core/fixtures/checks/invalid_check_2.py create mode 100644 tests/core/fixtures/checks/invalid_conf.yaml create mode 100644 tests/core/fixtures/checks/valid_check_1.py create mode 100644 tests/core/fixtures/checks/valid_check_2.py create mode 100644 tests/core/fixtures/checks/valid_conf.yaml create mode 100644 tests/core/fixtures/checks/valid_conf_2.yaml create mode 100644 tests/core/fixtures/checks/valid_sub_check.py diff --git a/config.py b/config.py index 3f15f5bfd2..b1444acd1f 100644 --- a/config.py +++ b/config.py @@ -30,7 +30,6 @@ SubprocessOutputEmptyError, ) - # CONSTANTS AGENT_VERSION = "5.8.0" DATADOG_CONF = "datadog.conf" @@ -677,6 +676,18 @@ def get_checksd_path(osname=None): else: return _unix_checksd_path() +def get_3rd_party_path(osname=None): + if not osname: + osname = get_os() + if osname in ['windows', 'mac']: + raise PathNotFound() + + cur_path = os.path.dirname(os.path.realpath(__file__)) + path = os.path.join(cur_path, '../3rd-party') + if os.path.exists(path): + return path + raise PathNotFound(path) + def get_win32service_file(osname, filename): # This file is needed to log in the event viewer for windows @@ -743,157 +754,189 @@ def check_yaml(conf_path): else: return check_config -def load_check_directory(agentConfig, hostname): - ''' Return the initialized checks from checks.d, and a mapping of checks that failed to - initialize. Only checks that have a configuration - file in conf.d will be returned. ''' - from checks import AgentCheck, AGENT_METRICS_CHECK_NAME - - initialized_checks = {} - init_failed_checks = {} +def _deprecated_configs(agentConfig): + """ Warn about deprecated configs + """ deprecated_checks = {} - agentConfig['checksd_hostname'] = hostname - deprecated_configs_enabled = [v for k,v in OLD_STYLE_PARAMETERS if len([l for l in agentConfig if l.startswith(k)]) > 0] for deprecated_config in deprecated_configs_enabled: msg = "Configuring %s in datadog.conf is not supported anymore. Please use conf.d" % deprecated_config deprecated_checks[deprecated_config] = {'error': msg, 'traceback': None} log.error(msg) + return deprecated_checks - osname = get_os() - checks_paths = [glob.glob(os.path.join(agentConfig['additional_checksd'], '*.py'))] - +def _all_configs_paths(osname, agentConfig): + """ Retrieve all configs and return their paths + """ try: - checksd_path = get_checksd_path(osname) - checks_paths.append(glob.glob(os.path.join(checksd_path, '*.py'))) + confd_path = get_confd_path(osname) + all_configs = glob.glob(os.path.join(confd_path, '*.yaml')) + all_default_configs = glob.glob(os.path.join(confd_path, '*.yaml.default')) except PathNotFound, e: - log.error(e.args[0]) + log.error("No conf.d folder found at '%s' or in the directory where the Agent is currently deployed.\n" % e.args[0]) sys.exit(3) + if all_default_configs: + current_configs = set([_conf_path_to_check_name(conf) for conf in all_configs]) + for default_config in all_default_configs: + if not _conf_path_to_check_name(default_config) in current_configs: + all_configs.append(default_config) + + # Compatibility code for the Nagios checks if it's still configured + # in datadog.conf + # FIXME: 6.x, should be removed + if not any('nagios' in config for config in itertools.chain(*all_configs)): + # check if it's configured in datadog.conf the old way + if any([nagios_key in agentConfig for nagios_key in NAGIOS_OLD_CONF_KEYS]): + all_configs.append('deprecated/nagios') + + return all_configs + +def _conf_path_to_check_name(conf_path): + return conf_path.rsplit('/', 1)[-1].split('.yaml')[0] + +def _checks_places(agentConfig, osname): + """ Return methods to generated paths to inspect for a check provided it's name + """ try: - confd_path = get_confd_path(osname) + checksd_path = get_checksd_path(osname) except PathNotFound, e: - log.error("No conf.d folder found at '%s' or in the directory where the Agent is currently deployed.\n" % e.args[0]) + log.error(e.args[0]) sys.exit(3) - # We don't support old style configs anymore - # So we iterate over the files in the checks.d directory - # If there is a matching configuration file in the conf.d directory - # then we import the check - for check in itertools.chain(*checks_paths): - check_name = os.path.basename(check).split('.')[0] - check_config = None - if check_name in initialized_checks or check_name in init_failed_checks: - log.debug('Skipping check %s because it has already been loaded from another location', check) - continue + places = [lambda name: os.path.join(agentConfig['additional_checksd'], '%s.py' % name)] - # Let's see if there is a conf.d for this check - conf_path = os.path.join(confd_path, '%s.yaml' % check_name) - conf_exists = False + try: + third_party_path = get_3rd_party_path(osname) + places.append(lambda name: os.path.join(third_party_path, name, 'check.py')) + except PathNotFound: + log.debug('No 3rd-party path found') - if os.path.exists(conf_path): - conf_exists = True - else: - log.debug("No configuration file for %s. Looking for defaults" % check_name) + places.append(lambda name: os.path.join(checksd_path, '%s.py' % name)) + return places - # Default checks read their config from the "[CHECKNAME].yaml.default" file - default_conf_path = os.path.join(confd_path, '%s.yaml.default' % check_name) - if not os.path.exists(default_conf_path): - log.debug("Default configuration file {0} is missing. Skipping check".format(default_conf_path)) - continue - conf_path = default_conf_path - conf_exists = True +def _validate_config(config_path, check_name, agentConfig): - if conf_exists: - try: - check_config = check_yaml(conf_path) - except Exception, e: - log.exception("Unable to parse yaml config in %s" % conf_path) - traceback_message = traceback.format_exc() - init_failed_checks[check_name] = {'error': str(e), 'traceback': traceback_message} + if config_path == 'deprecated/nagios': + log.warning("Configuring Nagios in datadog.conf is deprecated " + "and will be removed in a future version. " + "Please use conf.d") + check_config = {'instances':[dict((key, value) for (key, value) in agentConfig.iteritems() if key in NAGIOS_OLD_CONF_KEYS)]} + return True, check_config, {} + + try: + check_config = check_yaml(config_path) + except Exception, e: + log.exception("Unable to parse yaml config in %s" % config_path) + traceback_message = traceback.format_exc() + return False, None, {check_name: {'error': str(e), 'traceback': traceback_message}} + return True, check_config, {} + +def _validate_check(check_name, check_path): + from checks import AgentCheck + # Let's try to import the check + try: + check_module = imp.load_source('checksd_%s' % check_name, check_path) + except Exception, e: + traceback_message = traceback.format_exc() + # There is a configuration file for that check but the module can't be imported + log.exception('Unable to import check module %s.py from checks.d' % check_name) + return False, None, {check_name: {'error':e, 'traceback':traceback_message}} + + # We make sure that there is an AgentCheck class defined + check_class = None + classes = inspect.getmembers(check_module, inspect.isclass) + for _, clsmember in classes: + if clsmember == AgentCheck: + continue + if issubclass(clsmember, AgentCheck): + check_class = clsmember + if AgentCheck in clsmember.__bases__: continue - else: - # Compatibility code for the Nagios checks if it's still configured - # in datadog.conf - # FIXME: 6.x, should be removed - if check_name == 'nagios': - if any([nagios_key in agentConfig for nagios_key in NAGIOS_OLD_CONF_KEYS]): - log.warning("Configuring Nagios in datadog.conf is deprecated " - "and will be removed in a future version. " - "Please use conf.d") - check_config = {'instances':[dict((key, agentConfig[key]) for key in agentConfig if key in NAGIOS_OLD_CONF_KEYS)]} - else: - continue else: - log.debug("No configuration file for %s" % check_name) - continue + break - # If we are here, there is a valid matching configuration file. - # Let's try to import the check + if not check_class: + log.error('No check class (inheriting from AgentCheck) found in %s.py' % check_name) + return False, None, {} + return True, check_class, {} + +def _initialize_check(check_config, check_name, check_class, agentConfig): + init_config = check_config.get('init_config') or {} + instances = check_config['instances'] + try: try: - check_module = imp.load_source('checksd_%s' % check_name, check) - except Exception, e: - traceback_message = traceback.format_exc() - # There is a configuration file for that check but the module can't be imported - init_failed_checks[check_name] = {'error':e, 'traceback':traceback_message} - log.exception('Unable to import check module %s.py from checks.d' % check_name) - continue + check = check_class(check_name, init_config=init_config, + agentConfig=agentConfig, instances=instances) + except TypeError, e: + # Backwards compatibility for checks which don't support the + # instances argument in the constructor. + check = check_class(check_name, init_config=init_config, + agentConfig=agentConfig) + check.instances = instances + except Exception, e: + log.exception('Unable to initialize check %s' % check_name) + traceback_message = traceback.format_exc() + return {}, {check_name: {'error':e, 'traceback':traceback_message}} + else: + return {check_name: check}, {} - # We make sure that there is an AgentCheck class defined - check_class = None - classes = inspect.getmembers(check_module, inspect.isclass) - for _, clsmember in classes: - if clsmember == AgentCheck: - continue - if issubclass(clsmember, AgentCheck): - check_class = clsmember - if AgentCheck in clsmember.__bases__: - continue - else: - break +def _update_python_path(check_config): + # Add custom pythonpath(s) if available + if 'pythonpath' in check_config: + pythonpath = check_config['pythonpath'] + if not isinstance(pythonpath, list): + pythonpath = [pythonpath] + sys.path.extend(pythonpath) - if not check_class: - log.error('No check class (inheriting from AgentCheck) found in %s.py' % check_name) - continue +def load_check_directory(agentConfig, hostname): + ''' Return the initialized checks from checks.d, and a mapping of checks that failed to + initialize. Only checks that have a configuration + file in conf.d will be returned. ''' + from checks import AGENT_METRICS_CHECK_NAME + + initialized_checks = {} + init_failed_checks = {} + deprecated_checks = {} + agentConfig['checksd_hostname'] = hostname + osname = get_os() + + deprecated_checks.update(_deprecated_configs(agentConfig)) - # Look for the per-check config, which *must* exist - if not check_config.get('instances'): - log.error("Config %s is missing 'instances'" % conf_path) + all_configs_paths = _all_configs_paths(osname, agentConfig) + + checks_places = _checks_places(agentConfig, osname) + + for config_path in all_configs_paths: + # '/etc/dd-agent/checks.d/my_check.py' -> 'my_check' + check_name = _conf_path_to_check_name(config_path) + + conf_is_valid, check_config, invalid_check = _validate_config(config_path, check_name, agentConfig) + init_failed_checks.update(invalid_check) + if not conf_is_valid: continue - # Init all of the check's classes with - init_config = check_config.get('init_config', {}) - # init_config: in the configuration triggers init_config to be defined - # to None. - if init_config is None: - init_config = {} + # find check + for check_path_builder in checks_places: + check_path = check_path_builder(check_name) + if not os.path.exists(check_path): + continue - instances = check_config['instances'] - try: - try: - c = check_class(check_name, init_config=init_config, - agentConfig=agentConfig, instances=instances) - except TypeError, e: - # Backwards compatibility for checks which don't support the - # instances argument in the constructor. - c = check_class(check_name, init_config=init_config, - agentConfig=agentConfig) - c.instances = instances - except Exception, e: - log.exception('Unable to initialize check %s' % check_name) - traceback_message = traceback.format_exc() - init_failed_checks[check_name] = {'error':e, 'traceback':traceback_message} - else: - initialized_checks[check_name] = c + check_is_valid, check_class, invalid_check = _validate_check(check_name, check_path) + init_failed_checks.update(invalid_check) + if not check_is_valid: + continue + + init_success, init_failed = _initialize_check( + check_config, check_name, check_class, agentConfig + ) + initialized_checks.update(init_success) + init_failed_checks.update(init_failed) - # Add custom pythonpath(s) if available - if 'pythonpath' in check_config: - pythonpath = check_config['pythonpath'] - if not isinstance(pythonpath, list): - pythonpath = [pythonpath] - sys.path.extend(pythonpath) + _update_python_path(check_config) - log.debug('Loaded check.d/%s.py' % check_name) + log.debug('Loaded %s' % check_path) + break # we succesfully initialized this check, let's go to next config init_failed_checks.update(deprecated_checks) log.info('initialized checks.d checks: %s' % [k for k in initialized_checks.keys() if k != AGENT_METRICS_CHECK_NAME]) diff --git a/tests/core/fixtures/checks/__init__.py b/tests/core/fixtures/checks/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/core/fixtures/checks/invalid_check_1.py b/tests/core/fixtures/checks/invalid_check_1.py new file mode 100644 index 0000000000..d4f5f4f60b --- /dev/null +++ b/tests/core/fixtures/checks/invalid_check_1.py @@ -0,0 +1,2 @@ +class InvalidCheck(object): + pass diff --git a/tests/core/fixtures/checks/invalid_check_2.py b/tests/core/fixtures/checks/invalid_check_2.py new file mode 100644 index 0000000000..6c7d3207ed --- /dev/null +++ b/tests/core/fixtures/checks/invalid_check_2.py @@ -0,0 +1,4 @@ +import nothing # noqa + +class InvalidCheck(object): + pass diff --git a/tests/core/fixtures/checks/invalid_conf.yaml b/tests/core/fixtures/checks/invalid_conf.yaml new file mode 100644 index 0000000000..1d71e8262e --- /dev/null +++ b/tests/core/fixtures/checks/invalid_conf.yaml @@ -0,0 +1 @@ +init_config: diff --git a/tests/core/fixtures/checks/valid_check_1.py b/tests/core/fixtures/checks/valid_check_1.py new file mode 100644 index 0000000000..80a8c34fce --- /dev/null +++ b/tests/core/fixtures/checks/valid_check_1.py @@ -0,0 +1,8 @@ +from checks import AgentCheck + +OUTPUT = 'valid_check_1' + +class ValidCheck(AgentCheck): + + def check(self, instance): + return OUTPUT diff --git a/tests/core/fixtures/checks/valid_check_2.py b/tests/core/fixtures/checks/valid_check_2.py new file mode 100644 index 0000000000..6ae90cb04e --- /dev/null +++ b/tests/core/fixtures/checks/valid_check_2.py @@ -0,0 +1,8 @@ +from checks import AgentCheck + +OUTPUT = 'valid_check_2' + +class ValidCheck(AgentCheck): + + def check(self, instance): + return OUTPUT diff --git a/tests/core/fixtures/checks/valid_conf.yaml b/tests/core/fixtures/checks/valid_conf.yaml new file mode 100644 index 0000000000..5cc3ac9d15 --- /dev/null +++ b/tests/core/fixtures/checks/valid_conf.yaml @@ -0,0 +1,4 @@ +init_config: + +instances: + - host: localhost diff --git a/tests/core/fixtures/checks/valid_conf_2.yaml b/tests/core/fixtures/checks/valid_conf_2.yaml new file mode 100644 index 0000000000..7aa1d97035 --- /dev/null +++ b/tests/core/fixtures/checks/valid_conf_2.yaml @@ -0,0 +1,5 @@ +init_config: + +instances: + - host: localhost + - host: localh0st diff --git a/tests/core/fixtures/checks/valid_sub_check.py b/tests/core/fixtures/checks/valid_sub_check.py new file mode 100644 index 0000000000..5dbdfc6cb0 --- /dev/null +++ b/tests/core/fixtures/checks/valid_sub_check.py @@ -0,0 +1,8 @@ +from tests.core.fixtures.checks.valid_check_2 import ValidCheck + +OUTPUT = 'valid_check_1' + +class InheritedCheck(ValidCheck): + + def check(self, instance): + return OUTPUT diff --git a/tests/core/test_config.py b/tests/core/test_config.py index c5a4df8438..ee29628f86 100644 --- a/tests/core/test_config.py +++ b/tests/core/test_config.py @@ -3,7 +3,9 @@ import os import os.path import tempfile +import mock import unittest +from shutil import copyfile, rmtree # project from config import get_config, load_check_directory @@ -14,6 +16,7 @@ # No more hardcoded default checks DEFAULT_CHECKS = [] + class TestConfig(unittest.TestCase): def testWhiteSpaceConfig(self): """Leading whitespace confuse ConfigParser @@ -67,10 +70,10 @@ def testHostname(self): u'i-123445', u'5dfsdfsdrrfsv', u'432498234234A' - u'234234235235235235', # Couldn't find anything in the RFC saying it's not valid + u'234234235235235235', # Couldn't find anything in the RFC saying it's not valid u'A45fsdff045-dsflk4dfsdc.ret43tjssfd', u'4354sfsdkfj4TEfdlv56gdgdfRET.dsf-dg', - u'r'*255, + u'r' * 255, ] not_valid_hostnames = [ @@ -91,11 +94,11 @@ def testWindowsSplit(self): # Make the function run as if it was on windows func = Platform.is_win32 try: - Platform.is_win32 = staticmethod(lambda : True) + Platform.is_win32 = staticmethod(lambda: True) test_cases = [ - ("C:\\Documents\\Users\\script.py:C:\\Documents\\otherscript.py", ["C:\\Documents\\Users\\script.py","C:\\Documents\\otherscript.py"]), - ("C:\\Documents\\Users\\script.py:parser.py", ["C:\\Documents\\Users\\script.py","parser.py"]) + ("C:\\Documents\\Users\\script.py:C:\\Documents\\otherscript.py", ["C:\\Documents\\Users\\script.py", "C:\\Documents\\otherscript.py"]), + ("C:\\Documents\\Users\\script.py:parser.py", ["C:\\Documents\\Users\\script.py", "parser.py"]) ] for test_case, expected_result in test_cases: @@ -110,3 +113,150 @@ def testDefaultChecks(self): for c in DEFAULT_CHECKS: self.assertTrue(c in init_checks_names) + + +TMP_DIR = tempfile.gettempdir() +DD_AGENT_TEST_DIR = 'dd-agent-tests' +TEMP_3RD_PARTY_CHECKS_DIR = os.path.join(TMP_DIR, DD_AGENT_TEST_DIR, '3rd-party') +TEMP_ETC_CHECKS_DIR = os.path.join(TMP_DIR, DD_AGENT_TEST_DIR, 'etc', 'checks.d') +TEMP_ETC_CONF_DIR = os.path.join(TMP_DIR, DD_AGENT_TEST_DIR, 'etc', 'conf.d') +TEMP_AGENT_CHECK_DIR = os.path.join(TMP_DIR, DD_AGENT_TEST_DIR) +FIXTURE_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'fixtures', 'checks') + + +@mock.patch('config.get_checksd_path', return_value=TEMP_AGENT_CHECK_DIR) +@mock.patch('config.get_confd_path', return_value=TEMP_ETC_CONF_DIR) +@mock.patch('config.get_3rd_party_path', return_value=TEMP_3RD_PARTY_CHECKS_DIR) +class TestConfigLoadCheckDirectory(unittest.TestCase): + + TEMP_DIRS = [ + '%s/test_check' % TEMP_3RD_PARTY_CHECKS_DIR, + TEMP_ETC_CHECKS_DIR, TEMP_ETC_CONF_DIR, TEMP_AGENT_CHECK_DIR + ] + + def setUp(self): + for _dir in self.TEMP_DIRS: + if not os.path.exists(_dir): + os.makedirs(_dir) + + def testConfigInvalid(self, *args): + copyfile('%s/invalid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml' % TEMP_ETC_CONF_DIR) + copyfile('%s/valid_check_1.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_AGENT_CHECK_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(1, len(checks['init_failed_checks'])) + + def testConfigNotFound(self, *args): + copyfile('%s/valid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml' % TEMP_ETC_CONF_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(0, len(checks['init_failed_checks'])) + self.assertEquals(0, len(checks['initialized_checks'])) + + def testConfigAgentOnly(self, *args): + copyfile('%s/valid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml' % TEMP_ETC_CONF_DIR) + copyfile('%s/valid_check_1.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_AGENT_CHECK_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(1, len(checks['initialized_checks'])) + + def testConfigETCOnly(self, *args): + copyfile('%s/valid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml' % TEMP_ETC_CONF_DIR) + copyfile('%s/valid_check_1.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_ETC_CHECKS_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(1, len(checks['initialized_checks'])) + + def testConfigAgentETC(self, *args): + copyfile('%s/valid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml' % TEMP_ETC_CONF_DIR) + copyfile('%s/valid_check_2.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_AGENT_CHECK_DIR) + copyfile('%s/valid_check_1.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_ETC_CHECKS_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(1, len(checks['initialized_checks'])) + self.assertEquals('valid_check_1', checks['initialized_checks'][0].check(None)) + + def testConfigCheckNotAgentCheck(self, *args): + copyfile('%s/valid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml' % TEMP_ETC_CONF_DIR) + copyfile('%s/invalid_check_1.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_AGENT_CHECK_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(0, len(checks['init_failed_checks'])) + self.assertEquals(0, len(checks['initialized_checks'])) + + def testConfigCheckImportError(self, *args): + copyfile('%s/valid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml' % TEMP_ETC_CONF_DIR) + copyfile('%s/invalid_check_2.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_AGENT_CHECK_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(1, len(checks['init_failed_checks'])) + + def testConfig3rdPartyAgent(self, *args): + copyfile('%s/valid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml' % TEMP_ETC_CONF_DIR) + copyfile('%s/valid_check_2.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_AGENT_CHECK_DIR) + copyfile('%s/valid_check_1.py' % FIXTURE_PATH, + '%s/test_check/check.py' % TEMP_3RD_PARTY_CHECKS_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(1, len(checks['initialized_checks'])) + self.assertEquals('valid_check_1', checks['initialized_checks'][0].check(None)) + + def testConfigETC3rdParty(self, *args): + copyfile('%s/valid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml' % TEMP_ETC_CONF_DIR) + copyfile('%s/valid_check_2.py' % FIXTURE_PATH, + '%s/test_check/check.py' % TEMP_3RD_PARTY_CHECKS_DIR) + copyfile('%s/valid_check_1.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_ETC_CHECKS_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(1, len(checks['initialized_checks'])) + self.assertEquals('valid_check_1', checks['initialized_checks'][0].check(None)) + + def testConfigInheritedCheck(self, *args): + copyfile('%s/valid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml' % TEMP_ETC_CONF_DIR) + copyfile('%s/valid_sub_check.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_ETC_CHECKS_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(1, len(checks['initialized_checks'])) + self.assertEquals('valid_check_1', checks['initialized_checks'][0].check(None)) + + def testConfigDeprecatedNagiosConfig(self, *args): + copyfile('%s/valid_check_1.py' % FIXTURE_PATH, + '%s/nagios.py' % TEMP_ETC_CHECKS_DIR) + checks = load_check_directory({"nagios_perf_cfg": None, "additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(1, len(checks['initialized_checks'])) + self.assertEquals('valid_check_1', checks['initialized_checks'][0].check(None)) + + def testConfigDefault(self, *args): + copyfile('%s/valid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml.default' % TEMP_ETC_CONF_DIR) + copyfile('%s/valid_check_1.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_ETC_CHECKS_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(1, len(checks['initialized_checks'])) + + def testConfigCustomOverDefault(self, *args): + copyfile('%s/valid_conf.yaml' % FIXTURE_PATH, + '%s/test_check.yaml.default' % TEMP_ETC_CONF_DIR) + # a 2nd valid conf file, slightly different so that we can test which one has been picked up + # (with 2 instances for instance) + copyfile('%s/valid_conf_2.yaml' % FIXTURE_PATH, + '%s/test_check.yaml' % TEMP_ETC_CONF_DIR) + copyfile('%s/valid_check_1.py' % FIXTURE_PATH, + '%s/test_check.py' % TEMP_ETC_CHECKS_DIR) + checks = load_check_directory({"additional_checksd": TEMP_ETC_CHECKS_DIR}, "foo") + self.assertEquals(1, len(checks['initialized_checks'])) + self.assertEquals(2, checks['initialized_checks'][0].instance_count()) # check that we picked the right conf + + def tearDown(self): + for _dir in self.TEMP_DIRS: + rmtree(_dir)