nova instance transformer and tests

Change-Id: Id3eb11592c36ac196680f6b6d21bf40f1a67aebf
This commit is contained in:
Liat Har-Tal 2015-12-08 13:29:02 +00:00
parent c7942a5d85
commit 797240c436
18 changed files with 239 additions and 71 deletions

View File

@ -6,9 +6,10 @@ pbr>=1.6
Babel>=1.3
networkx>=1.10
oslo.log>=1.12.0 # Apache-2.0
oslo.policy>=0.3.0
pecan>=0.8.0
PasteDeploy>=1.5.0
Werkzeug>=0.7
oslo.policy>=0.3.0
keystonemiddleware>=2.3.0
stevedore>=1.5.0 # Apache-2.0
exrex>=0.9.4

View File

@ -39,3 +39,8 @@ all_files = 1
[upload_sphinx]
upload-dir = doc/build/html
[entry_points]
vitrage.transformers =
nova.instance = vitrage.entity_graph.transformer.nova_transformer.InstanceTransformer
nova.host = vitrage.entity_graph.transformer.nova_transformer.HostTransformer

View File

@ -15,3 +15,5 @@ testrepository>=0.0.18
testscenarios>=0.4
testtools>=1.4.0
exrex>=0.9.4
stevedore>=1.5.0 # Apache-2.0

View File

@ -0,0 +1 @@
__author__ = 'stack'

View File

@ -0,0 +1,41 @@
# Copyright 2015 - 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.
class VertexConstants(object):
TYPE = 'TYPE'
SUB_TYPE = 'SUB_TYPE'
ID = 'ID'
IS_VERTEX_DELETED = 'IS_VERTEX_DELETED'
VERTEX_DELETION_TIMESTAMP = 'VERTEX_DELETION_TIMESTAMP'
STATE = 'STATE'
PROJECT = 'PROJECT'
UPDATE_TIMESTAMP = 'UPDATE_TIMESTAMP'
class EdgeConstants(object):
RELATION_NAME = 'RELATION_NAME'
IS_EDGE_DELETED = 'IS_EDGE_DELETED'
EDGE_DELETION_TIMESTAMP = 'EDGE_DELETION_TIMESTAMP'
class EdgeLabels(object):
ON = 'on'
CONTAINS = 'contains'
class SynchronizerMessageMode(object):
SNAPSHOT = 'snapshot'
INIT_SNAPSHOT = 'init_snapshot'
UPDATE = 'update'

View File

@ -1,30 +0,0 @@
# Copyright 2015 - 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.
# Vertex properties
TYPE = 'TYPE'
SUB_TYPE = 'SUB_TYPE'
ID = 'ID'
VERTEX_ID = 'VERTEX_ID'
EVENT_TYPE = 'EVENT_TYPE'
IS_VERTEX_DELETED = 'IS_VERTEX_DELETED'
VERTEX_DELETION_TIMESTAMP = 'VERTEX_DELETION_TIMESTAMP'
STATE = 'STATE'
PROJECT = 'PROJECT'
TIMESTAMP = 'TIMESTAMP'
# Edge properties
RELATION_NAME = 'RELATION_NAME'
IS_EDGE_DELETED = 'IS_EDGE_DELETED'
EDGE_DELETION_TIMESTAMP = 'EDGE_DELETION_TIMESTAMP'

View File

