From d6852ee1b7d548321af104f2a0e4be523a49ed08 Mon Sep 17 00:00:00 2001 From: Joseph Davis Date: Tue, 26 Mar 2019 14:17:18 -0700 Subject: [PATCH] Detect missing metric_id before passing through bytearray() It is possible for a row in Cassandra to have a missing metric_id (shows as 'null' in cqlsh). This causes an ugly NoneType error to be passed up to the user on the command line for 'monaca metric-list'. Fix is to detect the missing value, log an error, and return the row with None for the metric_id. Change-Id: Ie617932c6b12a6cfe441510e120bb77a3470b9cf Story: 2005305 Task: 30194 --- .../cassandra/metrics_repository.py | 9 ++++ monasca_api/tests/test_repositories.py | 45 +++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/monasca_api/common/repositories/cassandra/metrics_repository.py b/monasca_api/common/repositories/cassandra/metrics_repository.py index aecb67d0c..f4bcec933 100644 --- a/monasca_api/common/repositories/cassandra/metrics_repository.py +++ b/monasca_api/common/repositories/cassandra/metrics_repository.py @@ -277,6 +277,15 @@ class MetricsRepository(metrics_repository.AbstractMetricsRepository): pair = d.split('\t') dim_map[pair[0]] = pair[1] + if row.metric_id is None: + LOG.error( + 'Metric is missing metric_id, using metric_id=None' + ' name: {}, dimensions: {}'.format( + row.metric_name, row.dimensions)) + return {'id': None, + 'name': row.metric_name, + 'dimensions': dim_map} + metric = {'id': binascii.hexlify(bytearray(row.metric_id)), 'name': row.metric_name, 'dimensions': dim_map} diff --git a/monasca_api/tests/test_repositories.py b/monasca_api/tests/test_repositories.py index 36696955b..46ba494b3 100644 --- a/monasca_api/tests/test_repositories.py +++ b/monasca_api/tests/test_repositories.py @@ -335,6 +335,51 @@ class TestRepoMetricsCassandra(base.BaseTestCase): u'hosttype': u'native' }}], result) + # As Cassandra allows sparse data, it is possible to have a missing metric_id + @patch("monasca_api.common.repositories.cassandra." + "metrics_repository.Cluster.connect") + def test_list_metrics_empty_metric_id(self, cassandra_connect_mock): + cassandra_session_mock = cassandra_connect_mock.return_value + cassandra_future_mock = cassandra_session_mock.execute_async.return_value + + Metric = namedtuple('Metric', 'metric_id metric_name dimensions') + + cassandra_future_mock.result.return_value = [ + Metric( + metric_id=None, + metric_name='disk.space_used_perc', + dimensions=[ + 'device\trootfs', + 'hostname\thost0', + 'hosttype\tnative', + 'mount_point\t/'] + ) + ] + + repo = cassandra_repo.MetricsRepository() + + result = repo.list_metrics( + "0b5e7d8c43f74430add94fba09ffd66e", + "region", + name="disk.space_user_perc", + dimensions={ + "hostname": "host0", + "hosttype": "native", + "mount_point": "/", + "device": "rootfs"}, + offset=None, + limit=1) + + self.assertEqual([{ + u'id': None, + u'name': u'disk.space_used_perc', + u'dimensions': { + u'device': u'rootfs', + u'hostname': u'host0', + u'mount_point': u'/', + u'hosttype': u'native' + }}], result) + @patch("monasca_api.common.repositories.cassandra." "metrics_repository.Cluster.connect") def test_list_metric_names(self, cassandra_connect_mock):