Allow using file to override metric map

Override the metric map of each datasource as soon as it is created by
the manager. This override comes from a file whose path is provided by
a setting in config file.

Loading at creation time allows the correct datasource be used when
get_backend is called, this allows loading a datasource whose metric
names get updated outside the watcher's codebase.

The function 'load_metric_map' returns empty-dict in any error case.
Also in case the file is empty where safe_load is unable finds any
yaml documents, it will return None. [1]

Some minor refactoring in the test_manager file for readability and
added tests for file load and metric override.

1 - https://pyyaml.org/wiki/PyYAMLDocumentation

Change-Id: I1df16245f4c7dfd34066f3ab0553cd67154faa58
Implements: blueprint file-based-metric-map
This commit is contained in:
Sumit Jamgade
2019-05-06 11:31:00 +02:00
parent 64d841b3f2
commit b620081714
4 changed files with 102 additions and 19 deletions

View File

@@ -16,44 +16,72 @@
import mock
from mock import MagicMock
from watcher.common import exception
from watcher.datasources import gnocchi
from watcher.datasources import manager as ds_manager
from watcher.datasources import monasca
from watcher.tests import base
class TestDataSourceManager(base.BaseTestCase):
def _dsm_config(self, **kwargs):
dss = ['gnocchi', 'ceilometer', 'monasca']
opts = dict(datasources=dss, metric_map_path=None)
opts.update(kwargs)
return MagicMock(**opts)
def _dsm(self, **kwargs):
opts = dict(config=self._dsm_config(), osc=mock.MagicMock())
opts.update(kwargs)
return ds_manager.DataSourceManager(**opts)
def test_get_backend(self):
manager = ds_manager.DataSourceManager(
config=mock.MagicMock(
datasources=['gnocchi', 'ceilometer', 'monasca']),
osc=mock.MagicMock())
manager = self._dsm()
backend = manager.get_backend(['host_cpu_usage', 'instance_cpu_usage'])
self.assertEqual(backend, manager.gnocchi)
def test_get_backend_order(self):
manager = ds_manager.DataSourceManager(
config=mock.MagicMock(
datasources=['monasca', 'ceilometer', 'gnocchi']),
osc=mock.MagicMock())
dss = ['monasca', 'ceilometer', 'gnocchi']
dsmcfg = self._dsm_config(datasources=dss)
manager = self._dsm(config=dsmcfg)
backend = manager.get_backend(['host_cpu_usage', 'instance_cpu_usage'])
self.assertEqual(backend, manager.monasca)
def test_get_backend_wrong_metric(self):
manager = ds_manager.DataSourceManager(
config=mock.MagicMock(
datasources=['gnocchi', 'ceilometer', 'monasca']),
osc=mock.MagicMock())
manager = self._dsm()
self.assertRaises(exception.NoSuchMetric, manager.get_backend,
['host_cpu', 'instance_cpu_usage'])
@mock.patch.object(gnocchi, 'GnocchiHelper')
def test_get_backend_error_datasource(self, m_gnocchi):
m_gnocchi.side_effect = exception.DataSourceNotAvailable
manager = ds_manager.DataSourceManager(
config=mock.MagicMock(
datasources=['gnocchi', 'ceilometer', 'monasca']),
osc=mock.MagicMock())
manager = self._dsm()
backend = manager.get_backend(['host_cpu_usage', 'instance_cpu_usage'])
self.assertEqual(backend, manager.ceilometer)
def test_metric_file_path_not_exists(self):
manager = self._dsm()
expected = ds_manager.DataSourceManager.metric_map
actual = manager.metric_map
self.assertEqual(expected, actual)
self.assertEqual({}, manager.load_metric_map('/nope/nope/nope.yaml'))
def test_metric_file_metric_override(self):
path = 'watcher.datasources.manager.DataSourceManager.load_metric_map'
retval = {
monasca.MonascaHelper.NAME: {"host_airflow": "host_fnspid"}
}
with mock.patch(path, return_value=retval):
dsmcfg = self._dsm_config(datasources=['monasca'])
manager = self._dsm(config=dsmcfg)
backend = manager.get_backend(['host_cpu_usage'])
self.assertEqual("host_fnspid", backend.METRIC_MAP['host_airflow'])
def test_metric_file_invalid_ds(self):
with mock.patch('yaml.safe_load') as mo:
mo.return_value = {"newds": {"metric_one": "i_am_metric_one"}}
mgr = self._dsm()
self.assertNotIn('newds', mgr.metric_map.keys())