Merge "Add type property to the template metadata"

This commit is contained in:
Zuul 2018-01-23 12:19:20 +00:00 committed by Gerrit Code Review
commit 9fce59c4d1
23 changed files with 421 additions and 7 deletions

View File

@ -25,6 +25,7 @@ The template is written in YAML language, with the following structure:
metadata:
version: <template version>
name: <unique template identifier>
type: <one of: standard, definition, equivalence>
description: <what this template does>
definitions:
entities:
@ -49,6 +50,7 @@ The template is divided into four main sections:
- *version -* the version of the template format. The default is 1.
- *name -* the name of the template
- *type -* the type of the template. Should be one of: standard, definition, equivalence
- *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.
@ -70,7 +72,9 @@ language, with the following structure:
::
metadata:
version: 2
name: <unique definition template identifier. Used in the includes section of regular templates>
type: definition
description: <what definitions this template contains>
definitions:
entities:
@ -159,7 +163,9 @@ The following template demonstrates
::
metadata:
version: 2
name: host_high_mem_load_to_instance_mem_suboptimal
type: standard
description: when there is high memory on the host, show implications on the instances
definitions:
entities:
@ -268,7 +274,9 @@ case-insensitive.
::
metadata:
version: 2
name: deduced_alarm_for_all_host_in_error
type: standard
description: raise deduced alarm for all hosts in error
definitions:
entities:
@ -297,7 +305,9 @@ an alarm on the hosting zone or an alarm on the hosting host.
::
metadata:
version: 2
name: deduced_alarm_two_possible_triggers
type: standard
description: deduced alarm using or in condition
definitions:
entities:
@ -520,7 +530,9 @@ E2 both are instances like this:
::
metadata:
version: 2
name: two_similar_instances
type: standard
definitions:
entities:
- entity:

View File

@ -0,0 +1,4 @@
---
features:
- Added a mandatory ``type`` property to the templates metadata section in
version 2. The type Should be one of {standard, definition, equivalence}

View File

@ -162,6 +162,11 @@ class TemplateTypes(object):
DEFINITION = 'definition'
EQUIVALENCE = 'equivalence'
@staticmethod
def types():
return [value for type, value in vars(TemplateTypes).items()
if not type.startswith(('_', 'types'))]
class TemplateStatus(object):
ACTIVE = 'ACTIVE'

View File

@ -47,8 +47,10 @@ class Scenario(object):
# noinspection PyAttributeOutsideInit
class TemplateData(object):
def __init__(self, name, version, entities, relationships, scenarios):
def __init__(self, name, type, version, entities,
relationships, scenarios):
self.name = name
self.type = type
self.version = version
self.entities = entities
self.relationships = relationships
@ -62,6 +64,14 @@ class TemplateData(object):
def name(self, template_name):
self._name = template_name
@property
def type(self):
return self._type
@type.setter
def type(self, template_type):
self._type = template_type
@property
def version(self):
return self._version

View File

@ -57,6 +57,9 @@ class TemplateLoader(object):
name = template_def[TFields.METADATA][TFields.NAME]
# type might be None, it is defined only in version 2
type = template_def[TFields.METADATA].get(TFields.TYPE)
if def_templates is None:
def_templates = {}
defs = {}
@ -86,8 +89,8 @@ class TemplateLoader(object):
self.relationships).\
build_scenarios(template_def[TFields.SCENARIOS])
return TemplateData(name, template_schema.version(), self.entities,
self.relationships, scenarios)
return TemplateData(name, type, template_schema.version(),
self.entities, self.relationships, scenarios)
def _build_entities(self, entities_defs):
entities = {}

View File

