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

Adhere to code style #3525

Merged
merged 2 commits into from
Apr 17, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 3 additions & 3 deletions kubelet/datadog_checks/kubelet/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from .kubelet import KubeletCheck
from .__about__ import __version__
from .common import PodListUtils, KubeletCredentials, get_pod_by_uid, is_static_pending_pod
from .common import KubeletCredentials, PodListUtils, get_pod_by_uid, is_static_pending_pod
from .kubelet import KubeletCheck

__all__ = [
'KubeletCheck',
'__version__',
'PodListUtils',
'KubeletCredentials',
'get_pod_by_uid',
'is_static_pending_pod'
'is_static_pending_pod',
]
45 changes: 22 additions & 23 deletions kubelet/datadog_checks/kubelet/cadvisor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,28 @@
# Licensed under Simplified BSD License (see LICENSE)
from __future__ import division

"""kubernetes check
Collects metrics from cAdvisor instance
"""
from fnmatch import fnmatch
import numbers
from six import iteritems
from six.moves.urllib.parse import urlparse
import logging
import numbers
from fnmatch import fnmatch

import requests
from six import iteritems
from six.moves.urllib.parse import urlparse

from .common import tags_for_docker, tags_for_pod, is_static_pending_pod, get_pod_by_uid
from datadog_checks.base.utils.tagging import tagger

from .common import get_pod_by_uid, is_static_pending_pod, tags_for_docker, tags_for_pod

"""kubernetes check
Collects metrics from cAdvisor instance
"""


NAMESPACE = "kubernetes"
DEFAULT_MAX_DEPTH = 10
DEFAULT_ENABLED_RATES = [
'diskio.io_service_bytes.stats.total',
'network.??_bytes',
'cpu.*.total']
DEFAULT_ENABLED_GAUGES = [
'memory.usage',
'memory.working_set',
'memory.rss',
'filesystem.usage']
DEFAULT_POD_LEVEL_METRICS = [
'network.*']
DEFAULT_ENABLED_RATES = ['diskio.io_service_bytes.stats.total', 'network.??_bytes', 'cpu.*.total']
DEFAULT_ENABLED_GAUGES = ['memory.usage', 'memory.working_set', 'memory.rss', 'filesystem.usage']
DEFAULT_POD_LEVEL_METRICS = ['network.*']

NET_ERRORS = ['rx_errors', 'tx_errors', 'rx_dropped', 'tx_dropped']

Expand All @@ -42,6 +37,7 @@ class CadvisorScraper(object):
class, as it uses its AgentCheck facilities and class members.
It is not possible to run it standalone.
"""

def __init__(self, *args, **kwargs):
super(CadvisorScraper, self).__init__(*args, **kwargs)

Expand All @@ -59,8 +55,7 @@ def detect_cadvisor(kubelet_url, cadvisor_port):
kubelet_hostname = urlparse(kubelet_url).hostname
if not kubelet_hostname:
raise ValueError("kubelet hostname empty")
url = "http://{}:{}{}".format(kubelet_hostname, cadvisor_port,
LEGACY_CADVISOR_METRICS_PATH)
url = "http://{}:{}{}".format(kubelet_hostname, cadvisor_port, LEGACY_CADVISOR_METRICS_PATH)

# Test the endpoint is present
r = requests.head(url, timeout=1)
Expand Down Expand Up @@ -171,8 +166,12 @@ def _update_container_metrics(self, instance, subcontainer, pod_list, pod_list_u
tags.append("kube_container_name:%s" % k_container_name)
else: # Standard container
cid = pod_list_utils.get_cid_by_name_tuple(
(pod.get('metadata', {}).get('namespace', ""),
pod.get('metadata', {}).get('name', ""), k_container_name))
(
pod.get('metadata', {}).get('namespace', ""),
pod.get('metadata', {}).get('name', ""),
k_container_name,
)
)
if pod_list_utils.is_excluded(cid):
self.log.debug("Filtering out " + cid)
return
Expand Down
18 changes: 12 additions & 6 deletions kubelet/datadog_checks/kubelet/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,14 @@
except ImportError:
# Don't fail on < 6.2
import logging

log = logging.getLogger(__name__)
log.info('Agent does not provide filtering logic, disabling container filtering')

def is_excluded(name, image):
return False


SOURCE_TYPE = 'kubelet'

CADVISOR_DEFAULT_PORT = 0
Expand Down Expand Up @@ -83,6 +85,7 @@ class PodListUtils(object):
Containers that are part of a static pod are not filtered, as we cannot curently
reliably determine their image name to pass to the filtering logic.
"""

