Refactor template loading

The template loading code was extracted from the TemplateData class and
placed in separate files, to allow future support of per-version loading
(i.e. different loaders for different template versions).
No real change was done in the code, it  was just split to separate files.

The changes:
* Separate the loading logic from the data
* Split the template loading to specific loaders: template, scenario and equivalences

Change-Id: I810da2682f3c1804312b26041b73280c040432a5
Implements: blueprint refactor-execute-mistral-definition
This commit is contained in:
Ifat Afek 2017-12-07 09:08:29 +00:00
parent fa43e38d34
commit fec7f59687
13 changed files with 506 additions and 402 deletions

View File

@ -22,7 +22,6 @@ from sympy import Symbol
ConditionVar = namedtuple('ConditionVar', ['symbol_name', 'positive']) ConditionVar = namedtuple('ConditionVar', ['symbol_name', 'positive'])
EdgeDescription = namedtuple('EdgeDescription', ['edge', 'source', 'target'])
class SymbolResolver(object): class SymbolResolver(object):

View File

@ -13,7 +13,8 @@
# under the License. # under the License.
from vitrage.common.exception import VitrageError from vitrage.common.exception import VitrageError
from vitrage.evaluator.equivalence_data import EquivalenceData from vitrage.evaluator.template_loading.equivalence_loader import \
EquivalenceLoader
from vitrage.utils import file as file_utils from vitrage.utils import file as file_utils
@ -25,8 +26,8 @@ class EquivalenceRepository(object):
equivalence_defs = file_utils.load_yaml_files(directory) equivalence_defs = file_utils.load_yaml_files(directory)
for equivalence_def in equivalence_defs: for equivalence_def in equivalence_defs:
equivalence_data = EquivalenceData(equivalence_def) equivalences = EquivalenceLoader(equivalence_def).equivalences
for equivalence in equivalence_data.equivalences: for equivalence in equivalences:
self._add_equivalence(equivalence) self._add_equivalence(equivalence)
return self.entity_equivalences return self.entity_equivalences

View File

@ -22,8 +22,9 @@ from oslo_utils import uuidutils
from vitrage.common.utils import get_portion from vitrage.common.utils import get_portion
from vitrage.evaluator.base import Template from vitrage.evaluator.base import Template
from vitrage.evaluator.equivalence_repository import EquivalenceRepository from vitrage.evaluator.equivalence_repository import EquivalenceRepository
from vitrage.evaluator.template_data import TemplateData
from vitrage.evaluator.template_fields import TemplateFields from vitrage.evaluator.template_fields import TemplateFields
from vitrage.evaluator.template_loading.scenario_loader import ScenarioLoader
from vitrage.evaluator.template_loading.template_loader import TemplateLoader
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.template_content_validator \ from vitrage.evaluator.template_validation.content.template_content_validator \
@ -127,7 +128,8 @@ class ScenarioRepository(object):
current_time, current_time,
result) result)
if result.is_valid_config: if result.is_valid_config:
template_data = TemplateData(template_def, self._def_templates) template_data = \
TemplateLoader().load(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)
@ -168,10 +170,10 @@ class ScenarioRepository(object):
scenarios_out = list(scenarios_in) scenarios_out = list(scenarios_in)
for entity_key in entity_keys: for entity_key in entity_keys:
for scenario in scenarios_in: for scenario in scenarios_in:
equivalent_scenario = TemplateData.ScenarioData. \ equivalent_scenario = \
build_equivalent_scenario(scenario, ScenarioLoader.build_equivalent_scenario(scenario,
symbol_name, symbol_name,
entity_key) entity_key)
scenarios_out.append(equivalent_scenario) scenarios_out.append(equivalent_scenario)
return scenarios_out return scenarios_out

View File