@ -20,6 +20,7 @@ from vitrage.evaluator.template_functions.v2.functions import GET_ATTR
from vitrage.evaluator.template_loading.v1.action_loader import ActionLoader
from vitrage.evaluator.template_loading.v1.execute_mistral_loader import \
ExecuteMistralLoader
from vitrage.evaluator.template_schema_factory import TemplateSchemaFactory
from vitrage.evaluator.template_validation.content.v1.\
add_causal_relationship_validator import AddCausalRelationshipValidator
from vitrage.evaluator.template_validation.content.v1.definitions_validator \
@ -29,6 +30,8 @@ from vitrage.evaluator.template_validation.content.v1.\
V1ExecuteMistralValidator
from vitrage.evaluator.template_validation.content.v1.mark_down_validator \
import MarkDownValidator
from vitrage.evaluator.template_validation.content.v1.metadata_validator \
import MetadataValidator as V1MetadataValidator
from vitrage.evaluator.template_validation.content.v1.raise_alarm_validator \
import RaiseAlarmValidator
from vitrage.evaluator.template_validation.content.v1.scenario_validator \
@ -38,7 +41,8 @@ from vitrage.evaluator.template_validation.content.v1.set_state_validator \
from vitrage.evaluator.template_validation.content.v2.\
execute_mistral_validator import ExecuteMistralValidator as \
V2ExecuteMistralValidator
from vitrage.evaluator.template_schema_factory import TemplateSchemaFactory
from vitrage.evaluator.template_validation.content.v2.metadata_validator \
import MetadataValidator as V2MetadataValidator
LOG = log.getLogger(__name__)
@ -47,6 +51,7 @@ class TemplateSchema1(object):
def __init__(self):
self.validators = {
TemplateFields.DEFINITIONS: DefinitionsValidator,
TemplateFields.METADATA: V1MetadataValidator,
TemplateFields.SCENARIOS: ScenarioValidator,
ActionType.ADD_CAUSAL_RELATIONSHIP: AddCausalRelationshipValidator,
ActionType.EXECUTE_MISTRAL: V1ExecuteMistralValidator,
@ -73,8 +78,9 @@ class TemplateSchema2(TemplateSchema1):
def __init__(self):
super(TemplateSchema2, self).__init__()
self.validators[TemplateFields.METADATA] = V2MetadataValidator
self.validators[ActionType.EXECUTE_MISTRAL] = \
V2ExecuteMistralValidator()
V2ExecuteMistralValidator
self.loaders[ActionType.EXECUTE_MISTRAL] = ActionLoader()
self.functions[GET_ATTR] = get_attr

View File

@ -30,6 +30,20 @@ def content_validation(template, def_templates=None):
template_definitions = {}
result, template_schema = get_template_schema(template)
# Validate metadata
metadata_validator = \
template_schema.validators.get(TemplateFields.METADATA) \
if result.is_valid_config and template_schema else None
if result.is_valid_config:
if metadata_validator:
metadata = template.get(TemplateFields.METADATA)
result = metadata_validator.validate(metadata)
else:
result.is_valid_config = False # Not supposed to happen
# Validate definitions
def_validator = \
template_schema.validators.get(TemplateFields.DEFINITIONS) \
if result.is_valid_config and template_schema else None
@ -71,6 +85,7 @@ def content_validation(template, def_templates=None):
entities_index,
relationship_index)
# Validate scenarios
if result.is_valid_config:
scenario_validator = template_schema.validators.get(
TemplateFields.SCENARIOS)

View File

@ -0,0 +1,29 @@
# Copyright 2018 - 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.evaluator.template_validation.content.base import \
get_content_correct_result
from vitrage.evaluator.template_validation.content.base import \
get_content_fault_result
class MetadataValidator(object):
@classmethod
def validate(cls, metadata):
# In v1 all metadata validations are done by the syntax validator
if metadata:
return get_content_correct_result()
else:
return get_content_fault_result(62)

View File

@ -0,0 +1,45 @@
# Copyright 2018 - 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 oslo_log import log
from vitrage.common.constants import TemplateTypes
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.status_messages import status_msgs
LOG = log.getLogger(__name__)
class MetadataValidator(object):
@classmethod
def validate(self, metadata):
if not metadata:
return get_content_fault_result(62)
type = metadata.get(TemplateFields.TYPE)
if not type:
LOG.error('%s status code: %s' % (status_msgs[64], 64))
return get_content_fault_result(64)
if type not in TemplateTypes.types():
LOG.error('%s status code: %s' % (status_msgs[65], 65))
return get_content_fault_result(65)
return get_content_correct_result()

View File

