Support templates with parameters in v3.

Change-Id: I5ddd4fb27694bfb4efe33753c85f4e3c58edb89a
Story: 2004056
Task: 29445
Depends-On: https://review.openstack.org/#/c/638096/
This commit is contained in:
Idan Hefetz 2019-02-20 07:18:41 +00:00
parent fb84a1f9c7
commit 72ce36b415
24 changed files with 430 additions and 216 deletions

View File

@ -17,65 +17,49 @@ from oslo_log import log
import re
import six
from vitrage.evaluator.template_validation.content.base import \
get_content_correct_result
from vitrage.evaluator.template_validation.content.base import \
get_content_fault_result
from vitrage.evaluator.template_validation.status_messages import status_msgs
from vitrage.evaluator.template_validation.base import ValidationError
LOG = log.getLogger(__name__)
FuncInfo = namedtuple('FuncInfo', ['name', 'func', 'error_code'])
class FunctionResolver(object):
@classmethod
def resolve_function(cls, func_info, template, **kwargs):
return cls._traverse_function(func_info, template, True, **kwargs)
def resolve_function(func_info, template, **kwargs):
return _traverse_function(func_info, template, resolve=True, **kwargs)
@classmethod
def validate_function(cls, func_info, template, **kwargs):
return cls._traverse_function(func_info, template, False, **kwargs)
@classmethod
def _traverse_function(cls, func_info, template, resolve, **kwargs):
return cls._recursive_resolve_function(
func_info, template, template, resolve, **kwargs)
def validate_function(func_info, template, **kwargs):
return _traverse_function(func_info, template, resolve=False, **kwargs)
@classmethod
def _recursive_resolve_function(cls, func_info, template, template_block,
resolve, **kwargs):
result = get_content_correct_result()
for key, value in template_block.items():
if result.is_valid_config:
if isinstance(value, six.string_types) and \
_is_wanted_function(value, func_info.name):
def _traverse_function(func_info, template, resolve, **kwargs):
return _recursive_resolve_function(
func_info, template, template, resolve, **kwargs)
func = func_info.func
if not func:
status = func_info.error_code
LOG.error('%s status code: %s' %
(status_msgs[status], status))
return get_content_fault_result(status)
result, resolved_value = func(value, template, **kwargs)
if result.is_valid_config and resolve:
template_block[key] = resolved_value
LOG.debug('Replaced %s with %s', value,
resolved_value)
def _recursive_resolve_function(func_info, template, template_block,
resolve, **kwargs):
elif isinstance(value, dict):
result = cls._recursive_resolve_function(
func_info, template, value, resolve, **kwargs)
for key, value in template_block.items():
if isinstance(value, six.string_types) and \
_is_wanted_function(value, func_info.name):
elif isinstance(value, list):
for item in value:
if result.is_valid_config:
result = cls._recursive_resolve_function(
func_info, template, item, resolve, **kwargs)
if not func_info.func:
raise ValidationError(func_info.error_code, value)
return result
resolved_value = func_info.func(value, template, **kwargs)
if resolve:
template_block[key] = resolved_value
LOG.debug('Replaced %s with %s', value, resolved_value)
elif isinstance(value, dict):
_recursive_resolve_function(
func_info, template, value, resolve, **kwargs)
elif isinstance(value, list):
for item in value:
_recursive_resolve_function(
func_info, template, item, resolve, **kwargs)
def is_function(str):

View File

@ -13,11 +13,10 @@
# under the License.
from oslo_log import log
from vitrage.evaluator.template_functions.function_resolver import \
FuncInfo
from vitrage.evaluator.template_functions.function_resolver import \
FunctionResolver
from vitrage.evaluator.template_functions import function_resolver
from vitrage.evaluator.template_functions import GET_PARAM
from vitrage.evaluator.template_validation.base import get_custom_fault_result
from vitrage.evaluator.template_validation.base import ValidationError
from vitrage.evaluator.template_validation.content.base import \
get_content_correct_result
from vitrage.evaluator.template_validation.content.base import \
@ -37,7 +36,13 @@ def resolve_parameters(template_def, params=None):
get_param = template_schema.functions.get(GET_PARAM)
return FunctionResolver().resolve_function(
func_info=FuncInfo(name=GET_PARAM, func=get_param, error_code=160),
template=template_def,
actual_params=params)
try:
function_resolver.resolve_function(
func_info=function_resolver.FuncInfo(
name=GET_PARAM, func=get_param, error_code=0),
template=template_def,
actual_params=params)
except ValidationError as e:
return get_custom_fault_result(e.code, e.details)
return get_content_correct_result()