def __init__(self, podlist):
self.containers = {}
self.static_pod_uids = set()
Expand Down Expand Up @@ -173,6 +176,7 @@ class KubeletCredentials(object):
"""
Holds the configured credentials to connect to the Kubelet.
"""

def __init__(self, kubelet_conn_info):
"""
Parses the kubelet_conn_info dict and computes credentials
Expand Down Expand Up @@ -233,9 +237,11 @@ def configure_scraper(self, scraper_config):
:param endpoint: url that will be scraped
"""
endpoint = scraper_config['prometheus_url']
scraper_config.update({
'ssl_ca_cert': self._ssl_verify,
'ssl_cert': self._ssl_cert,
'ssl_private_key': self._ssl_private_key,
'extra_headers': self.headers(endpoint) or {}
})
scraper_config.update(
{
'ssl_ca_cert': self._ssl_verify,
'ssl_cert': self._ssl_cert,
'ssl_private_key': self._ssl_private_key,
'extra_headers': self.headers(endpoint) or {},
}
)
123 changes: 61 additions & 62 deletions kubelet/datadog_checks/kubelet/kubelet.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,34 +3,36 @@
# Licensed under Simplified BSD License (see LICENSE)
from __future__ import division

import json
import logging
import re
from collections import defaultdict
from copy import deepcopy
from datetime import datetime, timedelta
import json

import requests
from kubeutil import get_connection_info
from six import iteritems
from six.moves.urllib.parse import urljoin

from datadog_checks.base.utils.date import parse_rfc3339, UTC
from datadog_checks.base.utils.date import UTC, parse_rfc3339
from datadog_checks.base.utils.tagging import tagger
from datadog_checks.checks import AgentCheck
from datadog_checks.checks.openmetrics import OpenMetricsBaseCheck
from datadog_checks.errors import CheckException
from kubeutil import get_connection_info
from six import iteritems
from six.moves.urllib.parse import urljoin

from .common import CADVISOR_DEFAULT_PORT, PodListUtils, KubeletCredentials
from .cadvisor import CadvisorScraper
from .common import CADVISOR_DEFAULT_PORT, KubeletCredentials, PodListUtils
from .prometheus import CadvisorPrometheusScraperMixin

try:
from datadog_agent import get_config
except ImportError:

def get_config(key):
return ""


KUBELET_HEALTH_PATH = '/healthz'
NODE_SPEC_PATH = '/spec'
POD_LIST_PATH = '/pods'
Expand Down Expand Up @@ -60,7 +62,7 @@ def get_config(key):

WHITELISTED_CONTAINER_STATE_REASONS = {
'waiting': ['errimagepull', 'imagepullbackoff', 'crashloopbackoff', 'containercreating'],
'terminated': ['oomkilled', 'containercannotrun', 'error']
'terminated': ['oomkilled', 'containercannotrun', 'error'],
}


Expand All @@ -71,6 +73,7 @@ class ExpiredPodFilter(object):
"""
Allows to filter old pods out of the podlist by providing a decoding hook
"""

