evaluator - loading template files
Change-Id: I588306430296d8df5df102eed257a41713a087e3
This commit is contained in:
parent
30ffba8565
commit
1e6bacf0fd
@ -22,3 +22,4 @@ keystonemiddleware>=2.3.0
|
|||||||
stevedore>=1.5.0 # Apache-2.0
|
stevedore>=1.5.0 # Apache-2.0
|
||||||
exrex>=0.9.4
|
exrex>=0.9.4
|
||||||
voluptuous>=0.8.8
|
voluptuous>=0.8.8
|
||||||
|
sympy>=0.7.6.1
|
||||||
|
@ -24,3 +24,4 @@ testtools>=1.4.0
|
|||||||
exrex>=0.9.4
|
exrex>=0.9.4
|
||||||
stevedore>=1.5.0 # Apache-2.0
|
stevedore>=1.5.0 # Apache-2.0
|
||||||
voluptuous>=0.8.8
|
voluptuous>=0.8.8
|
||||||
|
sympy>=0.7.6.1
|
||||||
|
@ -1,76 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
|
|
||||||
class Scenario(object):
|
|
||||||
|
|
||||||
TYPE_ENTITY = 'entity'
|
|
||||||
TYPE_RELATE = 'relationship'
|
|
||||||
|
|
||||||
def __init__(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
def get_condition(self):
|
|
||||||
"""Returns the condition for this scenario.
|
|
||||||
|
|
||||||
Each condition should be formatted in DNF (Disjunctive Normal Form),
|
|
||||||
e.g., (X and Y) or (X and Z) or (X and V and not W)...
|
|
||||||
where X, Y, Z, V, W are either entities or relationships
|
|
||||||
For details: https://en.wikipedia.org/wiki/Disjunctive_normal_form
|
|
||||||
|
|
||||||
:return: condition
|
|
||||||
"""
|
|
||||||
entity = 'replace with vertex'
|
|
||||||
|
|
||||||
relationship = 'replace with edge'
|
|
||||||
|
|
||||||
mock_entity = (entity, self.TYPE_ENTITY, True)
|
|
||||||
mock_relationship = (relationship, self.TYPE_RELATE, False)
|
|
||||||
|
|
||||||
# single "and" clause between entity and relationship
|
|
||||||
return [(mock_entity, mock_relationship)]
|
|
||||||
|
|
||||||
def get_actions(self):
|
|
||||||
"""Returns the action specifications for this scenario.
|
|
||||||
|
|
||||||
:return: list of actions to perform
|
|
||||||
:rtype: ActionSpecs
|
|
||||||
"""
|
|
||||||
action_spec = ActionSpecs()
|
|
||||||
return [action_spec]
|
|
||||||
|
|
||||||
|
|
||||||
class ActionSpecs(object):
|
|
||||||
|
|
||||||
def get_type(self):
|
|
||||||
return 'action type str'
|
|
||||||
|
|
||||||
def get_targets(self):
|
|
||||||
"""Returns dict of template_ids to apply action on
|
|
||||||
|
|
||||||
:return: dict of string:template_id
|
|
||||||
:rtype: dict
|
|
||||||
"""
|
|
||||||
|
|
||||||
# e.g., for adding edge, need two ids. for alarms, will need only one.
|
|
||||||
return {'source': 'source template_id',
|
|
||||||
'target': 'target template_id'}
|
|
||||||
|
|
||||||
def get_properties(self):
|
|
||||||
"""Returns the properties relevant to the action.
|
|
||||||
|
|
||||||
:return: dictionary of properties relevant to the action.
|
|
||||||
:rtype: dict
|
|
||||||
"""
|
|
||||||
return {'prop_key': 'prop_val'}
|
|
73
vitrage/evaluator/scenario_repository.py
Normal file
73
vitrage/evaluator/scenario_repository.py
Normal file
@ -0,0 +1,73 @@
|
|||||||
|
# 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 oslo_log import log
|
||||||
|
|
||||||
|
from vitrage.common import file_utils
|
||||||
|
from vitrage.evaluator.template import Template
|
||||||
|
from vitrage.evaluator.template_syntax_validator import syntax_validate
|
||||||
|
|
||||||
|
|
||||||
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
action_types = {
|
||||||
|
'RAISE_ALARM': 'raise_alarm',
|
||||||
|
'ADD_CAUSAL_RELATIONSHIP': 'add_causal_relationship',
|
||||||
|
'SET_STATE': 'set_state'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class ScenarioRepository(object):
|
||||||
|
|
||||||
|
def __init__(self, conf):
|
||||||
|
self._load_templates_files(conf)
|
||||||
|
self.scenarios = {}
|
||||||
|
|
||||||
|
def add_template(self, template_definition):
|
||||||
|
|
||||||
|
if syntax_validate(template_definition):
|
||||||
|
template = Template(template_definition)
|
||||||
|
print(template)
|
||||||
|
|
||||||
|
def get_relevant_scenarios(self, element_before, element_now):
|
||||||
|
"""Returns scenarios triggered by an event.
|
||||||
|
|
||||||
|
Returned scenarios are divided into two disjoint lists, based on the
|
||||||
|
element state (before/now) that triggered the scenario condition.
|
||||||
|
|
||||||
|
Note that this should intuitively mean that the "before" scenarios will
|
||||||
|
activate their "undo" operation, while the "now" will activate the
|
||||||
|
"execute" operation.
|
||||||
|
|
||||||
|
:param element_before:
|
||||||
|
:param element_now:
|
||||||
|
:return:
|
||||||
|
:rtype: dict
|
||||||
|
"""
|
||||||
|
|
||||||
|
# trigger_id_before = 'template_id of trigger for before scenario'
|
||||||
|
# trigger_id_now = 'template_id of trigger for now scenario'
|
||||||
|
|
||||||
|
# return {'before': [(scenario., trigger_id_before)],
|
||||||
|
# 'now': [(scenario.Scenario, trigger_id_now)]}
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _load_templates_files(self, conf):
|
||||||
|
|
||||||
|
templates_dir_path = conf.evaluator.templates_dir
|
||||||
|
template_definitions = file_utils.load_yaml_files(templates_dir_path)
|
||||||
|
|
||||||
|
for template_definition in template_definitions:
|
||||||
|
self.add_template(template_definition)
|
@ -11,11 +11,217 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# 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 collections import namedtuple
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
from sympy.logic.boolalg import And
|
||||||
|
from sympy.logic.boolalg import Not
|
||||||
|
from sympy.logic.boolalg import Or
|
||||||
|
from sympy.logic.boolalg import to_dnf
|
||||||
|
from sympy import Symbol
|
||||||
|
|
||||||
|
from vitrage.evaluator.template_fields import TemplateFields as TFields
|
||||||
|
from vitrage.graph import Edge
|
||||||
|
from vitrage.graph import Vertex
|
||||||
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
ConditionVar = namedtuple('ConditionVar', ['element', 'type', 'positive'])
|
||||||
|
ActionSpecs = namedtuple('ActionSpecs', ['type', 'targets', 'properties'])
|
||||||
|
Scenario = namedtuple('Scenario', ['condition', 'actions'])
|
||||||
|
|
||||||
|
|
||||||
|
TYPE_ENTITY = 'entity'
|
||||||
|
TYPE_RELATIONSHIP = 'relationship'
|
||||||
|
|
||||||
|
|
||||||
class Template(object):
|
class Template(object):
|
||||||
pass
|
|
||||||
|
def __init__(self, template_def):
|
||||||
|
|
||||||
|
super(Template, self).__init__()
|
||||||
|
|
||||||
|
self.template_name = template_def[TFields.METADATA][TFields.ID]
|
||||||
|
|
||||||
|
definitions = template_def[TFields.DEFINITIONS]
|
||||||
|
self.entities = self._build_entities(definitions[TFields.ENTITIES])
|
||||||
|
self.relationships = self._build_relationships(
|
||||||
|
definitions[TFields.RELATIONSHIPS])
|
||||||
|
|
||||||
|
self.scenarios = self._build_scenarios(template_def[TFields.SCENARIOS])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def entities(self):
|
||||||
|
return self._entities
|
||||||
|
|
||||||
|
@entities.setter
|
||||||
|
def entities(self, entities):
|
||||||
|
self._entities = entities
|
||||||
|
|
||||||
|
@property
|
||||||
|
def relationships(self):
|
||||||
|
return self._relationships
|
||||||
|
|
||||||
|
@relationships.setter
|
||||||
|
def relationships(self, relationships):
|
||||||
|
self._relationships = relationships
|
||||||
|
|
||||||
|
def _build_entities(self, entities_definitions):
|
||||||
|
|
||||||
|
entities = {}
|
||||||
|
for entity_definition in entities_definitions:
|
||||||
|
|
||||||
|
entity_dict = entity_definition[TFields.ENTITY]
|
||||||
|
template_id = entity_dict[TFields.TEMPLATE_ID]
|
||||||
|
entities[template_id] = Vertex(template_id, entity_dict)
|
||||||
|
|
||||||
|
return entities
|
||||||
|
|
||||||
|
def _build_relationships(self, relationships_defs):
|
||||||
|
|
||||||
|
relationships = {}
|
||||||
|
for relationship_def in relationships_defs:
|
||||||
|
|
||||||
|
relationship_dict = relationship_def[TFields.RELATIONSHIP]
|
||||||
|
relationship = self._create_edge(relationship_dict)
|
||||||
|
template_id = relationship_dict[TFields.TEMPLATE_ID]
|
||||||
|
relationships[template_id] = relationship
|
||||||
|
|
||||||
|
return relationships
|
||||||
|
|
||||||
|
def _create_edge(self, relationship_dict):
|
||||||
|
|
||||||
|
return Edge(relationship_dict[TFields.SOURCE],
|
||||||
|
relationship_dict[TFields.TARGET],
|
||||||
|
relationship_dict[TFields.RELATIONSHIP_TYPE],
|
||||||
|
relationship_dict)
|
||||||
|
|
||||||
|
def _build_scenarios(self, scenarios_defs):
|
||||||
|
|
||||||
|
scenarios = []
|
||||||
|
for scenarios_def in scenarios_defs:
|
||||||
|
|
||||||
|
scenario_dict = scenarios_def[TFields.SCENARIO]
|
||||||
|
condition = self._parse_condition(scenario_dict[TFields.CONDITION])
|
||||||
|
action_specs = self._build_actions(scenario_dict[TFields.ACTIONS])
|
||||||
|
scenarios.append(Scenario(condition, action_specs))
|
||||||
|
|
||||||
|
return scenarios
|
||||||
|
|
||||||
|
def _build_actions(self, actions_def):
|
||||||
|
|
||||||
|
actions = []
|
||||||
|
for action_def in actions_def:
|
||||||
|
action_dict = action_def[TFields.ACTION]
|
||||||
|
|
||||||
|
action_type = action_dict[TFields.ACTION_TYPE]
|
||||||
|
|
||||||
|
target_def = action_dict[TFields.ACTION_TARGET]
|
||||||
|
targets = self._extract_action_target(target_def)
|
||||||
|
|
||||||
|
properties = {}
|
||||||
|
if TFields.PROPERTIES in action_dict:
|
||||||
|
properties = action_dict[TFields.PROPERTIES]
|
||||||
|
|
||||||
|
actions.append(ActionSpecs(action_type, targets, properties))
|
||||||
|
|
||||||
|
return actions
|
||||||
|
|
||||||
|
def _extract_action_target(self, action_target):
|
||||||
|
|
||||||
|
targets = {}
|
||||||
|
|
||||||
|
for key, value in action_target.iteritems():
|
||||||
|
targets[key] = self._extract_variable(value)
|
||||||
|
|
||||||
|
return targets
|
||||||
|
|
||||||
|
def _parse_condition(self, condition_str):
|
||||||
|
"""Parse condition string into an object
|
||||||
|
|
||||||
|
The condition object is formatted in DNF (Disjunctive Normal Form),
|
||||||
|
e.g., (X and Y) or (X and Z) or (X and V and not W)...
|
||||||
|
where X, Y, Z, V, W are either entities or relationships
|
||||||
|
more details: https://en.wikipedia.org/wiki/Disjunctive_normal_form
|
||||||
|
|
||||||
|
The condition object itself is a list of tuples. each tuple represents
|
||||||
|
an AND expression compound ConditionElements. The list presents the
|
||||||
|
OR expression e.g. [(condition_element1, condition_element2)]
|
||||||
|
|
||||||
|
:param condition_str: the string as it written in the template itself
|
||||||
|
:return: Condition object
|
||||||
|
"""
|
||||||
|
|
||||||
|
condition_dnf = self.convert_to_dnf_format(condition_str)
|
||||||
|
|
||||||
|
if isinstance(condition_dnf, Or):
|
||||||
|
return self._extract_or_condition(condition_dnf)
|
||||||
|
|
||||||
|
if isinstance(condition_dnf, And):
|
||||||
|
return [self._extract_and_condition(condition_dnf)]
|
||||||
|
|
||||||
|
if isinstance(condition_dnf, Not):
|
||||||
|
return [(self._extract_not_condition(condition_dnf))]
|
||||||
|
|
||||||
|
if isinstance(condition_dnf, Symbol):
|
||||||
|
return [(self._extract_condition_variable(condition_dnf, False))]
|
||||||
|
|
||||||
|
def convert_to_dnf_format(self, condition_str):
|
||||||
|
|
||||||
|
condition_str = condition_str.replace('and', '&')
|
||||||
|
condition_str = condition_str.replace('or', '|')
|
||||||
|
condition_str = condition_str.replace('not ', '~')
|
||||||
|
|
||||||
|
return to_dnf(condition_str)
|
||||||
|
|
||||||
|
def _extract_or_condition(self, or_condition):
|
||||||
|
|
||||||
|
variables = []
|
||||||
|
for variable in or_condition.args:
|
||||||
|
|
||||||
|
if isinstance(variable, And):
|
||||||
|
variables.append((self._extract_and_condition(variable)),)
|
||||||
|
elif isinstance(variable, Not):
|
||||||
|
variables.append((self._extract_not_condition(variable),))
|
||||||
|
else:
|
||||||
|
variables.append((self._extract_condition_variable(variable,
|
||||||
|
False),))
|
||||||
|
return variables
|
||||||
|
|
||||||
|
def _extract_and_condition(self, and_condition):
|
||||||
|
|
||||||
|
variables = ()
|
||||||
|
for arg in and_condition.args:
|
||||||
|
if isinstance(arg, Not):
|
||||||
|
condition_var = self._extract_not_condition(arg)
|
||||||
|
else:
|
||||||
|
condition_var = self._extract_condition_variable(arg, False)
|
||||||
|
variables = variables + condition_var
|
||||||
|
|
||||||
|
return variables
|
||||||
|
|
||||||
|
def _extract_not_condition(self, not_condition):
|
||||||
|
self._extract_condition_variable(not_condition.args, True)
|
||||||
|
|
||||||
|
def _extract_condition_variable(self, symbol, not_):
|
||||||
|
|
||||||
|
template_id = symbol.__str__()
|
||||||
|
variable = self._extract_variable(template_id)
|
||||||
|
|
||||||
|
if variable:
|
||||||
|
return ConditionVar(variable[0], variable[1], not_)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
def _extract_variable(self, template_id):
|
||||||
|
|
||||||
|
if template_id in self.relationships:
|
||||||
|
return self.relationships[template_id], TYPE_RELATIONSHIP
|
||||||
|
|
||||||
|
if template_id in self.entities:
|
||||||
|
return self.entities[template_id], TYPE_ENTITY
|
||||||
|
|
||||||
|
LOG.error('Cannot find template_id = %s in template named: %s' %
|
||||||
|
(template_id, self.template_name))
|
||||||
|
return None
|
||||||
|
@ -1,27 +1,35 @@
|
|||||||
# Copyright 2016 - Nokia
|
# Copyright 2015 - Nokia
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# 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
|
# not use this file except in compliance with the License. You may obtain
|
||||||
# a copy of the License at
|
# a copy of the License at
|
||||||
#
|
#
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
#
|
#
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# 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 oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
from vitrage.common import file_utils
|
|
||||||
|
|
||||||
LOG = log.getLogger(__name__)
|
LOG = log.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
def load_templates_files(conf):
|
def syntax_validate(template_conf):
|
||||||
|
pass
|
||||||
|
|
||||||
templates_dir_path = conf.evaluator.templates_dir
|
|
||||||
template_files = file_utils.load_yaml_files(templates_dir_path)
|
|
||||||
|
|
||||||
for template_file in template_files:
|
def validate_scenario_condition(condition_str):
|
||||||
pass
|
"""Validate the condition content.
|
||||||
|
|
||||||
|
Check:
|
||||||
|
1. The brackets are valid
|
||||||
|
|
||||||
|
:param condition: the condition string
|
||||||
|
:return: True if the condition itself is valid, otherwise returns False
|
||||||
|
:rtype: bool
|
||||||
|
"""
|
||||||
|
pass
|
@ -1,40 +0,0 @@
|
|||||||
# 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.
|
|
||||||
|
|
||||||
import vitrage.evaluator.scenario as scenario
|
|
||||||
|
|
||||||
|
|
||||||
class ScenarioManager(object):
|
|
||||||
|
|
||||||
def get_relevant_scenarios(self, element_before, element_now):
|
|
||||||
"""Returns scenarios triggered by an event.
|
|
||||||
|
|
||||||
Returned scenarios are divided into two disjoint lists, based on the
|
|
||||||
element state (before/now) that triggered the scenario condition.
|
|
||||||
|
|
||||||
Note that this should intuitively mean that the "before" scenarios will
|
|
||||||
activate their "undo" operation, while the "now" will activate the
|
|
||||||
"execute" operation.
|
|
||||||
|
|
||||||
:param element_before:
|
|
||||||
:param element_now:
|
|
||||||
:return:
|
|
||||||
:rtype: dict
|
|
||||||
"""
|
|
||||||
|
|
||||||
trigger_id_before = 'template_id of trigger for before scenario'
|
|
||||||
trigger_id_now = 'template_id of trigger for now scenario'
|
|
||||||
|
|
||||||
return {'before': [(scenario.Scenario(), trigger_id_before)],
|
|
||||||
'now': [(scenario.Scenario(), trigger_id_now)]}
|
|
@ -32,7 +32,7 @@ DICT_STRUCTURE_SCHEMA_ERROR = '%s must refer to dictionary.'
|
|||||||
SCHEMA_CONTENT_ERROR = '%s must contain %s Fields.'
|
SCHEMA_CONTENT_ERROR = '%s must contain %s Fields.'
|
||||||
|
|
||||||
|
|
||||||
def validate(template_conf):
|
def syntax_validate(template_conf):
|
||||||
|
|
||||||
is_valid = validate_template_sections(template_conf)
|
is_valid = validate_template_sections(template_conf)
|
||||||
|
|
@ -39,13 +39,13 @@ scenarios:
|
|||||||
condition: alarm_on_host and host_contains_instance
|
condition: alarm_on_host and host_contains_instance
|
||||||
actions:
|
actions:
|
||||||
- action:
|
- action:
|
||||||
action_type: raise_alarm
|
action_type: RAISE_ALARM
|
||||||
properties:
|
properties:
|
||||||
alarm_type: VM_CPU_SUBOPTIMAL_PERFORMANCE
|
alarm_type: VM_CPU_SUBOPTIMAL_PERFORMANCE
|
||||||
action_target:
|
action_target:
|
||||||
target: 4
|
target: 4
|
||||||
- action:
|
- action:
|
||||||
action_type: set_state
|
action_type: SET_STATE
|
||||||
properties:
|
properties:
|
||||||
state: SUBOPTIMAL
|
state: SUBOPTIMAL
|
||||||
action_target:
|
action_target:
|
||||||
@ -54,7 +54,7 @@ scenarios:
|
|||||||
condition: alarm_on_host and alarm_on_instance and host_contains_instance
|
condition: alarm_on_host and alarm_on_instance and host_contains_instance
|
||||||
actions:
|
actions:
|
||||||
- action:
|
- action:
|
||||||
action_type: add_causal_relationship
|
action_type: ADD_CAUSAL_RELATIONSHIP
|
||||||
action_target:
|
action_target:
|
||||||
source: 1
|
source: 1
|
||||||
target: 2
|
target: 2
|
||||||
|
@ -11,10 +11,10 @@
|
|||||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
# 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 oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from vitrage.common import file_utils
|
from vitrage.evaluator.scenario_repository import ScenarioRepository
|
||||||
|
|
||||||
from vitrage.tests import base
|
from vitrage.tests import base
|
||||||
from vitrage.tests.mocks import utils
|
from vitrage.tests.mocks import utils
|
||||||
|
|
||||||
@ -22,7 +22,7 @@ from vitrage.tests.mocks import utils
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class TemplateLoaderTest(base.BaseTest):
|
class ScenarioRepositoryTest(base.BaseTest):
|
||||||
|
|
||||||
OPTS = [
|
OPTS = [
|
||||||
cfg.StrOpt('templates_dir',
|
cfg.StrOpt('templates_dir',
|
||||||
@ -30,17 +30,12 @@ class TemplateLoaderTest(base.BaseTest):
|
|||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
||||||
def setUp(self):
|
@classmethod
|
||||||
super(TemplateLoaderTest, self).setUp()
|
def setUpClass(cls):
|
||||||
|
|
||||||
self.template_dir_path = utils.get_resources_dir() + '/templates'
|
cls.conf = cfg.ConfigOpts()
|
||||||
|
cls.conf.register_opts(cls.OPTS, group='evaluator')
|
||||||
self.conf = cfg.ConfigOpts()
|
|
||||||
self.conf.register_opts(self.OPTS, group='evaluator')
|
|
||||||
|
|
||||||
self.template_yamls = file_utils.load_yaml_files(
|
|
||||||
self.template_dir_path
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_template_loader(self):
|
def test_template_loader(self):
|
||||||
pass
|
repository = ScenarioRepository(self.conf)
|
||||||
|
print(repository)
|
@ -17,7 +17,7 @@ from oslo_log import log as logging
|
|||||||
|
|
||||||
from vitrage.common import file_utils
|
from vitrage.common import file_utils
|
||||||
from vitrage.evaluator.template_fields import TemplateFields
|
from vitrage.evaluator.template_fields import TemplateFields
|
||||||
from vitrage.evaluator import template_validator
|
from vitrage.evaluator import template_syntax_validator
|
||||||
from vitrage.tests import base
|
from vitrage.tests import base
|
||||||
from vitrage.tests.mocks import utils
|
from vitrage.tests.mocks import utils
|
||||||
|
|
||||||
@ -40,37 +40,38 @@ class TemplateValidatorTest(base.BaseTest):
|
|||||||
return copy.deepcopy(self.first_template)
|
return copy.deepcopy(self.first_template)
|
||||||
|
|
||||||
def test_template_validator(self):
|
def test_template_validator(self):
|
||||||
self.assertTrue(template_validator.validate(self.first_template))
|
self.assertTrue(template_syntax_validator.syntax_validate(
|
||||||
|
self.first_template))
|
||||||
|
|
||||||
def test_validate_template_without_metadata_section(self):
|
def test_validate_template_without_metadata_section(self):
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
template.pop(TemplateFields.METADATA)
|
template.pop(TemplateFields.METADATA)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
def test_validate_template_without_id_in_metadata_section(self):
|
def test_validate_template_without_id_in_metadata_section(self):
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
template[TemplateFields.METADATA].pop(TemplateFields.ID)
|
template[TemplateFields.METADATA].pop(TemplateFields.ID)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
def test_validate_template_without_definitions_section(self):
|
def test_validate_template_without_definitions_section(self):
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
template.pop(TemplateFields.DEFINITIONS)
|
template.pop(TemplateFields.DEFINITIONS)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
def test_validate_template_without_entities(self):
|
def test_validate_template_without_entities(self):
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
template[TemplateFields.DEFINITIONS].pop(TemplateFields.ENTITIES)
|
template[TemplateFields.DEFINITIONS].pop(TemplateFields.ENTITIES)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
def test_validate_template_with_empty_entities(self):
|
def test_validate_template_with_empty_entities(self):
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
template[TemplateFields.DEFINITIONS][TemplateFields.ENTITIES] = []
|
template[TemplateFields.DEFINITIONS][TemplateFields.ENTITIES] = []
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
def test_validate_entity_without_required_fields(self):
|
def test_validate_entity_without_required_fields(self):
|
||||||
|
|
||||||
@ -78,13 +79,13 @@ class TemplateValidatorTest(base.BaseTest):
|
|||||||
definitions = template[TemplateFields.DEFINITIONS]
|
definitions = template[TemplateFields.DEFINITIONS]
|
||||||
entity = definitions[TemplateFields.ENTITIES][0]
|
entity = definitions[TemplateFields.ENTITIES][0]
|
||||||
entity[TemplateFields.ENTITY].pop(TemplateFields.CATEGORY)
|
entity[TemplateFields.ENTITY].pop(TemplateFields.CATEGORY)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
definitions = template[TemplateFields.DEFINITIONS]
|
definitions = template[TemplateFields.DEFINITIONS]
|
||||||
entity = definitions[TemplateFields.ENTITIES][0]
|
entity = definitions[TemplateFields.ENTITIES][0]
|
||||||
entity[TemplateFields.ENTITY].pop(TemplateFields.TEMPLATE_ID)
|
entity[TemplateFields.ENTITY].pop(TemplateFields.TEMPLATE_ID)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
def test_validate_relationships_without_required_fields(self):
|
def test_validate_relationships_without_required_fields(self):
|
||||||
|
|
||||||
@ -92,13 +93,13 @@ class TemplateValidatorTest(base.BaseTest):
|
|||||||
definitions = template[TemplateFields.DEFINITIONS]
|
definitions = template[TemplateFields.DEFINITIONS]
|
||||||
relationship = definitions[TemplateFields.RELATIONSHIPS][0]
|
relationship = definitions[TemplateFields.RELATIONSHIPS][0]
|
||||||
relationship[TemplateFields.RELATIONSHIP].pop(TemplateFields.SOURCE)
|
relationship[TemplateFields.RELATIONSHIP].pop(TemplateFields.SOURCE)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
definitions = template[TemplateFields.DEFINITIONS]
|
definitions = template[TemplateFields.DEFINITIONS]
|
||||||
relationship = definitions[TemplateFields.RELATIONSHIPS][0]
|
relationship = definitions[TemplateFields.RELATIONSHIPS][0]
|
||||||
relationship[TemplateFields.RELATIONSHIP].pop(TemplateFields.TARGET)
|
relationship[TemplateFields.RELATIONSHIP].pop(TemplateFields.TARGET)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
definitions = template[TemplateFields.DEFINITIONS]
|
definitions = template[TemplateFields.DEFINITIONS]
|
||||||
@ -106,37 +107,37 @@ class TemplateValidatorTest(base.BaseTest):
|
|||||||
relationship[TemplateFields.RELATIONSHIP].pop(
|
relationship[TemplateFields.RELATIONSHIP].pop(
|
||||||
TemplateFields.TEMPLATE_ID
|
TemplateFields.TEMPLATE_ID
|
||||||
)
|
)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
def test_validate_template_without_scenarios(self):
|
def test_validate_template_without_scenarios(self):
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
template.pop(TemplateFields.SCENARIOS)
|
template.pop(TemplateFields.SCENARIOS)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
def test_validate_template_with_empty_scenarios(self):
|
def test_validate_template_with_empty_scenarios(self):
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
template[TemplateFields.SCENARIOS] = []
|
template[TemplateFields.SCENARIOS] = []
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
def test_validate_scenario_without_required_fields(self):
|
def test_validate_scenario_without_required_fields(self):
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
scenario = template[TemplateFields.SCENARIOS][0]
|
scenario = template[TemplateFields.SCENARIOS][0]
|
||||||
scenario[TemplateFields.SCENARIO].pop(TemplateFields.CONDITION)
|
scenario[TemplateFields.SCENARIO].pop(TemplateFields.CONDITION)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
scenario = template[TemplateFields.SCENARIOS][0]
|
scenario = template[TemplateFields.SCENARIOS][0]
|
||||||
scenario[TemplateFields.SCENARIO].pop(TemplateFields.ACTIONS)
|
scenario[TemplateFields.SCENARIO].pop(TemplateFields.ACTIONS)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
def test_validate_template_with_empty_actions(self):
|
def test_validate_template_with_empty_actions(self):
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
scenario = template[TemplateFields.SCENARIOS][0]
|
scenario = template[TemplateFields.SCENARIOS][0]
|
||||||
scenario[TemplateFields.SCENARIO][TemplateFields.ACTIONS] = []
|
scenario[TemplateFields.SCENARIO][TemplateFields.ACTIONS] = []
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
def test_validate_action_without_required_fields(self):
|
def test_validate_action_without_required_fields(self):
|
||||||
|
|
||||||
@ -144,10 +145,10 @@ class TemplateValidatorTest(base.BaseTest):
|
|||||||
scenario = template[TemplateFields.SCENARIOS][0]
|
scenario = template[TemplateFields.SCENARIOS][0]
|
||||||
action = scenario[TemplateFields.SCENARIO][TemplateFields.ACTIONS][0]
|
action = scenario[TemplateFields.SCENARIO][TemplateFields.ACTIONS][0]
|
||||||
action[TemplateFields.ACTION].pop(TemplateFields.ACTION_TYPE)
|
action[TemplateFields.ACTION].pop(TemplateFields.ACTION_TYPE)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
|
||||||
template = self.clone_template
|
template = self.clone_template
|
||||||
scenario = template[TemplateFields.SCENARIOS][0]
|
scenario = template[TemplateFields.SCENARIOS][0]
|
||||||
action = scenario[TemplateFields.SCENARIO][TemplateFields.ACTIONS][0]
|
action = scenario[TemplateFields.SCENARIO][TemplateFields.ACTIONS][0]
|
||||||
action[TemplateFields.ACTION].pop(TemplateFields.ACTION_TARGET)
|
action[TemplateFields.ACTION].pop(TemplateFields.ACTION_TARGET)
|
||||||
self.assertFalse(template_validator.validate(template))
|
self.assertFalse(template_syntax_validator.syntax_validate(template))
|
||||||
|
Loading…
Reference in New Issue
Block a user