From 45dba72fa83348fa0a0428abf9c66835b57b4da5 Mon Sep 17 00:00:00 2001 From: Craig Bryant Date: Fri, 9 Jun 2017 07:38:15 -0600 Subject: [PATCH] Remove required healthcheck import of cassandra The healthcheck code did an import of the cassandra driver even if the metrics database is configured to be influx. The cassandra driver is always installed on devstack but may not be in containers where space is more of a premium. Change the code to use oslo_utils.importutils to try the import of the cassandra driver. This allows it to work correctly if no cassandra driver and metrics database is influx. Change-Id: I4055230eb7c203eb2ca82777647ab3b0c62bc367 --- monasca_api/healthcheck/metrics_db_check.py | 27 +++++++++----- .../tests/test_metrics_db_health_check.py | 36 +++++++++++++++---- 2 files changed, 48 insertions(+), 15 deletions(-) diff --git a/monasca_api/healthcheck/metrics_db_check.py b/monasca_api/healthcheck/metrics_db_check.py index 8a9f91a8f..e7cb2aed0 100644 --- a/monasca_api/healthcheck/metrics_db_check.py +++ b/monasca_api/healthcheck/metrics_db_check.py @@ -1,4 +1,5 @@ # Copyright 2017 FUJITSU LIMITED +# (C) Copyright 2017 Hewlett Packard Enterprise Development LP # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -14,9 +15,9 @@ import requests -from cassandra import cluster from oslo_config import cfg from oslo_log import log +from oslo_utils import importutils from monasca_api.common.repositories import exceptions from monasca_api.healthcheck import base @@ -42,11 +43,19 @@ class MetricsDbCheck(base.BaseHealthCheck): Otherwise unhealthy status is returned with explanation. """ - def health_check(self): + def __init__(self): + # Try to import cassandra. Not a problem if it can't be imported as long + # as the metrics db is influx + self._cluster = importutils.try_import('cassandra.cluster', None) metric_driver = CONF.repositories.metrics_driver - db = self._detected_database_type(metric_driver) + self._db = self._detected_database_type(metric_driver) + if self._db == 'cassandra' and self._cluster is None: + # Should not happen, but log if it does somehow + LOG.error("Metrics Database is Cassandra but cassandra.cluster" + "not importable. Unable to do health check") - if db == 'influxdb': + def health_check(self): + if self._db == 'influxdb': status = self._check_influxdb_status() else: status = self._check_cassandra_status() @@ -63,8 +72,7 @@ class MetricsDbCheck(base.BaseHealthCheck): raise exceptions.UnsupportedDriverException( 'Driver {0} is not supported by Healthcheck'.format(driver)) - @staticmethod - def _check_influxdb_status(): + def _check_influxdb_status(self): uri = 'http://{0}:{1}/ping'.format(CONF.influxdb.ip_address, CONF.influxdb.port) try: @@ -75,10 +83,11 @@ class MetricsDbCheck(base.BaseHealthCheck): return resp.ok, 'OK' if resp.ok else 'Error: {0}'.format( resp.status_code) - @staticmethod - def _check_cassandra_status(): + def _check_cassandra_status(self): + if self._cluster is None: + return False, "Cassandra driver not imported" try: - cassandra = cluster.Cluster( + cassandra = self._cluster.Cluster( CONF.cassandra.cluster_ip_addresses.split(',') ) session = cassandra.connect(CONF.cassandra.keyspace) diff --git a/monasca_api/tests/test_metrics_db_health_check.py b/monasca_api/tests/test_metrics_db_health_check.py index e94607e2f..c8fdf4c1b 100644 --- a/monasca_api/tests/test_metrics_db_health_check.py +++ b/monasca_api/tests/test_metrics_db_health_check.py @@ -1,4 +1,5 @@ # Copyright 2017 FUJITSU LIMITED +# (C) Copyright 2017 Hewlett Packard Enterprise Development LP # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain @@ -147,8 +148,8 @@ class TestMetricsDbHealthCheck(base.BaseTestCase): self.assertTrue(result.healthy) self.assertEqual('OK', result.message) - @mock.patch('monasca_api.healthcheck.metrics_db_check.cluster.Cluster') - def test_should_fail_cassandra_unavailable(self, cluster): + @mock.patch('monasca_api.healthcheck.metrics_db_check.importutils.try_import') + def test_should_fail_cassandra_unavailable(self, try_import): messaging_conf = { 'metrics_driver': 'cassandra.metrics_repository:MetricsRepository' } @@ -159,17 +160,40 @@ class TestMetricsDbHealthCheck(base.BaseTestCase): self._conf.config(group='repositories', **messaging_conf) self._conf.config(group='cassandra', **cassandra_conf) + cluster = mock.Mock() cas_mock = mock.Mock() - cluster.side_effect = cl.NoHostAvailable(message='Host unavailable', - errors='Unavailable') - cluster.return_value = cas_mock + cas_mock.side_effect = cl.NoHostAvailable(message='Host unavailable', + errors='Unavailable') + cluster.Cluster = cas_mock + try_import.return_value = cluster db_health = tdc.MetricsDbCheck() result = db_health.health_check() self.assertFalse(result.healthy) - @mock.patch('monasca_api.healthcheck.metrics_db_check.cluster.Cluster') + @mock.patch('monasca_api.healthcheck.metrics_db_check.importutils.try_import') + def test_should_fail_cassandra_no_driver(self, try_import): + messaging_conf = { + 'metrics_driver': 'cassandra.metrics_repository:MetricsRepository' + } + cassandra_conf = { + 'cluster_ip_addresses': 'localhost', + 'keyspace': 'test' + } + self._conf.config(group='repositories', **messaging_conf) + self._conf.config(group='cassandra', **cassandra_conf) + + # Simulate cassandra driver not available + try_import.return_value = None + + db_health = tdc.MetricsDbCheck() + db_health.cluster = None + result = db_health.health_check() + + self.assertFalse(result.healthy) + + @mock.patch('monasca_api.healthcheck.metrics_db_check.importutils.try_import') def test_should_pass_cassandra_is_available(self, _): messaging_conf = { 'metrics_driver': 'cassandra.metrics_repository:MetricsRepository'