Merge "Support the option to include definition template files in Vitrage templates."

This commit is contained in:
Jenkins 2017-09-27 08:20:45 +00:00 committed by Gerrit Code Review
commit fc30c1e378
28 changed files with 992 additions and 54 deletions

View File

@ -34,7 +34,8 @@ class TemplateApis(object):
FAILED_MSG = 'validation failed' FAILED_MSG = 'validation failed'
OK_MSG = 'validation OK' OK_MSG = 'validation OK'
def __init__(self, templates): def __init__(self, templates, def_templates={}):
self.def_templates = def_templates
self.templates = templates self.templates = templates
def get_templates(self, ctx): def get_templates(self, ctx):
@ -72,10 +73,10 @@ class TemplateApis(object):
results = [] results = []
for template in templates: for template in templates:
template_def = template[1] template_definition = template[1]
path = template[0] path = template[0]
syntax_result = syntax_validation(template_def) syntax_result = syntax_validation(template_definition)
if not syntax_result.is_valid_config: if not syntax_result.is_valid_config:
self._add_result(path, self._add_result(path,
self.FAILED_MSG, self.FAILED_MSG,
@ -85,7 +86,9 @@ class TemplateApis(object):
results) results)
continue continue
content_result = content_validation(template_def) content_result = content_validation(
template_definition,
self.def_templates)
if not content_result.is_valid_config: if not content_result.is_valid_config:
self._add_result(path, self._add_result(path,
self.FAILED_MSG, self.FAILED_MSG,

View File

@ -52,7 +52,9 @@ class VitrageApiHandlerService(os_service.Service):
endpoints = [TopologyApis(self.entity_graph, self.conf), endpoints = [TopologyApis(self.entity_graph, self.conf),
AlarmApis(self.entity_graph, self.conf), AlarmApis(self.entity_graph, self.conf),
RcaApis(self.entity_graph, self.conf), RcaApis(self.entity_graph, self.conf),
TemplateApis(self.scenario_repo.templates), TemplateApis(
self.scenario_repo.templates,
self.scenario_repo.def_templates),
EventApis(self.conf), EventApis(self.conf),
ResourceApis(self.entity_graph, self.conf)] ResourceApis(self.entity_graph, self.conf)]

View File

@ -24,5 +24,8 @@ OPTS = [
cfg.StrOpt('equivalences_dir', cfg.StrOpt('equivalences_dir',
default='/etc/vitrage/templates/equivalences', default='/etc/vitrage/templates/equivalences',
help='A path for entity equivalences used by the evaluator' help='A path for entity equivalences used by the evaluator'
) ),
cfg.StrOpt('def_templates_dir',
default='/etc/vitrage/templates/def_templates',
help='A path for def_template templates used by the evaluator')
] ]

View File

@ -23,6 +23,10 @@ from vitrage.evaluator.equivalence_repository import EquivalenceRepository
from vitrage.evaluator.template_data import TemplateData from vitrage.evaluator.template_data import TemplateData
from vitrage.evaluator.template_validation.content.template_content_validator \ from vitrage.evaluator.template_validation.content.template_content_validator \
import content_validation import content_validation
from vitrage.evaluator.template_validation.content.template_content_validator \
import def_template_content_validation
from vitrage.evaluator.template_validation.template_syntax_validator import \
def_template_syntax_validation
from vitrage.evaluator.template_validation.template_syntax_validator import \ from vitrage.evaluator.template_validation.template_syntax_validator import \
syntax_validation syntax_validation
from vitrage.utils import datetime as datetime_utils from vitrage.utils import datetime as datetime_utils
@ -31,21 +35,32 @@ from vitrage.utils import file as file_utils
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
EdgeKeyScenario = namedtuple('EdgeKeyScenario', ['label', 'source', 'target']) EdgeKeyScenario = namedtuple('EdgeKeyScenario', ['label', 'source', 'target'])
DEF_TEMPLATES_DIR_OPT = 'def_templates_dir'
class ScenarioRepository(object): class ScenarioRepository(object):
def __init__(self, conf): def __init__(self, conf):
self._templates = {} self._templates = {}
self._def_templates = {}
self.entity_equivalences = EquivalenceRepository().load_files( self.entity_equivalences = EquivalenceRepository().load_files(
conf.evaluator.equivalences_dir) conf.evaluator.equivalences_dir)
self.relationship_scenarios = defaultdict(list) self.relationship_scenarios = defaultdict(list)
self.entity_scenarios = defaultdict(list) self.entity_scenarios = defaultdict(list)
self._load_def_template_files(conf)
self._load_templates_files(conf) self._load_templates_files(conf)
@property @property
def templates(self): def templates(self):
return self._templates return self._templates
@property
def def_templates(self):
return self._def_templates
@def_templates.setter
def def_templates(self, def_templates):
self._def_templates = def_templates
@templates.setter @templates.setter
def templates(self, templates): def templates(self, templates):
self._templates = templates self._templates = templates
@ -82,27 +97,47 @@ class ScenarioRepository(object):
def add_template(self, template_def): def add_template(self, template_def):
current_time = datetime_utils.utcnow()
result = syntax_validation(template_def) result = syntax_validation(template_def)
if not result.is_valid_config: if not result.is_valid_config:
LOG.info('Unable to load template: %s' % result.comment) LOG.info('Unable to load template, syntax err: %s'
% result.comment)
else: else:
result = content_validation(template_def) result = content_validation(template_def, self._def_templates)
if not result.is_valid_config: if not result.is_valid_config:
LOG.info('Unable to load template: %s' % result.comment) LOG.info('Unable to load template, content err: %s'
% result.comment)
template_uuid = uuidutils.generate_uuid() template_uuid = uuidutils.generate_uuid()
current_time = datetime_utils.utcnow()
self.templates[str(template_uuid)] = Template(template_uuid, self.templates[str(template_uuid)] = Template(template_uuid,
template_def, template_def,
current_time, current_time,
result) result)
if result.is_valid_config: if result.is_valid_config:
template_data = TemplateData(template_def) template_data = TemplateData(template_def, self._def_templates)
for scenario in template_data.scenarios: for scenario in template_data.scenarios:
for equivalent_scenario in self._expand_equivalence(scenario): for equivalent_scenario in self._expand_equivalence(scenario):
self._add_scenario(equivalent_scenario) self._add_scenario(equivalent_scenario)
def add_def_template(self, def_template):
result = def_template_syntax_validation(def_template)
if not result.is_valid_config:
LOG.info('Unable to load definition template, syntax err: %s'
% result.comment)
else:
result = def_template_content_validation(def_template)
if not result.is_valid_config:
LOG.info('Unable to load definition template, content err: %s'
% result.comment)
current_time = datetime_utils.utcnow()
include_uuid = uuidutils.generate_uuid()
self._def_templates[str(include_uuid)] = Template(include_uuid,
def_template,
current_time,
result)
def _expand_equivalence(self, scenario): def _expand_equivalence(self, scenario):
equivalent_scenarios = [scenario] equivalent_scenarios = [scenario]
for symbol_name, entity in scenario.entities.items(): for symbol_name, entity in scenario.entities.items():
@ -133,6 +168,16 @@ class ScenarioRepository(object):
for relationship in scenario.relationships.values(): for relationship in scenario.relationships.values():
self._add_relationship_scenario(scenario, relationship) self._add_relationship_scenario(scenario, relationship)
def _load_def_template_files(self, conf):
if DEF_TEMPLATES_DIR_OPT in conf.evaluator:
def_templates_dir = conf.evaluator.def_templates_dir
def_templates = file_utils.load_yaml_files(def_templates_dir)
for def_template in def_templates:
self.add_def_template(def_template)
def _load_templates_files(self, conf): def _load_templates_files(self, conf):
templates_dir = conf.evaluator.templates_dir templates_dir = conf.evaluator.templates_dir

View File

@ -14,6 +14,7 @@
from collections import namedtuple from collections import namedtuple
from vitrage.common.constants import EdgeProperties as EProps from vitrage.common.constants import EdgeProperties as EProps
from vitrage.common.constants import VertexProperties as VProps from vitrage.common.constants import VertexProperties as VProps
from vitrage.common.exception import VitrageError from vitrage.common.exception import VitrageError
@ -26,6 +27,7 @@ from vitrage.graph.algo_driver.sub_graph_matching import NEG_CONDITION
from vitrage.graph.driver.networkx_graph import NXGraph from vitrage.graph.driver.networkx_graph import NXGraph
from vitrage.graph import Edge from vitrage.graph import Edge
from vitrage.graph import Vertex from vitrage.graph import Vertex
from vitrage.utils import evaluator as evaluator_utils
ActionSpecs = namedtuple('ActionSpecs', ['type', 'targets', 'properties']) ActionSpecs = namedtuple('ActionSpecs', ['type', 'targets', 'properties'])
Scenario = namedtuple('Scenario', ['id', Scenario = namedtuple('Scenario', ['id',
@ -61,18 +63,32 @@ class TemplateData(object):
'operational_severity': VProps.VITRAGE_OPERATIONAL_SEVERITY 'operational_severity': VProps.VITRAGE_OPERATIONAL_SEVERITY
} }
def __init__(self, template_def): def __init__(self, template_def, def_templates={}):
self.name = template_def[TFields.METADATA][TFields.NAME] self.name = template_def[TFields.METADATA][TFields.NAME]
defs = {}
if TFields.DEFINITIONS in template_def:
defs = template_def[TFields.DEFINITIONS] defs = template_def[TFields.DEFINITIONS]
if TFields.ENTITIES in defs:
self.entities = self._build_entities(defs[TFields.ENTITIES]) self.entities = self._build_entities(defs[TFields.ENTITIES])
self.relationships = {} self.relationships = {}
# Add definitions from template then from definition templates.
if TFields.INCLUDES in template_def:
includes = template_def[TFields.INCLUDES]
self._build_entities_from_def_templates(
includes, def_templates, self.entities)
if TFields.RELATIONSHIPS in defs: if TFields.RELATIONSHIPS in defs:
self.relationships = self._build_relationships( self.relationships = self._build_relationships(
defs[TFields.RELATIONSHIPS]) defs[TFields.RELATIONSHIPS])
if TFields.INCLUDES in template_def:
includes = template_def[TFields.INCLUDES]
self._build_relationships_with_def_templates(includes,
def_templates,
self.relationships)
self.scenarios = self._build_scenarios(template_def[TFields.SCENARIOS]) self.scenarios = self._build_scenarios(template_def[TFields.SCENARIOS])
@property @property
@ -120,6 +136,27 @@ class TemplateData(object):
return entities return entities
def _build_entities_from_def_templates(
self, includes, def_templates, entities):
for def_template_dict in includes:
name = def_template_dict[TFields.NAME]
def_template = evaluator_utils.find_def_template(
name, def_templates)
defs = def_template[TFields.DEFINITIONS]
entities_defs = defs[TFields.ENTITIES]
for entity_def in entities_defs:
entity_dict = entity_def[TFields.ENTITY]
template_id = entity_dict[TFields.TEMPLATE_ID]
if template_id not in entities:
properties = self._convert_properties_with_dictionary(
self._extract_properties(entity_dict))
entities[template_id] = Vertex(template_id, properties)
def _build_relationships(self, relationships_defs): def _build_relationships(self, relationships_defs):
relationships = {} relationships = {}
@ -132,6 +169,28 @@ class TemplateData(object):
return relationships return relationships
def _build_relationships_with_def_templates(
self, includes, def_templates, relationships):
for def_template_dict in includes:
name = def_template_dict[TFields.NAME]
def_template = evaluator_utils.find_def_template(
name, def_templates)
if TFields.RELATIONSHIPS in def_template[TFields.DEFINITIONS]:
defs = def_template[TFields.DEFINITIONS]
relationship_defs = defs[TFields.RELATIONSHIPS]
for relationship_def in relationship_defs:
relationship_dict = relationship_def[TFields.RELATIONSHIP]
template_id = relationship_dict[TFields.TEMPLATE_ID]
if template_id not in relationships:
relationship = self._extract_relationship_info(
relationship_dict)
relationships[template_id] = relationship
def _extract_relationship_info(self, relationship_dict): def _extract_relationship_info(self, relationship_dict):
source_id = relationship_dict[TFields.SOURCE] source_id = relationship_dict[TFields.SOURCE]

View File

@ -26,6 +26,7 @@ class TemplateFields(TemplateTopologyFields):
ACTION_TYPE = 'action_type' ACTION_TYPE = 'action_type'
CATEGORY = 'category' CATEGORY = 'category'
CONDITION = 'condition' CONDITION = 'condition'
INCLUDES = 'includes'
SEVERITY = 'severity' SEVERITY = 'severity'
SCENARIO = 'scenario' SCENARIO = 'scenario'
STATE = 'state' STATE = 'state'

View File

@ -43,18 +43,33 @@ from vitrage.evaluator.template_validation.content.raise_alarm_validator \
from vitrage.evaluator.template_validation.content.set_state_validator \ from vitrage.evaluator.template_validation.content.set_state_validator \
import SetStateValidator import SetStateValidator
from vitrage.evaluator.template_validation.status_messages import status_msgs from vitrage.evaluator.template_validation.status_messages import status_msgs
from vitrage.utils import evaluator as evaluator_utils
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
def content_validation(template): def content_validation(template, def_templates={}):
result = get_content_correct_result()
entities_index = {}
template_definitions = {}
if TemplateFields.DEFINITIONS in template:
template_definitions = template[TemplateFields.DEFINITIONS] template_definitions = template[TemplateFields.DEFINITIONS]
entities_index = {} if TemplateFields.ENTITIES in template_definitions:
entities = template_definitions[TemplateFields.ENTITIES] entities = template_definitions[TemplateFields.ENTITIES]
result = _validate_entities_definition(entities, entities_index) result = _validate_entities_definition(entities, entities_index)
# If there are duplicate definitions in several includes under the same
# name, will regard the first one
if result.is_valid_config and TemplateFields.INCLUDES in template:
template_includes = template[TemplateFields.INCLUDES]
result = _validate_definitions_with_includes(template_includes,
def_templates,
entities_index)
relationships_index = {} relationships_index = {}
if result.is_valid_config and \ if result.is_valid_config and \
@ -64,6 +79,15 @@ def content_validation(template):
result = _validate_relationships_definitions(relationships, result = _validate_relationships_definitions(relationships,
relationships_index, relationships_index,
entities_index) entities_index)
if result.is_valid_config and TemplateFields.INCLUDES in template:
template_includes = template[TemplateFields.INCLUDES]
result = _validate_relationships_definitions_with_includes(
template_includes,
def_templates,
entities_index,
relationships_index)
if result.is_valid_config: if result.is_valid_config:
scenarios = template[TemplateFields.SCENARIOS] scenarios = template[TemplateFields.SCENARIOS]
definitions_index = entities_index.copy() definitions_index = entities_index.copy()
@ -73,6 +97,25 @@ def content_validation(template):
return result return result
def def_template_content_validation(def_template):
def_template_definitions = def_template[TemplateFields.DEFINITIONS]
entities_index = {}
entities = def_template_definitions[TemplateFields.ENTITIES]
result = _validate_entities_definition(entities, entities_index)
relationships_index = {}
if result.is_valid_config \
and TemplateFields.RELATIONSHIPS in def_template_definitions:
relationships = def_template_definitions[TemplateFields.RELATIONSHIPS]
result = _validate_relationships_definitions(relationships,
relationships_index,
entities_index)
return result
def _validate_entities_definition(entities, entities_index): def _validate_entities_definition(entities, entities_index):
for entity in entities: for entity in entities:
@ -98,6 +141,49 @@ def _validate_entity_definition(entity_dict, entities_index):
return get_content_correct_result() return get_content_correct_result()
def _validate_definitions_with_includes(
template_includes, def_templates, entities_index):
for include in template_includes:
name = include[TemplateFields.NAME]
def_template = evaluator_utils.find_def_template(name, def_templates)
if not def_template:
LOG.error('%s status code: %s' % (status_msgs[142], 142))
return get_content_fault_result(142)
def_template_definitions = def_template[TemplateFields.DEFINITIONS]
def_template_entities = \
def_template_definitions[TemplateFields.ENTITIES]
result = _validate_include_entities_definition(
def_template_entities, entities_index)
if not result.is_valid_config:
return result
return get_content_correct_result()
def _validate_include_entities_definition(
def_template_entities,
entities_index):
for entity in def_template_entities:
entity_dict = entity[TemplateFields.ENTITY]
result = _validate_entity_definition(entity_dict, entities_index)
if not result.is_valid_config:
return result
if entity_dict[TemplateFields.TEMPLATE_ID] not in entities_index:
id = entity_dict[TemplateFields.TEMPLATE_ID]
entities_index[id] = entity_dict
return get_content_correct_result()
def _validate_relationships_definitions(relationships, def _validate_relationships_definitions(relationships,
relationships_index, relationships_index,
entities_index): entities_index):
@ -116,6 +202,49 @@ def _validate_relationships_definitions(relationships,
return get_content_correct_result() return get_content_correct_result()
def _validate_relationships_definitions_with_includes(template_includes,
def_templates,
entities_index,
relationships_index):
for include in template_includes:
name = include[TemplateFields.NAME]
def_template = evaluator_utils.find_def_template(name, def_templates)
if def_template:
defs = def_template[TemplateFields.DEFINITIONS]
relationships = defs[TemplateFields.RELATIONSHIPS]
for relationship in relationships:
relationship_dict = relationship[TemplateFields.RELATIONSHIP]
template_id = relationship_dict[TemplateFields.TEMPLATE_ID]
if template_id not in relationships_index:
result = _validate_def_template_relationship(
relationship_dict,
entities_index)
if not result.is_valid_config:
return result
relationships_index[template_id] = relationship_dict
return get_content_correct_result()
def _validate_def_template_relationship(relationship,
entities_index):
target = relationship[TemplateFields.TARGET]
result = validate_template_id(entities_index, target)
if result.is_valid_config:
source = relationship[TemplateFields.SOURCE]
result = validate_template_id(entities_index, source)
return result
def _validate_relationship(relationship, relationships_index, entities_index): def _validate_relationship(relationship, relationships_index, entities_index):
template_id = relationship[TemplateFields.TEMPLATE_ID] template_id = relationship[TemplateFields.TEMPLATE_ID]

View File

@ -79,4 +79,10 @@ status_msgs = {
'block', 'block',
134: 'condition can not contain only \'not\' clauses', 134: 'condition can not contain only \'not\' clauses',
135: 'condition must contain a common entity for all \'or\' clauses', 135: 'condition must contain a common entity for all \'or\' clauses',
# def_templates status messages 140-159
140: 'At least one template must be included',
141: 'Name field is unspecified for include',
142: 'Trying to include a template that does not exist',
143: 'Includable cannot have Includes or Scenarios',
} }

View File

@ -19,6 +19,7 @@ from voluptuous import All
from voluptuous import Any from voluptuous import Any
from voluptuous import Error from voluptuous import Error
from voluptuous import Invalid from voluptuous import Invalid
from voluptuous import Optional
from voluptuous import Required from voluptuous import Required
from voluptuous import Schema from voluptuous import Schema
@ -31,21 +32,24 @@ from vitrage.evaluator.template_validation.status_messages import status_msgs
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
RESULT_DESCRIPTION = 'Template syntax validation' RESULT_DESCRIPTION = 'Template syntax validation'
def syntax_validation(template_conf): def syntax_validation(template_conf):
result = _validate_template_sections(template_conf) result = _validate_template_sections(template_conf)
if result.is_valid_config: if result.is_valid_config:
metadata = template_conf[TemplateFields.METADATA] metadata = template_conf[TemplateFields.METADATA]
result = _validate_metadata_section(metadata) result = _validate_metadata_section(metadata)
if result.is_valid_config: if result.is_valid_config and TemplateFields.INCLUDES in template_conf:
includes = template_conf[TemplateFields.INCLUDES]
result = _validate_includes_section(includes)
if result.is_valid_config and TemplateFields.DEFINITIONS in template_conf:
definitions = template_conf[TemplateFields.DEFINITIONS] definitions = template_conf[TemplateFields.DEFINITIONS]
result = _validate_definitions_section(definitions) has_includes = TemplateFields.INCLUDES in template_conf
result = _validate_definitions_section(definitions, has_includes)
if result.is_valid_config: if result.is_valid_config:
scenarios = template_conf[TemplateFields.SCENARIOS] scenarios = template_conf[TemplateFields.SCENARIOS]
@ -54,18 +58,52 @@ def syntax_validation(template_conf):
return result return result
def _validate_template_sections(template_conf): def def_template_syntax_validation(def_template_conf):
result = _validate_def_template_template_sections(def_template_conf)
if TemplateFields.INCLUDES in def_template_conf or \
TemplateFields.SCENARIOS in def_template_conf:
LOG.error('%s status code: %s' % (status_msgs[143], 143))
return get_fault_result(RESULT_DESCRIPTION, 143)
if result.is_valid_config:
metadata = def_template_conf[TemplateFields.METADATA]
result = _validate_metadata_section(metadata)
if result.is_valid_config:
definitions = def_template_conf[TemplateFields.DEFINITIONS]
result = _validate_definitions_section(definitions, False)
return result
def _validate_def_template_template_sections(def_template_conf):
schema = Schema({ schema = Schema({
Required(TemplateFields.DEFINITIONS, msg=21): dict, Required(TemplateFields.DEFINITIONS, msg=21): dict,
Required(TemplateFields.METADATA, msg=62): dict, Required(TemplateFields.METADATA, msg=62): dict,
Required(TemplateFields.SCENARIOS, msg=80): list })
return _validate_dict_schema(schema, def_template_conf)
def _validate_template_sections(template_conf):
if TemplateFields.INCLUDES in template_conf:
schema = Schema({
Optional(TemplateFields.DEFINITIONS): dict,
Required(TemplateFields.METADATA, msg=62): dict,
Required(TemplateFields.SCENARIOS, msg=80): list,
Optional(TemplateFields.INCLUDES): list
})
else:
schema = Schema({
Required(TemplateFields.DEFINITIONS, msg=21): dict,
Required(TemplateFields.METADATA, msg=62): dict,
Required(TemplateFields.SCENARIOS, msg=80): list,
Optional(TemplateFields.INCLUDES): list
}) })
return _validate_dict_schema(schema, template_conf) return _validate_dict_schema(schema, template_conf)
def _validate_metadata_section(metadata): def _validate_metadata_section(metadata):
any_str = Any(str, six.text_type) any_str = Any(str, six.text_type)
schema = Schema({ schema = Schema({
@ -75,10 +113,45 @@ def _validate_metadata_section(metadata):
return _validate_dict_schema(schema, metadata) return _validate_dict_schema(schema, metadata)
def _validate_definitions_section(definitions): def _validate_includes_section(includes):
any_str = Any(str, six.text_type)
if not includes:
LOG.error('%s status code: %s' % (status_msgs[140], 140))
return get_fault_result(RESULT_DESCRIPTION, 140)
if TemplateFields.RELATIONSHIPS not in definitions or \ for name in includes:
definitions[TemplateFields.RELATIONSHIPS] != '': schema = Schema({
Required(TemplateFields.NAME, msg=141): any_str
})
result = _validate_name_schema(schema, name)
if not result.is_valid_config:
return result
return result
def _validate_name_schema(schema, name):
try:
schema(name)
except Error as e:
status_code = _get_status_code(e)
if status_code:
msg = status_msgs[status_code]
else:
# General syntax error
status_code = 4
msg = status_msgs[4] + str(e)
LOG.error('%s status code: %s' % (msg, status_code))
return get_fault_result(RESULT_DESCRIPTION, status_code, msg)
return get_correct_result(RESULT_DESCRIPTION)
def _validate_definitions_section(definitions, has_includes):
if TemplateFields.RELATIONSHIPS not in definitions \
or definitions[TemplateFields.RELATIONSHIPS] != '':
schema = Schema({ schema = Schema({
Required(TemplateFields.ENTITIES, msg=20): list, Required(TemplateFields.ENTITIES, msg=20): list,
TemplateFields.RELATIONSHIPS: list TemplateFields.RELATIONSHIPS: list
@ -88,8 +161,9 @@ def _validate_definitions_section(definitions):
else: else:
result = get_correct_result(RESULT_DESCRIPTION) result = get_correct_result(RESULT_DESCRIPTION)
if result.is_valid_config: if result.is_valid_config and TemplateFields.ENTITIES in definitions:
result = _validate_entities(definitions[TemplateFields.ENTITIES]) entities = definitions[TemplateFields.ENTITIES]
result = _validate_entities(entities, has_includes)
relationships = definitions.get(TemplateFields.RELATIONSHIPS, None) relationships = definitions.get(TemplateFields.RELATIONSHIPS, None)
if result.is_valid_config and relationships: if result.is_valid_config and relationships:
@ -98,9 +172,8 @@ def _validate_definitions_section(definitions):
return result return result
def _validate_entities(entities): def _validate_entities(entities, has_includes):
if not entities and not has_includes:
if not entities:
LOG.error('%s status code: %s' % (status_msgs[43], 43)) LOG.error('%s status code: %s' % (status_msgs[43], 43))
return get_fault_result(RESULT_DESCRIPTION, 43) return get_fault_result(RESULT_DESCRIPTION, 43)
@ -121,7 +194,6 @@ def _validate_entities(entities):
def _validate_entity_dict(entity_dict): def _validate_entity_dict(entity_dict):
any_str = Any(str, six.text_type) any_str = Any(str, six.text_type)
schema = Schema({ schema = Schema({
Required(TemplateFields.CATEGORY, msg=42): Required(TemplateFields.CATEGORY, msg=42):
@ -135,7 +207,6 @@ def _validate_entity_dict(entity_dict):
def _validate_relationships(relationships): def _validate_relationships(relationships):
for relationship in relationships: for relationship in relationships:
schema = Schema({ schema = Schema({
@ -153,7 +224,6 @@ def _validate_relationships(relationships):
def _validate_relationship_dict(relationship_dict): def _validate_relationship_dict(relationship_dict):
any_str = Any(str, six.text_type) any_str = Any(str, six.text_type)
schema = Schema({ schema = Schema({
Required(TemplateFields.SOURCE, msg=102): any_str, Required(TemplateFields.SOURCE, msg=102): any_str,
@ -166,7 +236,6 @@ def _validate_relationship_dict(relationship_dict):
def _validate_scenarios_section(scenarios): def _validate_scenarios_section(scenarios):
if not scenarios: if not scenarios:
LOG.error('%s status code: %s' % (status_msgs[81], 81)) LOG.error('%s status code: %s' % (status_msgs[81], 81))
return get_fault_result(RESULT_DESCRIPTION, 81) return get_fault_result(RESULT_DESCRIPTION, 81)
@ -188,7 +257,6 @@ def _validate_scenarios_section(scenarios):
def _validate_scenario(scenario): def _validate_scenario(scenario):
any_str = Any(str, six.text_type) any_str = Any(str, six.text_type)
schema = Schema({ schema = Schema({
Required(TemplateFields.CONDITION, msg=83): any_str, Required(TemplateFields.CONDITION, msg=83): any_str,
@ -203,7 +271,6 @@ def _validate_scenario(scenario):
def _validate_actions_schema(actions): def _validate_actions_schema(actions):
if not actions: if not actions:
LOG.error('%s status code: %s' % (status_msgs[121], 121)) LOG.error('%s status code: %s' % (status_msgs[121], 121))
return get_fault_result(RESULT_DESCRIPTION, 121) return get_fault_result(RESULT_DESCRIPTION, 121)
@ -225,7 +292,6 @@ def _validate_actions_schema(actions):
def _validate_action_schema(action): def _validate_action_schema(action):
schema = Schema({ schema = Schema({
Required(TemplateFields.ACTION_TYPE, msg=123): Required(TemplateFields.ACTION_TYPE, msg=123):
_validate_action_type_field(), _validate_action_type_field(),
@ -236,7 +302,6 @@ def _validate_action_schema(action):
def _validate_dict_schema(schema, value): def _validate_dict_schema(schema, value):
try: try:
schema(value) schema(value)
except Error as e: except Error as e:
@ -268,6 +333,7 @@ def _validate_template_id_value(msg=None):
return str(v) return str(v)
else: else:
raise Invalid(msg or 1) raise Invalid(msg or 1)
return f return f
@ -277,6 +343,7 @@ def _validate_category_field(msg=None):
return str(v) return str(v)
else: else:
raise Invalid(msg or 45) raise Invalid(msg or 45)
return f return f
@ -286,4 +353,5 @@ def _validate_action_type_field(msg=None):
return str(v) return str(v)
else: else:
raise Invalid(msg or 120) raise Invalid(msg or 120)
return f return f

View File

@ -13,6 +13,7 @@
# under the License. # under the License.
import codecs import codecs
from collections import namedtuple
import json import json
from os.path import dirname from os.path import dirname
from os import walk from os import walk
@ -47,6 +48,25 @@ def load_specs(target_filename, target_folder=None):
return json.load(reader(infile)) return json.load(reader(infile))
def get_def_templates_dict_from_list(def_temps_list):
"""Turns a list of def_temps into a dictionary of def_temps where the keys
are their index in the list. Used by unit tests
:param def_temps_list: def_temp list to convert
:type def_temps_list: list
:return: a def_temps dict
:rtype: dict
"""
Template = namedtuple('Template', 'data')
dict = {}
for num, item in zip(range(len(def_temps_list)), def_temps_list):
dict[num] = Template(item)
return dict
def _get_full_path(target_filename, target_folder): def _get_full_path(target_filename, target_folder):
"""Returns the full path for the given folder and filename """Returns the full path for the given folder and filename

View File

@ -0,0 +1,22 @@
metadata:
#a basic def_template file
name: basic_def_template
description: basic def_template for general tests
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

View File

@ -0,0 +1,43 @@
metadata:
name: large_def_template
description: definition template with entities and relationsihps for tests
definitions:
entities:
- entity:
category: ALARM
type: nagios
name: NETWORK_PROBLEM
template_id: network_alarm
- entity:
category: ALARM
type: nagios
name: CLUSTER_PROBLEM
template_id: cluster_alarm
- entity:
category: RESOURCE
type: nova.zone
template_id: nova_zone
- entity:
category: RESOURCE
type: openstack.cluster
template_id: openstack_cluster
- entity:
category: RESOURCE
type: neutron.network
template_id: neutron_network
relationships:
- relationship:
source: openstack_cluster
target: nova_zone
relationship_type: contains
template_id : cluster_contains_zone
- relationship:
source: neutron_network
target: nova_zone
relationship_type: attached
template_id : network_attached_zone
- relationship:
source: network_alarm
target: neutron_network
relationship_type: on
template_id : alarm_on_network

View File

@ -0,0 +1,10 @@
metadata:
name: single_entity
description: definition template with a single entity
definitions:
entities:
- entity:
category: RESOURCE
type: nova.host
template_id: resource

View File

@ -0,0 +1,22 @@
metadata:
name: def_template_with_include
description: a def_template with an include section for FAILING tests
includes:
- name: some_def_template
definitions:
entities:
- entity:
category: ALARM
type: nagios
name: host_problem
template_id: alarm_inc
- entity:
category: RESOURCE
type: nova.host
template_id: resource_inc
relationships:
- relationship:
source: alarm_inc
target: resource_inc
relationship_type: on
template_id : alarm_inc_on_host_inc

View File

@ -0,0 +1,30 @@
metadata:
name: def_template_with_scenarios
description: def_template with a scenarios section
definitions:
entities:
- entity:
category: ALARM
type: nagios
name: host_problem
template_id: alarm_scen
- entity:
category: RESOURCE
type: nova.host
template_id: resource_scen
relationships:
- relationship:
source: alarm_scen
target: resource_scen
relationship_type: on
template_id : alarm_scen_on_host_scen
scenarios:
- scenario:
condition: alarm_on_host_scen
actions:
- action:
action_type: set_state
properties:
state: SUBOPTIMAL
action_target:
target: resource_scen

View File

@ -0,0 +1,26 @@
metadata:
name: basic_template_with_include
description: basic template for general tests
includes:
- name: basic_def_template
definitions:
entities:
- entity:
category: ALARM
type: nagios
name: host_problem
template_id: alarm11
- entity:
category: RESOURCE
type: nova.host
template_id: resource11
scenarios:
- scenario:
condition: alarm_on_host
actions:
- action:
action_type: set_state
properties:
state: SUBOPTIMAL
action_target:
target: resource

View File

@ -0,0 +1,32 @@
metadata:
name: basic_template_with_include
description: basic template for general tests
includes:
- name: fake_def_template
definitions:
entities:
- entity:
category: ALARM
type: nagios
name: host_problem
template_id: alarm11
- entity:
category: RESOURCE
type: nova.host
template_id: resource11
relationships:
- relationship:
source: alarm11
target: resource11
relationship_type: on
template_id : alarm11_on_host11
scenarios:
- scenario:
condition: alarm_on_host11
actions:
- action:
action_type: set_state
properties:
state: SUBOPTIMAL
action_target:
target: resource11

View File

@ -0,0 +1,34 @@
metadata:
name: basic_template_with_two_includes
description: A template file which includes two defintion templates
includes:
- name: basic_def_template
- name: large_def_template
definitions:
entities:
- entity:
category: ALARM
type: nagios
name: host_problem
template_id: alarm11
- entity:
category: RESOURCE
type: nova.host
template_id: resource11
relationships:
#cluster_alarm from large_def_template and resource from basic_def_template
- relationship:
source: cluster_alarm
target: resource
relationship_type: on
template_id : alarm_on_resource
scenarios:
- scenario:
condition: alarm_on_resource
actions:
- action:
action_type: set_state
properties:
state: SUBOPTIMAL
action_target:
target: resource

View File

@ -0,0 +1,25 @@
metadata:
name: template_with_empty_include
description: template with an empty include to invoke error
includes:
definitions:
entities:
- entity:
category: ALARM
type: nagios
name: host_problem
template_id: alarm11
- entity:
category: RESOURCE
type: nova.host
template_id: resource11
scenarios:
- scenario:
condition: alarm_on_host
actions:
- action:
action_type: set_state
properties:
state: SUBOPTIMAL
action_target:
target: resource

View File

@ -0,0 +1,15 @@
metadata:
name: no_definitions_only_include
description: A template which only uses another definition template's definitions and has none of its own
includes:
- name: basic_def_template
scenarios:
- scenario:
condition: alarm_on_host
actions:
- action:
action_type: set_state
properties:
state: SUBOPTIMAL
action_target:
target: resource

View File

@ -0,0 +1,36 @@
metadata:
name: only_using_def_template_definitions
description: A template file which only uses the entities in the files it includes and has none of its own
includes:
- name: basic_def_template
- name: large_def_template
definitions:
relationships:
#cluster_alarm from large_def_template and resource from basic_def_template
- relationship:
source: cluster_alarm
target: resource
relationship_type: on
template_id : alarm_on_resource
scenarios:
- scenario:
condition: alarm_on_resource
actions:
- action:
action_type: set_state
properties:
state: SUBOPTIMAL
action_target:
#from large_def_template
target: openstack_cluster
- scenario:
#from large_def_template
condition: alarm_on_network
actions:
- action:
action_type: set_state
properties:
state: SUBOPTIMAL
action_target:
#from basic_def_template
target: resource

View File

@ -0,0 +1,16 @@
metadata:
name: basic_template_with_include
description: basic template for general tests
includes:
- name: basic_def_template
- name: single_entity
scenarios:
- scenario:
condition: alarm_on_host
actions:
- action:
action_type: set_state
properties:
state: SUBOPTIMAL
action_target:
target: resource

View File

@ -33,11 +33,66 @@ class TemplateContentValidatorTest(ValidatorTest):
def setUpClass(cls): def setUpClass(cls):
template_dir_path = '%s/templates/general' % utils.get_resources_dir() template_dir_path = '%s/templates/general' % utils.get_resources_dir()
cls.def_templates_tests_path = '%s/templates/def_template_tests/' % \
utils.get_resources_dir()
cls.def_templates_dir_path = cls.def_templates_tests_path +\
'definition_templates'
cls.templates = file_utils.load_yaml_files(template_dir_path) cls.templates = file_utils.load_yaml_files(template_dir_path)
def_templates_list = file_utils.load_yaml_files(
cls.def_templates_dir_path)
cls.def_templates = utils.get_def_templates_dict_from_list(
def_templates_list)
cls.first_template = cls.templates[0] cls.first_template = cls.templates[0]
cls._hide_useless_logging_messages() cls._hide_useless_logging_messages()
def test_template_with_conflicting_include_entities(self):
template_path = '/templates/with_conflicting_include_entities.yaml'
template = file_utils.load_yaml_file(self.def_templates_tests_path +
template_path)
self._execute_and_assert_with_fault_result(template,
2,
self.def_templates)
def test_template_with_no_defs_only_includes(self):
template_path = '/templates/only_using_def_template_definitions.yaml'
template = file_utils.load_yaml_file(self.def_templates_tests_path +
template_path)
self._execute_and_assert_with_correct_result(template,
self.def_templates)
def test_template_with_multiple_includes(self):
template_path = '/templates/basic_with_two_includes.yaml'
template = file_utils.load_yaml_file(self.def_templates_tests_path +
template_path)
self._execute_and_assert_with_correct_result(template,
self.def_templates)
def test_template_with_nonexisiting_includes(self):
template_path = '/templates/basic_with_include_that_doesnt_exist.yaml'
template = file_utils.load_yaml_file(self.def_templates_tests_path +
template_path)
self._execute_and_assert_with_fault_result(template, 142)
def test_template_with_missing_def_template_dir(self):
template_path = '/templates/basic_with_include.yaml'
template = file_utils.load_yaml_file(self.def_templates_tests_path +
template_path)
self._execute_and_assert_with_fault_result(template, 142)
def test_template_with_include(self):
template_path = '/templates/basic_with_include.yaml'
template = file_utils.load_yaml_file(self.def_templates_tests_path +
template_path)
self._execute_and_assert_with_correct_result(template,
self.def_templates)
@property @property
def clone_template(self): def clone_template(self):
return copy.deepcopy(self.first_template) return copy.deepcopy(self.first_template)
@ -217,14 +272,17 @@ class TemplateContentValidatorTest(ValidatorTest):
self._execute_and_assert_with_fault_result( self._execute_and_assert_with_fault_result(
template_definition, status_code) template_definition, status_code)
def _execute_and_assert_with_fault_result(self, template, status_code): def _execute_and_assert_with_fault_result(self,
template,
status_code,
def_temps={}):
result = validator.content_validation(template) result = validator.content_validation(template, def_temps)
self._assert_fault_result(result, status_code) self._assert_fault_result(result, status_code)
def _execute_and_assert_with_correct_result(self, template): def _execute_and_assert_with_correct_result(self, template, def_temps={}):
result = validator.content_validation(template) result = validator.content_validation(template, def_temps)
self._assert_correct_result(result) self._assert_correct_result(result)
def _create_scenario_actions(self, target, source): def _create_scenario_actions(self, target, source):

View File

@ -0,0 +1,74 @@
# Copyright 2017 - 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.status_messages import status_msgs
from vitrage.evaluator.template_validation import template_syntax_validator
from vitrage.tests import base
from vitrage.tests.mocks import utils
from vitrage.utils import file as file_utils
class DefTemplateSyntaxValidatorTest(base.BaseTest):
# noinspection PyPep8Naming
@classmethod
def setUpClass(cls):
cls.def_template_dir_path = utils.get_resources_dir() + \
'/templates/def_template_tests'
def test_def_template_with_include_section(self):
def_template_path = self.def_template_dir_path + \
'/definition_templates/with_include.yaml'
def_template = file_utils.load_yaml_file(def_template_path)
self._test_execution_with_fault_result_for_def_template(def_template,
143)
def test_def_template_with_scenario_section(self):
def_template_path = self.def_template_dir_path + \
'/definition_templates/with_scenarios.yaml'
def_template = file_utils.load_yaml_file(def_template_path)
self._test_execution_with_fault_result_for_def_template(def_template,
143)
def test_basic_def_template(self):
template_path = self.def_template_dir_path +\
'/templates/basic_with_include.yaml'
template = file_utils.load_yaml_file(template_path)
self._test_execution_with_correct_result(template)
def _test_execution_with_fault_result_for_def_template(self,
def_template,
expected_code):
result = template_syntax_validator.def_template_syntax_validation(
def_template)
# Test assertions
self.assertFalse(result.is_valid_config)
self.assertTrue(result.comment.startswith(status_msgs[expected_code]))
self.assertEqual(expected_code, result.status_code)
def _test_execution_with_correct_result(self, template):
# Test action
result = template_syntax_validator.syntax_validation(template)
# Test assertions
self.assertTrue(result.is_valid_config)
self.assertEqual(result.comment, status_msgs[0])
self.assertEqual(0, result.status_code)

View File

@ -29,6 +29,8 @@ class TemplateSyntaxValidatorTest(base.BaseTest):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
cls.def_template_dir_path = utils.get_resources_dir() + \
'/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.template_yamls = file_utils.load_yaml_files(template_dir_path) cls.template_yamls = file_utils.load_yaml_files(template_dir_path)
cls.first_template = cls.template_yamls[0] cls.first_template = cls.template_yamls[0]
@ -189,6 +191,19 @@ class TemplateSyntaxValidatorTest(base.BaseTest):
scenario[TemplateFields.SCENARIO][TemplateFields.ACTIONS] = [] scenario[TemplateFields.SCENARIO][TemplateFields.ACTIONS] = []
self._test_execution_with_fault_result(template, 121) self._test_execution_with_fault_result(template, 121)
def test_template_with_include_with_empty_name(self):
template_path = self.def_template_dir_path +\
'/templates/include_with_empty_name.yaml'
template = file_utils.load_yaml_file(template_path)
self._test_execution_with_fault_result(template, 4)
def test_template_with_include_with_no_defnitions(self):
template_path = self.def_template_dir_path +\
'/templates/no_definitions_only_include.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(
@ -214,7 +229,9 @@ class TemplateSyntaxValidatorTest(base.BaseTest):
self._test_execution_with_fault_result(template, status_msgs[100]) self._test_execution_with_fault_result(template, status_msgs[100])
def _test_execution_with_fault_result(self, template, expected_code): def _test_execution_with_fault_result(self,
template,
expected_code):
# Test action # Test action
result = template_syntax_validator.syntax_validation(template) result = template_syntax_validator.syntax_validation(template)

View File

@ -28,7 +28,6 @@ from vitrage.utils import file as file_utils
class ScenarioRepositoryTest(base.BaseTest): class ScenarioRepositoryTest(base.BaseTest):
BASE_DIR = utils.get_resources_dir() + '/templates/general' BASE_DIR = utils.get_resources_dir() + '/templates/general'
HOST_HIGH_CPU = 'host_high_cpu_load_to_instance_cpu_suboptimal'
OPTS = [ OPTS = [
cfg.StrOpt('templates_dir', cfg.StrOpt('templates_dir',
default=BASE_DIR, default=BASE_DIR,
@ -103,9 +102,15 @@ class EquivalentScenarioTest(base.BaseTest):
BASE_DIR = utils.get_resources_dir() + '/templates/equivalent_scenarios/' BASE_DIR = utils.get_resources_dir() + '/templates/equivalent_scenarios/'
OPTS = [ OPTS = [
cfg.StrOpt('templates_dir', cfg.StrOpt('templates_dir',
default=BASE_DIR), default=BASE_DIR,
),
cfg.StrOpt('def_templates_dir',
default=(utils.get_resources_dir() +
'/templates/def_template_tests'),
),
cfg.StrOpt('equivalences_dir', cfg.StrOpt('equivalences_dir',
default=BASE_DIR + '/equivalences')] default=BASE_DIR + '/equivalences',),
]
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):

View File

@ -37,6 +37,119 @@ from vitrage.utils import file as file_utils
class BasicTemplateTest(base.BaseTest): class BasicTemplateTest(base.BaseTest):
BASIC_TEMPLATE = 'basic.yaml' BASIC_TEMPLATE = 'basic.yaml'
BASIC_TEMPLATE_WITH_INCLUDE = 'basic_with_include.yaml'
DEF_TEMPLATE_TESTS_DIR = utils.get_resources_dir() +\
'/templates/def_template_tests'
def test_basic_template_with_include(self):
# Test setup
template_path = self.DEF_TEMPLATE_TESTS_DIR +\
'/templates/%s' % self.BASIC_TEMPLATE_WITH_INCLUDE
template_definition = file_utils.load_yaml_file(template_path, True)
def_templates_path = self.DEF_TEMPLATE_TESTS_DIR + \
'/definition_templates'
def_demplates_list = file_utils.load_yaml_files(
def_templates_path)
def_templates_dict = utils.get_def_templates_dict_from_list(
def_demplates_list)
template_data = TemplateData(template_definition, def_templates_dict)
entities = template_data.entities
relationships = template_data.relationships
scenarios = template_data.scenarios
definitions = template_definition[TFields.DEFINITIONS]
def_template = file_utils.load_yaml_file(
def_templates_path + '/basic_def_template.yaml')
def_template_entities = \
def_template[TFields.DEFINITIONS][TFields.ENTITIES]
def_template_relationships = \
def_template[TFields.DEFINITIONS][TFields.RELATIONSHIPS]
definitions[TFields.ENTITIES] += def_template_entities
definitions[TFields.RELATIONSHIPS] = def_template_relationships
# Assertions
for definition in definitions[TFields.ENTITIES]:
for key, value in definition['entity'].items():
new_key = TemplateData.PROPS_CONVERSION[key] if key in \
TemplateData.PROPS_CONVERSION else key
del definition['entity'][key]
definition['entity'][new_key] = value
self._validate_entities(entities, definitions[TFields.ENTITIES])
relate_def = def_template_relationships
self._validate_relationships(relationships, relate_def, entities)
self._validate_scenarios(scenarios, entities)
expected_entities = {
'alarm11': Vertex(
vertex_id='alarm11',
properties={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
VProps.VITRAGE_TYPE: NAGIOS_DATASOURCE,
VProps.NAME: 'host_problem'
}),
'resource11': Vertex(
vertex_id='resource11',
properties={VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE
}),
'alarm': Vertex(
vertex_id='alarm',
properties={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
VProps.VITRAGE_TYPE: NAGIOS_DATASOURCE,
VProps.NAME: 'host_problem'
}),
'resource': Vertex(
vertex_id='resource',
properties={VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE
})
}
expected_relationships = {
'alarm_on_host': EdgeDescription(
edge=Edge(source_id='alarm',
target_id='resource',
label=EdgeLabel.ON,
properties={EdgeProperties.RELATIONSHIP_TYPE:
EdgeLabel.ON}),
source=expected_entities['alarm'],
target=expected_entities['resource']
),
}
scenario_entities = {
'alarm': Vertex(
vertex_id='alarm',
properties={VProps.VITRAGE_CATEGORY: EntityCategory.ALARM,
VProps.VITRAGE_TYPE: NAGIOS_DATASOURCE,
VProps.NAME: 'host_problem'
}),
'resource': Vertex(
vertex_id='resource',
properties={VProps.VITRAGE_CATEGORY: EntityCategory.RESOURCE,
VProps.VITRAGE_TYPE: NOVA_HOST_DATASOURCE
})
}
expected_scenario = Scenario(
id='basic_template_with_include-scenario0',
condition=[
[ConditionVar(symbol_name='alarm_on_host',
positive=True)]],
actions=[
ActionSpecs(
type=ActionType.SET_STATE,
targets={'target': 'resource'},
properties={'state':
OperationalResourceState.SUBOPTIMAL})],
subgraphs=template_data.scenarios[0].subgraphs,
entities=scenario_entities,
relationships=expected_relationships
)
self._validate_strict_equal(template_data,
expected_entities,
expected_relationships,
expected_scenario)
def test_basic_template(self): def test_basic_template(self):

View File

@ -0,0 +1,24 @@
# Copyright 2017 - 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_fields import TemplateFields
def find_def_template(name, def_templates):
for def_template_obj in def_templates.values():
def_template = def_template_obj.data
if def_template[TemplateFields.METADATA][TemplateFields.NAME] == name:
return def_template
return None