@ -15,22 +15,12 @@
from collections import namedtuple from collections import namedtuple
from vitrage.common.constants import EdgeProperties as EProps
from vitrage.common.constants import VertexProperties as VProps
from vitrage.common.exception import VitrageError
from vitrage.evaluator.condition import EdgeDescription
from vitrage.evaluator.condition import get_condition_common_targets
from vitrage.evaluator.condition import parse_condition
from vitrage.evaluator.condition import SymbolResolver
from vitrage.evaluator.template_fields import TemplateFields as TFields
from vitrage.graph.algo_driver.sub_graph_matching import NEG_CONDITION
from vitrage.graph.driver.networkx_graph import NXGraph
from vitrage.graph import Edge
from vitrage.graph import Vertex
from vitrage.utils import evaluator as evaluator_utils
ActionSpecs = namedtuple( ActionSpecs = namedtuple(
'ActionSpecs', ['id', 'type', 'targets', 'properties']) 'ActionSpecs', ['id', 'type', 'targets', 'properties'])
EdgeDescription = namedtuple('EdgeDescription', ['edge', 'source', 'target'])
ENTITY = 'entity'
RELATIONSHIP = 'relationship'
class Scenario(object): class Scenario(object):
@ -52,63 +42,15 @@ class Scenario(object):
self.entities == other.entities and \ self.entities == other.entities and \
self.relationships == other.relationships self.relationships == other.relationships
ENTITY = 'entity'
RELATIONSHIP = 'relationship'
def copy_edge_desc(edge_desc):
return EdgeDescription(edge=edge_desc.edge.copy(),
source=edge_desc.source.copy(),
target=edge_desc.target.copy())
# noinspection PyAttributeOutsideInit # noinspection PyAttributeOutsideInit
class TemplateData(object): class TemplateData(object):
PROPS_CONVERSION = { def __init__(self, name, entities, relationships, scenarios):
'category': VProps.VITRAGE_CATEGORY, self.name = name
'type': VProps.VITRAGE_TYPE, self.entities = entities
'resource_id': VProps.VITRAGE_RESOURCE_ID, self.relationships = relationships
'sample_timestamp': VProps.VITRAGE_SAMPLE_TIMESTAMP, self.scenarios = scenarios
'is_deleted': VProps.VITRAGE_IS_DELETED,
'is_placeholder': VProps.VITRAGE_IS_PLACEHOLDER,
'aggregated_state': VProps.VITRAGE_AGGREGATED_STATE,
'operational_state': VProps.VITRAGE_OPERATIONAL_STATE,
'aggregated_severity': VProps.VITRAGE_AGGREGATED_SEVERITY,
'operational_severity': VProps.VITRAGE_OPERATIONAL_SEVERITY
}
def __init__(self, template_def, def_templates=None):
if def_templates is None:
def_templates = {}
self.name = template_def[TFields.METADATA][TFields.NAME]
defs = {}
self.entities = {}
if TFields.DEFINITIONS in template_def:
defs = template_def[TFields.DEFINITIONS]
if TFields.ENTITIES in defs:
self.entities = self._build_entities(defs[TFields.ENTITIES])
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:
self.relationships = self._build_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])
@property @property
def name(self): def name(self):
@ -141,312 +83,3 @@ class TemplateData(object):
@scenarios.setter @scenarios.setter
def scenarios(self, scenarios): def scenarios(self, scenarios):
self._scenarios = scenarios self._scenarios = scenarios
def _build_entities(self, entities_defs):
entities = {}
for entity_def in entities_defs:
entity_dict = entity_def[TFields.ENTITY]
template_id = entity_dict[TFields.TEMPLATE_ID]
properties = self._convert_properties_with_dictionary(
self._extract_properties(entity_dict))
entities[template_id] = Vertex(template_id, properties)
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):
relationships = {}
for relationship_def in relationships_defs:
relationship_dict = relationship_def[TFields.RELATIONSHIP]
relationship = self._extract_relationship_info(relationship_dict)
template_id = relationship_dict[TFields.TEMPLATE_ID]
relationships[template_id] = relationship
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):
source_id = relationship_dict[TFields.SOURCE]
target_id = relationship_dict[TFields.TARGET]
edge = Edge(source_id,
target_id,
relationship_dict[TFields.RELATIONSHIP_TYPE],
self._extract_properties(relationship_dict))
source = self.entities[source_id]
target = self.entities[target_id]
return EdgeDescription(edge, source, target)
@staticmethod
def _extract_properties(var_dict):
ignore_ids = [TFields.TEMPLATE_ID, TFields.SOURCE, TFields.TARGET]
return \
{key: var_dict[key] for key in var_dict if key not in ignore_ids}
@staticmethod
def _convert_props_with_set(properties):
converted_properties = set()
for key, value in properties:
new_key = TemplateData.PROPS_CONVERSION[key] if key in \
TemplateData.PROPS_CONVERSION else key
converted_properties.add((new_key, value))
return converted_properties
@staticmethod
def _convert_properties_with_dictionary(properties):
converted_properties = {}
for key, value in properties.items():
new_key = TemplateData.PROPS_CONVERSION[key] if key in \
TemplateData.PROPS_CONVERSION else key
converted_properties[new_key] = value
return converted_properties
def _build_scenarios(self, scenarios_defs):
scenarios = []
for counter, scenario_def in enumerate(scenarios_defs):
scenario_id = "%s-scenario%s" % (self.name, str(counter))
scenario_dict = scenario_def[TFields.SCENARIO]
scenarios.append(TemplateData.ScenarioData(
scenario_id,
scenario_dict, self).to_tuple())
return scenarios
class ScenarioData(object):
def __init__(self, scenario_id, scenario_dict, template_data):
self._template_entities = template_data.entities
self._template_relationships = template_data.relationships
self._entities = {}
self._relationships = {}
self.scenario_id = scenario_id
self.condition = parse_condition(scenario_dict[TFields.CONDITION])
self.valid_target = self._calculate_missing_action_target()
self.actions = self._build_actions(scenario_dict[TFields.ACTIONS],
scenario_id)
self.subgraphs = TemplateData.SubGraph.from_condition(
self.condition,
self._extract_var_and_update_index)
def __eq__(self, other):
return self.scenario_id == other.scenario_id \
and self.condition == other.condition \
and self.actions == other.actions
def to_tuple(self):
return Scenario(id=self.scenario_id,
condition=self.condition,
actions=self.actions,
subgraphs=self.subgraphs,
entities=self._entities,
relationships=self._relationships)
@classmethod
def build_equivalent_scenario(cls,
scenario,
template_id,
entity_props):
entities = scenario.entities.copy()
entities[template_id] = Vertex(
vertex_id=entities[template_id].vertex_id,
properties={k: v for k, v in entity_props})
relationships = {
rel_id: cls.build_equivalent_relationship(rel,
template_id,
entity_props)
for rel_id, rel in scenario.relationships.items()}
def extract_var(symbol_name):
if symbol_name in entities:
return entities[symbol_name], ENTITY
elif symbol_name in relationships:
return relationships[symbol_name], RELATIONSHIP
else:
raise VitrageError('invalid symbol name: {}'
.format(symbol_name))
subgraphs = TemplateData.SubGraph.from_condition(
scenario.condition, extract_var)
return Scenario(id=scenario.id + '_equivalence',
condition=scenario.condition,
actions=scenario.actions,
subgraphs=subgraphs,
entities=entities,
relationships=relationships)
@classmethod
def build_equivalent_relationship(cls,
relationship,
template_id,
entity_props):
source = relationship.source
target = relationship.target
if relationship.edge.source_id == template_id:
source = Vertex(vertex_id=source.vertex_id,
properties={k: v for k, v in entity_props})
elif relationship.edge.target_id == template_id:
target = Vertex(vertex_id=target.vertex_id,
properties={k: v for k, v in entity_props})
return EdgeDescription(source=source,
target=target,
edge=relationship.edge)
def _build_actions(self, actions_def, scenario_id):
actions = []
for counter, action_def in enumerate(actions_def):
action_id = '%s-action%s' % (scenario_id, str(counter))
action_dict = action_def[TFields.ACTION]
action_type = action_dict[TFields.ACTION_TYPE]
targets = action_dict.get(TFields.ACTION_TARGET,
self.valid_target)
properties = action_dict.get(TFields.PROPERTIES, {})
actions.append(
ActionSpecs(action_id, action_type, targets, properties))
return actions
def _extract_var_and_update_index(self, symbol_name):
if symbol_name in self._template_relationships:
relationship = self._template_relationships[symbol_name]
self._relationships[symbol_name] = relationship
self._entities.update({
relationship.edge.source_id: relationship.source,
relationship.edge.target_id: relationship.target
})
return relationship, RELATIONSHIP
entity = self._template_entities[symbol_name]
self._entities[symbol_name] = entity
return entity, ENTITY
def _calculate_missing_action_target(self):
"""Return a vertex that can be used as an action target.
External actions like execute_mistral do not have an explicit
action target. This parameter is a must for the sub-graph matching
algorithm. If it is missing, we would like to select an arbitrary
target from the condition.
"""
definition_index = self._template_entities.copy()
definition_index.update(self._template_relationships)
targets = \
get_condition_common_targets(self.condition,
definition_index,
self.TemplateDataSymbolResolver())
return {TFields.TARGET: targets.pop()} if targets else None
class TemplateDataSymbolResolver(SymbolResolver):
def is_relationship(self, symbol):
return isinstance(symbol, EdgeDescription)
def get_relationship_source_id(self, relationship):
return relationship.source.vertex_id
def get_relationship_target_id(self, relationship):
return relationship.target.vertex_id
def get_entity_id(self, entity):
return entity.vertex_id
class SubGraph(object):
@classmethod
def from_condition(cls, condition, extract_var):
return [cls.from_clause(clause, extract_var)
for clause in condition]
@classmethod
def from_clause(cls, clause, extract_var):
condition_g = NXGraph("scenario condition")
for term in clause:
variable, var_type = extract_var(term.symbol_name)
if var_type == ENTITY:
vertex = variable.copy()
vertex[VProps.VITRAGE_IS_DELETED] = False
vertex[VProps.VITRAGE_IS_PLACEHOLDER] = False
condition_g.add_vertex(vertex)
else: # type = relationship
# prevent overwritten of NEG_CONDITION and
# VITRAGE_IS_DELETED property when there are both "not A"
# and "A" in same template
edge_desc = copy_edge_desc(variable)
cls._set_edge_relationship_info(edge_desc, term.positive)
cls._add_edge_relationship(condition_g, edge_desc)
return condition_g
@staticmethod
def _set_edge_relationship_info(edge_description,
is_positive_condition):
if not is_positive_condition:
edge_description.edge[NEG_CONDITION] = True
edge_description.edge[EProps.VITRAGE_IS_DELETED] = True
else:
edge_description.edge[EProps.VITRAGE_IS_DELETED] = False
edge_description.edge[NEG_CONDITION] = False
edge_description.source[VProps.VITRAGE_IS_DELETED] = False
edge_description.source[VProps.VITRAGE_IS_PLACEHOLDER] = False
edge_description.target[VProps.VITRAGE_IS_DELETED] = False
edge_description.target[VProps.VITRAGE_IS_PLACEHOLDER] = False
@staticmethod
def _add_edge_relationship(condition_graph, edge_description):
condition_graph.add_vertex(edge_description.source)
condition_graph.add_vertex(edge_description.target)
condition_graph.add_edge(edge_description.edge)

