def test_bad_config(): with pytest.raises(Exception): KubeletCheck('kubelet', None, {}, [{}, {}])
def test_parse_quantity(): for raw, res in iteritems(QUANTITIES): assert KubeletCheck.parse_quantity(raw) == res
def test_report_container_state_metrics(monkeypatch, tagger): check = KubeletCheck('kubelet', None, {}, [{}]) check.pod_list_url = "dummyurl" monkeypatch.setattr( check, 'perform_kubelet_query', mock.Mock(return_value=MockStreamResponse('pods_crashed.json'))) monkeypatch.setattr(check, '_compute_pod_expiration_datetime', mock.Mock(return_value=None)) monkeypatch.setattr(check, 'gauge', mock.Mock()) attrs = {'is_excluded.return_value': False} check.pod_list_utils = mock.Mock(**attrs) pod_list = check.retrieve_pod_list() instance_tags = ["one:1", "two:2"] check._report_container_state_metrics(pod_list, instance_tags) calls = [ mock.call( 'kubernetes.containers.last_state.terminated', 1, [ 'kube_container_name:fluentd-gcp', 'kube_deployment:fluentd-gcp-v2.0.10' ] + instance_tags + ['reason:OOMKilled'], ), mock.call( 'kubernetes.containers.state.waiting', 1, [ 'kube_container_name:prometheus-to-sd-exporter', 'kube_deployment:fluentd-gcp-v2.0.10' ] + instance_tags + ['reason:CrashLoopBackOff'], ), mock.call( 'kubernetes.containers.restarts', 1, [ 'kube_container_name:fluentd-gcp', 'kube_deployment:fluentd-gcp-v2.0.10' ] + instance_tags, ), mock.call( 'kubernetes.containers.restarts', 0, [ 'kube_container_name:prometheus-to-sd-exporter', 'kube_deployment:fluentd-gcp-v2.0.10' ] + instance_tags, ), mock.call('kubernetes.containers.restarts', 0, ['kube_container_name:datadog-agent'] + instance_tags), mock.call('kubernetes.containers.restarts', 0, ['kube_container_name:datadog-agent'] + instance_tags), ] check.gauge.assert_has_calls(calls, any_order=True) container_state_gauges = [ x[0][2] for x in check.gauge.call_args_list if x[0][0].startswith('kubernetes.containers.state') ] if any(map(lambda e: 'reason:TransientReason' in e, container_state_gauges)): raise AssertionError( 'kubernetes.containers.state.* was submitted with a transient reason' ) if any( map(lambda e: not any(x for x in e if x.startswith('reason:')), container_state_gauges)): raise AssertionError( 'kubernetes.containers.state.* was submitted without a reason')
def mock_kubelet_check(monkeypatch, instances, kube_version=KUBE_1_14, stats_summary_fail=False): """ Returns a check that uses mocked data for responses from prometheus endpoints, pod list, and node spec. """ check = KubeletCheck('kubelet', None, {}, instances) monkeypatch.setattr( check, 'retrieve_pod_list', mock.Mock(return_value=json.loads(mock_from_file('pods.json')))) monkeypatch.setattr(check, '_retrieve_node_spec', mock.Mock(return_value=NODE_SPEC)) if stats_summary_fail: monkeypatch.setattr(check, '_retrieve_stats', mock.Mock(return_value={})) else: monkeypatch.setattr( check, '_retrieve_stats', mock.Mock( return_value=json.loads(mock_from_file('stats_summary.json')))) monkeypatch.setattr(check, '_perform_kubelet_check', mock.Mock(return_value=None)) monkeypatch.setattr(check, '_compute_pod_expiration_datetime', mock.Mock(return_value=None)) def mocked_poll(cadvisor_response, kubelet_response): def _mocked_poll(*args, **kwargs): scraper_config = args[0] prometheus_url = scraper_config['prometheus_url'] if prometheus_url.endswith('/metrics/cadvisor'): # Mock response for "/metrics/cadvisor" content = mock_from_file(cadvisor_response) elif prometheus_url.endswith('/metrics'): # Mock response for "/metrics" content = mock_from_file(kubelet_response) else: raise Exception("Must be a valid endpoint") attrs = { 'close.return_value': True, 'iter_lines.return_value': content.split('\n'), 'content': content } return mock.Mock(headers={'Content-Type': 'text/plain'}, **attrs) return _mocked_poll if kube_version == KUBE_POST_1_16: monkeypatch.setattr( check, 'poll', mock.Mock(side_effect=mocked_poll( cadvisor_response='cadvisor_metrics_post_1_16.txt', kubelet_response='kubelet_metrics_1_14.txt')), ) elif kube_version == KUBE_1_14: monkeypatch.setattr( check, 'poll', mock.Mock(side_effect=mocked_poll( cadvisor_response='cadvisor_metrics_pre_1_16.txt', kubelet_response='kubelet_metrics_1_14.txt', )), ) elif kube_version == KUBE_PRE_1_14: monkeypatch.setattr( check, 'poll', mock.Mock(side_effect=mocked_poll( cadvisor_response='cadvisor_metrics_pre_1_16.txt', kubelet_response='kubelet_metrics.txt')), ) return check