diff --git a/checks.d/docker.py b/checks.d/docker.py index 86af4f0c55..3d74d44ce0 100644 --- a/checks.d/docker.py +++ b/checks.d/docker.py @@ -12,6 +12,7 @@ # project from checks import AgentCheck +from config import _is_affirmative EVENT_TYPE = SOURCE_TYPE_NAME = 'docker' @@ -108,8 +109,8 @@ def unix_open(self, req): class Docker(AgentCheck): """Collect metrics and events from Docker API and cgroups""" - def __init__(self, name, init_config, agentConfig): - AgentCheck.__init__(self, name, init_config, agentConfig) + def __init__(self, name, init_config, agentConfig, instances=None): + AgentCheck.__init__(self, name, init_config, agentConfig, instances) # Initialize a HTTP opener with Unix socket support socket_timeout = int(init_config.get('socket_timeout', 0)) or DEFAULT_SOCKET_TIMEOUT @@ -127,7 +128,8 @@ def __init__(self, name, init_config, agentConfig): def check(self, instance): # Report image metrics - self._count_images(instance) + if _is_affirmative(instance.get('collect_images_stats', True)): + self._count_images(instance) # Get the list of containers and the index of their names containers, ids_to_names = self._get_and_count_containers(instance) @@ -136,7 +138,7 @@ def check(self, instance): skipped_container_ids = self._report_containers_metrics(containers, instance) # Send events from Docker API - if instance.get('collect_events', True): + if _is_affirmative(instance.get('collect_events', True)): self._process_events(instance, ids_to_names, skipped_container_ids) @@ -156,7 +158,7 @@ def _count_images(self, instance): def _get_and_count_containers(self, instance): tags = instance.get("tags", []) - with_size = instance.get('collect_container_size', False) + with_size = _is_affirmative(instance.get('collect_container_size', False)) service_check_name = 'docker.service_up' try: @@ -215,7 +217,7 @@ def _tags_match_patterns(self, tags, filters): def _report_containers_metrics(self, containers, instance): skipped_container_ids = [] - collect_uncommon_metrics = instance.get("collect_all_metrics", False) + collect_uncommon_metrics = _is_affirmative(instance.get("collect_all_metrics", False)) tags = instance.get("tags", []) # Pre-compile regex to include/exclude containers @@ -413,11 +415,13 @@ def _get_cgroup_file(self, cgroup, container_id, filename): def _find_cgroup(self, hierarchy, docker_root): """Finds the mount point for a specified cgroup hierarchy. Works with old style and new style mounts.""" + fp = None try: fp = open(os.path.join(docker_root, "/proc/mounts")) mounts = map(lambda x: x.split(), fp.read().splitlines()) finally: - fp.close() + if fp is not None: + fp.close() cgroup_mounts = filter(lambda x: x[2] == "cgroup", mounts) if len(cgroup_mounts) == 0: raise Exception("Can't find mounted cgroups. If you run the Agent inside a container," diff --git a/conf.d/docker.yaml.example b/conf.d/docker.yaml.example index 77cba87693..642cab6825 100644 --- a/conf.d/docker.yaml.example +++ b/conf.d/docker.yaml.example @@ -65,3 +65,8 @@ instances: # Collect all the available cgroups metrics. All the relevant metrics are collected by default. # # collect_all_metrics: false + + # Collect images stats + # Number of available active images and intermediate images as gauges + # + # collect_images_stats: true diff --git a/tests/common.py b/tests/common.py index 41e8ed1310..cdc78fc4e8 100644 --- a/tests/common.py +++ b/tests/common.py @@ -11,6 +11,26 @@ from config import get_checksd_path from util import get_os, get_hostname +def get_check_class(name): + checksd_path = get_checksd_path(get_os()) + if checksd_path not in sys.path: + sys.path.append(checksd_path) + + check_module = __import__(name) + 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 + + return check_class + def load_check(name, config, agentConfig): checksd_path = get_checksd_path(get_os()) if checksd_path not in sys.path: diff --git a/tests/test_docker.py b/tests/test_docker.py new file mode 100644 index 0000000000..3d1d927b77 --- /dev/null +++ b/tests/test_docker.py @@ -0,0 +1,77 @@ +import unittest + +from mock import patch + +from tests.common import get_check_class + +def _mocked_find_cgroup(*args, **kwargs): + return + +class DockerCheckTest(unittest.TestCase): + def test_tag_exclude_all(self): + """ exclude all, except ubuntu and debian. """ + instance = { + 'include': [ + 'docker_image:ubuntu', + 'docker_image:debian', + ], + 'exclude': ['.*'], + } + + klass = get_check_class('docker') + # NO-OP but loads the check + with patch.object(klass, '_find_cgroup', _mocked_find_cgroup): + check = klass('docker', {}, {}) + + check._prepare_filters(instance) + self.assertEquals(len(instance['exclude_patterns']), 1) + self.assertEquals(len(instance['include_patterns']), 2) + + truth_table_exclusion = { + 'some_tag': True, + 'debian:ubuntu': True, + 'docker_image:centos': True, + 'docker_image:ubuntu': False, + 'docker_image:debian': False, + } + + for tag, val in truth_table_exclusion.iteritems(): + self.assertEquals( + check._is_container_excluded(instance, [tag]), + val, + "{0} expected {1} but is not".format(tag, val) + ) + + def test_tag_include_all(self): + """ exclude all, except ubuntu and debian. """ + instance = { + 'include': [], + 'exclude': [ + 'docker_image:ubuntu', + 'docker_image:debian', + ], + } + + klass = get_check_class('docker') + # NO-OP but loads the check + with patch.object(klass, '_find_cgroup', _mocked_find_cgroup): + check = klass('docker', {}, {}) + + check._prepare_filters(instance) + self.assertEquals(len(instance['exclude_patterns']), 2) + self.assertEquals(len(instance['include_patterns']), 0) + + truth_table_exclusion = { + 'some_tag': False, + 'debian:ubuntu': False, + 'docker_image:centos': False, + 'docker_image:ubuntu': True, + 'docker_image:debian': True, + } + + for tag, val in truth_table_exclusion.iteritems(): + self.assertEquals( + check._is_container_excluded(instance, [tag]), + val, + "{0} expected {1} but is not".format(tag, val) + )