View File

@ -0,0 +1,14 @@
# Copyright 2017 - Alcatel-Lucent
#
# 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

@ -14,7 +14,7 @@
from vitrage.common.constants import TemplateTopologyFields from vitrage.common.constants import TemplateTopologyFields
from vitrage.common.exception import VitrageError from vitrage.common.exception import VitrageError
from vitrage.evaluator.template_data import TemplateData from vitrage.evaluator.template_loading.props_converter import PropsConverter
class Fields(TemplateTopologyFields): class Fields(TemplateTopologyFields):
@ -24,7 +24,7 @@ class Fields(TemplateTopologyFields):
# noinspection PyAttributeOutsideInit # noinspection PyAttributeOutsideInit
class EquivalenceData(object): class EquivalenceLoader(object):
def __init__(self, equivalence_def): def __init__(self, equivalence_def):
@ -54,7 +54,7 @@ class EquivalenceData(object):
for k, v in entity_def[Fields.ENTITY].items()} for k, v in entity_def[Fields.ENTITY].items()}
entity_key = frozenset( entity_key = frozenset(
TemplateData._convert_props_with_set(entity_props)) PropsConverter.convert_props_with_set(entity_props))
if entity_key in equivalence: if entity_key in equivalence:
raise VitrageError('duplicated entities found in ' raise VitrageError('duplicated entities found in '
'equivalence') 'equivalence')