def __init__(self, cutoff_date):
self.expired_count = 0
self.cutoff_date = cutoff_date
Expand Down Expand Up @@ -110,6 +113,7 @@ class KubeletCheck(CadvisorPrometheusScraperMixin, OpenMetricsBaseCheck, Cadviso
"""
Collect metrics from Kubelet.
"""

DEFAULT_METRIC_LIMIT = 0

def __init__(self, name, init_config, agentConfig, instances=None):
Expand Down Expand Up @@ -138,31 +142,34 @@ def _create_kubelet_prometheus_instance(self, instance):
This is so the base class can create a scraper_config with the proper values.
"""
kubelet_instance = deepcopy(instance)
kubelet_instance.update({
'namespace': self.NAMESPACE,

# We need to specify a prometheus_url so the base class can use it as the key for our config_map,
# we specify a dummy url that will be replaced in the `check()` function. We append it with "kubelet"
# so the key is different than the cadvisor scraper.
'prometheus_url': instance.get('kubelet_metrics_endpoint', 'dummy_url/kubelet'),
'metrics': [{
'apiserver_client_certificate_expiration_seconds': 'apiserver.certificate.expiration',
'rest_client_requests_total': 'rest.client.requests',
'rest_client_request_latency_seconds': 'rest.client.latency',
'kubelet_runtime_operations': 'kubelet.runtime.operations',
'kubelet_runtime_operations_errors': 'kubelet.runtime.errors',
'kubelet_network_plugin_operations_latency_microseconds': 'kubelet.network_plugin.latency',
'kubelet_volume_stats_available_bytes': 'kubelet.volume.stats.available_bytes',
'kubelet_volume_stats_capacity_bytes': 'kubelet.volume.stats.capacity_bytes',
'kubelet_volume_stats_used_bytes': 'kubelet.volume.stats.used_bytes',
'kubelet_volume_stats_inodes': 'kubelet.volume.stats.inodes',
'kubelet_volume_stats_inodes_free': 'kubelet.volume.stats.inodes_free',
'kubelet_volume_stats_inodes_used': 'kubelet.volume.stats.inodes_used',
}],
# Defaults that were set when the Kubelet scraper was based on PrometheusScraper
'send_monotonic_counter': instance.get('send_monotonic_counter', False),
'health_service_check': instance.get('health_service_check', False)
})
kubelet_instance.update(
{
'namespace': self.NAMESPACE,
# We need to specify a prometheus_url so the base class can use it as the key for our config_map,
# we specify a dummy url that will be replaced in the `check()` function. We append it with "kubelet"
# so the key is different than the cadvisor scraper.
'prometheus_url': instance.get('kubelet_metrics_endpoint', 'dummy_url/kubelet'),
'metrics': [
{
'apiserver_client_certificate_expiration_seconds': 'apiserver.certificate.expiration',
'rest_client_requests_total': 'rest.client.requests',
'rest_client_request_latency_seconds': 'rest.client.latency',
'kubelet_runtime_operations': 'kubelet.runtime.operations',
'kubelet_runtime_operations_errors': 'kubelet.runtime.errors',
'kubelet_network_plugin_operations_latency_microseconds': 'kubelet.network_plugin.latency',
'kubelet_volume_stats_available_bytes': 'kubelet.volume.stats.available_bytes',
'kubelet_volume_stats_capacity_bytes': 'kubelet.volume.stats.capacity_bytes',
'kubelet_volume_stats_used_bytes': 'kubelet.volume.stats.used_bytes',
'kubelet_volume_stats_inodes': 'kubelet.volume.stats.inodes',
'kubelet_volume_stats_inodes_free': 'kubelet.volume.stats.inodes_free',
'kubelet_volume_stats_inodes_used': 'kubelet.volume.stats.inodes_used',
}
],
# Defaults that were set when the Kubelet scraper was based on PrometheusScraper
'send_monotonic_counter': instance.get('send_monotonic_counter', False),
'health_service_check': instance.get('health_service_check', False),
}
)
return kubelet_instance

def check(self, instance):
Expand All @@ -181,25 +188,24 @@ def check(self, instance):
self._perform_kubelet_check(self.instance_tags)

if 'cadvisor_metrics_endpoint' in instance:
self.cadvisor_scraper_config['prometheus_url'] = \
instance.get('cadvisor_metrics_endpoint', urljoin(endpoint, CADVISOR_METRICS_PATH))
self.cadvisor_scraper_config['prometheus_url'] = instance.get(
'cadvisor_metrics_endpoint', urljoin(endpoint, CADVISOR_METRICS_PATH)
)
else:
self.cadvisor_scraper_config['prometheus_url'] = instance.get('metrics_endpoint',
urljoin(endpoint, CADVISOR_METRICS_PATH))
self.cadvisor_scraper_config['prometheus_url'] = instance.get(
'metrics_endpoint', urljoin(endpoint, CADVISOR_METRICS_PATH)
)

if 'metrics_endpoint' in instance:
self.log.warning('metrics_endpoint is deprecated, please specify cadvisor_metrics_endpoint instead.')

self.kubelet_scraper_config['prometheus_url'] = instance.get('kubelet_metrics_endpoint',
urljoin(endpoint, KUBELET_METRICS_PATH))
self.kubelet_scraper_config['prometheus_url'] = instance.get(
'kubelet_metrics_endpoint', urljoin(endpoint, KUBELET_METRICS_PATH)
)

# Kubelet credentials handling
self.kubelet_credentials.configure_scraper(
self.cadvisor_scraper_config
)
self.kubelet_credentials.configure_scraper(
self.kubelet_scraper_config
)
self.kubelet_credentials.configure_scraper(self.cadvisor_scraper_config)
self.kubelet_credentials.configure_scraper(self.kubelet_scraper_config)

# Legacy cadvisor support
try:
Expand All @@ -217,24 +223,14 @@ def check(self, instance):

if self.cadvisor_legacy_url: # Legacy cAdvisor
self.log.debug('processing legacy cadvisor metrics')
self.process_cadvisor(
instance,
self.cadvisor_legacy_url,
self.pod_list,
self.pod_list_utils
)
self.process_cadvisor(instance, self.cadvisor_legacy_url, self.pod_list, self.pod_list_utils)
elif self.cadvisor_scraper_config['prometheus_url']: # Prometheus
self.log.debug('processing cadvisor metrics')
self.process(
self.cadvisor_scraper_config,
metric_transformers=self.CADVISOR_METRIC_TRANSFORMERS
)
self.process(self.cadvisor_scraper_config, metric_transformers=self.CADVISOR_METRIC_TRANSFORMERS)

if self.kubelet_scraper_config['prometheus_url']: # Prometheus
self.log.debug('processing kubelet metrics')
self.process(
self.kubelet_scraper_config
)
self.process(self.kubelet_scraper_config)

# Free up memory
self.pod_list = None
Expand All @@ -251,7 +247,7 @@ def perform_kubelet_query(self, url, verbose=True, timeout=10, stream=False):
cert=self.kubelet_credentials.cert_pair(),
headers=self.kubelet_credentials.headers(url),
params={'verbose': verbose},
stream=stream
stream=stream,
)

def retrieve_pod_list(self):
Expand All @@ -273,8 +269,7 @@ def retrieve_pod_list(self):
pod_list['items'] = []
return pod_list
except Exception as e:
self.log.warning('failed to retrieve pod list from the kubelet at %s : %s'
% (self.pod_list_url, str(e)))
self.log.warning('failed to retrieve pod list from the kubelet at %s : %s' % (self.pod_list_url, str(e)))
return None

@staticmethod
Expand Down Expand Up @@ -337,8 +332,12 @@ def _perform_kubelet_check(self, instance_tags):

except Exception as e:
self.log.warning('kubelet check %s failed: %s' % (url, str(e)))
self.service_check(service_check_base, AgentCheck.CRITICAL,
message='Kubelet check %s failed: %s' % (url, str(e)), tags=instance_tags)
self.service_check(
service_check_base,
AgentCheck.CRITICAL,
message='Kubelet check %s failed: %s' % (url, str(e)),
tags=instance_tags,
)
else:
if is_ok:
self.service_check(service_check_base, AgentCheck.OK, tags=instance_tags)
Expand Down
Loading