HttpCheck can't detect changes if only change search_pattern

http check is not detecting changes when search_pattern was changed
but url keeps the same.
Add unit test for modify_config

Change-Id: I0762e963429ec9e5c7df0d9aef7e9ef1b9b57626
This commit is contained in:
Kaiyan Sheng 2016-09-06 10:04:13 -06:00
parent ddd6fb2312
commit 224c56bbcf
4 changed files with 456 additions and 25 deletions

View File

@ -0,0 +1,145 @@
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**
- [Modify_Config](#modify_config)
- [Examples](#examples)
- [Adding a new instance](#adding-a-new-instance)
- [Changing the current instance](#changing-the-current-instance)
- [License](#license)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
# Modify_Config
Modify_config is a function in "monasca_setup/main.py" (link: https://github
.com/openstack/monasca-agent/blob/master/monasca_setup/main.py). It compares
existing and detected configurations for each check plugin and writes out the
plugin configurations if there are changes.
## Examples
There are two examples shown here using http_check: one is to add a new
instance, another is to detect endpoint change on existing http_check instance.
#### Adding a new instance
old_config:
```
{'init_config': None,
'instances': [{'built_by': 'HttpCheck',
'name': 'logging',
'url': 'http://127.0.0.1:9200',
'use_keystone': False,
'match_pattern': '.*VERSION.*',
'collect_response_time': True,
'timeout': '10',
'dimensions': {'service': 'logging'}}]
}
```
monasca-setup arguments:
```
monasca-setup -d 'HttpCheck' -a 'url=http://192.168.10.6:8070 match_pattern=
.*OK.* name=monasca dimensions=service:monitoring'
```
input_config generated from monasca-setup:
```
{'http_check':
{'instances': [{'built_by': 'HttpCheck',
'name': 'monasca',
'url': 'http://192.168.10.6:8070',
'use_keystone': False,
'match_pattern': '.*OK.*',
'collect_response_time': True,
'timeout': '10',
'dimensions': {'service': 'monitoring'}
}]
'init_config': None
}
}
```
output_config from modify_config:
```
{'init_config': None,
'instances': [{'built_by': 'HttpCheck',
'name': 'logging',
'url': 'http://127.0.0.1:9200',
'use_keystone': False,
'match_pattern': '.*VERSION.*',
'collect_response_time': True,
'timeout': '10',
'dimensions': {'service': 'logging'}},
{'built_by': 'HttpCheck',
'name': 'monasca',
'url': 'http://192.168.10.6:8070',
'use_keystone': False,
'match_pattern': '.*OK.*',
'collect_response_time': True,
'timeout': '10',
'dimensions': {'service': 'monitoring'}}]
}
```
#### Changing the current instance
old_config:
```
{'init_config': None,
'instances': [{'built_by': 'HttpCheck',
'name': 'logging',
'url': 'http://192.168.10.6:8070',
'use_keystone': False,
'match_pattern': '.*VERSION.*',
'collect_response_time': True,
'timeout': '10',
'dimensions': {'service': 'logging'}}]
}
```
monasca-setup arguments:
```
monasca-setup -d 'HttpCheck' -a 'url=https://192.168.10.6:8070
match_pattern=.*VERSION.* dimensions=service:logging'
```
input_config generated from monasca-setup:
```
{'http_check':
{'instances': [{'built_by': 'HttpCheck',
'name': 'https://192.168.10.6:8070',
'url': 'https://192.168.10.6:8070',
'use_keystone': False,
'match_pattern': '.*VERSION.*',
'collect_response_time': True,
'dimensions': {'service': 'logging'}
}]
'init_config': None
}
}
```
output_config from modify_config:
```
{'init_config': None,
'instances': [{'built_by': 'HttpCheck',
'name': 'https://192.168.10.6:8070',
'url': 'https://192.168.10.6:8070',
'use_keystone': False,
'match_pattern': '.*VERSION.*',
'collect_response_time': True,
'dimensions': {'service': 'logging'}
}]
}
```
# License
(C) Copyright 2016 Hewlett Packard Enterprise Development LP

View File

@ -1,4 +1,4 @@
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development Company LP
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
"""Classes to aid in configuration of the agent."""
@ -102,6 +102,9 @@ def save_plugin_config(config_dir, plugin_name, user, conf):
def check_endpoint_changes(value, config):
"""Change urls in config with same path but different protocols into new
endpoints.
"""
new_url = value['instances'][0]['url']
old_urls = [i['url'] for i in config['instances'] if 'url' in i]
new_path = new_url.split("://")[1]
@ -111,7 +114,7 @@ def check_endpoint_changes(value, config):
if config['instances'][i]['url'] == config['instances'][i]['name']:
config['instances'][i]['name'] = new_url
config['instances'][i]['url'] = new_url
return value, config
return config
def delete_from_config(args, config, file_path, plugin_name):

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development Company LP
# (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP
""" Detect running daemons then configure and start the agent.
"""
@ -134,42 +134,64 @@ def base_configuration(args):
def modify_config(args, detected_config):
changes = False
# Compare existing and detected config for each check plugin and write out the plugin config if changes
for key, value in detected_config.iteritems():
"""Compare existing and detected config for each check plugin and write out
the plugin config if there are changes
"""
modified_config = False
for detection_plugin_name, new_config in detected_config.iteritems():
if args.overwrite:
changes = True
modified_config = True
if args.dry_run:
continue
else:
agent_config.save_plugin_config(args.config_dir, key, args.user, value)
agent_config.save_plugin_config(args.config_dir, detection_plugin_name, args.user, new_config)
else:
old_config = agent_config.read_plugin_config_from_disk(args.config_dir, key)
config = agent_config.read_plugin_config_from_disk(args.config_dir, detection_plugin_name)
# merge old and new config, new has precedence
if old_config is not None:
if key == "http_check":
old_config_urls = [i['url'] for i in old_config['instances'] if 'url' in i]
value, old_config = agent_config.check_endpoint_changes(value, old_config)
agent_config.merge_by_name(value['instances'], old_config['instances'])
# Sort before compare, if instances have no name the sort will fail making order changes significant
if config is not None:
# For HttpCheck, if the new input url has the same host and
# port but a different protocol comparing with one of the
# existing instances in http_check.yaml, we want to keep the
# existing http check instance and replace the url with the
# new protocol. If name in this instance is the same as the
# url, we replace name with new url too.
# For more details please see:
# monasca-agent/docs/DeveloperDocs/agent_internals.md
if detection_plugin_name == "http_check":
# Save old http_check urls from config for later comparison
config_urls = [i['url'] for i in config['instances'] if
'url' in i]
# Check endpoint change, use new protocol instead
# Note: config is possibly changed after running
# check_endpoint_changes function.
config = agent_config.check_endpoint_changes(new_config, config)
agent_config.merge_by_name(new_config['instances'], config['instances'])
# Sort before compare, if instances have no name the sort will
# fail making order changes significant
try:
value['instances'].sort(key=lambda k: k['name'])
old_config['instances'].sort(key=lambda k: k['name'])
new_config['instances'].sort(key=lambda k: k['name'])
config['instances'].sort(key=lambda k: k['name'])
except Exception:
pass
value_urls = [i['url'] for i in value['instances'] if 'url' in i]
if key == "http_check":
if value_urls == old_config_urls: # Don't write config if no change
if detection_plugin_name == "http_check":
new_config_urls = [i['url'] for i in new_config['instances'] if 'url' in i]
# Don't write config if no change
if new_config_urls == config_urls and new_config == config:
continue
else:
if value == old_config:
if new_config == config:
continue
changes = True
modified_config = True
if args.dry_run:
log.info("Changes would be made to the config file for the {0} check plugin".format(key))
log.info("Changes would be made to the config file for the {0}"
" check plugin".format(detection_plugin_name))
else:
agent_config.save_plugin_config(args.config_dir, key, args.user, value)
return changes
agent_config.save_plugin_config(args.config_dir, detection_plugin_name, args.user, new_config)
return modified_config
def validate_positive(value):

261
tests/test_modify_config.py Normal file
View File

@ -0,0 +1,261 @@
# (C) Copyright 2016 Hewlett Packard Enterprise Development LP
import collections
import mock
import unittest
import monasca_setup
import monasca_setup.agent_config
DEFAULT_HTTP_CHECK_CONFIG = {
'init_config': None,
'instances': [{'built_by': 'HttpCheck',
'match_pattern': '.*VERSION.*',
'url': 'http://127.0.0.1:9200',
'name': 'logging',
'timeout': '10',
'collect_response_time': True,
'use_keystone': False,
'dimensions': {'service': 'logging'}}]
}
DEFAULT_PROCESS_CHECK_CONFIG = {
'init_config': None,
'instances': [{'built_by': 'MonNotification',
'detailed': True,
'dimensions': {'component': 'monasca-notification'},
'exact_match': False,
'name': 'monasca-notification',
'search_string': ['monasca-notification']
}]
}
INPUT_ARGS = collections.namedtuple(
"InputArgs", ["overwrite", "user", "config_dir", "detection_args",
"detection_plugins", "dry_run"])
class TestModifyConfig(unittest.TestCase):
""" Unit tests for modify_config function in monasca_setup/main.py
More details are documented in:
monasca-agent/docs/DeveloperDocs/agent_internals.md
"""
def setUp(self):
self._config_data = {}
def save_config(self, config_dir, plugin_name, user, data):
self._config_data = data
@mock.patch('monasca_setup.main.agent_config.save_plugin_config')
@mock.patch('monasca_setup.main.agent_config.read_plugin_config_from_disk')
def test_no_modify_process_check_config(self, mock_read_config,
mock_save_config):
mock_read_config.return_value = DEFAULT_PROCESS_CHECK_CONFIG
mock_save_config.side_effect = self.save_config
# Add a new process check instance
same_built_by = DEFAULT_PROCESS_CHECK_CONFIG['instances'][0][
'built_by']
same_name = DEFAULT_PROCESS_CHECK_CONFIG['instances'][0][
'name']
args, detected_config = self._get_mon_api_check_args_and_config(
same_built_by, same_name)
self._check_no_change(args, detected_config)
@mock.patch('monasca_setup.main.agent_config.save_plugin_config')
@mock.patch('monasca_setup.main.agent_config.read_plugin_config_from_disk')
def test_modify_process_check_config(self, mock_read_config,
mock_save_config):
mock_read_config.return_value = DEFAULT_PROCESS_CHECK_CONFIG
mock_save_config.side_effect = self.save_config
# Add a new process check instance
built_by = 'MonAPI'
name = 'monasca-api'
args, detected_config = self._get_mon_api_check_args_and_config(
built_by, name)
expected_value = \
{'init_config': None,
'instances': [{'built_by': built_by,
'detailed': True,
'dimensions': {'component': 'monasca-api'},
'exact_match': False,
'name': name,
'search_string': ['monasca-api']
},
DEFAULT_PROCESS_CHECK_CONFIG['instances'][0]]
}
self._check_changes(args, detected_config, expected_value)
@mock.patch('monasca_setup.main.agent_config.save_plugin_config')
@mock.patch('monasca_setup.main.agent_config.read_plugin_config_from_disk')
def test_no_modify_http_check_config(self, mock_read_config,
mock_save_config):
mock_read_config.return_value = DEFAULT_HTTP_CHECK_CONFIG
mock_save_config.side_effect = self.save_config
# keep url and match_pattern are the same
same_url = DEFAULT_HTTP_CHECK_CONFIG['instances'][0]['url']
same_match_pattern = DEFAULT_HTTP_CHECK_CONFIG['instances'][0][
'match_pattern']
same_name = DEFAULT_HTTP_CHECK_CONFIG['instances'][0]['name']
args, detected_config = self. _get_http_check_args_and_config(
same_url, same_match_pattern, same_name)
self._check_no_change(args, detected_config)
@mock.patch('monasca_setup.main.agent_config.save_plugin_config')
@mock.patch('monasca_setup.main.agent_config.read_plugin_config_from_disk')
def test_modify_http_check_config(self, mock_read_config,
mock_save_config):
mock_read_config.return_value = DEFAULT_HTTP_CHECK_CONFIG
mock_save_config.side_effect = self.save_config
# Change protocol and match_pattern
url = 'https://127.0.0.1:9200'
match_pattern = '.*OK.*'
args, detected_config = self. _get_http_check_args_and_config(
url, match_pattern, 'logging')
expected_value = {'init_config': None,
'instances':
[{'built_by': 'HttpCheck',
'collect_response_time': True,
'url': url,
'match_pattern': match_pattern,
'name': 'logging',
'timeout': '10',
'use_keystone': False,
'dimensions': {'service': 'logging'}}]
}
self._check_changes(args, detected_config, expected_value)
@mock.patch('monasca_setup.main.agent_config.save_plugin_config')
@mock.patch('monasca_setup.main.agent_config.read_plugin_config_from_disk')
def test_http_check_endpoint_change(self, mock_read_config,
mock_save_config):
mock_read_config.return_value = DEFAULT_HTTP_CHECK_CONFIG
mock_save_config.side_effect = self.save_config
# Change only protocol
new_url = 'https://127.0.0.1:9200'
same_match_pattern = DEFAULT_HTTP_CHECK_CONFIG['instances'][0][
'match_pattern']
same_name = DEFAULT_HTTP_CHECK_CONFIG['instances'][0]['name']
args, detected_config = self. _get_http_check_args_and_config(
new_url, same_match_pattern, same_name)
expected_value = {'init_config': None,
'instances':
[{'built_by': 'HttpCheck',
'collect_response_time': True,
'url': new_url,
'match_pattern': same_match_pattern,
'name': same_name,
'timeout': '10',
'use_keystone': False,
'dimensions': {'service': 'logging'}}]
}
self._check_changes(args, detected_config, expected_value)
@mock.patch('monasca_setup.main.agent_config.save_plugin_config')
@mock.patch('monasca_setup.main.agent_config.read_plugin_config_from_disk')
def test_http_check_only_match_pattern(self, mock_read_config,
mock_save_config):
mock_read_config.return_value = DEFAULT_HTTP_CHECK_CONFIG
mock_save_config.side_effect = self.save_config
# Change only match_pattern
same_url = DEFAULT_HTTP_CHECK_CONFIG['instances'][0]['url']
new_match_pattern = '.*TEST.*'
same_name = DEFAULT_HTTP_CHECK_CONFIG['instances'][0]['name']
args, detected_config = self. _get_http_check_args_and_config(
same_url, new_match_pattern, same_name)
expected_value = {'init_config': None,
'instances':
[{'built_by': 'HttpCheck',
'collect_response_time': True,
'url': same_url,
'match_pattern': new_match_pattern,
'name': same_name,
'timeout': '10',
'use_keystone': False,
'dimensions': {'service': 'logging'}}]
}
self._check_changes(args, detected_config, expected_value)
@mock.patch('monasca_setup.main.agent_config.save_plugin_config')
@mock.patch('monasca_setup.main.agent_config.read_plugin_config_from_disk')
def test_http_check_new_url(self, mock_read_config, mock_save_config):
mock_read_config.return_value = DEFAULT_HTTP_CHECK_CONFIG
mock_save_config.side_effect = self.save_config
# Pass in a new url
new_url = 'http://192.168.10.6:8070'
new_match_pattern = '.*TEST.*'
new_name = new_url
args, detected_config = self. _get_http_check_args_and_config(
new_url, new_match_pattern, new_name)
expected_value = {'init_config': None,
'instances':
[{'built_by': 'HttpCheck',
'collect_response_time': True,
'url': new_url,
'match_pattern': new_match_pattern,
'name': new_name,
'timeout': '10',
'use_keystone': False,
'dimensions': {'service': 'logging'}},
DEFAULT_HTTP_CHECK_CONFIG['instances'][0]
]
}
self._check_changes(args, detected_config, expected_value)
def _check_no_change(self, args, detected_config):
changes = monasca_setup.main.modify_config(args, detected_config)
self.assertEqual(changes, False)
self.assertEqual(self._config_data, {})
def _check_changes(self, args, detected_config, expected_value):
changes = monasca_setup.main.modify_config(args, detected_config)
self.assertEqual(changes, True)
self.assertEqual(expected_value, self._config_data)
def _get_mon_api_check_args_and_config(self, built_by, name):
args = INPUT_ARGS(False, 'mon-agent', '/etc/monasca/agent', None,
['MonAPI'], False)
detected_config = {
'process':
{'instances': [{'built_by': built_by,
'detailed': True,
'dimensions': {
'component': name},
'exact_match': False,
'name': name,
'search_string': [name]
}],
'init_config': None
}
}
return args, detected_config
def _get_http_check_args_and_config(self, url, match_pattern, name):
args = INPUT_ARGS(False, 'mon-agent', '/etc/monasca/agent',
'url={0} match_pattern={1} name={2} timeout=10 '
'use_keystone=False'.format(
url, match_pattern, name),
['HttpCheck'], False)
detected_config = {
'http_check':
{'instances': [{'name': name,
'url': url,
'built_by': 'HttpCheck',
'use_keystone': False,
'match_pattern': match_pattern,
'collect_response_time': True,
'timeout': '10',
'dimensions': {'service': 'logging'}
}],
'init_config': None
}
}
return args, detected_config