Skip to content

Commit

Permalink
[http_check] check response status code
Browse files Browse the repository at this point in the history
  • Loading branch information
yannmh committed Mar 6, 2015
1 parent 578c920 commit 9e86409
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 41 deletions.
47 changes: 25 additions & 22 deletions checks.d/http_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,43 +45,45 @@ def __init__(self, name, init_config, agentConfig, instances):
def _load_conf(self, instance):
# Fetches the conf
tags = instance.get('tags', [])
username = instance.get('username', None)
password = instance.get('password', None)
username = instance.get('username')
password = instance.get('password')
http_response_status_code = instance.get('http_response_status_code', "(1|2|3)\d\d")
timeout = int(instance.get('timeout', 10))
config_headers = instance.get('headers', {})
headers = agent_headers(self.agentConfig)
headers.update(config_headers)
url = instance.get('url', None)
content_match = instance.get('content_match', None)
url = instance.get('url')
content_match = instance.get('content_match')
response_time = _is_affirmative(instance.get('collect_response_time', True))
if url is None:
if not url:
raise Exception("Bad configuration. You must specify a url")
include_content = _is_affirmative(instance.get('include_content', False))
ssl = _is_affirmative(instance.get('disable_ssl_validation', True))
ssl_expire = _is_affirmative(instance.get('check_certificate_expiration', True))

return url, username, password, timeout, include_content, headers, response_time,\
content_match, tags, ssl, ssl_expire
return url, username, password, http_response_status_code, timeout, include_content,\
headers, response_time, content_match, tags, ssl, ssl_expire

def _check(self, instance):
addr, username, password, timeout, include_content, headers, response_time,\
content_match, tags, disable_ssl_validation, ssl_expire = self._load_conf(instance)
addr, username, password, http_response_status_code, timeout, include_content, headers,\
response_time, content_match, tags, disable_ssl_validation,\
ssl_expire = self._load_conf(instance)
start = time.time()

service_checks = []

try:
self.log.debug("Connecting to %s" % addr)
if disable_ssl_validation and urlparse(addr)[0] == "https":
self.warning("Skipping SSL certificate validation for %s based on configuration" % addr)
self.warning("Skipping SSL certificate validation for %s based on configuration"
% addr)

auth = None
if username is not None and password is not None:
auth = (username, password)

r = requests.get(addr, auth=auth, timeout=timeout, headers=headers,
verify=not disable_ssl_validation)
r.raise_for_status()

except socket.timeout, e:
length = int((time.time() - start) * 1000)
Expand All @@ -93,16 +95,6 @@ def _check(self, instance):
"%s. Connection failed after %s ms" % (str(e), length)
))

except requests.exceptions.HTTPError, r:
length = int((time.time() - start) * 1000)
self.log.info("%s is DOWN, error code: %s" % (addr, str(r.status_code)))

content = r.content if include_content else ''

service_checks.append((
self.SC_STATUS, Status.DOWN, (r.status_code, r.reason, content or '')
))