View File

@ -0,0 +1,49 @@
# 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 VertexProperties as VProps
class PropsConverter(object):
PROPS_CONVERSION = {
'category': VProps.VITRAGE_CATEGORY,
'type': VProps.VITRAGE_TYPE,
'resource_id': VProps.VITRAGE_RESOURCE_ID,
'sample_timestamp': VProps.VITRAGE_SAMPLE_TIMESTAMP,
'is_deleted': VProps.VITRAGE_IS_DELETED,
'is_placeholder': VProps.VITRAGE_IS_PLACEHOLDER,
'aggregated_state': VProps.VITRAGE_AGGREGATED_STATE,
'operational_state': VProps.VITRAGE_OPERATIONAL_STATE,
'aggregated_severity': VProps.VITRAGE_AGGREGATED_SEVERITY,
'operational_severity': VProps.VITRAGE_OPERATIONAL_SEVERITY
}
@classmethod
def convert_props_with_set(cls, properties):
converted_properties = set()
for key, value in properties:
new_key = cls.PROPS_CONVERSION[key] if key in \
cls.PROPS_CONVERSION else key
converted_properties.add((new_key, value))
return converted_properties
@classmethod
def convert_props_with_dictionary(cls, properties):
converted_properties = {}
for key, value in properties.items():
new_key = cls.PROPS_CONVERSION[key] if key in \
cls.PROPS_CONVERSION else key
converted_properties[new_key] = value
return converted_properties

View File

@ -0,0 +1,165 @@
# 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.exception import VitrageError
from vitrage.evaluator.condition import get_condition_common_targets
from vitrage.evaluator.condition import parse_condition
from vitrage.evaluator.condition import SymbolResolver
from vitrage.evaluator.template_data import ActionSpecs
from vitrage.evaluator.template_data import EdgeDescription
from vitrage.evaluator.template_data import ENTITY
from vitrage.evaluator.template_data import RELATIONSHIP
from vitrage.evaluator.template_data import Scenario
from vitrage.evaluator.template_fields import TemplateFields as TFields
from vitrage.evaluator.template_loading.subgraph_builder import SubGraphBuilder
from vitrage.graph import Vertex
class ScenarioLoader(object):
def __init__(self, name, entities, relationships):
self.name = name
self._template_entities = entities
self._template_relationships = relationships
self.entities = {}
self.relationships = {}
self.valid_target = None
def build_scenarios(self, scenarios_defs):
scenarios = []
for counter, scenario_def in enumerate(scenarios_defs):
scenario_id = "%s-scenario%s" % (self.name, str(counter))
scenario_dict = scenario_def[TFields.SCENARIO]
condition = parse_condition(scenario_dict[TFields.CONDITION])
self.valid_target = \
self._calculate_missing_action_target(condition)
actions = self._build_actions(scenario_dict[TFields.ACTIONS],
scenario_id)
subgraphs = SubGraphBuilder.from_condition(
condition,
self._extract_var_and_update_index)
scenarios.append(
Scenario(scenario_id, condition, actions, subgraphs,
self.entities, self.relationships))
return scenarios
@classmethod
def build_equivalent_scenario(cls, scenario, template_id, entity_props):
entities = scenario.entities.copy()
entities[template_id] = Vertex(
vertex_id=entities[template_id].vertex_id,
properties={k: v for k, v in entity_props})
relationships = {
rel_id: cls._build_equivalent_relationship(rel,
template_id,
entity_props)
for rel_id, rel in scenario.relationships.items()}
def extract_var(symbol_name):
if symbol_name in entities:
return entities[symbol_name], ENTITY
elif symbol_name in relationships:
return relationships[symbol_name], RELATIONSHIP
else:
raise VitrageError('invalid symbol name: {}'
.format(symbol_name))
subgraphs = SubGraphBuilder.from_condition(
scenario.condition, extract_var)
return Scenario(id=scenario.id + '_equivalence',
condition=scenario.condition,
actions=scenario.actions,
subgraphs=subgraphs,
entities=entities,
relationships=relationships)
def _build_actions(self, actions_def, scenario_id):
actions = []
for counter, action_def in enumerate(actions_def):
action_id = '%s-action%s' % (scenario_id, str(counter))
action_dict = action_def[TFields.ACTION]
action_type = action_dict[TFields.ACTION_TYPE]
targets = action_dict.get(TFields.ACTION_TARGET,
self.valid_target)
properties = action_dict.get(TFields.PROPERTIES, {})
actions.append(
ActionSpecs(action_id, action_type, targets, properties))
return actions
def _extract_var_and_update_index(self, symbol_name):
if symbol_name in self._template_relationships:
relationship = self._template_relationships[symbol_name]
self.relationships[symbol_name] = relationship
self.entities.update({
relationship.edge.source_id: relationship.source,
relationship.edge.target_id: relationship.target
})
return relationship, RELATIONSHIP
entity = self._template_entities[symbol_name]
self.entities[symbol_name] = entity
return entity, ENTITY
def _calculate_missing_action_target(self, condition):
"""Return a vertex that can be used as an action target.
External actions like execute_mistral do not have an explicit
action target. This parameter is a must for the sub-graph matching
algorithm. If it is missing, we would like to select an arbitrary
target from the condition.
"""
definition_index = self._template_entities.copy()
definition_index.update(self._template_relationships)
targets = \
get_condition_common_targets(condition,
definition_index,
self.TemplateDataSymbolResolver())
return {TFields.TARGET: targets.pop()} if targets else None
class TemplateDataSymbolResolver(SymbolResolver):
def is_relationship(self, symbol):
return isinstance(symbol, EdgeDescription)
def get_relationship_source_id(self, relationship):
return relationship.source.vertex_id
def get_relationship_target_id(self, relationship):
return relationship.target.vertex_id
def get_entity_id(self, entity):
return entity.vertex_id
@staticmethod
def _build_equivalent_relationship(relationship,
template_id,
entity_props):
source = relationship.source
target = relationship.target
if relationship.edge.source_id == template_id:
source = Vertex(vertex_id=source.vertex_id,
properties={k: v for k, v in entity_props})
elif relationship.edge.target_id == template_id:
target = Vertex(vertex_id=target.vertex_id,
properties={k: v for k, v in entity_props})
return EdgeDescription(source=source,
target=target,
edge=relationship.edge)

