Files
watcher/watcher/tests/decision_engine/datasources/test_grafana_helper.py
licanwei e5884a963b Don't throw exception when missing metrics
When querying data from datasource, it's possible to miss some data.
In this case if we throw an exception, Audit will failed because of
the exception. We should remove the exception and give the decision
to the strategy.

Change-Id: I1b0e6b78b3bba4df9ba16e093b3910aab1de922e
Closes-Bug: #1847434
(cherry picked from commit f685bf62ab)
2019-10-18 02:54:10 +00:00

302 lines
12 KiB
Python

# -*- encoding: utf-8 -*-
# Copyright (c) 2019 European Organization for Nuclear Research (CERN)
#
# Authors: Corne Lukken <info@dantalion.nl>
#
# 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 a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import mock
from oslo_config import cfg
from oslo_log import log
from watcher.common import clients
from watcher.common import exception
from watcher.decision_engine.datasources import grafana
from watcher.tests import base
import requests
CONF = cfg.CONF
LOG = log.getLogger(__name__)
@mock.patch.object(clients.OpenStackClients, 'nova', mock.Mock())
class TestGrafana(base.BaseTestCase):
"""Test the GrafanaHelper datasource
Objects under test are preceded with t_ and mocked objects are preceded
with m_ , additionally, patched objects are preceded with p_ no object
under test should be created in setUp this can influence the results.
"""
def setUp(self):
super(TestGrafana, self).setUp()
self.p_conf = mock.patch.object(
grafana, 'CONF',
new_callable=mock.PropertyMock)
self.m_conf = self.p_conf.start()
self.addCleanup(self.p_conf.stop)
self.m_conf.grafana_client.token = \
"eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk=="
self.m_conf.grafana_client.base_url = "https://grafana.proxy/api/"
self.m_conf.grafana_client.project_id_map = {'host_cpu_usage': 7221}
self.m_conf.grafana_client.database_map = \
{'host_cpu_usage': 'mock_db'}
self.m_conf.grafana_client.attribute_map = \
{'host_cpu_usage': 'hostname'}
self.m_conf.grafana_client.translator_map = \
{'host_cpu_usage': 'influxdb'}
self.m_conf.grafana_client.query_map = \
{'host_cpu_usage': 'SELECT 100-{0}("{0}_value") FROM {3}.'
'cpu_percent WHERE ("host" =~ /^{1}$/ AND '
'"type_instance" =~/^idle$/ AND time > '
'(now()-{2}m)'}
self.m_grafana = grafana.GrafanaHelper(osc=mock.Mock())
stat_agg_patcher = mock.patch.object(
self.m_grafana, 'statistic_aggregation',
spec=grafana.GrafanaHelper.statistic_aggregation)
self.mock_aggregation = stat_agg_patcher.start()
self.addCleanup(stat_agg_patcher.stop)
self.m_compute_node = mock.Mock(
id='16a86790-327a-45f9-bc82-45839f062fdc',
hostname='example.hostname.ch'
)
self.m_instance = mock.Mock(
id='73b1ff78-aca7-404f-ac43-3ed16c1fa555',
human_id='example.hostname'
)
def test_configured(self):
"""Initialize GrafanaHelper and check if configured is true"""
t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
self.assertTrue(t_grafana.configured)
def test_configured_error(self):
"""Butcher the required configuration and test if configured is false
"""
self.m_conf.grafana_client.base_url = ""
t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
self.assertFalse(t_grafana.configured)
def test_configured_raise_error(self):
"""Test raising error when using improperly configured GrafanHelper
Assure that the _get_metric method raises errors if the metric is
missing from the map
"""
# Clear the METRIC_MAP of Grafana since it is a static variable that
# other tests might have set before this test runs.
grafana.GrafanaHelper.METRIC_MAP = {}
self.m_conf.grafana_client.base_url = ""
t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
self.assertFalse(t_grafana.configured)
self.assertEqual({}, t_grafana.METRIC_MAP)
self.assertRaises(
exception.MetricNotAvailable,
t_grafana.get_host_cpu_usage,
self.m_compute_node
)
@mock.patch.object(requests, 'get')
def test_request_raise_error(self, m_request):
"""Test raising error when status code of request indicates problem
Assure that the _request method raises errors if the response indicates
problems.
"""
m_request.return_value = mock.Mock(status_code=404)
t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
self.assertIsNone(t_grafana.get_host_cpu_usage(self.m_compute_node))
def test_no_metric_raise_error(self):
"""Test raising error when specified meter does not exist"""
t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
self.assertRaises(exception.MetricNotAvailable,
t_grafana.statistic_aggregation,
self.m_compute_node,
'none existing meter', 60)
@mock.patch.object(grafana.GrafanaHelper, '_request')
def test_get_metric_raise_error(self, m_request):
"""Test raising error when endpoint unable to deliver data for metric
"""
m_request.return_value.content = "{}"
t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
self.assertRaises(exception.NoSuchMetricForHost,
t_grafana.get_host_cpu_usage,
self.m_compute_node, 60)
def test_metric_builder(self):
"""Creates valid and invalid sets of configuration for metrics
Ensures that a valid metric entry can be configured even if multiple
invalid configurations exist for other metrics.
"""
self.m_conf.grafana_client.project_id_map = {
'host_cpu_usage': 7221,
'host_ram_usage': 7221,
'instance_ram_allocated': 7221,
}
self.m_conf.grafana_client.database_map = {
'host_cpu_usage': 'mock_db',
'instance_cpu_usage': 'mock_db',
'instance_ram_allocated': 'mock_db',
}
self.m_conf.grafana_client.attribute_map = {
'host_cpu_usage': 'hostname',
'host_power': 'hostname',
'instance_ram_allocated': 'human_id',
}
self.m_conf.grafana_client.translator_map = {
'host_cpu_usage': 'influxdb',
'host_inlet_temp': 'influxdb',
# validate that invalid entries don't get added
'instance_ram_usage': 'dummy',
'instance_ram_allocated': 'influxdb',
}
self.m_conf.grafana_client.query_map = {
'host_cpu_usage': 'SHOW SERIES',
'instance_ram_usage': 'SHOW SERIES',
'instance_ram_allocated': 'SHOW SERIES',
}
expected_result = {
'host_cpu_usage': {
'db': 'mock_db',
'project': 7221,
'attribute': 'hostname',
'translator': 'influxdb',
'query': 'SHOW SERIES'},
'instance_ram_allocated': {
'db': 'mock_db',
'project': 7221,
'attribute': 'human_id',
'translator': 'influxdb',
'query': 'SHOW SERIES'},
}
t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
self.assertEqual(t_grafana.METRIC_MAP, expected_result)
@mock.patch.object(grafana.GrafanaHelper, '_request')
def test_statistic_aggregation(self, m_request):
m_request.return_value.content = "{ \"results\": [{ \"series\": [{ " \
"\"columns\": [\"time\",\"mean\"]," \
"\"values\": [[1552500855000, " \
"67.3550078657577]]}]}]}"
t_grafana = grafana.GrafanaHelper(osc=mock.Mock())
result = t_grafana.statistic_aggregation(
self.m_compute_node, 'compute_node', 'host_cpu_usage', 60)
self.assertEqual(result, 67.3550078657577)
def test_get_host_cpu_usage(self):
self.m_grafana.get_host_cpu_usage(self.m_compute_node, 60, 'min', 15)
self.mock_aggregation.assert_called_once_with(
self.m_compute_node, 'compute_node', 'host_cpu_usage', 60, 'min',
15)
def test_get_host_ram_usage(self):
self.m_grafana.get_host_ram_usage(self.m_compute_node, 60,
'min', 15)
self.mock_aggregation.assert_called_once_with(
self.m_compute_node, 'compute_node', 'host_ram_usage', 60, 'min',
15)
def test_get_host_outlet_temperature(self):
self.m_grafana.get_host_outlet_temp(self.m_compute_node, 60,
'min', 15)
self.mock_aggregation.assert_called_once_with(
self.m_compute_node, 'compute_node', 'host_outlet_temp', 60, 'min',
15)
def test_get_host_inlet_temperature(self):
self.m_grafana.get_host_inlet_temp(self.m_compute_node, 60,
'min', 15)
self.mock_aggregation.assert_called_once_with(
self.m_compute_node, 'compute_node', 'host_inlet_temp', 60, 'min',
15)
def test_get_host_airflow(self):
self.m_grafana.get_host_airflow(self.m_compute_node, 60,
'min', 15)
self.mock_aggregation.assert_called_once_with(
self.m_compute_node, 'compute_node', 'host_airflow', 60, 'min',
15)
def test_get_host_power(self):
self.m_grafana.get_host_power(self.m_compute_node, 60,
'min', 15)
self.mock_aggregation.assert_called_once_with(
self.m_compute_node, 'compute_node', 'host_power', 60, 'min',
15)
def test_get_instance_cpu_usage(self):
self.m_grafana.get_instance_cpu_usage(self.m_compute_node, 60,
'min', 15)
self.mock_aggregation.assert_called_once_with(
self.m_compute_node, 'instance', 'instance_cpu_usage', 60,
'min', 15)
def test_get_instance_ram_usage(self):
self.m_grafana.get_instance_ram_usage(self.m_compute_node, 60,
'min', 15)
self.mock_aggregation.assert_called_once_with(
self.m_compute_node, 'instance', 'instance_ram_usage', 60,
'min', 15)
def test_get_instance_ram_allocated(self):
self.m_grafana.get_instance_ram_allocated(self.m_compute_node, 60,
'min', 15)
self.mock_aggregation.assert_called_once_with(
self.m_compute_node, 'instance', 'instance_ram_allocated', 60,
'min', 15)
def test_get_instance_l3_cache_usage(self):
self.m_grafana.get_instance_l3_cache_usage(self.m_compute_node, 60,
'min', 15)
self.mock_aggregation.assert_called_once_with(
self.m_compute_node, 'instance', 'instance_l3_cache_usage', 60,
'min', 15)
def test_get_instance_root_disk_allocated(self):
self.m_grafana.get_instance_root_disk_size(self.m_compute_node, 60,
'min', 15)
self.mock_aggregation.assert_called_once_with(
self.m_compute_node, 'instance', 'instance_root_disk_size', 60,
'min', 15)