Merge "Added a version to Vitrage templates"
This commit is contained in:
commit
e8c4066881
@ -17,6 +17,7 @@ The template is written in YAML language, with the following structure:
|
|||||||
::
|
::
|
||||||
|
|
||||||
metadata:
|
metadata:
|
||||||
|
version: <template version>
|
||||||
name: <unique template identifier>
|
name: <unique template identifier>
|
||||||
description: <what this template does>
|
description: <what this template does>
|
||||||
definitions:
|
definitions:
|
||||||
@ -38,17 +39,21 @@ The template is written in YAML language, with the following structure:
|
|||||||
|
|
||||||
The template is divided into four main sections:
|
The template is divided into four main sections:
|
||||||
|
|
||||||
- *metadata:* Contains the template name, and brief description of what the template does (optional)
|
- *metadata:* Contains general information about the template.
|
||||||
|
|
||||||
|
- *version -* the version of the template format. The default is 1.
|
||||||
|
- *name -* the name of the template
|
||||||
|
- *description -* a brief description of what the template does (optional)
|
||||||
- *definitions:* This section is **mandatory** unless an include section is specified in the template (see below).
|
- *definitions:* This section is **mandatory** unless an include section is specified in the template (see below).
|
||||||
This section contains the atomic definitions referenced later on, for entities and relationships.
|
This section contains the atomic definitions referenced later on, for entities and relationships.
|
||||||
|
|
||||||
- *entities –* describes the resources and alarms which are relevant to the template scenario (conceptually, corresponds to a vertex in the entity graph)
|
- *entities –* describes the resources and alarms which are relevant to the template scenario (conceptually, corresponds to a vertex in the entity graph)
|
||||||
- *relationships –* the relationships between the entities (conceptually, corresponds to an edge in the entity graph)
|
- *relationships –* the relationships between the entities (conceptually, corresponds to an edge in the entity graph)
|
||||||
- *includes:* This section is optional. If included, it must contain a list of names of definition templates as they appear in the metadata section of said templates.
|
- *includes:* This section is optional. If included, it must contain a list of names of definition templates as they appear in the metadata section of said templates.
|
||||||
If only definitions from included definition templates are used to create scenarios within the template, then the *definitions* section is **optional**.
|
If only definitions from included definition templates are used to create scenarios within the template, then the *definitions* section is **optional**.
|
||||||
- *scenarios:* A list of if-then scenarios to consider. Each scenario is comprised of:
|
- *scenarios:* A list of if-then scenarios to consider. Each scenario is comprised of:
|
||||||
- *condition –* the condition to be met. This condition will be phrased referencing the entities and relationships previously defined.
|
- *condition –* the condition to be met. This condition will be phrased referencing the entities and relationships previously defined.
|
||||||
- *action(s) –* a list of actions to execute when the condition is met.
|
- *action(s) –* a list of actions to execute when the condition is met.
|
||||||
|
|
||||||
|
|
||||||
Definition Template Structure
|
Definition Template Structure
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- A ``version`` field was added to the metadata section of Vitrage templates,
|
||||||
|
to allow future changes that are not backward-compatible. The default
|
||||||
|
version is 1.
|
@ -123,6 +123,7 @@ class TemplateTopologyFields(object):
|
|||||||
METADATA = 'metadata'
|
METADATA = 'metadata'
|
||||||
DESCRIPTION = 'description'
|
DESCRIPTION = 'description'
|
||||||
NAME = 'name'
|
NAME = 'name'
|
||||||
|
VERSION = 'version'
|
||||||
|
|
||||||
DEFINITIONS = 'definitions'
|
DEFINITIONS = 'definitions'
|
||||||
|
|
||||||
|
@ -15,6 +15,10 @@
|
|||||||
from vitrage.common.constants import TemplateTopologyFields
|
from vitrage.common.constants import TemplateTopologyFields
|
||||||
|
|
||||||
|
|
||||||
|
DEFAULT_VERSION = '1'
|
||||||
|
SUPPORTED_VERSIONS = ['1']
|
||||||
|
|
||||||
|
|
||||||
class TemplateFields(TemplateTopologyFields):
|
class TemplateFields(TemplateTopologyFields):
|
||||||
|
|
||||||
SCENARIOS = 'scenarios'
|
SCENARIOS = 'scenarios'
|
||||||
|
@ -14,13 +14,18 @@
|
|||||||
|
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
|
from vitrage.evaluator.template_fields import DEFAULT_VERSION
|
||||||
|
from vitrage.evaluator.template_fields import SUPPORTED_VERSIONS
|
||||||
from vitrage.evaluator.template_fields import TemplateFields
|
from vitrage.evaluator.template_fields import TemplateFields
|
||||||
from vitrage.evaluator.template_validation.content.base import \
|
from vitrage.evaluator.template_validation.content.base import \
|
||||||
get_content_correct_result
|
get_content_correct_result
|
||||||
|
from vitrage.evaluator.template_validation.content.base import \
|
||||||
|
get_content_fault_result
|
||||||
from vitrage.evaluator.template_validation.content.definitions_validator \
|
from vitrage.evaluator.template_validation.content.definitions_validator \
|
||||||
import DefinitionsValidator as DefValidator
|
import DefinitionsValidator as DefValidator
|
||||||
from vitrage.evaluator.template_validation.content.scenario_validator import \
|
from vitrage.evaluator.template_validation.content.scenario_validator import \
|
||||||
ScenarioValidator
|
ScenarioValidator
|
||||||
|
from vitrage.evaluator.template_validation.status_messages import status_msgs
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
@ -30,11 +35,12 @@ def content_validation(template, def_templates=None):
|
|||||||
if def_templates is None:
|
if def_templates is None:
|
||||||
def_templates = {}
|
def_templates = {}
|
||||||
|
|
||||||
result = get_content_correct_result()
|
result = _validate_version(template)
|
||||||
|
|
||||||
entities_index = {}
|
entities_index = {}
|
||||||
template_definitions = {}
|
template_definitions = {}
|
||||||
|
|
||||||
if TemplateFields.DEFINITIONS in template:
|
if result.is_valid_config and TemplateFields.DEFINITIONS in template:
|
||||||
template_definitions = template[TemplateFields.DEFINITIONS]
|
template_definitions = template[TemplateFields.DEFINITIONS]
|
||||||
|
|
||||||
if TemplateFields.ENTITIES in template_definitions:
|
if TemplateFields.ENTITIES in template_definitions:
|
||||||
@ -76,3 +82,18 @@ def content_validation(template, def_templates=None):
|
|||||||
result = ScenarioValidator(definitions_index).validate(scenarios)
|
result = ScenarioValidator(definitions_index).validate(scenarios)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_version(template):
|
||||||
|
metadata = template.get(TemplateFields.METADATA)
|
||||||
|
|
||||||
|
if metadata is None:
|
||||||
|
LOG.error('%s status code: %s' % (status_msgs[62], 62))
|
||||||
|
return get_content_fault_result(62)
|
||||||
|
|
||||||
|
version = metadata.get(TemplateFields.VERSION, DEFAULT_VERSION)
|
||||||
|
if version in SUPPORTED_VERSIONS:
|
||||||
|
return get_content_correct_result()
|
||||||
|
else:
|
||||||
|
LOG.error('%s status code: %s' % (status_msgs[63], 63))
|
||||||
|
return get_content_fault_result(63)
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
from vitrage.common.constants import EdgeLabel
|
from vitrage.common.constants import EdgeLabel
|
||||||
from vitrage.common.constants import EntityCategory
|
from vitrage.common.constants import EntityCategory
|
||||||
from vitrage.evaluator.actions.base import action_types
|
from vitrage.evaluator.actions.base import action_types
|
||||||
|
from vitrage.evaluator.template_fields import SUPPORTED_VERSIONS
|
||||||
|
|
||||||
status_msgs = {
|
status_msgs = {
|
||||||
|
|
||||||
@ -41,6 +42,8 @@ status_msgs = {
|
|||||||
# metadata section status messages 60-79
|
# metadata section status messages 60-79
|
||||||
60: 'metadata section must contain id field.',
|
60: 'metadata section must contain id field.',
|
||||||
62: 'metadata is a mandatory section.',
|
62: 'metadata is a mandatory section.',
|
||||||
|
63: 'Unsupported version. Version must be one of: {versions}'
|
||||||
|
.format(versions=SUPPORTED_VERSIONS),
|
||||||
|
|
||||||
# scenarios section status messages 80-99
|
# scenarios section status messages 80-99
|
||||||
80: 'scenarios is a mandatory section.',
|
80: 'scenarios is a mandatory section.',
|
||||||
|
@ -115,6 +115,7 @@ def _validate_metadata_section(metadata):
|
|||||||
any_str = Any(str, six.text_type)
|
any_str = Any(str, six.text_type)
|
||||||
|
|
||||||
schema = Schema({
|
schema = Schema({
|
||||||
|
TemplateFields.VERSION: any_str,
|
||||||
Required(TemplateFields.NAME, msg=60): any_str,
|
Required(TemplateFields.NAME, msg=60): any_str,
|
||||||
TemplateFields.DESCRIPTION: any_str
|
TemplateFields.DESCRIPTION: any_str
|
||||||
})
|
})
|
||||||
|
@ -0,0 +1,30 @@
|
|||||||
|
metadata:
|
||||||
|
version: 999
|
||||||
|
name: invalid_version
|
||||||
|
description: template with an invalid version
|
||||||
|
definitions:
|
||||||
|
entities:
|
||||||
|
- entity:
|
||||||
|
category: ALARM
|
||||||
|
name: compute.host.down
|
||||||
|
template_id: host_down_alarm
|
||||||
|
- entity:
|
||||||
|
category: RESOURCE
|
||||||
|
type: nova.host
|
||||||
|
template_id: host
|
||||||
|
relationships:
|
||||||
|
- relationship:
|
||||||
|
source: host_down_alarm
|
||||||
|
relationship_type: on
|
||||||
|
target: host
|
||||||
|
template_id : host_down_alarm_on_host
|
||||||
|
scenarios:
|
||||||
|
- scenario:
|
||||||
|
condition: host_down_alarm_on_host
|
||||||
|
actions:
|
||||||
|
- action:
|
||||||
|
action_type: set_state
|
||||||
|
properties:
|
||||||
|
state: ERROR
|
||||||
|
action_target:
|
||||||
|
target: host
|
29
vitrage/tests/resources/templates/version/no_version.yaml
Normal file
29
vitrage/tests/resources/templates/version/no_version.yaml
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
metadata:
|
||||||
|
name: no_version
|
||||||
|
description: template without version
|
||||||
|
definitions:
|
||||||
|
entities:
|
||||||
|
- entity:
|
||||||
|
category: ALARM
|
||||||
|
name: compute.host.down
|
||||||
|
template_id: host_down_alarm
|
||||||
|
- entity:
|
||||||
|
category: RESOURCE
|
||||||
|
type: nova.host
|
||||||
|
template_id: host
|
||||||
|
relationships:
|
||||||
|
- relationship:
|
||||||
|
source: host_down_alarm
|
||||||
|
relationship_type: on
|
||||||
|
target: host
|
||||||
|
template_id : host_down_alarm_on_host
|
||||||
|
scenarios:
|
||||||
|
- scenario:
|
||||||
|
condition: host_down_alarm_on_host
|
||||||
|
actions:
|
||||||
|
- action:
|
||||||
|
action_type: set_state
|
||||||
|
properties:
|
||||||
|
state: ERROR
|
||||||
|
action_target:
|
||||||
|
target: host
|
30
vitrage/tests/resources/templates/version/version1.yaml
Normal file
30
vitrage/tests/resources/templates/version/version1.yaml
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
metadata:
|
||||||
|
version: 1
|
||||||
|
name: version_1
|
||||||
|
description: template with version 1
|
||||||
|
definitions:
|
||||||
|
entities:
|
||||||
|
- entity:
|
||||||
|
category: ALARM
|
||||||
|
name: compute.host.down
|
||||||
|
template_id: host_down_alarm
|
||||||
|
- entity:
|
||||||
|
category: RESOURCE
|
||||||
|
type: nova.host
|
||||||
|
template_id: host
|
||||||
|
relationships:
|
||||||
|
- relationship:
|
||||||
|
source: host_down_alarm
|
||||||
|
relationship_type: on
|
||||||
|
target: host
|
||||||
|
template_id : host_down_alarm_on_host
|
||||||
|
scenarios:
|
||||||
|
- scenario:
|
||||||
|
condition: host_down_alarm_on_host
|
||||||
|
actions:
|
||||||
|
- action:
|
||||||
|
action_type: set_state
|
||||||
|
properties:
|
||||||
|
state: ERROR
|
||||||
|
action_target:
|
||||||
|
target: host
|
@ -25,6 +25,7 @@ from vitrage.utils import file as file_utils
|
|||||||
|
|
||||||
CONDITION_TEMPLATES_DIR = '%s/templates/evaluator/conditions/%s'
|
CONDITION_TEMPLATES_DIR = '%s/templates/evaluator/conditions/%s'
|
||||||
REGEX_TEMPLATE_DIR = '%s/templates/regex/%s'
|
REGEX_TEMPLATE_DIR = '%s/templates/regex/%s'
|
||||||
|
VERSION_TEMPLATE_DIR = '%s/templates/version/%s'
|
||||||
|
|
||||||
|
|
||||||
class TemplateContentValidatorTest(ValidatorTest):
|
class TemplateContentValidatorTest(ValidatorTest):
|
||||||
@ -277,6 +278,27 @@ class TemplateContentValidatorTest(ValidatorTest):
|
|||||||
self._execute_and_assert_with_correct_result(
|
self._execute_and_assert_with_correct_result(
|
||||||
basic_regex_template)
|
basic_regex_template)
|
||||||
|
|
||||||
|
def test_validate_template_with_no_version(self):
|
||||||
|
invalid_version_path = \
|
||||||
|
VERSION_TEMPLATE_DIR % (utils.get_resources_dir(),
|
||||||
|
"no_version.yaml")
|
||||||
|
template = file_utils.load_yaml_file(invalid_version_path)
|
||||||
|
self._execute_and_assert_with_correct_result(template)
|
||||||
|
|
||||||
|
def test_validate_template_with_version_1(self):
|
||||||
|
invalid_version_path = \
|
||||||
|
VERSION_TEMPLATE_DIR % (utils.get_resources_dir(),
|
||||||
|
"version1.yaml")
|
||||||
|
template = file_utils.load_yaml_file(invalid_version_path)
|
||||||
|
self._execute_and_assert_with_correct_result(template)
|
||||||
|
|
||||||
|
def test_validate_template_with_invalid_version(self):
|
||||||
|
invalid_version_path = \
|
||||||
|
VERSION_TEMPLATE_DIR % (utils.get_resources_dir(),
|
||||||
|
"invalid_version.yaml")
|
||||||
|
template = file_utils.load_yaml_file(invalid_version_path)
|
||||||
|
self._execute_and_assert_with_fault_result(template, 63)
|
||||||
|
|
||||||
def _execute_condition_template_with_correct_result(self, template_name):
|
def _execute_condition_template_with_correct_result(self, template_name):
|
||||||
template_path = CONDITION_TEMPLATES_DIR % (utils.get_resources_dir(),
|
template_path = CONDITION_TEMPLATES_DIR % (utils.get_resources_dir(),
|
||||||
template_name)
|
template_name)
|
||||||
|
@ -36,6 +36,8 @@ class TemplateSyntaxValidatorTest(base.BaseTest):
|
|||||||
cls.def_template_dir_path = utils.get_resources_dir() + \
|
cls.def_template_dir_path = utils.get_resources_dir() + \
|
||||||
'/templates/def_template_tests'
|
'/templates/def_template_tests'
|
||||||
template_dir_path = '%s/templates/general' % utils.get_resources_dir()
|
template_dir_path = '%s/templates/general' % utils.get_resources_dir()
|
||||||
|
cls.version_dir_path = '%s/templates/version/' \
|
||||||
|
% utils.get_resources_dir()
|
||||||
cls.template_yamls = file_utils.load_yaml_files(template_dir_path)
|
cls.template_yamls = file_utils.load_yaml_files(template_dir_path)
|
||||||
cls.bad_template = \
|
cls.bad_template = \
|
||||||
ScenarioRepository._load_template_file(template_dir_path
|
ScenarioRepository._load_template_file(template_dir_path
|
||||||
@ -219,6 +221,23 @@ class TemplateSyntaxValidatorTest(base.BaseTest):
|
|||||||
template = file_utils.load_yaml_file(template_path)
|
template = file_utils.load_yaml_file(template_path)
|
||||||
self._test_execution_with_correct_result(template)
|
self._test_execution_with_correct_result(template)
|
||||||
|
|
||||||
|
def test_template_with_no_version(self):
|
||||||
|
template_path = self.version_dir_path + 'no_version.yaml'
|
||||||
|
template = file_utils.load_yaml_file(template_path)
|
||||||
|
self._test_execution_with_correct_result(template)
|
||||||
|
|
||||||
|
def test_template_with_valid_version(self):
|
||||||
|
template_path = self.version_dir_path + 'version1.yaml'
|
||||||
|
template = file_utils.load_yaml_file(template_path)
|
||||||
|
self._test_execution_with_correct_result(template)
|
||||||
|
|
||||||
|
def test_template_with_invalid_version(self):
|
||||||
|
# Invalid version number is checked by the content validator, not by
|
||||||
|
# the syntax validator
|
||||||
|
template_path = self.version_dir_path + 'invalid_version.yaml'
|
||||||
|
template = file_utils.load_yaml_file(template_path)
|
||||||
|
self._test_execution_with_correct_result(template)
|
||||||
|
|
||||||
def _test_validate_action_without_required_fields(self):
|
def _test_validate_action_without_required_fields(self):
|
||||||
|
|
||||||
self._test_validate_action_without_required_field(
|
self._test_validate_action_without_required_field(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user