View File

@ -0,0 +1,76 @@
# 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 EdgeProperties as EProps
from vitrage.common.constants import VertexProperties as VProps
from vitrage.evaluator.template_data import EdgeDescription
from vitrage.evaluator.template_data import ENTITY
from vitrage.graph.algo_driver.sub_graph_matching import NEG_CONDITION
from vitrage.graph.driver.networkx_graph import NXGraph
class SubGraphBuilder(object):
@classmethod
def from_condition(cls, condition, extract_var):
return [cls.from_clause(clause, extract_var)
for clause in condition]
@classmethod
def from_clause(cls, clause, extract_var):
condition_g = NXGraph("scenario condition")
for term in clause:
variable, var_type = extract_var(term.symbol_name)
if var_type == ENTITY:
vertex = variable.copy()
vertex[VProps.VITRAGE_IS_DELETED] = False
vertex[VProps.VITRAGE_IS_PLACEHOLDER] = False
condition_g.add_vertex(vertex)
else: # type = relationship
# prevent overwritten of NEG_CONDITION and
# VITRAGE_IS_DELETED property when there are both "not A"
# and "A" in same template
edge_desc = cls._copy_edge_desc(variable)
cls._set_edge_relationship_info(edge_desc, term.positive)
cls._add_edge_relationship(condition_g, edge_desc)
return condition_g
@staticmethod
def _set_edge_relationship_info(edge_description,
is_positive_condition):
if not is_positive_condition:
edge_description.edge[NEG_CONDITION] = True
edge_description.edge[EProps.VITRAGE_IS_DELETED] = True
else:
edge_description.edge[EProps.VITRAGE_IS_DELETED] = False
edge_description.edge[NEG_CONDITION] = False
edge_description.source[VProps.VITRAGE_IS_DELETED] = False
edge_description.source[VProps.VITRAGE_IS_PLACEHOLDER] = False
edge_description.target[VProps.VITRAGE_IS_DELETED] = False
edge_description.target[VProps.VITRAGE_IS_PLACEHOLDER] = False
@staticmethod
def _add_edge_relationship(condition_graph, edge_description):
condition_graph.add_vertex(edge_description.source)
condition_graph.add_vertex(edge_description.target)
condition_graph.add_edge(edge_description.edge)
@staticmethod
def _copy_edge_desc(edge_desc):
return EdgeDescription(edge=edge_desc.edge.copy(),
source=edge_desc.source.copy(),
target=edge_desc.target.copy())

View File