except requests.exceptions.ConnectionError, e:
length = int((time.time() - start) * 1000)
self.log.info("%s is DOWN, error: %s. Connection failed after %s ms"
Expand Down Expand Up @@ -138,6 +130,18 @@ def _check(self, instance):
tags_list.append('url:%s' % addr)
self.gauge('network.http.response_time', running_time, tags=tags_list)

# Check HTTP response status code
if not (service_checks or re.match(http_response_status_code, str(r.status_code))):
self.log.info("Incorrect HTTP return code. Expected %s, got %s"
% (http_response_status_code, str(r.status_code)))

service_checks.append((
self.SC_STATUS,
Status.DOWN,
"Incorrect HTTP return code. Expected %s, got %s"
% (http_response_status_code, str(r.status_code))
))

if not service_checks:
# Host is UP
# Check content matching is set
Expand Down Expand Up @@ -197,7 +201,6 @@ def _create_status_event(self, sc_name, status, msg, instance):
else:
source_type = "%s.%s" % (NetworkCheck.SOURCE_TYPE_NAME, instance_source_type_name)


# Get the handles you want to notify
notify = instance.get('notify', self.init_config.get('notify', []))
notify_message = ""
Expand Down
6 changes: 6 additions & 0 deletions conf.d/http_check.yaml.example
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ instances:
# username: user
# password: pass

# The (optional) http_response_status_code parameter will instruct the check
# to look for a particular HTTP response status code.
# The check will report as DOWN if status code returned differs.
# This defaults to 1xx, 2xx and 3xx HTTP status code: (1|2|3)\d\d.
# http_response_status_code: 401

# The (optional) window and threshold parameters allow you to trigger
# alerts only if the check fails x times within the last y attempts
# where x is the threshold and y is the window.
Expand Down
50 changes: 33 additions & 17 deletions tests/test_http_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,29 @@

CONFIG = {
'instances': [{
'name': 'bad_url',
'name': 'conn_error',
'url': 'https://thereisnosuchlink.com',
'check_certificate_expiration': False,
'timeout': 1,
}, {
'name': 'content_mismatch',
'url': 'https://github.com',
'name': 'http_error_status_code',
'url': 'http://httpbin.org/404',
'check_certificate_expiration': False,
'timeout': 1,
}, {
'name': 'status_code_match',
'url': 'http://httpbin.org/404',
'http_response_status_code': '4..',
'check_certificate_expiration': False,
'content_match': 'thereisnosuchword'
'timeout': 1,
}, {
'name': 'simple_match',
'name': 'cnt_mismatch',
'url': 'https://github.com',
'timeout': 1,
'check_certificate_expiration': False,
'content_match': 'github'
'content_match': 'thereisnosuchword'
}, {
'name': 'regexp_match',
'name': 'cnt_match',
'url': 'https://github.com',
'timeout': 1,
'check_certificate_expiration': False,
Expand All @@ -48,7 +53,7 @@
'check_certificate_expiration': True,
'days_warning': 9999
}, {
'name': 'bad_url',
'name': 'conn_error',
'url': 'https://thereisnosuchlink.com',
'timeout': 1,
'check_certificate_expiration': True,
Expand Down Expand Up @@ -91,18 +96,29 @@ def wait_for_async_service_checks(self, count):

def test_check(self):
self.run_check(CONFIG)
# Overrides self.service_checks attribute when values are available
self.service_checks = self.wait_for_async_service_checks(4)
# Overrides self.service_checks attribute when values are available\
self.service_checks = self.wait_for_async_service_checks(5)

self.assertServiceCheck("http_check.bad_url", status=AgentCheck.CRITICAL,
# HTTP connection error
self.assertServiceCheck("http_check.conn_error", status=AgentCheck.CRITICAL,
tags=['url:https://thereisnosuchlink.com'])
self.assertServiceCheck("http_check.content_mismatch", status=AgentCheck.CRITICAL,

# 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)

# HTTP response status code match
self.assertServiceCheck("http_check.status_code_match", status=AgentCheck.OK,
tags=['url:http://httpbin.org/404'])

# Content match & mismatching
self.assertServiceCheck("http_check.cnt_mismatch", status=AgentCheck.CRITICAL,
tags=['url:https://github.com'])
self.assertServiceCheck("http_check.content_mismatch", status=AgentCheck.OK,
self.assertServiceCheck("http_check.cnt_mismatch", status=AgentCheck.OK,
tags=['url:https://github.com'], count=0)
self.assertServiceCheck("http_check.simple_match", status=AgentCheck.OK,
tags=['url:https://github.com'])
self.assertServiceCheck("http_check.regexp_match", status=AgentCheck.OK,
self.assertServiceCheck("http_check.cnt_match", status=AgentCheck.OK,
tags=['url:https://github.com'])

def test_check_ssl(self):
Expand All @@ -113,7 +129,7 @@ def test_check_ssl(self):
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.bad_url", status=AgentCheck.CRITICAL,
self.assertServiceCheck("http_check.ssl_cert.conn_error", status=AgentCheck.CRITICAL,
tags=['url:https://thereisnosuchlink.com'])

@mock.patch('ssl.SSLSocket.getpeercert', return_value=FAKE_CERT)
Expand Down
5 changes: 3 additions & 2 deletions tests/test_service_checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ def testHTTPHeaders(self):
}

self.init_check(config, 'http_check')
url, username, password, timeout, include_content, headers, response_time, content_match,\
tags, ssl, ssl_expiration = self.check._load_conf(config['instances'][0])
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.assertTrue(headers["X-Auth-Token"] == "SOME-AUTH-TOKEN", headers)
self.assertTrue(headers.get('User-Agent') == agent_headers(self.agentConfig).get('User-Agent'), headers)
Expand Down

0 comments on commit 9e86409

Please sign in to comment.