Merge "Added a version to Vitrage templates"

This commit is contained in:
Zuul 2017-12-04 21:05:49 +00:00 committed by Gerrit Code Review
commit e8c4066881
12 changed files with 177 additions and 7 deletions

View File

@ -17,6 +17,7 @@ The template is written in YAML language, with the following structure:
::
metadata:
version: <template version>
name: <unique template identifier>
description: <what this template does>
definitions:
@ -38,17 +39,21 @@ The template is written in YAML language, with the following structure:
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).
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)
- *relationships * the relationships between the entities (conceptually, corresponds to an edge 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)
- *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**.
- *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.
- *action(s) * a list of actions to execute when the condition is met.
- *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.
Definition Template Structure

View File

@ -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.

View File

@ -123,6 +123,7 @@ class TemplateTopologyFields(object):
METADATA = 'metadata'
DESCRIPTION = 'description'
NAME = 'name'
VERSION = 'version'
DEFINITIONS = 'definitions'

View File

@ -15,6 +15,10 @@
from vitrage.common.constants import TemplateTopologyFields
DEFAULT_VERSION = '1'
SUPPORTED_VERSIONS = ['1']
class TemplateFields(TemplateTopologyFields):
SCENARIOS = 'scenarios'

View File

@ -14,13 +14,18 @@
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_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.content.definitions_validator \
import DefinitionsValidator as DefValidator
from vitrage.evaluator.template_validation.content.scenario_validator import \
ScenarioValidator
from vitrage.evaluator.template_validation.status_messages import status_msgs
LOG = log.getLogger(__name__)
@ -30,11 +35,12 @@ def content_validation(template, def_templates=None):
if def_templates is None:
def_templates = {}
result = get_content_correct_result()
result = _validate_version(template)
entities_index = {}
template_definitions = {}
if TemplateFields.DEFINITIONS in template:
if result.is_valid_config and TemplateFields.DEFINITIONS in template:
template_definitions = template[TemplateFields.DEFINITIONS]
if TemplateFields.ENTITIES in template_definitions:
@ -76,3 +82,18 @@ def content_validation(template, def_templates=None):
result = ScenarioValidator(definitions_index).validate(scenarios)
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)

View File

@ -14,6 +14,7 @@
from vitrage.common.constants import EdgeLabel
from vitrage.common.constants import EntityCategory
from vitrage.evaluator.actions.base import action_types
from vitrage.evaluator.template_fields import SUPPORTED_VERSIONS
status_msgs = {
@ -41,6 +42,8 @@ status_msgs = {
# metadata section status messages 60-79
60: 'metadata section must contain id field.',
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
80: 'scenarios is a mandatory section.',

View File

@ -115,6 +115,7 @@ def _validate_metadata_section(metadata):
any_str = Any(str, six.text_type)
schema = Schema({
TemplateFields.VERSION: any_str,
Required(TemplateFields.NAME, msg=60): any_str,
TemplateFields.DESCRIPTION: any_str
})

View File

@ -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

View 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

View 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

View File

@ -25,6 +25,7 @@ from vitrage.utils import file as file_utils
CONDITION_TEMPLATES_DIR = '%s/templates/evaluator/conditions/%s'
REGEX_TEMPLATE_DIR = '%s/templates/regex/%s'
VERSION_TEMPLATE_DIR = '%s/templates/version/%s'
class TemplateContentValidatorTest(ValidatorTest):
@ -277,6 +278,27 @@ class TemplateContentValidatorTest(ValidatorTest):
self._execute_and_assert_with_correct_result(
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):
template_path = CONDITION_TEMPLATES_DIR % (utils.get_resources_dir(),
template_name)

View File

@ -36,6 +36,8 @@ class TemplateSyntaxValidatorTest(base.BaseTest):
cls.def_template_dir_path = utils.get_resources_dir() + \
'/templates/def_template_tests'
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.bad_template = \
ScenarioRepository._load_template_file(template_dir_path
@ -219,6 +221,23 @@ class TemplateSyntaxValidatorTest(base.BaseTest):
template = file_utils.load_yaml_file(template_path)
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):
self._test_validate_action_without_required_field(