diff --git a/checks.d/http_check.py b/checks.d/http_check.py index 5bd693b44a..2349afb361 100644 --- a/checks.d/http_check.py +++ b/checks.d/http_check.py @@ -35,8 +35,8 @@ def get_ca_certs_path(): class HTTPCheck(NetworkCheck): SOURCE_TYPE_NAME = 'system' - SC_STATUS = 'http_check' - SC_SSL_CERT = 'http_check.ssl_cert' + SC_STATUS = 'http.can_connect' + SC_SSL_CERT = 'http.ssl_cert' def __init__(self, name, init_config, agentConfig, instances): self.ca_certs = init_config.get('ca_certs', get_ca_certs_path()) @@ -250,9 +250,10 @@ def _create_status_event(self, sc_name, status, msg, instance): def report_as_service_check(self, sc_name, status, instance, msg=None): instance_name = instance['name'] - service_check_name = self.normalize(instance_name, sc_name) url = instance.get('url', None) - sc_tags = ['url:%s' % url] + sc_tags = ['url:{0}'.format(url), "instance:{0}".format(instance_name)] + custom_tags = instance.get('tags', []) + tags = sc_tags + custom_tags if sc_name == self.SC_STATUS: # format the HTTP response body into the event @@ -266,9 +267,9 @@ def report_as_service_check(self, sc_name, status, instance, msg=None): msg = "%d %s\n\n%s" % (code, reason, content) msg = msg.rstrip() - self.service_check(service_check_name, + self.service_check(sc_name, NetworkCheck.STATUS_TO_SERVICE_CHECK[status], - tags=sc_tags, + tags=tags, message=msg ) diff --git a/checks.d/tcp_check.py b/checks.d/tcp_check.py index 913eaa8b56..9e39383231 100644 --- a/checks.d/tcp_check.py +++ b/checks.d/tcp_check.py @@ -10,7 +10,7 @@ class BadConfException(Exception): pass class TCPCheck(NetworkCheck): SOURCE_TYPE_NAME = 'system' - SERVICE_CHECK_PREFIX = 'tcp_check' + SERVICE_CHECK_NAME = 'tcp.can_connect' def _load_conf(self, instance): # Fetches the conf @@ -154,16 +154,19 @@ def _create_status_event(self, sc_name, status, msg, instance): def report_as_service_check(self, sc_name, status, instance, msg=None): instance_name = instance['name'] - service_check_name = self.normalize(instance_name, self.SERVICE_CHECK_PREFIX) host = instance.get('host', None) port = instance.get('port', None) + custom_tags = instance.get('tags', []) if status == Status.UP: msg = None - self.service_check(service_check_name, + tags = custom_tags + ['target_host:{0}'.format(host), + 'port:{0}'.format(port), + 'instance:{0}'.format(instance_name)] + + self.service_check(self.SERVICE_CHECK_NAME, NetworkCheck.STATUS_TO_SERVICE_CHECK[status], - tags= ['target_host:%s' % host, - 'port:%s' % port], + tags=tags, message=msg ) diff --git a/tests/checks/common.py b/tests/checks/common.py index ddd5166363..2f4aaaf5ed 100644 --- a/tests/checks/common.py +++ b/tests/checks/common.py @@ -444,3 +444,24 @@ def assertIn(self, first, second): def assertNotIn(self, first, second): self.assertTrue(first not in second, "{0} in {1}".format(first, second)) + + def assertWarning(self, warning, count=None, at_least=1, exact_match=True): + log.debug("Looking for warning {0}".format(warning)) + if count is not None: + log.debug(" * should have exactly {0} statuses".format(count)) + elif at_least is not None: + log.debug(" * should have at least {0} statuses".format(count)) + + if exact_match: + candidates = [w for w in self.warnings if w == warning] + else: + candidates = [w for w in self.warnings if warning in w] + + try: + self._candidates_size_assert(candidates, count=count, at_least=at_least) + except AssertionError: + log.error("Candidates size assertion for {0}, count: {1}, " + "at_least: {2}) failed".format(warning, count, at_least)) + raise + + log.debug("{0} FOUND !".format(warning)) diff --git a/tests/checks/integration/test_http_check.py b/tests/checks/integration/test_http_check.py index 46409400e1..a4fdbb4407 100644 --- a/tests/checks/integration/test_http_check.py +++ b/tests/checks/integration/test_http_check.py @@ -23,6 +23,7 @@ 'http_response_status_code': '4..', 'check_certificate_expiration': False, 'timeout': 1, + 'tags': ["foo:bar"] }, { 'name': 'cnt_mismatch', 'url': 'https://github.com', @@ -100,26 +101,35 @@ def test_check(self): self.service_checks = self.wait_for_async_service_checks(5) # HTTP connection error - self.assertServiceCheck("http_check.conn_error", status=AgentCheck.CRITICAL, - tags=['url:https://thereisnosuchlink.com']) + tags = ['url:https://thereisnosuchlink.com', 'instance:conn_error'] + + self.assertServiceCheck("http.can_connect", status=AgentCheck.CRITICAL, + tags=tags + ) # Wrong HTTP response status code - self.assertServiceCheck("http_check.http_error_status_code", status=AgentCheck.CRITICAL, - tags=['url:http://httpbin.org/404']) - self.assertServiceCheck("http_check.http_error_status_code", status=AgentCheck.OK, - tags=['url:http://httpbin.org/404'], count=0) + tags = ['url:http://httpbin.org/404', 'instance:http_error_status_code'] + self.assertServiceCheck("http.can_connect", + status=AgentCheck.CRITICAL, + tags=tags) + + self.assertServiceCheck("http.can_connect", status=AgentCheck.OK, + tags=tags, count=0) # HTTP response status code match - self.assertServiceCheck("http_check.status_code_match", status=AgentCheck.OK, - tags=['url:http://httpbin.org/404']) + tags = ['url:http://httpbin.org/404', 'instance:status_code_match', 'foo:bar'] + self.assertServiceCheck("http.can_connect", status=AgentCheck.OK, + tags=tags) # Content match & mismatching - self.assertServiceCheck("http_check.cnt_mismatch", status=AgentCheck.CRITICAL, - tags=['url:https://github.com']) - self.assertServiceCheck("http_check.cnt_mismatch", status=AgentCheck.OK, - tags=['url:https://github.com'], count=0) - self.assertServiceCheck("http_check.cnt_match", status=AgentCheck.OK, - tags=['url:https://github.com']) + tags = ['url:https://github.com', 'instance:cnt_mismatch'] + self.assertServiceCheck("http.can_connect", status=AgentCheck.CRITICAL, + tags=tags) + self.assertServiceCheck("http.can_connect", status=AgentCheck.OK, + tags=tags, count=0) + tags = ['url:https://github.com', 'instance:cnt_match'] + self.assertServiceCheck("http.can_connect", status=AgentCheck.OK, + tags=tags) self.coverage_report() @@ -127,12 +137,17 @@ def test_check_ssl(self): self.run_check(CONFIG_SSL_ONLY) # Overrides self.service_checks attribute when values are available self.service_checks = self.wait_for_async_service_checks(6) - self.assertServiceCheck("http_check.ssl_cert.good_cert", status=AgentCheck.OK, - tags=['url:https://github.com']) - self.assertServiceCheck("http_check.ssl_cert.cert_exp_soon", status=AgentCheck.WARNING, - tags=['url:https://github.com']) - self.assertServiceCheck("http_check.ssl_cert.conn_error", status=AgentCheck.CRITICAL, - tags=['url:https://thereisnosuchlink.com']) + tags = ['url:https://github.com', 'instance:good_cert'] + self.assertServiceCheck("http.ssl_cert", status=AgentCheck.OK, + tags=tags) + + tags = ['url:https://github.com', 'instance:cert_exp_soon'] + self.assertServiceCheck("http.ssl_cert", status=AgentCheck.WARNING, + tags=tags) + + tags = ['url:https://thereisnosuchlink.com', 'instance:conn_error'] + self.assertServiceCheck("http.ssl_cert", status=AgentCheck.CRITICAL, + tags=tags) self.coverage_report() @@ -142,6 +157,7 @@ def test_mock_case(self, getpeercert_func): # Overrides self.service_checks attribute when values are av # Needed for the HTTP headers self.service_checks = self.wait_for_async_service_checks(2) - self.assertServiceCheck("http_check.ssl_cert.expired_cert", status=AgentCheck.CRITICAL, - tags=['url:https://github.com']) + tags = ['url:https://github.com', 'instance:expired_cert'] + self.assertServiceCheck("http.ssl_cert", status=AgentCheck.CRITICAL, + tags=tags) self.coverage_report() diff --git a/tests/core/test_service_checks.py b/tests/core/test_service_checks.py index ccfec0eefd..7f9c28cc9a 100644 --- a/tests/core/test_service_checks.py +++ b/tests/core/test_service_checks.py @@ -1,34 +1,28 @@ # stdlib +import logging from Queue import Empty -import unittest import time +import unittest -# 3p +# 3rd party from nose.plugins.attrib import attr -import nose.tools as nt # project from config import AGENT_VERSION -from tests.checks.common import load_check +from tests.checks.common import AgentCheckTest, load_check from util import headers as agent_headers - @attr(requires='core_integration') -class ServiceCheckTestCase(unittest.TestCase): +class ServiceCheckTestCase(AgentCheckTest): - def setUp(self): - self.checks = [] + CHECK_NAME = "http_check" - def init_check(self, config, check_name): - self.agentConfig = { + def testHTTPHeaders(self): + agentConfig = { 'version': AGENT_VERSION, 'api_key': 'toto' } - self.check = load_check(check_name, config, self.agentConfig) - self.checks.append(self.check) - - def testHTTPHeaders(self): config = { 'init_config': {}, 'instances': [{ @@ -39,40 +33,53 @@ def testHTTPHeaders(self): }] } - self.init_check(config, 'http_check') - url, username, password, timeout, http_response_status_code, include_content, headers, \ - response_time, content_match, tags, ssl, \ - ssl_expiration = self.check._load_conf(config['instances'][0]) + self.load_check(config, agentConfig) + url, username, password, http_response_status_code, timeout,\ + include_content, headers, response_time, content_match,\ + tags, ssl, ssl_expiration = self.check._load_conf(config['instances'][0]) + + self.assertEqual(headers["X-Auth-Token"], "SOME-AUTH-TOKEN", headers) + expected_headers = agent_headers(agentConfig).get('User-Agent') + self.assertEqual(expected_headers, headers.get('User-Agent'), headers) - self.assertTrue(headers["X-Auth-Token"] == "SOME-AUTH-TOKEN", headers) - self.assertTrue(headers.get('User-Agent') == agent_headers(self.agentConfig).get('User-Agent'), headers) def testHTTPWarning(self): + self.CHECK_NAME = "http_check" + config = { 'init_config': {}, 'instances': [{ 'url': 'http://127.0.0.1:55555', 'name': 'DownService', 'timeout': 1 - }, { + },{ 'url': 'https://google.com', 'name': 'UpService', 'timeout': 1 }] } - self.init_check(config, 'http_check') - self.check.run() - time.sleep(1) + + self.run_check(config, force_reload=True) + time.sleep(2) # This would normally be called during the next run(), it is what # flushes the results of the check + self.check._process_results() - warnings = self.check.get_warnings() + self.warnings = self.check.get_warnings() + + self.assertEqual(len(self.warnings), 4, self.warnings) + self.assertWarning("Skipping SSL certificate validation for " + "https://google.com based on configuration", count=1) + self.assertWarning("Using events for service checks is deprecated in " + "favor of monitors and will be removed in future versions of the " + "Datadog Agent.", count=3) - self.assertTrue(len(warnings) == 4, warnings) - self.assertTrue(len([k for k in warnings if "Skipping SSL certificate validation" in k]) == 1, warnings) + self.check.stop() def testHTTP(self): + self.CHECK_NAME = "http_check" + # No passwords this time config = { 'init_config': {}, @@ -87,36 +94,27 @@ def testHTTP(self): }] } - self.init_check(config, 'http_check') + self.run_check(config, force_reload=True) + time.sleep(2) + self.assertEqual(self.check.pool.get_nworkers(), 2) - def verify_service_checks(service_checks): - for service_check in service_checks: - if service_check['check'] == 'http_check.DownService': - self.assertEqual(service_check['status'], 2, service_check) - elif service_check['check'] == 'http_check.UpService': - self.assertEqual(service_check['status'], 0, service_check) - else: - raise Exception('Bad check name %s' % service_check) + self.check._process_results() + self.events = self.check.get_events() + self.service_checks = self.check.get_service_checks() - self.check.run() - time.sleep(2) - nt.assert_equals(self.check.pool.get_nworkers(), 2) - # This would normally be called during the next run(), it is what - # flushes the results of the check - self.check._process_results() + self.assertEqual(type(self.events), type([])) + self.assertEqual(len(self.events), 1, self.events) + self.assertEqual(self.events[0]['event_object'], 'DownService') - events = self.check.get_events() - service_checks = self.check.get_service_checks() + self.assertEqual(type(self.service_checks), type([])) + self.assertEqual(len(self.service_checks), 2, self.service_checks) # 1 per instance - assert events - self.assertEqual(type(events), type([])) - self.assertEqual(len(events), 1, events) - self.assertEqual(events[0]['event_object'], 'DownService') - assert service_checks - self.assertEqual(type(service_checks), type([])) - self.assertEqual(len(service_checks), 2, service_checks) # 1 per instance - verify_service_checks(service_checks) + expected_tags = ["instance:DownService", "url:http://127.0.0.1:55555"] + self.assertServiceCheck("http.can_connect", status=2, tags=expected_tags) + + expected_tags = ["instance:UpService", "url:http://google.com"] + self.assertServiceCheck("http.can_connect", status=0, tags=expected_tags) events = self.check.get_events() service_checks = self.check.get_service_checks() @@ -127,27 +125,6 @@ def verify_service_checks(service_checks): # result Q should be empty here self.assertRaises(Empty, self.check.resultsq.get_nowait) - # We change the stored status, so next check should trigger an event - self.check.log.warning(self.check.notified) - self.check.notified[('UpService', 'http_check')] = "DOWN" - - time.sleep(1) - self.check.run() - time.sleep(1) - self.check.run() - - time.sleep(1) - events = self.check.get_events() - service_checks = self.check.get_service_checks() - - self.assertEqual(type(events), type([]), events) - self.assertEqual(len(events), 1, events) - self.assertEqual(events[0]['event_object'], 'UpService', events) - self.assertEqual(type(service_checks), type([])) - # FIXME: sometimes it's 3 instead of 2 - self.assertTrue(len(service_checks) >= 2, service_checks) # Only 2 because the second run wasn't flushed - verify_service_checks(service_checks) - # Cleanup the threads self.check.stop() @@ -161,12 +138,12 @@ def testTCP(self): 'port': 65530, 'timeout': 1, 'name': 'DownService' - }, { + },{ 'host': '126.0.0.1', 'port': 65530, 'timeout': 1, 'name': 'DownService2' - }, { + },{ 'host': 'datadoghq.com', 'port': 80, 'timeout': 1, @@ -175,67 +152,34 @@ def testTCP(self): }] } - self.init_check(config, 'tcp_check') - def verify_service_checks(service_checks): - for service_check in service_checks: - if service_check['check'].startswith('tcp_check.DownService'): - self.assertEqual(service_check['status'], 2, service_check) - elif service_check['check'] == 'tcp_check.UpService': - self.assertEqual(service_check['status'], 0, service_check) - else: - raise Exception('Bad check name %s' % service_check['check']) - - self.check.run() + self.CHECK_NAME = "tcp_check" + self.run_check(config, force_reload=True) time.sleep(2) - nt.assert_equals(self.check.pool.get_nworkers(), 3) + self.assertEqual(self.check.pool.get_nworkers(), 3) # This would normally be called during the next run(), it is what # flushes the results of the check self.check._process_results() - events = self.check.get_events() - service_checks = self.check.get_service_checks() + self.events = self.check.get_events() + self.service_checks = self.check.get_service_checks() - assert events - self.assertEqual(type(events), type([])) - self.assertEqual(len(events), 2, events) - for event in events: - self.assertTrue(event['event_object'][:11] == 'DownService') - assert service_checks - self.assertEqual(type(service_checks), type([])) - self.assertEqual(len(service_checks), 3, service_checks) # 1 per instance - verify_service_checks(service_checks) - events = self.check.get_events() - service_checks = self.check.get_service_checks() - self.assertEqual(type(events), type([])) - self.assertEqual(len(events), 0) - self.assertEqual(type(service_checks), type([])) - self.assertEqual(len(service_checks), 0) - # result Q should be empty here - self.assertRaises(Empty, self.check.resultsq.get_nowait) + self.assertEqual(type(self.events), type([])) + self.assertEqual(len(self.events), 2, self.events) + for event in self.events: + self.assertTrue(event['event_object'][:11] == 'DownService') - # We change the stored status, so next check should trigger an event - self.check.notified[('UpService', None)] = "DOWN" + self.assertEqual(type(self.service_checks), type([])) + self.assertEqual(len(self.service_checks), 3, self.service_checks) # 1 per instance - time.sleep(1) - self.check.run() - time.sleep(2) - self.check.run() + expected_tags = ["instance:DownService", "target_host:127.0.0.1", "port:65530"] + self.assertServiceCheck("tcp.can_connect", status=2, tags=expected_tags) - events = self.check.get_events() - service_checks = self.check.get_service_checks() + expected_tags = ["instance:DownService2", "target_host:126.0.0.1", "port:65530"] + self.assertServiceCheck("tcp.can_connect", status=2, tags=expected_tags) - assert events - self.assertEqual(type(events), type([])) - self.assertEqual(len(events), 1) - self.assertEqual(events[0]['event_object'], 'UpService') - assert service_checks - self.assertEqual(type(service_checks), type([])) - # FIXME: sometimes it's 4 instead of 3 - self.assertTrue(len(service_checks) >= 3, service_checks) # Only 3 because the second run wasn't flushed - verify_service_checks(service_checks) + expected_tags = ["instance:UpService", "target_host:datadoghq.com", "port:80"] + self.assertServiceCheck("tcp.can_connect", status=0, tags=expected_tags) - def tearDown(self): - for check in self.checks: - check.stop() + self.check.stop()