Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[AD] Add docker labels as tags in AD #3564

Merged
merged 3 commits into from
Nov 3, 2017
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion datadog.conf.example
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ gce_updated_hostname: yes

# ========================================================================== #
# Service Discovery #
# See http://docs.datadoghq.com/guides/servicediscovery/ for details #
# See https://docs.datadoghq.com/guides/autodiscovery/ for details #
# ========================================================================== #
#
# Service discovery allows the agent to look for running services
Expand Down Expand Up @@ -141,6 +141,15 @@ gce_updated_hostname: yes
# Enable JMX checks for service discovery
# sd_jmx_enable: no
#
# Docker labels as tags
# We can extract docker labels and add them as tags to all metrics reported by service discovery.
# All you have to do is supply a comma-separated list of label names to extract from containers when found.
#
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a reference to docker_daemon's collect_labels_as_tags for docker/kube metrics

# docker_labels_as_tags: label_name
#
# Example:
# docker_labels_as_tags: com.docker.compose.service, com.docker.compose.project
#
# ========================================================================== #
# Other #
# ========================================================================== #
Expand Down
62 changes: 59 additions & 3 deletions tests/core/test_dockerutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,16 +72,72 @@ def test_image_name_from_image_repodigests(self):
self.assertEqual('alpine', du.image_name_extractor(co))

def test_extract_container_tags(self):
test_data = [
no_label_test_data = [
# Nominal case
[{'Image': 'redis:3.2'}, ['docker_image:redis:3.2', 'image_name:redis', 'image_tag:3.2']],
# No tag
[{'Image': 'redis'}, ['docker_image:redis', 'image_name:redis']],
# No image
[{}, []],
]
for test in test_data:
self.assertEqual(test[1], DockerUtil().extract_container_tags(test[0]))
labeled_test_data = [
# No labels
(
# ctr inspect
{
'Image': 'redis:3.2',
'Config': {
'Labels': {}
}
},
# labels as tags
[],
# expected result
['docker_image:redis:3.2', 'image_name:redis', 'image_tag:3.2']
),
# Un-monitored labels
(
{
'Image': 'redis:3.2',
'Config': {
'Labels': {
'foo': 'bar'
}
}
},
[],
['docker_image:redis:3.2', 'image_name:redis', 'image_tag:3.2']
),
# no labels, with labels_as_tags list
(
{
'Image': 'redis:3.2',
'Config': {
'Labels': {}
}
},
['foo'],
['docker_image:redis:3.2', 'image_name:redis', 'image_tag:3.2']
),
# labels and labels_as_tags list
(
{
'Image': 'redis:3.2',
'Config': {
'Labels': {'foo': 'bar', 'f00': 'b4r'}
}
},
['foo'],
['docker_image:redis:3.2', 'image_name:redis', 'image_tag:3.2', 'foo:bar']
),

]
for test in no_label_test_data:
self.assertEqual(test[1], DockerUtil().extract_container_tags(test[0], []))

for test in labeled_test_data:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

self.assertEqual(test[2], DockerUtil().extract_container_tags(test[0], test[1]))


def test_docker_host_tags_ok(self):
mock_version = mock.MagicMock(name='version', return_value={'Version': '1.13.1'})
Expand Down
17 changes: 15 additions & 2 deletions utils/dockerutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -513,23 +513,27 @@ def find_cgroup_filename_pattern(cls, mountpoints, container_id):

raise MountException("Cannot find Docker cgroup directory. Be sure your system is supported.")

def extract_container_tags(self, co):
def extract_container_tags(self, co, labels_as_tags):
"""
Retrives docker_image, image_name and image_tag tags as a list for a
container. If the container or image is invalid, will gracefully
return an empty list
return an empty list.
Also extract container labels on demand.
"""
tags = []
docker_image = self.image_name_extractor(co)
image_name_array = self.image_tag_extractor(co, 0)
image_tag_array = self.image_tag_extractor(co, 1)
label_tags = self.label_extractor(co, labels_as_tags)

if docker_image:
tags.append('docker_image:%s' % docker_image)
if image_name_array and len(image_name_array) > 0:
tags.append('image_name:%s' % image_name_array[0])
if image_tag_array and len(image_tag_array) > 0:
tags.append('image_tag:%s' % image_tag_array[0])
if label_tags:
tags += label_tags
return tags

def image_tag_extractor(self, entity, key):
Expand Down Expand Up @@ -603,6 +607,15 @@ def image_name_resolver(self, image):
else:
return image

def label_extractor(self, ctr, lbl_to_tags):
"""Returns a list of tags based on a container and a label name list"""
tags = []
labels = ctr.get('Config', {}).get('Labels', {})
for lbl_name, lbl_val in labels.iteritems():
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be extra-safe, let's add a if not labels: return tags, I had the issue of a Config/Env being present but None instead of missing. See #3528

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch!

if lbl_name in lbl_to_tags:
tags.append('{}:{}'.format(lbl_name, lbl_val))
return tags

@classmethod
def container_name_extractor(cls, co):
names = co.get('Names', [])
Expand Down
9 changes: 8 additions & 1 deletion utils/service_discovery/sd_docker_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ def __init__(self, agentConfig):
'tags': self._get_additional_tags,
}

# docker labels we'll add as tags to all instances SD configures
self.docker_labels_as_tags = agentConfig.get('docker_labels_as_tags', '')
if self.docker_labels_as_tags:
self.docker_labels_as_tags = [label.strip() for label in self.docker_labels_as_tags.split(',')]
else:
self.docker_labels_as_tags = []

AbstractSDBackend.__init__(self, agentConfig)

def _make_fetch_state(self):
Expand Down Expand Up @@ -284,7 +291,7 @@ def _extract_port_from_list(self, ports, tpl_var):
def get_tags(self, state, c_id):
"""Extract useful tags from docker or platform APIs. These are collected by default."""
c_inspect = state.inspect_container(c_id)
tags = self.dockerutil.extract_container_tags(c_inspect)
tags = self.dockerutil.extract_container_tags(c_inspect, self.docker_labels_as_tags)

if Platform.is_k8s():
if not self.kubeutil.init_success:
Expand Down