From 7b166480dde2b759ddefc85ab721f6a406806c4c Mon Sep 17 00:00:00 2001 From: Conor Branagan Date: Fri, 14 Nov 2014 15:15:01 -0800 Subject: [PATCH] Add a service check for Couchbase. - With a test that should work without Couchbase running (testing failure) - Also cleaned up some pre-omnibus code checking the Python version. --- checks.d/couchbase.py | 37 +++++++++++++++++++++++-------------- tests/test_couchbase.py | 23 ++++++++++++++++++----- 2 files changed, 41 insertions(+), 19 deletions(-) diff --git a/checks.d/couchbase.py b/checks.d/couchbase.py index 6b78117839..1c3291c147 100644 --- a/checks.d/couchbase.py +++ b/checks.d/couchbase.py @@ -18,6 +18,7 @@ class Couchbase(AgentCheck): """Extracts stats from Couchbase via its REST API http://docs.couchbase.com/couchbase-manual-2.0/#using-the-rest-api """ + SERVICE_CHECK_NAME = 'couchbase.can_connect' def _create_metrics(self, data, tags=None): storage_totals = data['stats']['storageTotals'] @@ -45,18 +46,14 @@ def _create_metrics(self, data, tags=None): def _get_stats(self, url, instance): - "Hit a given URL and return the parsed json" + """ Hit a given URL and return the parsed json. """ self.log.debug('Fetching Couchbase stats at url: %s' % url) req = urllib2.Request(url, None, headers(self.agentConfig)) if 'user' in instance and 'password' in instance: add_basic_auth(req, instance['user'], instance['password']) - if instance['is_recent_python']: - timeout = instance.get('timeout' , DEFAULT_TIMEOUT) - request = urllib2.urlopen(req,timeout=timeout) - else: - request = urllib2.urlopen(req) - + timeout = float(instance.get('timeout', DEFAULT_TIMEOUT)) + request = urllib2.urlopen(req, timeout=timeout) response = request.read() return json.loads(response) @@ -72,7 +69,6 @@ def check(self, instance): else: tags = list(set(tags)) tags.append('instance:%s' % server) - instance['is_recent_python'] = sys.version_info >= (2,6,0) data = self.get_data(server, instance) self._create_metrics(data, tags=list(set(tags))) @@ -85,12 +81,25 @@ def get_data(self, server, instance): # build couchbase stats entry point url = '%s%s' % (server, COUCHBASE_STATS_PATH) - overall_stats = self._get_stats(url, instance) - # No overall stats? bail out now - if overall_stats is None: - raise Exception("No data returned from couchbase endpoint: %s" % url) - + # Fetch initial stats and capture a service check based on response. + service_check_tags = {'instance:%s' % server} + try: + overall_stats = self._get_stats(url, instance) + # No overall stats? bail out now + if overall_stats is None: + raise Exception("No data returned from couchbase endpoint: %s" % url) + except urllib2.URLError as e: + self.service_check(self.SERVICE_CHECK_NAME, AgentCheck.CRITICAL, + tags=service_check_tags, message=e.reason) + raise + except Exception as e: + self.service_check(self.SERVICE_CHECK_NAME, AgentCheck.CRITICAL, + tags=service_check_tags, message=str(e)) + raise + else: + self.service_check(self.SERVICE_CHECK_NAME, AgentCheck.OK) + couchbase['stats'] = overall_stats nodes = overall_stats['nodes'] @@ -130,7 +139,7 @@ def camel_case_to_joined_lower(self, variable): # remove duplicate _ converted_variable = re.sub('_+', '_', converted_variable) - + # handle special case of starting/ending underscores converted_variable = re.sub('^_|_$', '', converted_variable) diff --git a/tests/test_couchbase.py b/tests/test_couchbase.py index 7d0d6034e8..e893238fbc 100644 --- a/tests/test_couchbase.py +++ b/tests/test_couchbase.py @@ -1,8 +1,11 @@ import unittest from tests.common import load_check +from checks import AgentCheck from nose.plugins.attrib import attr from nose.plugins.skip import SkipTest + +@attr('couchbase') class CouchbaseTestCase(unittest.TestCase): def setUp(self): @@ -11,6 +14,7 @@ def setUp(self): 'server': 'http://localhost:8091', 'user': 'Administrator', 'password': 'password', + 'timeout': 0.1 }] } self.agentConfig = { @@ -19,7 +23,6 @@ def setUp(self): } self.check = load_check('couchbase', self.config, self.agentConfig) - @attr('couchbase') def test_camel_case_to_joined_lower(self): test_pairs = { 'camelCase' : 'camel_case', @@ -36,17 +39,16 @@ def test_camel_case_to_joined_lower(self): for test_input, expected_output in test_pairs.items(): test_output = self.check.camel_case_to_joined_lower(test_input) - self.assertEqual(test_output, expected_output, + self.assertEqual(test_output, expected_output, 'Input was %s, expected output was %s, actual output was %s' % (test_input, expected_output, test_output)) - @attr('couchbase') def test_metrics_casing(self): raise SkipTest("Skipped for now as it's hard to configure couchbase on travis") self.check.check(self.config['instances'][0]) metrics = self.check.get_metrics() - camel_cased_metrics = [u'couchbase.hdd.used_by_data', + camel_cased_metrics = [u'couchbase.hdd.used_by_data', u'couchbase.ram.used_by_data', u'couchbase.ram.quota_total', u'couchbase.ram.quota_used', @@ -55,7 +57,6 @@ def test_metrics_casing(self): found_metrics = [k[0] for k in metrics if k[0] in camel_cased_metrics] self.assertEqual(found_metrics.sort(), camel_cased_metrics.sort()) - @attr('couchbase') def test_metrics(self): raise SkipTest("Skipped for now as it's hard to configure couchbase on travis") self.check.check(self.config['instances'][0]) @@ -68,3 +69,15 @@ def test_metrics(self): self.assertTrue(len([k for k in metrics if -1 != k[0].find('by_node')]) > 1, 'Unable to fund any per node metrics') self.assertTrue(len([k for k in metrics if -1 != k[0].find('by_bucket')]) > 1, 'Unable to fund any per node metrics') + + def test_service_check(self): + try: + self.check.check(self.config['instances'][0]) + except Exception: + service_checks = self.check.get_service_checks() + self.assertEqual(len(service_checks), 1) + service_check = service_checks[0] + self.assertEqual(service_check['check'], self.check.SERVICE_CHECK_NAME) + self.assertEqual(service_check['status'], AgentCheck.CRITICAL) + else: + raise Exception('Couchbase check should have failed')