@ -0,0 +1,164 @@
# 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 VertexProperties as VProps
from vitrage.evaluator.template_data import EdgeDescription
from vitrage.evaluator.template_data import TemplateData
from vitrage.evaluator.template_fields import TemplateFields as TFields
from vitrage.evaluator.template_loading.props_converter import PropsConverter
from vitrage.evaluator.template_loading.scenario_loader import ScenarioLoader
from vitrage.graph import Edge
from vitrage.graph import Vertex
from vitrage.utils import evaluator as evaluator_utils
class TemplateLoader(object):
PROPS_CONVERSION = {
'category': VProps.VITRAGE_CATEGORY,
'type': VProps.VITRAGE_TYPE,
'resource_id': VProps.VITRAGE_RESOURCE_ID,
'sample_timestamp': VProps.VITRAGE_SAMPLE_TIMESTAMP,
'is_deleted': VProps.VITRAGE_IS_DELETED,
'is_placeholder': VProps.VITRAGE_IS_PLACEHOLDER,
'aggregated_state': VProps.VITRAGE_AGGREGATED_STATE,
'operational_state': VProps.VITRAGE_OPERATIONAL_STATE,
'aggregated_severity': VProps.VITRAGE_AGGREGATED_SEVERITY,
'operational_severity': VProps.VITRAGE_OPERATIONAL_SEVERITY
}
def __init__(self):
self.entities = {}
self.relationships = {}
def load(self, template_def, def_templates=None):
name = template_def[TFields.METADATA][TFields.NAME]
if def_templates is None:
def_templates = {}
defs = {}
if TFields.DEFINITIONS in template_def:
defs = template_def[TFields.DEFINITIONS]
if TFields.ENTITIES in defs:
self.entities = self._build_entities(defs[TFields.ENTITIES])
# 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:
self.relationships = self._build_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)
scenarios = ScenarioLoader(name, self.entities, self.relationships)\
.build_scenarios(template_def[TFields.SCENARIOS])
return TemplateData(name, self.entities, self.relationships, scenarios)
def _build_entities(self, entities_defs):
entities = {}
for entity_def in entities_defs:
entity_dict = entity_def[TFields.ENTITY]
template_id = entity_dict[TFields.TEMPLATE_ID]
properties = PropsConverter.convert_props_with_dictionary(
self._extract_properties(entity_dict))
entities[template_id] = Vertex(template_id, properties)
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 = \
PropsConverter.convert_props_with_dictionary(
self._extract_properties(entity_dict))
entities[template_id] = Vertex(template_id, properties)
def _build_relationships(self, relationships_defs):
relationships = {}
for relationship_def in relationships_defs:
relationship_dict = relationship_def[TFields.RELATIONSHIP]
relationship = self._extract_relationship_info(relationship_dict)
template_id = relationship_dict[TFields.TEMPLATE_ID]
relationships[template_id] = relationship
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):
source_id = relationship_dict[TFields.SOURCE]
target_id = relationship_dict[TFields.TARGET]
edge = Edge(source_id,
target_id,
relationship_dict[TFields.RELATIONSHIP_TYPE],
self._extract_properties(relationship_dict))
source = self.entities[source_id]
target = self.entities[target_id]
return EdgeDescription(edge, source, target)
@staticmethod
def _extract_properties(var_dict):
ignore_ids = [TFields.TEMPLATE_ID, TFields.SOURCE, TFields.TARGET]
return \
{key: var_dict[key] for key in var_dict if key not in ignore_ids}

View File

@ -12,9 +12,9 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from vitrage.evaluator.condition import EdgeDescription
from vitrage.evaluator.condition import SymbolResolver from vitrage.evaluator.condition import SymbolResolver
from vitrage.evaluator.template_data import TemplateData from vitrage.evaluator.template_data import EdgeDescription
from vitrage.evaluator.template_loading.template_loader import TemplateLoader
from vitrage.evaluator.template_validation.content.scenario_validator \ from vitrage.evaluator.template_validation.content.scenario_validator \
import get_condition_common_targets import get_condition_common_targets
from vitrage.tests import base from vitrage.tests import base
@ -93,7 +93,7 @@ class ConditionTest(base.BaseTest):
template_name) template_name)
template_definition = file_utils.load_yaml_file(template_path, True) template_definition = file_utils.load_yaml_file(template_path, True)
template_data = TemplateData(template_definition) template_data = TemplateLoader().load(template_definition)
definitions_index = template_data.entities.copy() definitions_index = template_data.entities.copy()
definitions_index.update(template_data.relationships) definitions_index.update(template_data.relationships)

View File