@ -12,6 +12,7 @@
# License for the specific language governing permissions and limitations
# under the License.
from vitrage.common.constants import EntityCategory
from vitrage.common.constants import TemplateTypes
from vitrage.evaluator.actions.base import action_types
from vitrage.evaluator.template_schema_factory import TemplateSchemaFactory
@ -44,6 +45,10 @@ status_msgs = {
62: 'metadata is a mandatory section.',
63: 'Unsupported version. Version must be one of: {versions}'
.format(versions=TemplateSchemaFactory.supported_versions()),
64: 'metadata section must contain a type field in version 2. Type must be'
' one of: {types}'.format(types=TemplateTypes.types()),
65: 'Invalid template type. Type must be one of: {types}'
.format(types=TemplateTypes.types()),
# scenarios section status messages 80-99
80: 'scenarios is a mandatory section.',

View File

@ -117,7 +117,8 @@ def _validate_metadata_section(metadata):
schema = Schema({
TemplateFields.VERSION: any_str,
Required(TemplateFields.NAME, msg=60): any_str,
TemplateFields.DESCRIPTION: any_str
TemplateFields.DESCRIPTION: any_str,
TemplateFields.TYPE: any_str,
})
return _validate_dict_schema(schema, metadata)

View File

@ -2,6 +2,7 @@ metadata:
version: 2
name: v2_execute_mistral
description: execute mistral
type: standard
definitions:
entities:
- entity:

View File

@ -0,0 +1,32 @@
metadata:
version: 2
name: v2_standard
type: standard
description: v2 standard template
definitions:
entities:
- entity:
category: ALARM
type: nagios
name: host_problem
template_id: alarm
- entity:
category: RESOURCE
type: nova.host
template_id: resource
relationships:
- relationship:
source: alarm
target: resource
relationship_type: on
template_id : alarm_on_host
scenarios:
- scenario:
condition: alarm_on_host
actions:
- action:
action_type: set_state
properties:
state: SUBOPTIMAL
action_target:
target: resource

View File

@ -2,6 +2,7 @@ metadata:
version: 2
name: v2_with_func
description: template with a function
type: standard
definitions:
entities:
- entity:

View File

@ -0,0 +1,15 @@
# Copyright 2018 - 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.
__author__ = 'stack'

View File

@ -0,0 +1,15 @@
# Copyright 2018 - 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.
__author__ = 'stack'

View File

@ -0,0 +1,51 @@
# Copyright 2018 - 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.
# Copyright 2016 - 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.common.constants import TemplateTypes
from vitrage.evaluator.template_loading.template_loader import TemplateLoader
from vitrage.tests import base
from vitrage.tests.mocks import utils
from vitrage.utils import file as file_utils
class TemplateLoaderTest(base.BaseTest):
STANDARD_TEMPLATE = 'v2_standard.yaml'
def test_standard_template(self):
template_path = '%s/templates/version/v2/%s' % \
(utils.get_resources_dir(), self.STANDARD_TEMPLATE)
template_definition = file_utils.load_yaml_file(template_path, True)
template_data = TemplateLoader().load(template_definition)
self.assertIsNotNone(template_data)
type = template_data.type
self.assertIsNotNone(type, 'v2 template must include a type')
self.assertEqual(TemplateTypes.STANDARD, type,
'type should be ' + TemplateTypes.STANDARD)

View File

@ -0,0 +1,62 @@
# Copyright 2018 - 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.common.constants import TemplateTypes
from vitrage.evaluator.template_fields import TemplateFields
from vitrage.evaluator.template_validation.content.v1.metadata_validator \
import MetadataValidator
from vitrage.tests.unit.evaluator.template_validation.content.base import \
ValidatorTest
class MetadataValidatorTest(ValidatorTest):
def test_validate_metadata_standard(self):
# In v1, all metadata validations are done by the syntax validator
metadata = {TemplateFields.NAME: 'blabla',
TemplateFields.VERSION: '2',
TemplateFields.TYPE: TemplateTypes.STANDARD}
result = MetadataValidator.validate(metadata)
self._assert_correct_result(result)
def test_validate_metadata_definition(self):
# In v1, all metadata validations are done by the syntax validator
metadata = {TemplateFields.NAME: 'blabla',
TemplateFields.VERSION: '2',
TemplateFields.TYPE: TemplateTypes.DEFINITION}
result = MetadataValidator.validate(metadata)
self._assert_correct_result(result)
def test_validate_metadata_equivalence(self):
# In v1, all metadata validations are done by the syntax validator
metadata = {TemplateFields.NAME: 'blabla',
TemplateFields.VERSION: '2',
TemplateFields.TYPE: TemplateTypes.EQUIVALENCE}
result = MetadataValidator.validate(metadata)
self._assert_correct_result(result)
def test_validate_metadata_invalid_type(self):
# In v1, all metadata validations are done by the syntax validator
metadata = {TemplateFields.NAME: 'blabla',
TemplateFields.VERSION: '2',
TemplateFields.TYPE: 'invalid type'}
result = MetadataValidator.validate(metadata)
self._assert_correct_result(result)
def test_validate_metadata_no_type(self):
# In v1, all metadata validations are done by the syntax validator
metadata = {TemplateFields.NAME: 'blabla',
TemplateFields.VERSION: '2'}
result = MetadataValidator.validate(metadata)
self._assert_correct_result(result)

View File

@ -0,0 +1,57 @@
# Copyright 2018 - 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.common.constants import TemplateTypes
from vitrage.evaluator.template_fields import TemplateFields
from vitrage.evaluator.template_validation.content.v2.metadata_validator \
import MetadataValidator
from vitrage.tests.unit.evaluator.template_validation.content.base import \
ValidatorTest
class MetadataValidatorTest(ValidatorTest):
def test_validate_metadata_standard(self):
metadata = {TemplateFields.NAME: 'blabla',
TemplateFields.VERSION: '2',
TemplateFields.TYPE: TemplateTypes.STANDARD}
result = MetadataValidator.validate(metadata)
self._assert_correct_result(result)
def test_validate_metadata_definition(self):
metadata = {TemplateFields.NAME: 'blabla',
TemplateFields.VERSION: '2',
TemplateFields.TYPE: TemplateTypes.DEFINITION}
result = MetadataValidator.validate(metadata)
self._assert_correct_result(result)
def test_validate_metadata_equivalence(self):
metadata = {TemplateFields.NAME: 'blabla',
TemplateFields.VERSION: '2',
TemplateFields.TYPE: TemplateTypes.EQUIVALENCE}
result = MetadataValidator.validate(metadata)
self._assert_correct_result(result)
def test_validate_metadata_invalid_type(self):
metadata = {TemplateFields.NAME: 'blabla',
TemplateFields.VERSION: '2',
TemplateFields.TYPE: 'invalid type'}
result = MetadataValidator.validate(metadata)
self._assert_fault_result(result, 65)
def test_validate_metadata_no_type(self):
metadata = {TemplateFields.NAME: 'blabla',
TemplateFields.VERSION: '2'}
result = MetadataValidator.validate(metadata)
self._assert_fault_result(result, 64)

View File

@ -34,7 +34,7 @@ from vitrage.tests.mocks import utils
from vitrage.utils import file as file_utils
class BasicTemplateTest(base.BaseTest):
class TemplateLoaderTest(base.BaseTest):
BASIC_TEMPLATE = 'basic.yaml'
BASIC_TEMPLATE_WITH_INCLUDE = 'basic_with_include.yaml'

View File

@ -0,0 +1,30 @@
metadata:
version: 2
name: v2_definition
description: v2 definition template
type: definition
definitions:
entities:
- entity:
category: ALARM
name: notifiers.mistral.trigger.alarm.2
template_id: alarm_2
- entity:
category: ALARM
name: notifiers.mistral.trigger.alarm.for.function
template_id: alarm_for_func
- entity:
category: RESOURCE
type: nova.host
template_id: host
relationships:
- relationship:
source: alarm_2
relationship_type: on
target: host
template_id : alarm_2_on_host
- relationship:
source: alarm_for_func
relationship_type: on
target: host
template_id : alarm_for_func_on_host

View File

@ -0,0 +1,14 @@
metadata:
name: v2_equivalence
version: 2
type: equivalence
equivalences:
- equivalence:
- entity:
category: ALARM
type: nagios
name: host_problem
- entity:
category: ALARM
type: zabbix
name: host_problem

View File

@ -2,6 +2,7 @@ metadata:
version: 2
name: v2_execute_mistral
description: execute mistral
type: standard
definitions:
entities:
- entity: