state normalization support implementation

implements: blueprint state-normalization-support
Change-Id: I6272d01f12ae4a0a901e0aa61b7defbb8e114c39
This commit is contained in:
Alexey Weyl 2016-02-29 13:26:19 +02:00
parent 642ce2c058
commit b56311901a
33 changed files with 1002 additions and 191 deletions

View File

@ -45,7 +45,7 @@ def main():
conf, synchronizer_launcher.create_send_to_queue_callback(event_queue))
launcher.launch_service(entity_graph_svc.VitrageGraphService(
event_queue, e_graph, initialization_status))
conf, event_queue, e_graph, initialization_status))
launcher.launch_service(api_handler_svc.VitrageApiHandlerService(
e_graph))

View File

@ -1,4 +1,5 @@
# Copyright 2015 - Alcatel-Lucent
# 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
@ -19,6 +20,8 @@ class VertexProperties(object):
ID = 'id'
IS_DELETED = 'is_deleted'
STATE = 'state'
VITRAGE_STATE = 'vitrage_state'
AGGREGATED_STATE = 'aggregated_state'
PROJECT_ID = 'project_id'
UPDATE_TIMESTAMP = 'update_timestamp'
NAME = 'name'

View File

@ -20,7 +20,8 @@ import yaml
LOG = log.getLogger(__name__)
def load_files(dir_path, suffix=None,
def load_files(dir_path,
suffix=None,
with_pathname=False,
with_exception=False):
try:

View File

@ -1,4 +1,5 @@
# Copyright 2015 - Alcatel-Lucent
# 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
@ -12,4 +13,12 @@
# License for the specific language governing permissions and limitations
# under the License.
__author__ = 'stack'
from oslo_config import cfg
OPTS = [
cfg.StrOpt('states_plugins_dir',
default='/etc/vitrage/states_plugins',
help='A path for the configuration files of the plugins states'
),
]

View File

@ -1,4 +1,5 @@
# Copyright 2015 - Alcatel-Lucent
# 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
@ -18,7 +19,8 @@ from vitrage.common.constants import EventAction
from vitrage.common.constants import VertexProperties as VProps
from vitrage.entity_graph.processor import base as processor
from vitrage.entity_graph.processor import entity_graph
from vitrage.entity_graph import transformer_manager
from vitrage.entity_graph.states.state_manager import StateManager
from vitrage.entity_graph.transformer_manager import TransformerManager
from vitrage.graph import Direction
LOG = log.getLogger(__name__)
@ -28,8 +30,10 @@ class Processor(processor.ProcessorBase):
NUMBER_OF_PLUGINS = 5
def __init__(self, initialization_status, e_graph=None):
self.transformer = transformer_manager.TransformerManager()
def __init__(self, cfg, initialization_status, e_graph=None):
self.cfg = cfg
self.transformer_manager = TransformerManager()
self.state_manager = StateManager(self.cfg)
self._initialize_events_actions()
self.initialization_status = initialization_status
self.entity_graph = entity_graph.EntityGraph("Entity Graph") if \
@ -47,7 +51,7 @@ class Processor(processor.ProcessorBase):
"""
entity = self.transform_entity(event)
# TODO(Alexey): need to check here the NOT_RELEVANT action as well
self._calculate_aggregated_state(entity.vertex, entity.action)
return self.actions[entity.action](entity.vertex, entity.neighbors)
def create_entity(self, new_vertex, neighbors):
@ -64,7 +68,7 @@ class Processor(processor.ProcessorBase):
LOG.debug("Add entity to entity graph: %s", new_vertex)
self.entity_graph.add_vertex(new_vertex)
self._connect_neighbors(neighbors, [])
self._connect_neighbors(neighbors, [], EventAction.CREATE)
def update_entity(self, updated_vertex, neighbors):
"""Updates the vertex in the entity graph
@ -135,7 +139,9 @@ class Processor(processor.ProcessorBase):
self.initialization_status.RECEIVED_ALL_END_MESSAGES
def transform_entity(self, event):
return self.transformer.transform(event)
entity = self.transformer_manager.transform(event)
LOG.debug('Transformed entity: %s', entity)
return entity
def _update_neighbors(self, vertex, neighbors):
"""Updates vertices neighbor connections
@ -147,9 +153,9 @@ class Processor(processor.ProcessorBase):
(valid_edges, obsolete_edges) = self._find_edges_status(
vertex, neighbors)
self._delete_old_connections(vertex, obsolete_edges)
self._connect_neighbors(neighbors, valid_edges)
self._connect_neighbors(neighbors, valid_edges, EventAction.UPDATE)
def _connect_neighbors(self, neighbors, valid_edges):
def _connect_neighbors(self, neighbors, valid_edges, action):
"""Updates the neighbor vertex and adds the connection edges """
LOG.debug("Connect neighbors. Neighbors: %s, valid_edges: %s",
neighbors, valid_edges)
@ -159,6 +165,7 @@ class Processor(processor.ProcessorBase):
not self.entity_graph.is_vertex_deleted(graph_vertex):
if self.entity_graph.can_update_vertex(graph_vertex, vertex):
LOG.debug("Updates vertex: %s", vertex)
self._calculate_aggregated_state(vertex, action)
self.entity_graph.update_vertex(vertex)
if edge not in valid_edges:
@ -227,3 +234,36 @@ class Processor(processor.ProcessorBase):
EventAction.DELETE: self.delete_entity,
EventAction.END_MESSAGE: self.handle_end_message
}
def _calculate_aggregated_state(self, vertex, action):
LOG.debug("calculate event state")
if action == EventAction.UPDATE or action == EventAction.DELETE:
graph_vertex = self.entity_graph.get_vertex(vertex.vertex_id)
elif action == EventAction.CREATE:
graph_vertex = None
elif action == EventAction.END_MESSAGE:
return None
else:
LOG.info('not recognized action: %s for vertex: %s',
action, vertex)
state = self._get_updated_property(vertex,
graph_vertex,
VProps.STATE)
vitrage_state = self._get_updated_property(vertex,
graph_vertex,
VProps.VITRAGE_STATE)
vertex[VProps.AGGREGATED_STATE] = self.state_manager.aggregated_state(
state, vitrage_state, vertex[VProps.TYPE])
@staticmethod
def _get_updated_property(new_vertex, graph_vertex, prop):
if new_vertex and prop in new_vertex.properties and new_vertex[prop]:
return new_vertex[prop]
elif graph_vertex and prop in graph_vertex.properties \
and graph_vertex[prop]:
return graph_vertex[prop]
return None

View File

@ -25,10 +25,12 @@ LOG = log.getLogger(__name__)
class VitrageGraphService(os_service.Service):
def __init__(self, event_queue, entity_graph, initialization_status):
def __init__(self, cfg, event_queue, entity_graph, initialization_status):
super(VitrageGraphService, self).__init__()
self.queue = event_queue
self.processor = proc.Processor(initialization_status,
self.cfg = cfg
self.processor = proc.Processor(self.cfg,
initialization_status,
e_graph=entity_graph)
def start(self):

View File

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

View File

@ -0,0 +1,21 @@
# 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 AlarmState(object):
HIGH = 'HIGH'
MEDIUM = 'MEDIUM'
LOW = 'LOW'
OK = 'OK'
UNKNOWN = 'UNKNOWN'

View File

@ -0,0 +1,32 @@
# 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 ResourceState(object):
TERMINATED = 'TERMINATED'
ERROR = 'ERROR'
UNRECOGNIZED = 'UNRECOGNIZED'
UNAVAILABLE = 'UNAVAILABLE'
SUSPENDED = 'SUSPENDED'
HIBERNATE = 'HIBERNATE'
PAUSED = 'PAUSED'
TERMINATING = 'TERMINATING'
SUSPENDING = 'SUSPENDING'
REBUILDING = 'REBUILDING'
STARTING = 'STARTING'
SUBOPTIMAL = 'SUBOPTIMAL'
AVAILABLE = 'AVAILABLE'
RUNNING = 'RUNNING'
CREATING = 'CREATING'
UNDEFINED = 'UNDEFINED'

View File

@ -0,0 +1,146 @@
# 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 os
from oslo_log import log
from vitrage.common.constants import EntityCategory
from vitrage.common import file_utils
from vitrage.entity_graph.states.alarm_state import AlarmState
from vitrage.entity_graph.states.resource_state import ResourceState
LOG = log.getLogger(__name__)
class StateManager(object):
STATES = 'states'
PRIORITIES = 'priorities'
UNKNOWN_TYPE = 'unknown_type'
def __init__(self, cfg):
self.cfg = cfg
self.category_unknown_type = self._init_category_unknown_type()
self.category_additional_data = self._init_category_additional_data()
self.states_plugins = self._load_state_configurations()
def normalize_state(self, plugin_name, state):
upper_state = state if not state else state.upper()
return self.states_plugins[plugin_name][self.STATES][upper_state] \
if upper_state in self.states_plugins[plugin_name][self.STATES] else \
self.states_plugins[plugin_name][self.UNKNOWN_TYPE]
def state_priority(self, plugin_name, normalized_state):
# no need to check if normalized_state exists, cause it exists for sure
upper_state = normalized_state if not normalized_state else \
normalized_state.upper()
return self.states_plugins[plugin_name][self.PRIORITIES][upper_state]
def aggregated_state(self, state1, state2, plugin_name,
is_normalized=False):
upper_state1 = state1 if not state1 else state1.upper()
upper_state2 = state2 if not state2 else state2.upper()
normalized_state1 = upper_state1.upper() if is_normalized else \
self.normalize_state(plugin_name, upper_state1)
normalized_state2 = upper_state2.upper() if is_normalized else \
self.normalize_state(plugin_name, upper_state2)
priority_state1 = self.state_priority(plugin_name,
normalized_state1)
priority_state2 = self.state_priority(plugin_name,
normalized_state2)
return normalized_state1 if priority_state1 > priority_state2 \
else normalized_state2
def _load_state_configurations(self):
states_plugins = {}
files = file_utils.load_files(
self.cfg.entity_graph.states_plugins_dir, '.yaml')
for file_name in files:
full_path = self.cfg.entity_graph.states_plugins_dir + '/' \
+ file_name
states, priorities, unknown_type = \
self._retrieve_states_and_priorities_from_file(full_path)
states_plugins[os.path.splitext(file_name)[0]] = {
self.STATES: states,
self.PRIORITIES: priorities,
self.UNKNOWN_TYPE: unknown_type
}
# TODO(Alexey): implement this after finishing implement load
# specific plugins from configuration
# self._is_all_plugins_states_exists()
return states_plugins
def _retrieve_states_and_priorities_from_file(self, full_path):
states = {}
priorities = {}
config = file_utils.load_yaml_file(full_path, with_exception=True)
for item in config['states']:
normalized_state = item['normalized state']
# original to normalized state
normalized_state_name = normalized_state['name']
for original_state in normalized_state['original states']:
states[original_state['name'].upper()] = normalized_state_name
self._add_default_states(states, priorities)
# normalized state priority
priorities[normalized_state_name] = \
int(normalized_state['priority'])
self.category_additional_data[config['category']](states,
priorities,
full_path)
category_unknown_type = self.category_unknown_type[config['category']]
return states, priorities, category_unknown_type
@staticmethod
def _add_default_states(states, priorities):
states[None] = ResourceState.UNDEFINED
priorities[ResourceState.UNDEFINED] = 0
@staticmethod
def _init_category_unknown_type():
return {
EntityCategory.RESOURCE: ResourceState.UNRECOGNIZED,
EntityCategory.ALARM: AlarmState.UNKNOWN
}
def _init_category_additional_data(self):
return {
EntityCategory.RESOURCE: self._resource_additional_states,
EntityCategory.ALARM: self._alarm_additional_states
}
@staticmethod
def _resource_additional_states(states, priorities, full_path):
if ResourceState.UNRECOGNIZED not in priorities:
raise ValueError('%s state is not defined in %s',
ResourceState.UNRECOGNIZED, full_path)
@staticmethod
def _alarm_additional_states(states, priorities, full_path):
if AlarmState.UNKNOWN not in priorities:
raise ValueError('%s state is not defined in %s',
AlarmState.UNKNOWN, full_path)

View File

@ -1,4 +1,5 @@
# Copyright 2015 - Alcatel-Lucent
# 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
@ -32,10 +33,10 @@ LOG = logging.getLogger(__name__)
class TransformerManager(object):
def __init__(self):
self.transformers = self.register_transformer_classes()
self.transformers = self._register_transformer_classes()
@staticmethod
def register_transformer_classes():
def _register_transformer_classes():
transformers = {}

View File

@ -22,7 +22,6 @@ def create_vertex(vitrage_id,
entity_id=None,
entity_category=None,
entity_type=None,
entity_project=None,
entity_state=None,
is_deleted=False,
update_timestamp=None,
@ -38,8 +37,6 @@ def create_vertex(vitrage_id,
:type entity_category: str
:param entity_type:
:type entity_type: str
:param entity_project:
:type entity_project: str
:param entity_state:
:type entity_state: str
:param is_deleted:
@ -56,7 +53,6 @@ def create_vertex(vitrage_id,
properties = {
VConst.ID: entity_id,
VConst.PROJECT_ID: entity_project,
VConst.STATE: entity_state,
VConst.TYPE: entity_type,
VConst.CATEGORY: entity_category,

View File

@ -26,5 +26,6 @@ def list_opts():
('synchronizer', vitrage.synchronizer.OPTS),
('evaluator', vitrage.evaluator.OPTS),
('synchronizer_plugins', vitrage.synchronizer.plugins.OPTS),
('consistency', vitrage.entity_graph.consistency.OPTS)
('consistency', vitrage.entity_graph.consistency.OPTS),
('entity_graph', vitrage.entity_graph.OPTS)
]

View File

@ -85,12 +85,13 @@ class InstanceTransformer(transformer_base.TransformerBase):
def _create_entity_vertex(self, entity_event):
sync_mode = entity_event[SyncProps.SYNC_MODE]
project = extract_field_value(entity_event, self.PROJECT_ID[sync_mode])
metadata = {
VProps.NAME: extract_field_value(
entity_event,
self.INSTANCE_NAME[sync_mode]),
VProps.IS_PLACEHOLDER: False
VProps.NAME: extract_field_value(entity_event,
self.INSTANCE_NAME[sync_mode]),
VProps.IS_PLACEHOLDER: False,
VProps.PROJECT_ID: project
}
entity_key = self.extract_key(entity_event)
@ -98,7 +99,6 @@ class InstanceTransformer(transformer_base.TransformerBase):
entity_id = extract_field_value(
entity_event,
self.INSTANCE_ID[sync_mode])
project = extract_field_value(entity_event, self.PROJECT_ID[sync_mode])
state = extract_field_value(
entity_event,
self.INSTANCE_STATE[sync_mode])
@ -111,7 +111,6 @@ class InstanceTransformer(transformer_base.TransformerBase):
entity_id=entity_id,
entity_category=EntityCategory.RESOURCE,
entity_type=self.INSTANCE_TYPE,
entity_project=project,
entity_state=state,
update_timestamp=update_timestamp,
metadata=metadata)

View File

@ -69,36 +69,35 @@ class StaticPhysicalSynchronizer(SynchronizerBase):
def _get_changes_entities(self):
entities_updates = []
if os.path.isdir(self.cfg.synchronizer_plugins.static_plugins_dir):
entities_updates = []
files = file_utils.load_files(
self.cfg.synchronizer_plugins.static_plugins_dir, '.yaml')
entities_updates = []
files = file_utils.load_files(
self.cfg.synchronizer_plugins.static_plugins_dir, '.yaml')
for file in files:
full_path = self.cfg.synchronizer_plugins.static_plugins_dir +\
'/' + file
config = file_utils.load_yaml_file(full_path)
if config:
if file in self.cache:
if str(config) != str(self.cache[file]):
# TODO(alexey_weyl): need also to remove deleted
# files from cache
for file in files:
full_path = self.cfg.synchronizer_plugins.static_plugins_dir +\
'/' + file
config = file_utils.load_yaml_file(full_path)
if config:
if file in self.cache:
if str(config) != str(self.cache[file]):
# TODO(alexey_weyl): need also to remove deleted
# files from cache
self._update_on_existing_entities(
self.cache[file][self.ENTITIES_SECTION],
config[self.ENTITIES_SECTION],
entities_updates)
self._update_on_existing_entities(
self.cache[file][self.ENTITIES_SECTION],
config[self.ENTITIES_SECTION],
entities_updates)
self._update_on_new_entities(
config[self.ENTITIES_SECTION],
self.cache[file][self.ENTITIES_SECTION],
entities_updates)
self._update_on_new_entities(
config[self.ENTITIES_SECTION],
self.cache[file][self.ENTITIES_SECTION],
entities_updates)
self.cache[file] = config
else:
self.cache[file] = config
entities_updates += \
self._get_entities_from_file(file, full_path)
else:
self.cache[file] = config
entities_updates += \
self._get_entities_from_file(file, full_path)
return entities_updates

View File

@ -1,4 +1,4 @@
# Copyright 2015 - Alcatel-Lucent
# 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

View File

@ -0,0 +1,52 @@
# 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 SynchronizerProperties as SyncProps
from vitrage.common.constants import SyncMode
from vitrage.entity_graph.initialization_status import InitializationStatus
from vitrage.entity_graph.processor import processor as proc
from vitrage.tests.mocks import mock_syncronizer as mock_sync
from vitrage.tests.unit.entity_graph.base import TestEntityGraphUnitBase
class TestEntityGraphFunctionalBase(TestEntityGraphUnitBase):
def _create_processor_with_graph(self, conf, processor=None):
events = self._create_mock_events()
if not processor:
processor = proc.Processor(conf, InitializationStatus())
for event in events:
processor.process_event(event)
return processor
def _create_mock_events(self):
gen_list = mock_sync.simple_zone_generators(
self.NUM_ZONES,
self.NUM_HOSTS,
snapshot_events=self.NUM_ZONES,
snap_vals={SyncProps.SYNC_MODE: SyncMode.INIT_SNAPSHOT})
gen_list += mock_sync.simple_host_generators(
self.NUM_ZONES,
self.NUM_HOSTS,
self.NUM_HOSTS,
snap_vals={SyncProps.SYNC_MODE: SyncMode.INIT_SNAPSHOT})
gen_list += mock_sync.simple_instance_generators(
self.NUM_HOSTS,
self.NUM_INSTANCES,
self.NUM_INSTANCES,
snap_vals={SyncProps.SYNC_MODE: SyncMode.INIT_SNAPSHOT})
return mock_sync.generate_sequential_events_list(gen_list)

View File

@ -28,12 +28,13 @@ from vitrage.entity_graph.consistency.consistency_enforcer \
from vitrage.entity_graph.initialization_status import InitializationStatus
from vitrage.entity_graph.processor.processor import Processor
import vitrage.graph.utils as graph_utils
from vitrage.tests.unit.entity_graph import TestEntityGraphBase
from vitrage.tests.functional.entity_graph.base import \
TestEntityGraphFunctionalBase
class TestConsistency(TestEntityGraphBase):
class TestConsistencyFunctional(TestEntityGraphFunctionalBase):
OPTS = [
CONSISTENCY_OPTS = [
cfg.IntOpt('consistency_interval',
default=1,
min=1),
@ -43,11 +44,12 @@ class TestConsistency(TestEntityGraphBase):
]
def setUp(self):
super(TestConsistency, self).setUp()
super(TestConsistencyFunctional, self).setUp()
self.initialization_status = InitializationStatus()
self.processor = Processor(self.initialization_status)
self.conf = cfg.ConfigOpts()
self.conf.register_opts(self.OPTS, group='consistency')
self.conf.register_opts(self.CONSISTENCY_OPTS, group='consistency')
self.conf.register_opts(self.PROCESSOR_OPTS, group='entity_graph')
self.processor = Processor(self.conf, self.initialization_status)
self.consistency_enforcer = ConsistencyEnforcer(
self.conf, self.processor.entity_graph, self.initialization_status)
@ -57,7 +59,7 @@ class TestConsistency(TestEntityGraphBase):
# Setup
num_external_alarms = self.NUM_HOSTS - 2
num_instances_per_host = 4
self._create_processor_with_graph(processor=self.processor)
self._create_processor_with_graph(self.conf, processor=self.processor)
self._add_alarms()
self._set_end_messages()
self.assertEqual(self._num_total_expected_vertices() +
@ -105,7 +107,7 @@ class TestConsistency(TestEntityGraphBase):
len(self.processor.entity_graph.get_vertices()))
def _periodic_process_setup_stage(self, consistency_interval):
self._create_processor_with_graph(processor=self.processor)
self._create_processor_with_graph(self.conf, processor=self.processor)
current_time = utcnow()
# set all vertices to be have timestamp that consistency won't get

View File

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

View File

@ -0,0 +1,48 @@
# 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_config import cfg
from vitrage.tests.functional.entity_graph.base import \
TestEntityGraphFunctionalBase
class TestProcessorFunctional(TestEntityGraphFunctionalBase):
ZONE_SPEC = 'ZONE_SPEC'
HOST_SPEC = 'HOST_SPEC'
INSTANCE_SPEC = 'INSTANCE_SPEC'
NUM_VERTICES_AFTER_CREATION = 2
NUM_EDGES_AFTER_CREATION = 1
NUM_VERTICES_AFTER_DELETION = 1
NUM_EDGES_AFTER_DELETION = 0
def setUp(self):
super(TestProcessorFunctional, self).setUp()
self.conf = cfg.ConfigOpts()
self.conf.register_opts(self.PROCESSOR_OPTS, group='entity_graph')
def test_create_entity_graph(self):
processor = self._create_processor_with_graph(self.conf)
# check number of entities
num_vertices = len(processor.entity_graph)
self.assertEqual(self._num_total_expected_vertices(), num_vertices)
# TODO(Alexey): add this check and to check also the number of edges
# check all entities create a tree and no free floating vertices exists
# it will be done only after we will have zone plugin
# vertex = graph.find_vertex_in_graph()
# bfs_list = graph.algo.bfs(graph)
# self.assertEqual(num_vertices, len(bfs_list))

View File

@ -0,0 +1,69 @@
# 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_config import cfg
from vitrage.common.constants import EventAction
from vitrage.common.constants import SyncMode
from vitrage.common.constants import VertexProperties as VProps
from vitrage.entity_graph.initialization_status import InitializationStatus
from vitrage.entity_graph.processor import processor as proc
from vitrage.entity_graph.states.resource_state import ResourceState
from vitrage.synchronizer.plugins.nova.instance.transformer import \
InstanceTransformer
from vitrage.tests.functional.entity_graph.base import \
TestEntityGraphFunctionalBase
class TestStateManagerFunctional(TestEntityGraphFunctionalBase):
def setUp(self):
super(TestStateManagerFunctional, self).setUp()
self.conf = cfg.ConfigOpts()
self.conf.register_opts(self.PROCESSOR_OPTS, group='entity_graph')
def test_state_on_update(self):
# setup
processor = proc.Processor(self.conf, InitializationStatus())
event = self._create_event(spec_type='INSTANCE_SPEC',
sync_mode=SyncMode.INIT_SNAPSHOT)
# action
processor.process_event(event)
# test assertions
instance_transformer = InstanceTransformer({})
vitrage_id = instance_transformer.extract_key(event)
vertex = processor.entity_graph.get_vertex(vitrage_id)
self.assertEqual(ResourceState.RUNNING,
vertex[VProps.AGGREGATED_STATE])
def test_state_on_neighbor_update(self):
# setup
vertex, neighbors, processor = self._create_entity(
spec_type='INSTANCE_SPEC',
sync_mode=SyncMode.INIT_SNAPSHOT)
self.assertEqual(2, processor.entity_graph.num_vertices())
neighbors[0].vertex[VProps.STATE] = 'available'
neighbors[0].vertex[VProps.IS_PLACEHOLDER] = False
# action
processor._connect_neighbors(neighbors, [], EventAction.UPDATE)
# test assertions
neighbor_vertex = processor.entity_graph.get_vertex(
neighbors[0].vertex.vertex_id)
self.assertEqual(ResourceState.AVAILABLE,
neighbor_vertex[VProps.AGGREGATED_STATE])

View File

@ -0,0 +1,28 @@
category: ALARM
states:
- normalized state:
name: UNKNOWN
priority: 50
original states:
- name: UNKNOWN
- normalized state:
name: HIGH
priority: 40
original states:
- name: CRITITCAL
- name: DOWN
- normalized state:
name: MEDIUM
priority: 30
original states:
- name: WARNING
- normalized state:
name: LOW
priority: 20
original states:
- normalized state:
name: OK
priority: 10
original states:
- name: OK
- name: UP

View File

@ -0,0 +1,26 @@
category: RESOURCE
states:
- normalized state:
name: TERMINATED
priority: 150
original states:
- name: DELETED
- normalized state:
name: ERROR
priority: 140
original states:
- name: ERROR
- normalized state:
name: UNRECOGNIZED
priority: 130
original states:
- normalized state:
name: SUBOPTIMAL
priority: 40
original states:
- name: SUBOPTIMAL
- normalized state:
name: AVAILABLE
priority: 30
original states:
- name: available

View File

@ -0,0 +1,46 @@
category: RESOURCE
states:
- normalized state:
name: TERMINATED
priority: 150
original states:
- name: DELETED
- normalized state:
name: ERROR
priority: 140
original states:
- name: ERROR
- normalized state:
name: UNRECOGNIZED
priority: 130
original states:
- normalized state:
name: SUSPENDED
priority: 110
original states:
- name: SUSPENDED
- normalized state:
name: REBUILDING
priority: 60
original states:
- name: REBUILD
- normalized state:
name: STARTING
priority: 50
original states:
- name: VERIFY_RESIZE
- name: REVERT_RESIZE
- name: PASSWORD
- name: REBOOT
- name: BUILD
- name: HARD_REBOOT
- normalized state:
name: SUBOPTIMAL
priority: 40
original states:
- name: SUBOPTIMAL
- normalized state:
name: RUNNING
priority: 20
original states:
- name: ACTIVE

View File

@ -0,0 +1,26 @@
category: RESOURCE
states:
- normalized state:
name: TERMINATED
priority: 150
original states:
- name: DELETED
- normalized state:
name: ERROR
priority: 140
original states:
- name: ERROR
- normalized state:
name: UNRECOGNIZED
priority: 130
original states:
- normalized state:
name: SUBOPTIMAL
priority: 40
original states:
- name: SUBOPTIMAL
- normalized state:
name: AVAILABLE
priority: 30
original states:
- name: available

View File

@ -0,0 +1,26 @@
category: RESOURCE
states:
- normalized state:
name: TERMINATED
priority: 150
original states:
- name: DELETED
- normalized state:
name: ERROR
priority: 140
original states:
- name: ERROR
- normalized state:
name: UNRECOGNIZED
priority: 130
original states:
- normalized state:
name: SUBOPTIMAL
priority: 40
original states:
- name: SUBOPTIMAL
- normalized state:
name: AVAILABLE
priority: 30
original states:
- name: available

View File

@ -12,87 +12,4 @@
# License for the specific language governing permissions and limitations
# under the License.
from vitrage.common.constants import EntityCategory
from vitrage.common.constants import SynchronizerProperties as SyncProps
from vitrage.common.constants import SyncMode
from vitrage.common.datetime_utils import utcnow
from vitrage.entity_graph.initialization_status import InitializationStatus
from vitrage.entity_graph.processor import processor as proc
import vitrage.graph.utils as graph_utils
from vitrage.tests import base
from vitrage.tests.mocks import mock_syncronizer as mock_sync
class TestEntityGraphBase(base.BaseTest):
NUM_NODES = 1
NUM_ZONES = 2
NUM_HOSTS = 4
NUM_INSTANCES = 16
def _create_processor_with_graph(self, processor=None):
events = self._create_mock_events()
if not processor:
processor = proc.Processor(InitializationStatus())
for event in events:
processor.process_event(event)
return processor
def _create_mock_events(self):
gen_list = mock_sync.simple_zone_generators(
self.NUM_ZONES,
self.NUM_HOSTS,
snapshot_events=self.NUM_ZONES,
snap_vals={SyncProps.SYNC_MODE: SyncMode.INIT_SNAPSHOT})
gen_list += mock_sync.simple_host_generators(
self.NUM_ZONES,
self.NUM_HOSTS,
self.NUM_HOSTS,
snap_vals={SyncProps.SYNC_MODE: SyncMode.INIT_SNAPSHOT})
gen_list += mock_sync.simple_instance_generators(
self.NUM_HOSTS,
self.NUM_INSTANCES,
self.NUM_INSTANCES,
snap_vals={SyncProps.SYNC_MODE: SyncMode.INIT_SNAPSHOT})
return mock_sync.generate_sequential_events_list(gen_list)
@staticmethod
def _create_event(spec_type=None, sync_mode=None,
event_type=None, properties=None):
# generate event
spec_list = mock_sync.simple_instance_generators(1, 1, 1)
events_list = mock_sync.generate_random_events_list(
spec_list)
# update properties
if sync_mode is not None:
events_list[0][SyncProps.SYNC_MODE] = sync_mode
if event_type is not None:
events_list[0][SyncProps.EVENT_TYPE] = event_type
if properties is not None:
for key, value in properties.iteritems():
events_list[0][key] = value
return events_list[0]
@staticmethod
def _create_alarm(vitrage_id, alarm_type):
return graph_utils.create_vertex(
vitrage_id,
entity_id=vitrage_id,
entity_category=EntityCategory.ALARM,
entity_type=alarm_type,
entity_state='Running',
is_deleted=False,
update_timestamp=utcnow(),
is_placeholder=False,
)
def _num_total_expected_vertices(self):
return self.NUM_NODES + self.NUM_ZONES + self.NUM_HOSTS + \
self.NUM_INSTANCES
__author__ = 'stack'

View File

@ -0,0 +1,123 @@
# 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_config import cfg
from vitrage.common.constants import EntityCategory
from vitrage.common.constants import SynchronizerProperties as SyncProps
from vitrage.common.constants import SyncMode
from vitrage.common.datetime_utils import utcnow
from vitrage.entity_graph.initialization_status import InitializationStatus
from vitrage.entity_graph.processor import processor as proc
import vitrage.graph.utils as graph_utils
from vitrage.tests import base
from vitrage.tests.mocks import mock_syncronizer as mock_sync
from vitrage.tests.mocks import utils
class TestEntityGraphUnitBase(base.BaseTest):
PROCESSOR_OPTS = [
cfg.StrOpt('states_plugins_dir',
default=utils.get_resources_dir() + '/states_plugins'),
]
NUM_NODES = 1
NUM_ZONES = 2
NUM_HOSTS = 4
NUM_INSTANCES = 16
def _create_processor_with_graph(self, conf, processor=None):
events = self._create_mock_events()
if not processor:
processor = proc.Processor(conf, InitializationStatus())
for event in events:
processor.process_event(event)
return processor
def _create_mock_events(self):
gen_list = mock_sync.simple_zone_generators(
self.NUM_ZONES,
self.NUM_HOSTS,
snapshot_events=self.NUM_ZONES,
snap_vals={SyncProps.SYNC_MODE: SyncMode.INIT_SNAPSHOT})
gen_list += mock_sync.simple_host_generators(
self.NUM_ZONES,
self.NUM_HOSTS,
self.NUM_HOSTS,
snap_vals={SyncProps.SYNC_MODE: SyncMode.INIT_SNAPSHOT})
gen_list += mock_sync.simple_instance_generators(
self.NUM_HOSTS,
self.NUM_INSTANCES,
self.NUM_INSTANCES,
snap_vals={SyncProps.SYNC_MODE: SyncMode.INIT_SNAPSHOT})
return mock_sync.generate_sequential_events_list(gen_list)
def _create_entity(self, processor=None, spec_type=None, sync_mode=None,
event_type=None, properties=None):
# create instance event with host neighbor
event = self._create_event(spec_type=spec_type,
sync_mode=sync_mode,
event_type=event_type,
properties=properties)
# add instance entity with host
if processor is None:
processor = proc.Processor(self.conf, InitializationStatus())
vertex, neighbors, event_type = processor.transform_entity(event)
processor.create_entity(vertex, neighbors)
return vertex, neighbors, processor
@staticmethod
def _create_event(spec_type=None, sync_mode=None,
event_type=None, properties=None):
# generate event
spec_list = mock_sync.simple_instance_generators(1, 1, 1)
events_list = mock_sync.generate_random_events_list(
spec_list)
# update properties
if sync_mode is not None:
events_list[0][SyncProps.SYNC_MODE] = sync_mode
if event_type is not None:
events_list[0][SyncProps.EVENT_TYPE] = event_type
if properties is not None:
for key, value in properties.iteritems():
events_list[0][key] = value
return events_list[0]
@staticmethod
def _create_alarm(vitrage_id, alarm_type):
return graph_utils.create_vertex(
vitrage_id,
entity_id=vitrage_id,
entity_category=EntityCategory.ALARM,
entity_type=alarm_type,
entity_state='Running',
is_deleted=False,
update_timestamp=utcnow(),
is_placeholder=False,
)
def _num_total_expected_vertices(self):
return self.NUM_NODES + self.NUM_ZONES + self.NUM_HOSTS + \
self.NUM_INSTANCES

View File

@ -18,13 +18,14 @@ from vitrage.graph import driver as graph
from vitrage.tests import base
class BaseProcessor(base.BaseTest):
class TestBaseProcessor(base.BaseTest):
def setUp(self):
super(BaseProcessor, self).setUp()
super(TestBaseProcessor, self).setUp()
self.transform = transformer_manager.TransformerManager()
def _update_vertex_to_graph(self, entity_graph, category, type, id,
@staticmethod
def _update_vertex_to_graph(entity_graph, category, type, id,
is_deleted, is_placeholder_data,
additional_prop):
# create vertex properties

View File

@ -17,7 +17,7 @@ from vitrage.entity_graph.processor import entity_graph as entity_g
from vitrage.tests.unit.entity_graph.processor import base
class TestEntityGraphManager(base.BaseProcessor):
class TestEntityGraphManager(base.TestBaseProcessor):
def setUp(self):
super(TestEntityGraphManager, self).setUp()

View File

@ -14,16 +14,20 @@
import unittest
from oslo_config import cfg
from vitrage.common.constants import EventAction
from vitrage.common.constants import SynchronizerProperties as SyncProps
from vitrage.common.constants import SyncMode
from vitrage.common.constants import VertexProperties
from vitrage.common.constants import VertexProperties as VProps
from vitrage.common.datetime_utils import utcnow
from vitrage.entity_graph.initialization_status import InitializationStatus
from vitrage.entity_graph.processor import processor as proc
from vitrage.tests.unit.entity_graph import TestEntityGraphBase
from vitrage.entity_graph.states.resource_state import ResourceState
from vitrage.tests.unit.entity_graph.base import TestEntityGraphUnitBase
class TestProcessorBase(TestEntityGraphBase):
class TestProcessor(TestEntityGraphUnitBase):
ZONE_SPEC = 'ZONE_SPEC'
HOST_SPEC = 'HOST_SPEC'
@ -34,27 +38,15 @@ class TestProcessorBase(TestEntityGraphBase):
NUM_EDGES_AFTER_DELETION = 0
def setUp(self):
super(TestProcessorBase, self).setUp()
def test_create_entity_graph(self):
processor = self._create_processor_with_graph()
# check number of entities
num_vertices = len(processor.entity_graph)
self.assertEqual(self._num_total_expected_vertices(), num_vertices)
# TODO(Alexey): add this check and to check also the number of edges
# check all entities create a tree and no free floating vertices exists
# it will be done only after we will have zone plugin
# vertex = graph.find_vertex_in_graph()
# bfs_list = graph.algo.bfs(graph)
# self.assertEqual(num_vertices, len(bfs_list))
super(TestProcessor, self).setUp()
self.conf = cfg.ConfigOpts()
self.conf.register_opts(self.PROCESSOR_OPTS, group='entity_graph')
# TODO(Alexey): un skip this test when instance transformer update is ready
@unittest.skip('Not ready yet')
def test_process_event(self):
# check create instance event
processor = proc.Processor(InitializationStatus())
processor = proc.Processor(self.conf, InitializationStatus())
event = self._create_event(spec_type=self.INSTANCE_SPEC,
sync_mode=SyncMode.INIT_SNAPSHOT)
processor.process_event(event)
@ -90,18 +82,18 @@ class TestProcessorBase(TestEntityGraphBase):
# check added entity
vertex = processor.entity_graph.get_vertex(vertex.vertex_id)
self.assertEqual('STARTING', vertex.properties[VertexProperties.STATE])
self.assertEqual('STARTING', vertex.properties[VProps.STATE])
# update instance event with state running
vertex.properties[VertexProperties.STATE] = 'RUNNING'
vertex.properties[VertexProperties.UPDATE_TIMESTAMP] = str(utcnow())
vertex.properties[VProps.STATE] = 'RUNNING'
vertex.properties[VProps.UPDATE_TIMESTAMP] = str(utcnow())
processor.update_entity(vertex, neighbors)
# check state
self._check_graph(processor, self.NUM_VERTICES_AFTER_CREATION,
self.NUM_EDGES_AFTER_CREATION)
vertex = processor.entity_graph.get_vertex(vertex.vertex_id)
self.assertEqual('RUNNING', vertex.properties[VertexProperties.STATE])
self.assertEqual('RUNNING', vertex.properties[VProps.STATE])
def test_change_parent(self):
# create instance event with host neighbor and check validity
@ -110,7 +102,7 @@ class TestProcessorBase(TestEntityGraphBase):
# update instance event with state running
(neighbor_vertex, neighbor_edge) = neighbors[0]
old_neighbor_id = neighbor_vertex.vertex_id
neighbor_vertex.properties[VertexProperties.ID] = 'newhost-2'
neighbor_vertex.properties[VProps.ID] = 'newhost-2'
neighbor_vertex.vertex_id = 'RESOURCE_HOST_newhost-2'
neighbor_edge.source_id = 'RESOURCE_HOST_newhost-2'
processor.update_entity(vertex, neighbors)
@ -141,7 +133,7 @@ class TestProcessorBase(TestEntityGraphBase):
# update instance event with state running
(neighbor_vertex, neighbor_edge) = neighbors[0]
old_neighbor_id = neighbor_vertex.vertex_id
neighbor_vertex.properties[VertexProperties.ID] = 'newhost-2'
neighbor_vertex.properties[VProps.ID] = 'newhost-2'
neighbor_vertex.vertex_id = 'RESOURCE_HOST_newhost-2'
neighbor_edge.source_id = 'RESOURCE_HOST_newhost-2'
processor._update_neighbors(vertex, neighbors)
@ -171,6 +163,66 @@ class TestProcessorBase(TestEntityGraphBase):
self.NUM_VERTICES_AFTER_DELETION,
self.NUM_EDGES_AFTER_DELETION)
def test_calculate_aggregated_state(self):
# setup
instances = []
for i in range(6):
(vertex, neighbors, processor) = self._create_and_check_entity()
instances.append((vertex, processor))
# action
# state already exists and its updated
instances[0][0][VProps.STATE] = 'SUSPENDED'
instances[0][1]._calculate_aggregated_state(instances[0][0],
EventAction.UPDATE)
# vitrage state doesn't exist and its updated
del instances[1][0][VProps.STATE]
instances[1][1].entity_graph.update_vertex(instances[1][0])
instances[1][0][VProps.VITRAGE_STATE] = 'SUBOPTIMAL'
instances[1][1]._calculate_aggregated_state(instances[1][0],
EventAction.UPDATE)
# state exists and vitrage state changes
instances[2][0][VProps.VITRAGE_STATE] = 'SUBOPTIMAL'
instances[2][1]._calculate_aggregated_state(instances[2][0],
EventAction.UPDATE)
# vitrage state exists and state changes
del instances[3][0][VProps.STATE]
instances[3][0][VProps.VITRAGE_STATE] = 'SUBOPTIMAL'
instances[3][1].entity_graph.update_vertex(instances[3][0])
instances[3][0][VProps.STATE] = 'SUSPENDED'
instances[3][1]._calculate_aggregated_state(instances[3][0],
EventAction.UPDATE)
# state and vitrage state exists and state changes
instances[4][0][VProps.VITRAGE_STATE] = 'SUBOPTIMAL'
instances[4][1].entity_graph.update_vertex(instances[4][0])
instances[4][0][VProps.STATE] = 'SUSPENDED'
instances[4][1]._calculate_aggregated_state(instances[4][0],
EventAction.UPDATE)
# state and vitrage state exists and vitrage state changes
instances[5][0][VProps.VITRAGE_STATE] = 'SUBOPTIMAL'
instances[5][1].entity_graph.update_vertex(instances[5][0])
instances[5][1]._calculate_aggregated_state(instances[5][0],
EventAction.UPDATE)
# test assertions
self.assertEqual(ResourceState.SUSPENDED,
instances[0][0][VProps.AGGREGATED_STATE])
self.assertEqual(ResourceState.SUBOPTIMAL,
instances[1][0][VProps.AGGREGATED_STATE])
self.assertEqual(ResourceState.SUBOPTIMAL,
instances[2][0][VProps.AGGREGATED_STATE])
self.assertEqual(ResourceState.SUSPENDED,
instances[3][0][VProps.AGGREGATED_STATE])
self.assertEqual(ResourceState.SUSPENDED,
instances[4][0][VProps.AGGREGATED_STATE])
self.assertEqual(ResourceState.SUBOPTIMAL,
instances[5][0][VProps.AGGREGATED_STATE])
def _create_and_check_entity(self, properties={}):
# create instance event with host neighbor
(vertex, neighbors, processor) = self._create_entity(
@ -185,23 +237,6 @@ class TestProcessorBase(TestEntityGraphBase):
return vertex, neighbors, processor
def _create_entity(self, processor=None, spec_type=None, sync_mode=None,
event_type=None, properties=None):
# create instance event with host neighbor
event = self._create_event(spec_type=spec_type,
sync_mode=sync_mode,
event_type=event_type,
properties=properties)
# add instance entity with host
if processor is None:
processor = proc.Processor(InitializationStatus())
(vertex, neighbors, event_type) = processor.transform_entity(event)
processor.create_entity(vertex, neighbors)
return vertex, neighbors, processor
def _check_graph(self, processor, num_vertices, num_edges):
self.assertEqual(num_vertices, len(processor.entity_graph))
self.assertEqual(num_edges, processor.entity_graph.num_edges())

View File

@ -0,0 +1,122 @@
# 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_config import cfg
from vitrage.entity_graph.states.resource_state import ResourceState
from vitrage.entity_graph.states.state_manager import StateManager
from vitrage.tests import base
from vitrage.tests.mocks import utils
class TestStateManager(base.BaseTest):
OPTS = [
cfg.StrOpt('states_plugins_dir',
default=utils.get_resources_dir() + '/states_plugins'),
]
def setUp(self):
super(TestStateManager, self).setUp()
self.conf = cfg.ConfigOpts()
self.conf.register_opts(self.OPTS, group='entity_graph')
def test_load_state_plugins(self):
# action
StateManager(self.conf)
# test assertions
# TODO(Alexey): check that UNRECOGNIZED exists
# TODO(Alexey): check that if UNRECOGNIZED is missing then it throws
# exception
# TODO(Alexey): check that all of the state plugins configured exists
# TODO(Alexey): check that if one of the state plugins is missing then
# it throws an exception
def test_normalize_state(self):
# setup
state_manager = StateManager(self.conf)
# action
normalized_state = \
state_manager.normalize_state('nova.instance', 'REBUILD')
# test assertions
self.assertEqual(ResourceState.REBUILDING, normalized_state)
def test_state_priority(self):
# setup
state_manager = StateManager(self.conf)
# action
state_priority = \
state_manager.state_priority('nova.instance',
ResourceState.REBUILDING)
# test assertions
self.assertEqual(60, state_priority)
def test_aggregated_state_normalized(self):
# setup
state_manager = StateManager(self.conf)
# action
aggregated_state_nova_instance_1 = state_manager.aggregated_state(
ResourceState.REBUILDING, ResourceState.SUBOPTIMAL,
'nova.instance', True)
aggregated_state_nova_instance_2 = state_manager.aggregated_state(
ResourceState.SUBOPTIMAL, ResourceState.REBUILDING,
'nova.instance', True)
# test assertions
self.assertEqual(ResourceState.REBUILDING,
aggregated_state_nova_instance_1)
self.assertEqual(ResourceState.REBUILDING,
aggregated_state_nova_instance_2)
def test_aggregated_state_not_normalized(self):
# setup
state_manager = StateManager(self.conf)
# action
aggregated_state_nova_instance_1 = state_manager.aggregated_state(
'REBOOT', 'REBUILD', 'nova.instance')
aggregated_state_nova_instance_2 = state_manager.aggregated_state(
'REBUILD', 'REBOOT', 'nova.instance')
# test assertions
self.assertEqual(ResourceState.REBUILDING,
aggregated_state_nova_instance_1)
self.assertEqual(ResourceState.REBUILDING,
aggregated_state_nova_instance_2)
def test_aggregated_state_functionalities(self):
# setup
state_manager = StateManager(self.conf)
# action
aggregated_state_nova_instance_1 = state_manager.aggregated_state(
'ACTIVE', None, 'nova.instance')
aggregated_state_nova_instance_2 = state_manager.aggregated_state(
None, 'ACTIVE', 'nova.instance')
aggregated_state_nova_instance_3 = state_manager.aggregated_state(
None, None, 'nova.instance')
# test assertions
self.assertEqual(ResourceState.RUNNING,
aggregated_state_nova_instance_1)
self.assertEqual(ResourceState.RUNNING,
aggregated_state_nova_instance_2)
self.assertEqual(ResourceState.UNDEFINED,
aggregated_state_nova_instance_3)

View File

@ -14,17 +14,27 @@
import testtools
from oslo_config import cfg
from vitrage.entity_graph.initialization_status import InitializationStatus
from vitrage.entity_graph.processor import processor as proc
from vitrage.tests.mocks import mock_syncronizer as mock_sync
from vitrage.tests.mocks import utils
class BaseMock(testtools.TestCase):
"""Base test class for Vitrage API tests."""
PROCESSOR_OPTS = [
cfg.StrOpt('states_plugins_dir',
default=utils.get_resources_dir() + '/states_plugins'),
]
def create_processor_with_graph(self):
self.conf = cfg.ConfigOpts()
self.conf.register_opts(self.PROCESSOR_OPTS, group='entity_graph')
events = self._create_mock_events()
processor = proc.Processor(InitializationStatus())
processor = proc.Processor(self.conf, InitializationStatus())
for event in events:
processor.process_event(event)