704ab58a4e
- auto detecting kibana process - building configuration - collecting metrics Change-Id: I4c457b8396d8131fa18c76305a8f069626c51256
279 lines
11 KiB
Python
279 lines
11 KiB
Python
# Copyright 2016 FUJITSU LIMITED
|
|
#
|
|
# 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 contextlib
|
|
import logging
|
|
import os
|
|
import unittest
|
|
import mock
|
|
import psutil
|
|
import json
|
|
|
|
from monasca_setup.detection.plugins import kibana
|
|
|
|
LOG = logging.getLogger(kibana.__name__)
|
|
|
|
_KIBANA_METRICS = ['heap_size',
|
|
'heap_used',
|
|
'load',
|
|
'req_sec',
|
|
'resp_time_avg',
|
|
'resp_time_max']
|
|
|
|
|
|
class JsonResponse(object):
|
|
|
|
def __init__(self, data):
|
|
self.data = data
|
|
|
|
def json(self):
|
|
return self.data
|
|
|
|
|
|
class PSUtilGetProc(object):
|
|
cmdLine = ['kibana']
|
|
|
|
def as_dict(self):
|
|
return {'name': 'kibana',
|
|
'cmdline': PSUtilGetProc.cmdLine}
|
|
|
|
def cmdline(self):
|
|
return self.cmdLine
|
|
|
|
|
|
class KibanaDetectionTest(unittest.TestCase):
|
|
def setUp(self):
|
|
unittest.TestCase.setUp(self)
|
|
with mock.patch.object(kibana.Kibana, '_detect') as mock_detect:
|
|
self.kibana_plugin = kibana.Kibana('temp_dir')
|
|
self.assertTrue(mock_detect.called)
|
|
|
|
def _detect(self,
|
|
kibana_plugin,
|
|
config_is_file=True,
|
|
deps_installed=True):
|
|
kibana_plugin.available = False
|
|
psutil_mock = PSUtilGetProc()
|
|
|
|
process_iter_patch = mock.patch.object(psutil, 'process_iter',
|
|
return_value=[psutil_mock])
|
|
isfile_patch = mock.patch.object(os.path, 'isfile',
|
|
return_value=config_is_file)
|
|
deps_installed_patch = mock.patch.object(kibana_plugin,
|
|
'dependencies_installed',
|
|
return_value=deps_installed)
|
|
|
|
with contextlib.nested(process_iter_patch,
|
|
isfile_patch,
|
|
deps_installed_patch) as (
|
|
mock_process_iter, mock_isfile, mock_deps_installed):
|
|
kibana_plugin._detect()
|
|
self.assertTrue(mock_process_iter.called)
|
|
self.assertTrue(mock_isfile.called)
|
|
self.assertTrue(mock_deps_installed.called)
|
|
|
|
def _verify_kibana_conf(self, kibana_check, kibana_url):
|
|
|
|
self.assertIn('init_config', kibana_check)
|
|
self.assertIsNotNone(kibana_check['init_config'])
|
|
self.assertIn('url', kibana_check['init_config'])
|
|
self.assertEqual(kibana_check['init_config']['url'], kibana_url)
|
|
|
|
self.assertIn('instances', kibana_check)
|
|
self.assertEqual(1, len(kibana_check['instances']))
|
|
|
|
for instance in kibana_check['instances']:
|
|
self.assertIn('metrics', instance)
|
|
self.assertEqual(list, type(instance['metrics']))
|
|
self.assertItemsEqual(_KIBANA_METRICS, instance['metrics'])
|
|
|
|
def _verify_process_conf(self, process_check, kibana_user):
|
|
# minimize check here, do not check how process should work
|
|
# just find the user
|
|
|
|
self.assertIn('instances', process_check)
|
|
self.assertEqual(1, len(process_check['instances']))
|
|
|
|
for instance in process_check['instances']:
|
|
if not kibana_user:
|
|
self.assertNotIn('username', instance)
|
|
else:
|
|
self.assertIn('username', instance)
|
|
self.assertEqual(kibana_user, instance['username'])
|
|
|
|
def test_no_detect_no_process(self):
|
|
with mock.patch.object(LOG, 'error') as mock_log_error:
|
|
PSUtilGetProc.cmdLine = []
|
|
self._detect(self.kibana_plugin)
|
|
self.assertFalse(self.kibana_plugin.available)
|
|
|
|
self.assertEqual(mock_log_error.call_count, 1)
|
|
self.assertEqual(mock_log_error.call_args[0][0],
|
|
'Kibana process has not been found. '
|
|
'Plugin for Kibana will not be configured.')
|
|
|
|
def test_no_detect_no_dependencies(self):
|
|
with mock.patch.object(LOG, 'error') as mock_log_error:
|
|
self._detect(self.kibana_plugin, deps_installed=False)
|
|
self.assertFalse(self.kibana_plugin.available)
|
|
|
|
self.assertEqual(mock_log_error.call_count, 1)
|
|
self.assertEqual(mock_log_error.call_args[0][0],
|
|
'Kibana plugin dependencies are not satisfied. '
|
|
'Module "pyaml" not found. '
|
|
'Plugin for Kibana will not be configured.')
|
|
|
|
def test_no_detect_no_default_config_file(self):
|
|
with mock.patch.object(LOG, 'error') as mock_log_error:
|
|
self._detect(self.kibana_plugin, config_is_file=False)
|
|
self.assertFalse(self.kibana_plugin.available)
|
|
|
|
self.assertEqual(mock_log_error.call_count, 1)
|
|
self.assertEqual(mock_log_error.call_args[0][0],
|
|
'Kibana plugin cannot find configuration '
|
|
'file /opt/kibana/config/kibana.yml. '
|
|
'Plugin for Kibana will not be configured.')
|
|
|
|
def test_no_detect_no_args_config_file(self):
|
|
config_file = '/fake/config'
|
|
|
|
patch_log_error = mock.patch.object(LOG, 'error')
|
|
|
|
with patch_log_error as mock_log_error:
|
|
self.kibana_plugin.args = {'kibana-config': config_file}
|
|
|
|
self._detect(self.kibana_plugin, config_is_file=False)
|
|
self.assertFalse(self.kibana_plugin.available)
|
|
|
|
self.assertEqual(mock_log_error.call_count, 1)
|
|
self.assertEqual(mock_log_error.call_args[0][0],
|
|
'Kibana plugin cannot find configuration '
|
|
'file %s. '
|
|
'Plugin for Kibana will not be configured.'
|
|
% config_file)
|
|
|
|
def test_detect_ok(self):
|
|
self._detect(self.kibana_plugin)
|
|
self.assertTrue(self.kibana_plugin.available)
|
|
|
|
def test_build_config_unreadable_config(self):
|
|
patch_log_error = mock.patch.object(LOG, 'error')
|
|
patch_log_exception = mock.patch.object(LOG, 'exception')
|
|
patch_read_config = mock.patch.object(self.kibana_plugin,
|
|
'_read_config',
|
|
side_effect=Exception('oh'))
|
|
|
|
with contextlib.nested(
|
|
patch_log_error,
|
|
patch_log_exception,
|
|
patch_read_config
|
|
) as (mock_log_error, mock_log_exception, _):
|
|
self.kibana_plugin.build_config()
|
|
|
|
self.assertEqual(mock_log_error.call_count, 1)
|
|
self.assertEqual(mock_log_error.call_args[0][0],
|
|
'Failed to read configuration at '
|
|
'/opt/kibana/config/kibana.yml')
|
|
|
|
self.assertEqual(mock_log_exception.call_count, 1)
|
|
self.assertEqual(repr(mock_log_exception.call_args[0][0]),
|
|
repr(Exception('oh')))
|
|
|
|
def test_build_config_https_support(self):
|
|
config = ('localhost', 5700, 'https')
|
|
patch_log_error = mock.patch.object(LOG, 'error')
|
|
patch_read_config = mock.patch.object(self.kibana_plugin,
|
|
'_read_config',
|
|
return_value=config)
|
|
|
|
with contextlib.nested(
|
|
patch_log_error,
|
|
patch_read_config
|
|
) as (mock_log_error, _):
|
|
self.assertIsNone(self.kibana_plugin.build_config())
|
|
|
|
self.assertEqual(mock_log_error.call_count, 1)
|
|
self.assertEqual(mock_log_error.call_args[0][0],
|
|
'"https" protocol is currently not supported')
|
|
|
|
def test_build_config_no_metric_support(self):
|
|
config = ('localhost', 5700, 'http')
|
|
patch_log_warning = mock.patch.object(LOG, 'warning')
|
|
patch_read_config = mock.patch.object(self.kibana_plugin,
|
|
'_read_config',
|
|
return_value=config)
|
|
has_metric_patch = mock.patch.object(self.kibana_plugin,
|
|
'_has_metrics_support',
|
|
return_value=False)
|
|
|
|
with contextlib.nested(
|
|
patch_log_warning,
|
|
patch_read_config,
|
|
has_metric_patch
|
|
) as (patch_log_warning, _, __):
|
|
self.assertIsNone(self.kibana_plugin.build_config())
|
|
|
|
self.assertEqual(patch_log_warning.call_count, 1)
|
|
self.assertEqual(patch_log_warning.call_args[0][0],
|
|
'Running kibana does not support '
|
|
'metrics, skipping...')
|
|
|
|
def test_build_config_ok_no_kibana_user(self):
|
|
self._test_build_config_ok(None)
|
|
|
|
def test_build_config_ok_kibana_user(self):
|
|
self._test_build_config_ok('kibana-wizard')
|
|
|
|
def _test_build_config_ok(self, kibana_user):
|
|
kibana_host = 'localhost'
|
|
kibana_port = 5700
|
|
kibana_protocol = 'http'
|
|
|
|
kibana_cfg = (kibana_host, kibana_port, kibana_protocol)
|
|
kibana_url = '%s://%s:%d/api/status' % (
|
|
kibana_protocol,
|
|
kibana_host,
|
|
kibana_port
|
|
)
|
|
|
|
fixture_file = (os.path.dirname(os.path.abspath(__file__))
|
|
+ '/../checks_d/fixtures/test_kibana.json')
|
|
response = json.load(file(fixture_file))
|
|
|
|
get_metric_req_ret = mock.Mock(
|
|
wraps=JsonResponse(response)
|
|
)
|
|
|
|
patch_read_config = mock.patch.object(self.kibana_plugin,
|
|
'_read_config',
|
|
return_value=kibana_cfg)
|
|
has_metric_patch = mock.patch.object(self.kibana_plugin,
|
|
'_has_metrics_support',
|
|
return_value=True)
|
|
get_metrics_patch = mock.patch.object(self.kibana_plugin,
|
|
'_get_metrics_request',
|
|
return_value=get_metric_req_ret)
|
|
|
|
self.kibana_plugin.args = {'kibana-user': kibana_user}
|
|
|
|
with contextlib.nested(patch_read_config,
|
|
has_metric_patch,
|
|
get_metrics_patch):
|
|
conf = self.kibana_plugin.build_config()
|
|
self.assertIsNotNone(conf)
|
|
|
|
self.assertItemsEqual(['kibana', 'process'], conf.keys())
|
|
self._verify_kibana_conf(conf['kibana'], kibana_url)
|
|
self._verify_process_conf(conf['process'], kibana_user)
|