@ -13,12 +13,19 @@
# under the License.
import abc
import six
from collections import namedtuple
from oslo_log import log as logging
LOG = logging.getLogger(__name__)
EntityWrapper = \
namedtuple('EntityWrapper', ['entity_vertex', 'neighbors'], 'action')
@six.add_metaclass(abc.ABCMeta)
class Transformer(object):
@abc.abstractmethod
@ -28,13 +35,14 @@ class Transformer(object):
:return: An EntityWrapper. EntityWrapper is namedTuple that contains
an entity vertex and a list of vertex and an edge pair that describe
the entity's neighbors.
:rtype: EntityWrapper
"""
pass
@abc.abstractmethod
def get_key_fields(self):
def key_fields(self):
pass
@abc.abstractmethod
def get_key(self, entity_event):
def extract_key(self, entity_event):
pass

View File

@ -0,0 +1,47 @@
# Copyright 2015 - 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.
from oslo_log import log as logging
from vitrage.common.constants import VertexConstants as vertex_cons
from vitrage.entity_graph.transformer import base
LOG = logging.getLogger(__name__)
KEY_SEPARATOR = ':'
ENTITY_TYPE = 'RESOURCE'
INSTANCE_SUB_TYPE = 'nova.instance'
HOST_SUB_TYPE = 'nova.host'
class InstanceTransformer(base.Transformer):
# # Fields returned from Nova Instance snapshot
ENTITY_ID_DICT = {'snapshot': 'id',
'init_snapshot': 'id',
'update': 'instance_id'}
def transform(self, entity_event):
pass
def key_fields(self):
return [vertex_cons.TYPE, vertex_cons.SUB_TYPE, vertex_cons.ID]
def extract_key(self, entity_event):
sync_mode = entity_event['sync_mode']
return KEY_SEPARATOR.join(
[ENTITY_TYPE,
INSTANCE_SUB_TYPE,
entity_event[self.ENTITY_ID_DICT[sync_mode]]])

View File

@ -0,0 +1,29 @@
# Copyright 2014 - Mirantis, Inc.
# Copyright 2014 - StackStorm, Inc.
#
# 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 as logging
LOG = logging.getLogger(__name__)
class TransformerManager(object):
def __init__(self):
self.transformers = self.register_transformer_classes()
@staticmethod
def register_transformer_classes():
pass

View File

@ -67,7 +67,7 @@ class Edge(object):
:param source_id: source vertex id
:type source_id: str
:param target_id: target vertex id
:param target_id: target vertex id`
:type target_id: str
:param label:

View File

@ -25,14 +25,14 @@ multiple instances of the same entity type.
from os.path import curdir
from os import walk
from random import randint
import random
from entity_model import CommonEntityModel as cem
def _get_filename_path(filename):
base_dir = None
for i in walk("../%s" % curdir):
for i in walk("../../%s" % curdir):
if i[0].find('resources') != -1 and filename in i[2]:
base_dir = i[0]
break
@ -46,8 +46,6 @@ class MockEventGenerator(object):
"""Represents a single generator.
A generator can generate events for several instances of the same type
file is expected to be in the ../resources folder
"""
def __init__(self, filename, instance_num, generator_name='generator'):
@ -75,7 +73,7 @@ class MockEventGenerator(object):
param_type = line_params[1].lower()
params_dict[param_type][line_params[0]] = line_params[2]
except KeyError as ke:
print("Syntax error: {0}".format(ke.message))
print("Syntax error ({0}): {1}".format(ke.errno, ke.strerror))
def prepare_instance_models(self):
"""Create the models for all the instances """
@ -97,7 +95,7 @@ class MockEventGenerator(object):
data_stream = []
for _ in xrange(event_num):
model = self.models[randint(0, self.instance_num - 1)]
model = self.models[random.randint(0, self.instance_num - 1)]
model.generate_dynamic_params()
data_stream.append(model.params)
return data_stream

View File

@ -20,7 +20,7 @@ of what can be returned
usage example:
test_entity_spec_list = [
{'filename': '../resources/mock_nova_instance_config_1.txt',
{'filename': '../resources/mock_nova_inst_snapshot.txt',
'#instances': 10,
'name': 'Instance (vm) generator'
}

View File

@ -1,4 +1,4 @@
event_type S snapshot
sync_mode D snapshot|init_snapshot
OS-DCF:diskConfig S AUTO
OS-EXT-AZ:availability_zone S nova
OS-EXT-SRV-ATTR:host D [a-z]{4}-devstack

View File

@ -1,4 +1,4 @@
event_type S update
sync_mode S update
u-OS-DCF:diskConfig S AUTO
u-OS-EXT-AZ:availability_zone S nova
u-OS-EXT-SRV-ATTR:host D [a-z]{4}-devstack
@ -22,7 +22,7 @@ u-config_drive D True|False
u-created D \d{2}:\d{2}:\d{2} \d{2}:\d{2}:\d{2}
u-flavor D m1.nano
u-hostId D [0-9a-f]{56}
u-id S [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}
instance_id S [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}
u-image D cirros-[a-z]+ ([a-z0-9]+)
u-key_name D -
u-metadata D \{\}

View File

@ -13,8 +13,16 @@
# under the License.
from oslotest import base
import sys
class BaseTest(base.BaseTestCase):
"""Test case base class for all unit tests."""
def assert_list_equal(self, l1, l2):
if tuple(sys.version_info)[0:2] < (2, 7):
# for python 2.6 compatibility
self.assertEqual(l1, l2)
else:
super(BaseTest, self).assertListEqual(l1, l2)

View File

@ -1,26 +0,0 @@
# Copyright 2015 - 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.
from oslo_log import log as logging
from vitrage.tests.unit import base
LOG = logging.getLogger(__name__)
class TransformNovaInstanceTest(base.BaseTest):
def test_transform_instance(self):
LOG.debug('Test transform Nova instance into entity wrapper')
self.assertTrue(True)

View File

@ -0,0 +1,83 @@
# Copyright 2015 - 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.
from oslo_log import log as logging
from vitrage.common.constants import VertexConstants as vertexCons
from vitrage.entity_graph.transformer import nova_transformer as nt
from vitrage.tests.mocks import mock_syncronizer as mock_sync
from vitrage.tests.unit import base
LOG = logging.getLogger(__name__)
def get_nova_instance_transformer():
return nt.InstanceTransformer()
def get_instance_entity_spec_list(config_file_path, number_of_instances):
"""Returns a list of nova instance specifications by
given specific configuration file.
:rtype : list
"""
return {
'filename': config_file_path,
'#instances': number_of_instances,
'name': 'Instance generator'
}
class NovaInstanceTransformerTest(base.BaseTest):
def test_key_fields(self):
LOG.debug('Test get key fields from nova instance transformer')
transformer = get_nova_instance_transformer()
expected_key_fields = [vertexCons.TYPE,
vertexCons.SUB_TYPE,
vertexCons.ID]
observed_key_fields = transformer.key_fields()
self.assert_list_equal(expected_key_fields, observed_key_fields)
def test_extract_key(self):
LOG.debug('Test get key from nova instance transformer')
transformer = get_nova_instance_transformer()
instance_specifications = [
get_instance_entity_spec_list('mock_nova_inst_snapshot.txt', 1),
get_instance_entity_spec_list('mock_nova_inst_update.txt', 1)
]
spec_list = mock_sync.get_mock_generators(instance_specifications)
instance_events = mock_sync.generate_random_events_list(spec_list)
for event in instance_events:
observed_key = transformer.extract_key(event)
observed_key_fields = observed_key.split(nt.KEY_SEPARATOR)
self.assertEqual(nt.ENTITY_TYPE, observed_key_fields[0])
self.assertEqual(nt.INSTANCE_SUB_TYPE, observed_key_fields[1])
event_id = event[transformer.ENTITY_ID_DICT[event['sync_mode']]]
self.assertEqual(event_id, observed_key_fields[2])
expected_key = nt.KEY_SEPARATOR.join(
[nt.ENTITY_TYPE,
nt.INSTANCE_SUB_TYPE,
event_id])
self.assertEqual(expected_key, observed_key)

View File

@ -0,0 +1 @@
__author__ = 'stack'