@ -18,7 +18,8 @@ from vitrage.datasources.nagios import NAGIOS_DATASOURCE
from vitrage.datasources.zabbix import ZABBIX_DATASOURCE from vitrage.datasources.zabbix import ZABBIX_DATASOURCE
from vitrage.evaluator.actions.evaluator_event_transformer \ from vitrage.evaluator.actions.evaluator_event_transformer \
import VITRAGE_DATASOURCE import VITRAGE_DATASOURCE
from vitrage.evaluator.equivalence_data import EquivalenceData from vitrage.evaluator.template_loading.equivalence_loader import \
EquivalenceLoader
from vitrage.tests import base from vitrage.tests import base
from vitrage.tests.mocks import utils from vitrage.tests.mocks import utils
from vitrage.utils import file as file_utils from vitrage.utils import file as file_utils
@ -35,8 +36,7 @@ class EquivalenceTemplateTest(base.BaseTest):
self.BASIC_TEMPLATE) self.BASIC_TEMPLATE)
equivalence_definition = file_utils.load_yaml_file(equivalence_path, equivalence_definition = file_utils.load_yaml_file(equivalence_path,
True) True)
equivalence_data = EquivalenceData(equivalence_definition) equivalences = EquivalenceLoader(equivalence_definition).equivalences
equivalences = equivalence_data.equivalences
expected = [ expected = [
frozenset([ frozenset([

View File

@ -25,8 +25,8 @@ from vitrage.evaluator.scenario_evaluator import ActionType
from vitrage.evaluator.template_data import ActionSpecs from vitrage.evaluator.template_data import ActionSpecs
from vitrage.evaluator.template_data import EdgeDescription from vitrage.evaluator.template_data import EdgeDescription
from vitrage.evaluator.template_data import Scenario from vitrage.evaluator.template_data import Scenario
from vitrage.evaluator.template_data import TemplateData
from vitrage.evaluator.template_fields import TemplateFields as TFields from vitrage.evaluator.template_fields import TemplateFields as TFields
from vitrage.evaluator.template_loading.template_loader import TemplateLoader
from vitrage.graph import Edge from vitrage.graph import Edge
from vitrage.graph import Vertex from vitrage.graph import Vertex
from vitrage.tests import base from vitrage.tests import base
@ -53,7 +53,8 @@ class BasicTemplateTest(base.BaseTest):
def_templates_path) def_templates_path)
def_templates_dict = utils.get_def_templates_dict_from_list( def_templates_dict = utils.get_def_templates_dict_from_list(
def_demplates_list) def_demplates_list)
template_data = TemplateData(template_definition, def_templates_dict) template_data = \
TemplateLoader().load(template_definition, def_templates_dict)
entities = template_data.entities entities = template_data.entities
relationships = template_data.relationships relationships = template_data.relationships
scenarios = template_data.scenarios scenarios = template_data.scenarios
@ -70,8 +71,8 @@ class BasicTemplateTest(base.BaseTest):
# Assertions # Assertions
for definition in definitions[TFields.ENTITIES]: for definition in definitions[TFields.ENTITIES]:
for key, value in definition['entity'].items(): for key, value in definition['entity'].items():
new_key = TemplateData.PROPS_CONVERSION[key] if key in \ new_key = TemplateLoader.PROPS_CONVERSION[key] if key in \
TemplateData.PROPS_CONVERSION else key TemplateLoader.PROPS_CONVERSION else key
del definition['entity'][key] del definition['entity'][key]
definition['entity'][new_key] = value definition['entity'][new_key] = value
self._validate_entities(entities, definitions[TFields.ENTITIES]) self._validate_entities(entities, definitions[TFields.ENTITIES])
@ -159,7 +160,7 @@ class BasicTemplateTest(base.BaseTest):
self.BASIC_TEMPLATE) self.BASIC_TEMPLATE)
template_definition = file_utils.load_yaml_file(template_path, True) template_definition = file_utils.load_yaml_file(template_path, True)
template_data = TemplateData(template_definition) template_data = TemplateLoader().load(template_definition)
entities = template_data.entities entities = template_data.entities
relationships = template_data.relationships relationships = template_data.relationships
scenarios = template_data.scenarios scenarios = template_data.scenarios
@ -168,8 +169,8 @@ class BasicTemplateTest(base.BaseTest):
# Assertions # Assertions
for definition in definitions[TFields.ENTITIES]: for definition in definitions[TFields.ENTITIES]:
for key, value in definition['entity'].items(): for key, value in definition['entity'].items():
new_key = TemplateData.PROPS_CONVERSION[key] if key in \ new_key = TemplateLoader.PROPS_CONVERSION[key] if key in \
TemplateData.PROPS_CONVERSION else key TemplateLoader.PROPS_CONVERSION else key
del definition['entity'][key] del definition['entity'][key]
definition['entity'][new_key] = value definition['entity'][new_key] = value
self._validate_entities(entities, definitions[TFields.ENTITIES]) self._validate_entities(entities, definitions[TFields.ENTITIES])