View File

@ -15,11 +15,7 @@ from oslo_log import log
from vitrage.evaluator.template_fields import TemplateFields
from vitrage.evaluator.template_functions import GET_PARAM
from vitrage.evaluator.template_validation.content.base import \
get_content_correct_result
from vitrage.evaluator.template_validation.content.base import \
get_content_fault_result
from vitrage.evaluator.template_validation.status_messages import status_msgs
from vitrage.evaluator.template_validation.base import ValidationError
LOG = log.getLogger(__name__)
@ -112,42 +108,39 @@ def get_param(param_name, template, **kwargs):
:param kwargs: Additional arguments.
The expected argument is actual_params, a dict with key=value pairs of
parameter values.
:return: A tuple of (Result, param value)
The parameter value is taken from the actual_params, if given, or from the
default value that is defined in the template parameters section.
If none exists, a fault result is returned.
:return: The parameter value is taken from the actual_params, if given, or
from the default value that is defined in the template parameters section.
If none exists, or param_name does not contains a valid function call
a ValidationError is raised.
:raises: ValidationError
"""
param_defs = template.get(TemplateFields.PARAMETERS)
actual_params = kwargs.get('actual_params')
if not param_defs:
LOG.error('%s status code: %s' % (status_msgs[161], 161))
return get_content_fault_result(161), None
raise ValidationError(161)
if param_name.startswith(GET_PARAM):
if not param_name.startswith(GET_PARAM + '(') or \
not param_name.endswith(')') or \
len(param_name) < len(GET_PARAM) + 3:
LOG.error('%s status code: %s' % (status_msgs[162], 162))
return get_content_fault_result(162), None
raise ValidationError(162, param_name)
param_name = extract_param_name(param_name)
if not param_name:
LOG.error('%s status code: %s' % (status_msgs[162], 162))
return get_content_fault_result(162), None
extracted_param_name = extract_param_name(param_name)
if not extracted_param_name:
raise ValidationError(162, param_name)
# Make sure the parameter is defined in the parameters section
found_param_def = None
for param_key, param_value in param_defs.items():
if param_name == param_key:
if extracted_param_name == param_key:
found_param_def = param_key, param_value
if not found_param_def:
LOG.error('%s status code: %s' % (status_msgs[161], 161))
return get_content_fault_result(161), None
raise ValidationError(161, extracted_param_name)
# Check if an actual value was assigned to this parameter
param_value = get_actual_value(param_name, actual_params)
param_value = get_actual_value(extracted_param_name, actual_params)
if not param_value:
found_param_value = found_param_def[1]
default = found_param_value.get(TemplateFields.DEFAULT) \
@ -155,9 +148,9 @@ def get_param(param_name, template, **kwargs):
if default:
param_value = default
else:
return get_content_fault_result(163), None
raise ValidationError(163, extracted_param_name)
return get_content_correct_result(), param_value
return param_value
def extract_param_name(param):

View File

@ -127,7 +127,10 @@ class TemplateSchema3(object):
ActionType.SET_STATE: V3ActionLoader(),
}
self.functions = {GET_ATTR: get_attr}
self.functions = {
GET_ATTR: get_attr,
GET_PARAM: get_param
}
def version(self):
return '3'

View File

@ -40,7 +40,7 @@ def validate_template(template, def_templates, params=None):
try:
template_schema.validators[SYNTAX].validate(template)
template_schema.validators[CONTENT].validate(template)
template_schema.validators[CONTENT].validate(template, params)
except base.ValidationError as e:
return base.get_custom_fault_result(e.code, e.details)
except VoluptuousError as e:

View File

@ -43,7 +43,7 @@ def get_fault_result(description, code, msg=None):
def get_custom_fault_result(code, msg):
return Result('Template validation', False, code,
status_msgs[code] + ' ' + msg)
status_msgs[code] + ' - ' + msg)
def get_status_code(voluptuous_error):

View File

@ -104,6 +104,5 @@ def content_validation(template, def_templates=None, params=None):
def parameters_validation(template_schema, template, actual_params):
params_validator = \
template_schema.validators.get(GET_PARAM) if template_schema else None
params_validator = template_schema.validators[GET_PARAM]
return params_validator.validate(template, actual_params)

View File

@ -21,6 +21,9 @@ from vitrage.evaluator.base import get_template_schema
from vitrage.evaluator import condition as dnf
from vitrage.evaluator.template_fields import TemplateFields
from vitrage.evaluator.template_functions import function_resolver
from vitrage.evaluator.template_functions import GET_PARAM
from vitrage.evaluator.template_functions.v2.functions import get_param
from vitrage.evaluator.template_loading.template_loader_v3 import \
TemplateLoader as V3TemplateLoader
from vitrage.evaluator.template_validation.base import ValidationError
@ -33,9 +36,10 @@ RELATION = 'relationship'
class ContentValidator(object):
@staticmethod
def validate(template):
def validate(template, actual_params):
_validate_entities_regex(template)
_validate_conditions(template)
_validate_parameters(template, actual_params)
# As part of validation, when it is finished,
# we try to load the template, as some validations can only be
@ -69,6 +73,14 @@ def _validate_conditions(template):
_validate_not_condition(condition)
def _validate_parameters(template, actual_params):
function_resolver.validate_function(
func_info=function_resolver.FuncInfo(
name=GET_PARAM, func=get_param, error_code=160),
template=template,
actual_params=actual_params)
def _validate_condition_entity_ids(template, condition):
curr_str = ' ' + condition + ' '

View File

@ -12,11 +12,12 @@
# License for the specific language governing permissions and limitations
# under the License.
from vitrage.evaluator.template_functions.function_resolver import \
FuncInfo
from vitrage.evaluator.template_functions.function_resolver import \
FunctionResolver
from vitrage.evaluator.template_functions import function_resolver
from vitrage.evaluator.template_functions import GET_PARAM
from vitrage.evaluator.template_validation.base import get_custom_fault_result
from vitrage.evaluator.template_validation.base import ValidationError
from vitrage.evaluator.template_validation.content.base import \
get_content_correct_result
class GetParamValidator(object):
@ -25,7 +26,12 @@ class GetParamValidator(object):
def validate(cls, template, actual_params):
# if there is a get_param in the template, an error message will be
# returned since func is None
return FunctionResolver().validate_function(
func_info=FuncInfo(name=GET_PARAM, func=None, error_code=160),
template=template,
actual_params=actual_params)
try:
function_resolver.validate_function(
func_info=function_resolver.FuncInfo(
name=GET_PARAM, func=None, error_code=160),
template=template,
actual_params=actual_params)
except ValidationError as e:
return get_custom_fault_result(e.code, e.details)
return get_content_correct_result()

View File

@ -12,19 +12,25 @@
# License for the specific language governing permissions and limitations
# under the License.
from vitrage.evaluator.template_functions.function_resolver import \
FuncInfo
from vitrage.evaluator.template_functions.function_resolver import \
FunctionResolver
from vitrage.evaluator.template_functions import function_resolver
from vitrage.evaluator.template_functions import GET_PARAM
from vitrage.evaluator.template_functions.v2.functions import get_param
from vitrage.evaluator.template_validation.base import get_custom_fault_result
from vitrage.evaluator.template_validation.base import ValidationError
from vitrage.evaluator.template_validation.content.base import \
get_content_correct_result
class GetParamValidator(object):
@classmethod
def validate(cls, template, actual_params):
return FunctionResolver().validate_function(
func_info=FuncInfo(name=GET_PARAM, func=get_param, error_code=160),
template=template,
actual_params=actual_params)
try:
function_resolver.validate_function(
function_resolver.FuncInfo(
name=GET_PARAM, func=get_param, error_code=0),
template,
actual_params=actual_params)
except ValidationError as e:
return get_custom_fault_result(e.code, e.details)
return get_content_correct_result()

View File

@ -44,6 +44,7 @@ class SyntaxValidator(object):
Required(TF.ENTITIES, msg=10000): _entities_schema(),
Required(TF.METADATA, msg=62): _metadata_schema(),
Required(TF.SCENARIOS, msg=80): _scenarios_schema(template),
Optional(TF.PARAMETERS): _parameters_schema(),
})(template)
@ -79,6 +80,15 @@ def _scenarios_schema(template):
})])
def _parameters_schema():
return Schema({
any_str: Any(any_str, Schema({
Optional(TF.DESCRIPTION): any_str,
Optional(TF.DEFAULT): any_str,
})),
})
def _raise_alarm_schema(template):
return Schema({
Optional(ActionType.RAISE_ALARM): Schema({

View File

@ -19,6 +19,8 @@ from oslo_utils import timeutils
# noinspection PyPackageRequirements
from oslotest import base
import sys
from testtools import matchers
from testtools.matchers import HasLength
@ -91,6 +93,10 @@ class BaseTest(base.BaseTestCase):
dict(g2_edges.get(e_source_id)),
"Edges of each graph are not equal")
def assert_starts_with(self, expected_prefix, observed_str, msg=None):
self.assertThat(observed_str,
matchers.StartsWith(expected_prefix), msg)
@staticmethod
def path_get(project_file=None):
root = os.path.abspath(os.path.join(os.path.dirname(__file__),

View File

@ -23,10 +23,7 @@ from vitrage.tests.unit.entity_graph.base import TestEntityGraphUnitBase
class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
TEMPLATE_WITH_PARAMS = 'with_params.yaml'
TEMPLATE_WITH_EXTRA_PARAM_DEF = 'with_extra_param_def.yaml'
TEMPLATE_WITH_MISSING_PARAM_DEF = 'with_missing_param_def.yaml'
TEMPLATE_WITHOUT_PARAMS = 'without_params.yaml'
VALIDATION_FAILED = 'validation failed'
VALIDATION_OK = 'validation OK'
@ -46,13 +43,14 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
super(TestTemplates, self).tearDown()
self._delete_templates()
def test_validate_template_with_no_params(self):
# Setup
def _load_template_content(self, template_filename):
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_PARAMS)
files_content = [(template_path, self._load_yaml_file(template_path))]
template_filename)
return [(template_path, self._load_yaml_file(template_path))]
def _validate_template_with_no_params(self, template_filename):
files_content = self._load_template_content(template_filename)
# Action
results = self.apis.validate_template(
ctx=None, templates=files_content, template_type=None, params=None)
@ -62,14 +60,11 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
self.VALIDATION_FAILED, 163,
'Failed to resolve parameter', results)
def test_validate_template_with_missing_param(self):
def _validate_template_with_missing_param(self, template_filename):
# Setup
apis = TemplateApis(notifier=self.MockNotifier(), db=self._db)
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_PARAMS)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
params = {'template_name': 'template_with_params_1',
'alarm_name': 'My alarm', 'new_state': 'SUBOPTIMAL'}
@ -82,14 +77,10 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
self.VALIDATION_FAILED, 163,
'Failed to resolve parameter', results)
def test_validate_template_with_actual_params(self):
def _validate_template_with_actual_params(self, template_filename):
# Setup
apis = TemplateApis(notifier=self.MockNotifier(), db=self._db)
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_PARAMS)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
params = {'template_name': 'template_with_params_2',
'alarm_type': 'zabbix', 'alarm_name': 'My alarm',
'new_state': 'SUBOPTIMAL'}
@ -102,14 +93,10 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
self._assert_validate_template_result(
self.VALIDATION_OK, 0, 'Template validation is OK', results)
def test_validate_template_with_missing_param_def(self):
def _validate_template_with_missing_param_def(self, template_filename):
# Setup
apis = TemplateApis(notifier=self.MockNotifier(), db=self._db)
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_MISSING_PARAM_DEF)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
params = {'alarm_type': 'zabbix', 'alarm_name': 'My alarm',
'new_state': 'SUBOPTIMAL'}
@ -122,14 +109,10 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
self.VALIDATION_FAILED, 161, 'get_param called for a parameter '
'that is not defined in the \'parameters\' block', results)
def test_validate_template_without_params(self):
def _validate_template_without_params(self, template_filename):
# Setup
apis = TemplateApis(notifier=self.MockNotifier(), db=self._db)
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITHOUT_PARAMS)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
# Action
results = apis.validate_template(ctx=None, templates=files_content,
@ -139,14 +122,10 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
self._assert_validate_template_result(
self.VALIDATION_OK, 0, 'Template validation is OK', results)
def test_validate_template_with_extra_actual_param(self):
def _validate_template_with_extra_actual_param(self, template_filename):
# Setup
apis = TemplateApis(notifier=self.MockNotifier(), db=self._db)
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_PARAMS)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
params = {'template_name': 'template_with_params_2',
'alarm_type': 'zabbix', 'alarm_name': 'My alarm',
'new_state': 'SUBOPTIMAL',
@ -160,14 +139,10 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
self._assert_validate_template_result(
self.VALIDATION_OK, 0, 'Template validation is OK', results)
def test_validate_template_with_extra_param_def(self):
def _validate_template_with_extra_param_def(self, template_filename):
# Setup
apis = TemplateApis(notifier=self.MockNotifier(), db=self._db)
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_EXTRA_PARAM_DEF)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
params = {'template_name': 'template_with_params_2',
'alarm_type': 'zabbix', 'alarm_name': 'My alarm',
'new_state': 'SUBOPTIMAL'}
@ -180,12 +155,9 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
self._assert_validate_template_result(
self.VALIDATION_OK, 0, 'Template validation is OK', results)
def test_add_template_with_no_params(self):
def _add_template_with_no_params(self, template_filename):
# Setup
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_PARAMS)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
# Action.
added_templates = \
@ -196,15 +168,12 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
# Test assertions
self.assertThat(added_templates, matchers.HasLength(1))
self.assertEqual('ERROR', added_templates[0]['status'])
self.assertEqual('Failed to resolve parameter',
added_templates[0]['status details'])
self.assert_starts_with('Failed to resolve parameter',
added_templates[0]['status details'])
def test_add_template_with_missing_param(self):
def _add_template_with_missing_param(self, template_filename):
# Setup
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_PARAMS)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
params = {'template_name': 'template_with_params_3',
'alarm_name': 'My alarm', 'new_state': 'SUBOPTIMAL'}
@ -217,15 +186,12 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
# Test assertions
self.assertThat(added_templates, matchers.HasLength(1))
self.assertEqual('ERROR', added_templates[0]['status'])
self.assertEqual('Failed to resolve parameter',
added_templates[0]['status details'])
self.assert_starts_with('Failed to resolve parameter',
added_templates[0]['status details'])
def test_add_template_with_actual_params(self):
def _add_template_with_actual_params(self, template_filename):
# Setup
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_PARAMS)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
params = {'template_name': 'template_with_params_4',
'alarm_type': 'zabbix', 'alarm_name': 'My alarm',
'new_state': 'SUBOPTIMAL'}
@ -240,12 +206,9 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
self.assertThat(added_templates, matchers.HasLength(1))
self.assertEqual('LOADING', added_templates[0]['status'])
def test_add_template_with_missing_param_def(self):
def _add_template_with_missing_param_def(self, template_filename):
# Setup
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_MISSING_PARAM_DEF)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
params = {'alarm_type': 'zabbix', 'alarm_name': 'My alarm',
'new_state': 'SUBOPTIMAL'}
@ -257,16 +220,13 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
# Test assertions
self.assertEqual('ERROR', added_templates[0]['status'])
self.assertEqual('get_param called for a parameter that is not '
'defined in the \'parameters\' block',
added_templates[0]['status details'])
self.assert_starts_with('get_param called for a parameter that is not '
'defined in the \'parameters\' block',
added_templates[0]['status details'])
def test_add_template_without_params(self):
def _add_template_without_params(self, template_filename):
# Setup
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITHOUT_PARAMS)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
# Action
added_templates = \
@ -278,12 +238,9 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
self.assertThat(added_templates, matchers.HasLength(1))
self.assertEqual('LOADING', added_templates[0]['status'])
def test_add_template_with_extra_actual_param(self):
def _add_template_with_extra_actual_param(self, template_filename):
# Setup
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_PARAMS)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
params = {'template_name': 'template_with_extra_actual_param',
'alarm_type': 'zabbix', 'alarm_name': 'My alarm',
'new_state': 'SUBOPTIMAL',
@ -299,12 +256,9 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
self.assertThat(added_templates, matchers.HasLength(1))
self.assertEqual('LOADING', added_templates[0]['status'])
def test_add_template_with_extra_param_def(self):
def _add_template_with_extra_param_def(self, template_filename):
# Setup
template_path = '%s/templates/parameters/%s' % (
utils.get_resources_dir(),
self.TEMPLATE_WITH_EXTRA_PARAM_DEF)
files_content = [(template_path, self._load_yaml_file(template_path))]
files_content = self._load_template_content(template_filename)
params = {'template_name': 'template_with_extra_param_def',
'alarm_type': 'zabbix', 'alarm_name': 'My alarm',
'new_state': 'SUBOPTIMAL'}
@ -329,7 +283,7 @@ class TestTemplates(TestEntityGraphUnitBase, TestConfiguration):
self.assertThat(results, matchers.HasLength(1))
self.assertEqual(expected_status, results[0]['status'])
self.assertEqual(expected_status_code, results[0]['status code'])
self.assertEqual(expected_message, results[0]['message'])
self.assert_starts_with(expected_message, results[0]['message'])
def _delete_templates(self):
if self.added_template:

View File

@ -0,0 +1,67 @@
# Copyright 2019 - Nokia
#
# 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.
from vitrage.tests.functional.api_handler.test_templates import TestTemplates
TEMPLATE_WITH_PARAMS = 'v2_with_params.yaml'
TEMPLATE_WITH_EXTRA_PARAM_DEF = 'v2_with_extra_param_def.yaml'
TEMPLATE_WITH_MISSING_PARAM_DEF = 'v2_with_missing_param_def.yaml'
TEMPLATE_WITHOUT_PARAMS = 'v2_without_params.yaml'
class TestTemplatesV2(TestTemplates):
def test_validate_template_with_no_params(self):
self._validate_template_with_no_params(TEMPLATE_WITH_PARAMS)
def test_validate_template_with_missing_param(self):
self._validate_template_with_missing_param(TEMPLATE_WITH_PARAMS)
def test_validate_template_with_actual_params(self):
self._validate_template_with_actual_params(TEMPLATE_WITH_PARAMS)
def test_validate_template_with_missing_param_def(self):
self._validate_template_with_missing_param_def(
TEMPLATE_WITH_MISSING_PARAM_DEF)
def test_validate_template_without_params(self):
self._validate_template_without_params(TEMPLATE_WITHOUT_PARAMS)
def test_validate_template_with_extra_actual_param(self):
self._validate_template_with_extra_actual_param(TEMPLATE_WITH_PARAMS)
def test_validate_template_with_extra_param_def(self):
self._validate_template_with_extra_param_def(
TEMPLATE_WITH_EXTRA_PARAM_DEF)
def test_add_template_with_no_params(self):
self._add_template_with_no_params(TEMPLATE_WITH_PARAMS)
def test_add_template_with_missing_param(self):
self._add_template_with_missing_param(TEMPLATE_WITH_PARAMS)
def test_add_template_with_actual_params(self):
self._add_template_with_actual_params(TEMPLATE_WITH_PARAMS)
def test_add_template_with_missing_param_def(self):
self._add_template_with_missing_param_def(
TEMPLATE_WITH_MISSING_PARAM_DEF)
def test_add_template_without_params(self):
self._add_template_without_params(TEMPLATE_WITHOUT_PARAMS)
def test_add_template_with_extra_actual_param(self):
self._add_template_with_extra_actual_param(TEMPLATE_WITH_PARAMS)
def test_add_template_with_extra_param_def(self):
self._add_template_with_extra_param_def(TEMPLATE_WITH_EXTRA_PARAM_DEF)

View File

@ -0,0 +1,60 @@
# Copyright 2019 - Nokia
#
# 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.
from vitrage.tests.functional.api_handler.test_templates import TestTemplates
TEMPLATE_WITH_PARAMS = 'v3_with_params.yaml'
TEMPLATE_WITH_EXTRA_PARAM_DEF = 'v3_with_extra_param_def.yaml'
TEMPLATE_WITH_MISSING_PARAM_DEF = 'v3_with_missing_param_def.yaml'
class TestTemplatesV3(TestTemplates):
def test_validate_template_with_no_params(self):
self._validate_template_with_no_params(TEMPLATE_WITH_PARAMS)
def test_validate_template_with_missing_param(self):
self._validate_template_with_missing_param(TEMPLATE_WITH_PARAMS)
def test_validate_template_with_actual_params(self):
self._validate_template_with_actual_params(TEMPLATE_WITH_PARAMS)
def test_validate_template_with_missing_param_def(self):
self._validate_template_with_missing_param_def(
TEMPLATE_WITH_MISSING_PARAM_DEF)
def test_validate_template_with_extra_actual_param(self):
self._validate_template_with_extra_actual_param(TEMPLATE_WITH_PARAMS)
def test_validate_template_with_extra_param_def(self):
self._validate_template_with_extra_param_def(
TEMPLATE_WITH_EXTRA_PARAM_DEF)
def test_add_template_with_no_params(self):
self._add_template_with_no_params(TEMPLATE_WITH_PARAMS)
def test_add_template_with_missing_param(self):
self._add_template_with_missing_param(TEMPLATE_WITH_PARAMS)
def test_add_template_with_actual_params(self):
self._add_template_with_actual_params(TEMPLATE_WITH_PARAMS)
def test_add_template_with_missing_param_def(self):
self._add_template_with_missing_param_def(
TEMPLATE_WITH_MISSING_PARAM_DEF)
def test_add_template_with_extra_actual_param(self):
self._add_template_with_extra_actual_param(TEMPLATE_WITH_PARAMS)
def test_add_template_with_extra_param_def(self):
self._add_template_with_extra_param_def(TEMPLATE_WITH_EXTRA_PARAM_DEF)

View File

@ -0,0 +1,30 @@
metadata:
version: 3
type: standard
name: get_param(template_name)
description: template with extra parameter def (extra_param is unused)
parameters:
template_name:
description: the name of the template
default: template_with_params
alarm_type:
description: the type of the alarm
alarm_name:
new_state:
default: ERROR
extra_param:
description: a parameter definition that is unused in the template
entities:
alarm:
category: ALARM
type: get_param(alarm_type)
name: get_param(alarm_name)
host:
category: RESOURCE
type: nova.host
scenarios:
- condition: alarm [on] host
actions:
- set_state:
state: get_param(new_state)
target: host

View File

@ -0,0 +1,24 @@
metadata:
version: 3
type: standard
name: template_with_missing_param_def
description: INVALID template with missing parameter def for alarm_name
parameters:
alarm_type:
description: the type of the alarm
new_state:
default: ERROR
entities:
alarm:
category: ALARM
type: get_param(alarm_type)
name: get_param(alarm_name)
host:
category: RESOURCE
type: nova.host
scenarios:
- condition: alarm [on] host
actions:
- set_state:
state: get_param(new_state)
target: host

View File

@ -0,0 +1,28 @@
metadata:
version: 3
type: standard
name: get_param(template_name)
description: template with parameters
parameters:
template_name:
description: the name of the template
default: template_with_params
alarm_type:
description: the type of the alarm
alarm_name:
new_state:
default: ERROR
entities:
alarm:
category: ALARM
type: get_param(alarm_type)
name: get_param(alarm_name)
host:
category: RESOURCE
type: nova.host
scenarios:
- condition: alarm [on] host
actions:
- set_state:
state: get_param(new_state)
target: host

View File

@ -26,11 +26,13 @@ class ParametersValidatorTest(ValidatorTest):
"""
def test_validate_no_parameters(self):
result = GetParamValidator.validate(template={}, actual_params=None)
result = GetParamValidator.validate(
template={'alarm_name': "Don't add a comment"}, actual_params=None)
self._assert_correct_result(result)
def test_validate_empty_parameters(self):
result = GetParamValidator.validate(template={}, actual_params={})
result = GetParamValidator.validate(
template={'alarm_name': '+2 for everybody'}, actual_params={})
self._assert_correct_result(result)
def test_validate_with_parameter(self):

View File

@ -14,6 +14,7 @@
from vitrage.evaluator.template_fields import TemplateFields
from vitrage.evaluator.template_functions.v2.functions import get_param
from vitrage.evaluator.template_validation.base import ValidationError
from vitrage.evaluator.template_validation.content.v2.get_param_validator \
import GetParamValidator
from vitrage.tests.unit.evaluator.template_validation.content.base import \
@ -70,13 +71,15 @@ class ParametersValidatorTest(ValidatorTest):
def test_validate_get_param_with_no_parameters(self):
template = {'alarm_name': 'get_param(param1)'}
result, _ = get_param('get_param(param1)', template)
self._assert_fault_result(result, 161)
self.assert_get_param_result('get_param(param1)',
template,
expected_error_code=161)
def test_validate_get_param_with_empty_parameters(self):
template = {}
result, _ = get_param('get_param(param1)', template)
self._assert_fault_result(result, 161)
self.assert_get_param_result('get_param(param1)',
template,
expected_error_code=161)
def test_validate_get_param_with_undefined_parameter(self):
template = {
@ -90,8 +93,9 @@ class ParametersValidatorTest(ValidatorTest):
},
}
}
result, _ = get_param('get_param(undefined)', template)
self._assert_fault_result(result, 161)
self.assert_get_param_result('get_param(undefined)',
template,
expected_error_code=161)
def test_validate_get_param_with_valid_parameter(self):
template = {
@ -105,8 +109,9 @@ class ParametersValidatorTest(ValidatorTest):
},
}
}
result, result_value = get_param('get_param(param1)', template)
self._assert_correct_result(result)
self.assert_get_param_result('get_param(param1)',
template,
expected_error_code=0)
def test_validate_get_param_with_malformed_parameter(self):
template = {
@ -121,23 +126,23 @@ class ParametersValidatorTest(ValidatorTest):
}
}
result, _ = get_param('get_param(param1', template)
self._assert_fault_result(result, 162)
self.assert_get_param_result(
'get_param(param1', template, expected_error_code=162)
result, _ = get_param('get_paramparam1)', template)
self._assert_fault_result(result, 162)
self.assert_get_param_result(
'get_paramparam1)', template, expected_error_code=162)
result, _ = get_param('get_paramparam1', template)
self._assert_fault_result(result, 162)
self.assert_get_param_result(
'get_paramparam1', template, expected_error_code=162)
result, _ = get_param('get_param', template)
self._assert_fault_result(result, 162)
self.assert_get_param_result(
'get_param', template, expected_error_code=162)
result, _ = get_param('get_param()', template)
self._assert_fault_result(result, 162)
self.assert_get_param_result(
'get_param()', template, expected_error_code=162)
result, _ = get_param('get_param)param1(', template)
self._assert_fault_result(result, 162)
self.assert_get_param_result(
'get_param)param1(', template, expected_error_code=162)
def test_validate_get_param_with_actual_parameter(self):
template = {
@ -155,10 +160,10 @@ class ParametersValidatorTest(ValidatorTest):
'param1': 'value1',
'param2': 'value2'
}
result, result_value = get_param('get_param(param2)', template,
actual_params=actual_params)
self._assert_correct_result(result)
self.assertEqual('value2', result_value)
self.assert_get_param_result('get_param(param2)',
template,
actual_params,
expected_result='value2')
def test_validate_get_param_with_missing_actual_parameter(self):
template = {
@ -175,9 +180,9 @@ class ParametersValidatorTest(ValidatorTest):
actual_params = {
'param1': 'value1',
}
result, _ = get_param('get_param(param2)', template,
actual_params=actual_params)
self._assert_fault_result(result, 163)
self.assert_get_param_result('get_param(param2)',
template, actual_params,
expected_error_code=163)
def test_validate_get_param_with_default_actual_parameter(self):
template = {
@ -194,7 +199,27 @@ class ParametersValidatorTest(ValidatorTest):
actual_params = {
'param2': 'value2',
}
result, result_value = get_param('get_param(param1)', template,
actual_params=actual_params)
self._assert_correct_result(result)
self.assertEqual('this is my default', result_value)
self.assert_get_param_result('get_param(param1)',
template,
actual_params,
expected_result='this is my default')
def assert_get_param_result(self,
func_str,
template,
actual_params=None,
expected_result=None,
expected_error_code=None):
error = None
try:
result = get_param(func_str, template, actual_params=actual_params)
except ValidationError as e:
error = e
if expected_error_code:
self.assertIsNotNone(error)
self.assertEqual(error.code, expected_error_code)
else:
self.assertIsNone(error)
if expected_result:
self.assertEqual(expected_result, result)