Bug fixes + aodh tempest
Change-Id: I0222995278fb8e4d2566cd56eba21e12c28273fa
This commit is contained in:
parent
3035e7fc39
commit
380352bc96
@ -27,8 +27,8 @@ OPTS = [
|
||||
help='Aodh driver class path',
|
||||
required=True),
|
||||
cfg.IntOpt('changes_interval',
|
||||
default=30,
|
||||
min=30,
|
||||
default=20,
|
||||
min=20,
|
||||
help='interval between checking changes in aodh data source',
|
||||
required=True),
|
||||
]
|
||||
|
@ -50,7 +50,14 @@ class CinderVolumeDriver(DriverBase):
|
||||
|
||||
@staticmethod
|
||||
def get_event_types(conf):
|
||||
return ['volume.']
|
||||
return ['volume.create.start',
|
||||
'volume.create.end',
|
||||
'volume.attach.start',
|
||||
'volume.attach.end',
|
||||
'volume.detach.start',
|
||||
'volume.detach.end',
|
||||
'volume.delete.start',
|
||||
'volume.delete.end']
|
||||
|
||||
@staticmethod
|
||||
def get_topic(conf):
|
||||
|
@ -46,8 +46,11 @@ class InstanceDriver(NovaDriverBase):
|
||||
@staticmethod
|
||||
def get_event_types(conf):
|
||||
# Add event_types to receive notifications about
|
||||
return ['compute.instance.create',
|
||||
'compute.instance.delete',
|
||||
return ['compute.instance.create.start',
|
||||
'compute.instance.create.error',
|
||||
'compute.instance.create.end',
|
||||
'compute.instance.delete.start',
|
||||
'compute.instance.delete.end',
|
||||
'compute.instance.finish_resize.end',
|
||||
'compute.instance.live_migration.post.dest.end',
|
||||
'compute.instance.live_migration._post.end',
|
||||
|
@ -29,8 +29,8 @@ OPTS = [
|
||||
help='Static physical driver class path',
|
||||
required=True),
|
||||
cfg.IntOpt('changes_interval',
|
||||
default=5,
|
||||
min=5,
|
||||
default=20,
|
||||
min=20,
|
||||
help='interval between checking changes in the configuration '
|
||||
'files of the physical topology data sources',
|
||||
required=True),
|
||||
|
@ -276,20 +276,23 @@ class Processor(processor.ProcessorBase):
|
||||
def _calculate_aggregated_state(self, vertex, action):
|
||||
LOG.debug("calculate event state")
|
||||
|
||||
if action in [EventAction.UPDATE_ENTITY,
|
||||
EventAction.DELETE_ENTITY,
|
||||
EventAction.CREATE_ENTITY]:
|
||||
graph_vertex = self.entity_graph.get_vertex(vertex.vertex_id)
|
||||
elif action in [EventAction.END_MESSAGE,
|
||||
EventAction.UPDATE_RELATIONSHIP,
|
||||
EventAction.DELETE_RELATIONSHIP]:
|
||||
return None
|
||||
else:
|
||||
LOG.error('unrecognized action: %s for vertex: %s',
|
||||
action, vertex)
|
||||
return None
|
||||
try:
|
||||
if action in [EventAction.UPDATE_ENTITY,
|
||||
EventAction.DELETE_ENTITY,
|
||||
EventAction.CREATE_ENTITY]:
|
||||
graph_vertex = self.entity_graph.get_vertex(vertex.vertex_id)
|
||||
elif action in [EventAction.END_MESSAGE,
|
||||
EventAction.UPDATE_RELATIONSHIP,
|
||||
EventAction.DELETE_RELATIONSHIP]:
|
||||
return None
|
||||
else:
|
||||
LOG.error('unrecognized action: %s for vertex: %s',
|
||||
action, vertex)
|
||||
return None
|
||||
|
||||
self.state_manager.aggregated_state(vertex, graph_vertex)
|
||||
self.state_manager.aggregated_state(vertex, graph_vertex)
|
||||
except Exception as e:
|
||||
LOG.exception("Calculate aggregated state failed - %s", e)
|
||||
|
||||
def _enrich_event(self, event):
|
||||
attr = self.transformer_manager.get_enrich_query(event)
|
||||
|
@ -41,8 +41,7 @@ class AlarmsHelper(BaseVitrageTest):
|
||||
|
||||
def get_all_alarms(self):
|
||||
"""Get Alarms returned by the cli """
|
||||
return utils.run_vitrage_command_with_user(
|
||||
'vitrage alarms list', self.conf.service_credentials.user)
|
||||
return utils.run_vitrage_command_as_admin('vitrage alarms list')
|
||||
|
||||
@staticmethod
|
||||
def filter_alarms(alarms_list, component):
|
||||
|
@ -11,30 +11,251 @@
|
||||
# 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 time
|
||||
|
||||
from oslo_log import log as logging
|
||||
from oslotest import base
|
||||
from vitrage_tempest_tests.tests.base_mock import BaseMock
|
||||
|
||||
from vitrage import clients
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.datasources import AODH_DATASOURCE
|
||||
from vitrage.datasources import CINDER_VOLUME_DATASOURCE
|
||||
from vitrage.datasources import NOVA_HOST_DATASOURCE
|
||||
from vitrage.datasources import NOVA_INSTANCE_DATASOURCE
|
||||
from vitrage.datasources import NOVA_ZONE_DATASOURCE
|
||||
from vitrage.datasources import OPENSTACK_CLUSTER
|
||||
from vitrage.datasources.static_physical import SWITCH
|
||||
from vitrage.graph import Edge
|
||||
from vitrage.graph import NXGraph
|
||||
from vitrage.graph import Vertex
|
||||
from vitrage import keystone_client
|
||||
from vitrage import service
|
||||
from vitrage_tempest_tests.tests import OPTS
|
||||
import vitrage_tempest_tests.tests.utils as utils
|
||||
from vitrageclient import client as v_client
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseVitrageTest(base.BaseTestCase):
|
||||
class BaseApiTest(base.BaseTestCase):
|
||||
"""Base test class for Vitrage API tests."""
|
||||
|
||||
NUM_VERTICES_PER_TYPE = 'num_vertices'
|
||||
NUM_EDGES_PER_TYPE = 'num_edges_per_type'
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(BaseVitrageTest, cls).setUpClass()
|
||||
cls.conf = utils.get_conf()
|
||||
super(BaseApiTest, cls).setUpClass()
|
||||
cls.conf = service.prepare_service([])
|
||||
cls.conf.register_opts(list(OPTS), group='keystone_authtoken')
|
||||
cls.vitrage_client = \
|
||||
v_client.Client('1', session=keystone_client.get_session(cls.conf))
|
||||
cls.nova_client = clients.nova_client(cls.conf)
|
||||
cls.cinder_client = clients.cinder_client(cls.conf)
|
||||
|
||||
def _create_graph_by_mock(self):
|
||||
"""Create MOCK Graph and copied to the string """
|
||||
self.mock_client = BaseMock()
|
||||
processor = self.mock_client.create_processor_with_graph()
|
||||
entity_graph = processor.entity_graph
|
||||
mock_graph_output = entity_graph.output_graph()
|
||||
LOG.info("The mock graph is : " + mock_graph_output)
|
||||
def _create_volume_and_attach(self, name, size, instance_id, mount_point):
|
||||
volume = self.cinder_client.volumes.create(display_name=name,
|
||||
size=size)
|
||||
time.sleep(3)
|
||||
self.cinder_client.volumes.attach(volume=volume,
|
||||
instance_uuid=instance_id,
|
||||
mountpoint=mount_point)
|
||||
|
||||
self._wait_for_status(20,
|
||||
self._check_num_volumes,
|
||||
num_volumes=1)
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
return volume
|
||||
|
||||
def _create_instances(self, num_instances):
|
||||
flavors_list = self.nova_client.flavors.list()
|
||||
images_list = self.nova_client.images.list()
|
||||
|
||||
resources = [self.nova_client.servers.create(
|
||||
name='%s-%s' % ('vm', index),
|
||||
flavor=flavors_list[0],
|
||||
image=images_list[0]) for index in range(num_instances)]
|
||||
|
||||
self._wait_for_status(20,
|
||||
self._check_num_instances,
|
||||
num_instances=num_instances)
|
||||
time.sleep(2)
|
||||
|
||||
return resources
|
||||
|
||||
def _delete_instances(self):
|
||||
instances = self.nova_client.servers.list()
|
||||
for instance in instances:
|
||||
try:
|
||||
self.nova_client.servers.delete(instance)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self._wait_for_status(20,
|
||||
self._check_num_instances,
|
||||
num_instances=0)
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
def _delete_volumes(self):
|
||||
volumes = self.cinder_client.volumes.list()
|
||||
for volume in volumes:
|
||||
try:
|
||||
self.cinder_client.volumes.detach(volume)
|
||||
self.cinder_client.volumes.force_delete(volume)
|
||||
except Exception:
|
||||
self.cinder_client.volumes.force_delete(volume)
|
||||
|
||||
self._wait_for_status(30,
|
||||
self._check_num_volumes,
|
||||
num_volumes=0)
|
||||
|
||||
time.sleep(2)
|
||||
|
||||
def _check_num_instances(self, num_instances=0):
|
||||
return len(self.nova_client.servers.list()) == num_instances
|
||||
|
||||
def _check_num_volumes(self, num_volumes=0):
|
||||
return len(self.cinder_client.volumes.list()) == num_volumes
|
||||
|
||||
@staticmethod
|
||||
def _create_graph_from_graph_dictionary(api_graph):
|
||||
graph = NXGraph()
|
||||
|
||||
nodes = api_graph['nodes']
|
||||
for i in xrange(len(nodes)):
|
||||
graph.add_vertex(Vertex(str(i), nodes[i]))
|
||||
|
||||
edges = api_graph['links']
|
||||
for i in xrange(len(edges)):
|
||||
graph.add_edge(Edge(str(edges[i]['source']),
|
||||
str(edges[i]['target']),
|
||||
edges[i]['relationship_type']))
|
||||
|
||||
return graph
|
||||
|
||||
def _create_graph_from_tree_dictionary(self,
|
||||
api_graph,
|
||||
graph=None,
|
||||
ancestor=None):
|
||||
children = []
|
||||
graph = NXGraph() if not graph else graph
|
||||
|
||||
if 'children' in api_graph:
|
||||
children = api_graph.copy()['children']
|
||||
del api_graph['children']
|
||||
|
||||
vertex = Vertex(api_graph[VProps.VITRAGE_ID], api_graph)
|
||||
graph.add_vertex(vertex)
|
||||
if ancestor:
|
||||
graph.add_edge(Edge(ancestor[VProps.VITRAGE_ID],
|
||||
vertex[VProps.VITRAGE_ID],
|
||||
'label'))
|
||||
|
||||
for entity in children:
|
||||
self._create_graph_from_tree_dictionary(entity, graph, vertex)
|
||||
|
||||
return graph
|
||||
|
||||
@staticmethod
|
||||
def _wait_for_status(max_waiting, func, **kwargs):
|
||||
count = 0
|
||||
while count < max_waiting:
|
||||
if func(**kwargs):
|
||||
return True
|
||||
count += 1
|
||||
time.sleep(2)
|
||||
LOG.info("wait_for_status - False ")
|
||||
return False
|
||||
|
||||
def _entities_validation_data(self, **kwargs):
|
||||
validation_data = []
|
||||
|
||||
# openstack.cluster
|
||||
props = {VProps.CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.TYPE: OPENSTACK_CLUSTER,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get('cluster_entities', 1),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get('cluster_edges', 1)}
|
||||
validation_data.append(props)
|
||||
|
||||
# nova.zone
|
||||
props = {VProps.CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.TYPE: NOVA_ZONE_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get('zone_entities', 1),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get('zone_edges', 2)}
|
||||
validation_data.append(props)
|
||||
|
||||
# nova.host
|
||||
props = {VProps.CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.TYPE: NOVA_HOST_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get('host_entities', 1),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get('host_edges', 1)}
|
||||
validation_data.append(props)
|
||||
|
||||
# nova.instance
|
||||
props = {VProps.CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.TYPE: NOVA_INSTANCE_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get('instance_entities',
|
||||
0),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get('instance_edges', 0)}
|
||||
validation_data.append(props)
|
||||
|
||||
# cinder.volume
|
||||
props = {VProps.CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.TYPE: CINDER_VOLUME_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get('volume_entities', 0),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get('volume_edges', 0)}
|
||||
validation_data.append(props)
|
||||
|
||||
# switch
|
||||
props = {VProps.CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.TYPE: SWITCH,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get('switch_entities', 0),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get('switch_edges', 0)}
|
||||
validation_data.append(props)
|
||||
|
||||
# aodh
|
||||
props = {VProps.CATEGORY: EntityCategory.ALARM,
|
||||
VProps.TYPE: AODH_DATASOURCE,
|
||||
self.NUM_VERTICES_PER_TYPE: kwargs.get('aodh_entities', 0),
|
||||
self.NUM_EDGES_PER_TYPE: kwargs.get('aodh_edges', 0)}
|
||||
validation_data.append(props)
|
||||
|
||||
return validation_data
|
||||
|
||||
def _validate_graph_correctness(self,
|
||||
graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities):
|
||||
self.assertIsNot(None, graph)
|
||||
self.assertIsNot(None, entities)
|
||||
self.assertEqual(num_entities, graph.num_vertices())
|
||||
self.assertEqual(num_edges, graph.num_edges())
|
||||
|
||||
for entity in entities:
|
||||
query = {
|
||||
VProps.CATEGORY: entity[VProps.CATEGORY],
|
||||
VProps.TYPE: entity[VProps.TYPE],
|
||||
VProps.IS_DELETED: False,
|
||||
VProps.IS_PLACEHOLDER: False
|
||||
}
|
||||
vertices = graph.get_vertices(vertex_attr_filter=query)
|
||||
self.assertEqual(entity[self.NUM_VERTICES_PER_TYPE],
|
||||
len(vertices),
|
||||
'%s%s' % ('Num vertices is incorrect for: %s',
|
||||
entity[VProps.TYPE]))
|
||||
|
||||
num_edges = sum([len(graph.get_edges(vertex.vertex_id))
|
||||
for vertex in vertices])
|
||||
self.assertEqual(entity[self.NUM_EDGES_PER_TYPE],
|
||||
num_edges,
|
||||
'%s%s' % ('Num edges is incorrect for: %s',
|
||||
entity[VProps.TYPE]))
|
||||
|
||||
@staticmethod
|
||||
def get_flavor_id_from_list():
|
||||
|
@ -12,29 +12,93 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import random
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage_tempest_tests.tests.api.topology.base import BaseTopologyTest
|
||||
from vitrage import clients
|
||||
from vitrage_tempest_tests.tests.api.base import BaseApiTest
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestAodhAlarm(BaseTopologyTest):
|
||||
class TestAodhAlarm(BaseApiTest):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestAodhAlarm, cls).setUpClass()
|
||||
cls.ceilometer_client = clients.ceilometer_client(cls.conf)
|
||||
|
||||
def test_alarm(self):
|
||||
def test_alarm_with_resource_id(self):
|
||||
try:
|
||||
# create entities
|
||||
self._create_switches()
|
||||
self._create_instances(num_instances=1)
|
||||
self._create_ceilometer_alarm(self._find_instance_resource_id())
|
||||
api_graph = self.vitrage_client.topology.get()
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1, host_edges=4,
|
||||
instance_entities=3, instance_edges=4,
|
||||
volume_entities=1, volume_edges=1)
|
||||
self._validate_graph_correctness(graph, 7, 6, entities)
|
||||
host_entities=1, host_edges=2,
|
||||
instance_entities=1, instance_edges=2,
|
||||
aodh_entities=1, aodh_edges=1)
|
||||
self._validate_graph_correctness(graph, 5, 4, entities)
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
self._delete_ceilometer_alarms()
|
||||
self._delete_instances()
|
||||
|
||||
def test_alarm_without_resource_id(self):
|
||||
try:
|
||||
# create entities
|
||||
self._create_ceilometer_alarm()
|
||||
api_graph = self.vitrage_client.topology.get()
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data(
|
||||
host_entities=1, host_edges=1,
|
||||
aodh_entities=1, aodh_edges=0)
|
||||
self._validate_graph_correctness(graph, 4, 2, entities)
|
||||
finally:
|
||||
self._delete_ceilometer_alarms()
|
||||
|
||||
def _create_ceilometer_alarm(self, resource_id=None):
|
||||
aodh_request = self._aodh_request(resource_id=resource_id)
|
||||
self.ceilometer_client.alarms.create(**aodh_request)
|
||||
self._wait_for_status(20,
|
||||
self._check_num_alarms,
|
||||
num_alarms=1)
|
||||
time.sleep(25)
|
||||
|
||||
def _delete_ceilometer_alarms(self):
|
||||
alarms = self.ceilometer_client.alarms.list()
|
||||
for alarm in alarms:
|
||||
self.ceilometer_client.alarms.delete(alarm.alarm_id)
|
||||
self._wait_for_status(20,
|
||||
self._check_num_alarms,
|
||||
num_alarms=0)
|
||||
time.sleep(25)
|
||||
|
||||
def _check_num_alarms(self, num_alarms=0):
|
||||
return len(self.ceilometer_client.alarms.list()) == num_alarms
|
||||
|
||||
def _aodh_request(self, resource_id=None):
|
||||
query = []
|
||||
if resource_id:
|
||||
query = [
|
||||
dict(
|
||||
field=u'resource_id',
|
||||
type='',
|
||||
op=u'eq',
|
||||
value=resource_id)
|
||||
]
|
||||
|
||||
random_name = '%s-%s' % ('test', random.randrange(0, 100000, 1))
|
||||
return dict(
|
||||
name=random_name,
|
||||
description=u'test alarm',
|
||||
event_rule=dict(query=query),
|
||||
severity='low',
|
||||
state='alarm', # ok/alarm/insufficient data
|
||||
type=u'event')
|
||||
|
||||
def _find_instance_resource_id(self):
|
||||
servers = self.nova_client.servers.list()
|
||||
return servers[0].id
|
||||
|
@ -13,7 +13,6 @@
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage_tempest_tests.tests.api.topology.base import BaseTopologyTest
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -13,7 +13,6 @@
|
||||
# under the License.
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage_tempest_tests.tests.api.topology.base import BaseTopologyTest
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -12,18 +12,18 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import os
|
||||
import socket
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage_tempest_tests.tests.api.topology.base import BaseTopologyTest
|
||||
from vitrage_tempest_tests.tests.api.base import BaseApiTest
|
||||
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class TestStaticPhysical(BaseTopologyTest):
|
||||
class TestStaticPhysical(BaseApiTest):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
@ -40,7 +40,7 @@ class TestStaticPhysical(BaseTopologyTest):
|
||||
switch_entities=2, switch_edges=2)
|
||||
self._validate_graph_correctness(graph, 5, 4, entities)
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
self._delete_switches()
|
||||
|
||||
@staticmethod
|
||||
def _create_switches():
|
||||
@ -59,4 +59,12 @@ class TestStaticPhysical(BaseTopologyTest):
|
||||
new_file.write(template_data)
|
||||
new_file.close()
|
||||
|
||||
time.sleep(7)
|
||||
time.sleep(25)
|
||||
|
||||
@staticmethod
|
||||
def _delete_switches():
|
||||
path = '/etc/vitrage/static_datasources/tempest_configuration.yaml'
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
time.sleep(25)
|
||||
|
@ -13,51 +13,25 @@
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import os
|
||||
import os.path
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
from tempest import test
|
||||
|
||||
from vitrage import clients
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.datasources import CINDER_VOLUME_DATASOURCE
|
||||
from vitrage.datasources import NOVA_HOST_DATASOURCE
|
||||
from vitrage.datasources import NOVA_INSTANCE_DATASOURCE
|
||||
from vitrage.datasources import NOVA_ZONE_DATASOURCE
|
||||
from vitrage.datasources import OPENSTACK_CLUSTER
|
||||
from vitrage.datasources.static_physical import SWITCH
|
||||
from vitrage.graph import Edge
|
||||
from vitrage.graph import NXGraph
|
||||
from vitrage.graph import Vertex
|
||||
from vitrage import keystone_client
|
||||
from vitrage import service
|
||||
from vitrage_tempest_tests.tests import OPTS
|
||||
from vitrageclient import client as v_client
|
||||
from vitrage_tempest_tests.tests.api.base import BaseApiTest
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BaseTopologyTest(test.BaseTestCase):
|
||||
class BaseTopologyTest(BaseApiTest):
|
||||
"""Topology test class for Vitrage API tests."""
|
||||
|
||||
NUM_ENTITIES_PER_TYPE = 'num_vertices'
|
||||
NUM_EDGES_PER_TYPE = 'num_edges_per_type'
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(BaseTopologyTest, cls).setUpClass()
|
||||
cls.conf = service.prepare_service([])
|
||||
cls.conf.register_opts(list(OPTS), group='keystone_authtoken')
|
||||
cls.vitrage_client = \
|
||||
v_client.Client('1', session=keystone_client.get_session(cls.conf))
|
||||
cls.nova_client = clients.nova_client(cls.conf)
|
||||
cls.cinder_client = clients.cinder_client(cls.conf)
|
||||
|
||||
def _rollback_to_default(self):
|
||||
self._delete_entities(instance=True, volume=True, static_physical=True)
|
||||
self._delete_entities()
|
||||
api_graph = self.vitrage_client.topology.get()
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data()
|
||||
@ -66,157 +40,23 @@ class BaseTopologyTest(test.BaseTestCase):
|
||||
def _create_entities(self, num_instances=0, num_volumes=0, end_sleep=3):
|
||||
if num_instances > 0:
|
||||
resources = self._create_instances(num_instances)
|
||||
self._wait_for_status(20,
|
||||
self._check_num_instances,
|
||||
num_instances=num_instances)
|
||||
time.sleep(1)
|
||||
|
||||
if num_volumes > 0:
|
||||
self._create_volume_and_attach('volume-1', 1,
|
||||
resources[0].__dict__['id'],
|
||||
'/tmp/vda')
|
||||
self._wait_for_status(20,
|
||||
self._check_num_volumes,
|
||||
num_volumes=1)
|
||||
|
||||
# waiting until all the entities creation were processed by the
|
||||
# entity graph processor
|
||||
time.sleep(end_sleep)
|
||||
|
||||
def _delete_entities(self,
|
||||
instance=False,
|
||||
volume=False,
|
||||
static_physical=False):
|
||||
if volume:
|
||||
self._delete_volumes()
|
||||
self._wait_for_status(30,
|
||||
self._check_num_volumes,
|
||||
num_volumes=0)
|
||||
|
||||
if instance:
|
||||
self._delete_instances()
|
||||
self._wait_for_status(20,
|
||||
self._check_num_instances,
|
||||
num_instances=0)
|
||||
|
||||
if static_physical:
|
||||
self._delete_switches()
|
||||
time.sleep(2)
|
||||
def _delete_entities(self):
|
||||
self._delete_volumes()
|
||||
self._delete_instances()
|
||||
|
||||
# waiting until all the entities deletion were processed by the
|
||||
# entity graph processor
|
||||
time.sleep(5)
|
||||
|
||||
def _delete_switches(self):
|
||||
path = '/etc/vitrage/static_datasources/tempest_configuration.yaml'
|
||||
if os.path.exists(path):
|
||||
os.remove(path)
|
||||
|
||||
def _entities_validation_data(self, cluster_entities=1, cluster_edges=1,
|
||||
zone_entities=1, zone_edges=2,
|
||||
host_entities=1, host_edges=1,
|
||||
instance_entities=0, instance_edges=0,
|
||||
volume_entities=0, volume_edges=0,
|
||||
switch_entities=0, switch_edges=0):
|
||||
return [
|
||||
{VProps.TYPE: OPENSTACK_CLUSTER,
|
||||
self.NUM_ENTITIES_PER_TYPE: cluster_entities,
|
||||
self.NUM_EDGES_PER_TYPE: cluster_edges},
|
||||
{VProps.TYPE: NOVA_ZONE_DATASOURCE,
|
||||
self.NUM_ENTITIES_PER_TYPE: zone_entities,
|
||||
self.NUM_EDGES_PER_TYPE: zone_edges},
|
||||
{VProps.TYPE: NOVA_HOST_DATASOURCE,
|
||||
self.NUM_ENTITIES_PER_TYPE: host_entities,
|
||||
self.NUM_EDGES_PER_TYPE: host_edges},
|
||||
{VProps.TYPE: NOVA_INSTANCE_DATASOURCE,
|
||||
self.NUM_ENTITIES_PER_TYPE: instance_entities,
|
||||
self.NUM_EDGES_PER_TYPE: instance_edges},
|
||||
{VProps.TYPE: CINDER_VOLUME_DATASOURCE,
|
||||
self.NUM_ENTITIES_PER_TYPE: volume_entities,
|
||||
self.NUM_EDGES_PER_TYPE: volume_edges},
|
||||
{VProps.TYPE: SWITCH,
|
||||
self.NUM_ENTITIES_PER_TYPE: switch_entities,
|
||||
self.NUM_EDGES_PER_TYPE: switch_edges}
|
||||
]
|
||||
|
||||
def _validate_graph_correctness(self,
|
||||
graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities):
|
||||
self.assertIsNot(None, graph)
|
||||
self.assertIsNot(None, entities)
|
||||
self.assertEqual(num_entities, graph.num_vertices())
|
||||
self.assertEqual(num_edges, graph.num_edges())
|
||||
|
||||
for entity in entities:
|
||||
query = {
|
||||
VProps.CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.TYPE: entity[VProps.TYPE],
|
||||
VProps.IS_DELETED: False,
|
||||
VProps.IS_PLACEHOLDER: False
|
||||
}
|
||||
vertices = graph.get_vertices(vertex_attr_filter=query)
|
||||
self.assertEqual(entity[self.NUM_ENTITIES_PER_TYPE], len(vertices))
|
||||
|
||||
num_edges = sum([len(graph.get_edges(vertex.vertex_id))
|
||||
for vertex in vertices])
|
||||
self.assertEqual(entity[self.NUM_EDGES_PER_TYPE], num_edges)
|
||||
|
||||
def _check_num_instances(self, num_instances=0):
|
||||
return len(self.nova_client.servers.list()) == num_instances
|
||||
|
||||
def _check_num_volumes(self, num_volumes=0):
|
||||
return len(self.cinder_client.volumes.list()) == num_volumes
|
||||
|
||||
def _create_volume_and_attach(self, name, size, instance_id, mount_point):
|
||||
volume = self.cinder_client.volumes.create(display_name=name,
|
||||
size=size)
|
||||
time.sleep(3)
|
||||
self.cinder_client.volumes.attach(volume=volume,
|
||||
instance_uuid=instance_id,
|
||||
mountpoint=mount_point)
|
||||
return volume
|
||||
|
||||
def _create_instances(self, num_machines):
|
||||
flavors_list = self.nova_client.flavors.list()
|
||||
images_list = self.nova_client.images.list()
|
||||
|
||||
resources = [self.nova_client.servers.create(
|
||||
name='%s-%s' % ('vm', index),
|
||||
flavor=flavors_list[0],
|
||||
image=images_list[0]) for index in range(num_machines)]
|
||||
|
||||
return resources
|
||||
|
||||
def _delete_instances(self):
|
||||
instances = self.nova_client.servers.list()
|
||||
for instance in instances:
|
||||
try:
|
||||
self.nova_client.servers.delete(instance)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _delete_volumes(self):
|
||||
volumes = self.cinder_client.volumes.list()
|
||||
for volume in volumes:
|
||||
try:
|
||||
self.cinder_client.volumes.detach(volume)
|
||||
self.cinder_client.volumes.force_delete(volume)
|
||||
except Exception:
|
||||
self.cinder_client.volumes.force_delete(volume)
|
||||
|
||||
@staticmethod
|
||||
def _wait_for_status(max_waiting, func, **kwargs):
|
||||
count = 0
|
||||
while count < max_waiting:
|
||||
if func(**kwargs):
|
||||
return True
|
||||
count += 1
|
||||
time.sleep(2)
|
||||
LOG.info("wait_for_status - False ")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _compare_graphs(api_graph, cli_graph):
|
||||
"""Compare Graph object to graph form terminal """
|
||||
@ -240,45 +80,6 @@ class BaseTopologyTest(test.BaseTestCase):
|
||||
|
||||
return sorted_cli_graph == sorted_api_graph
|
||||
|
||||
@staticmethod
|
||||
def _create_graph_from_graph_dictionary(api_graph):
|
||||
graph = NXGraph()
|
||||
|
||||
nodes = api_graph['nodes']
|
||||
for i in xrange(len(nodes)):
|
||||
graph.add_vertex(Vertex(str(i), nodes[i]))
|
||||
|
||||
edges = api_graph['links']
|
||||
for i in xrange(len(edges)):
|
||||
graph.add_edge(Edge(str(edges[i]['source']),
|
||||
str(edges[i]['target']),
|
||||
edges[i]['relationship_type']))
|
||||
|
||||
return graph
|
||||
|
||||
def _create_graph_from_tree_dictionary(self,
|
||||
api_graph,
|
||||
graph=None,
|
||||
ancestor=None):
|
||||
children = []
|
||||
graph = NXGraph() if not graph else graph
|
||||
|
||||
if 'children' in api_graph:
|
||||
children = api_graph.copy()['children']
|
||||
del api_graph['children']
|
||||
|
||||
vertex = Vertex(api_graph[VProps.VITRAGE_ID], api_graph)
|
||||
graph.add_vertex(vertex)
|
||||
if ancestor:
|
||||
graph.add_edge(Edge(ancestor[VProps.VITRAGE_ID],
|
||||
vertex[VProps.VITRAGE_ID],
|
||||
'label'))
|
||||
|
||||
for entity in children:
|
||||
self._create_graph_from_tree_dictionary(entity, graph, vertex)
|
||||
|
||||
return graph
|
||||
|
||||
@staticmethod
|
||||
def _graph_query():
|
||||
return '{"and": [{"==": {"category": "RESOURCE"}},' \
|
||||
|
@ -12,21 +12,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import time
|
||||
|
||||
from oslo_log import log as logging
|
||||
|
||||
from vitrage.common.constants import EntityCategory
|
||||
from vitrage.common.constants import VertexProperties as VProps
|
||||
from vitrage.datasources import CINDER_VOLUME_DATASOURCE
|
||||
from vitrage.datasources import NOVA_HOST_DATASOURCE
|
||||
from vitrage.datasources import NOVA_INSTANCE_DATASOURCE
|
||||
from vitrage.datasources import NOVA_ZONE_DATASOURCE
|
||||
from vitrage.datasources import OPENSTACK_CLUSTER
|
||||
from vitrage.graph import Edge
|
||||
from vitrage.graph import NXGraph
|
||||
from vitrage.graph import Vertex
|
||||
from vitrage_tempest_tests.tests.api.topology.base import BaseTopologyTest
|
||||
import vitrage_tempest_tests.tests.utils as utils
|
||||
|
||||
@ -36,9 +23,6 @@ LOG = logging.getLogger(__name__)
|
||||
class TestTopology(BaseTopologyTest):
|
||||
"""Topology test class for Vitrage API tests."""
|
||||
|
||||
NUM_ENTITIES_PER_TYPE = 'num_vertices'
|
||||
NUM_EDGES_PER_TYPE = 'num_edges_per_type'
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestTopology, cls).setUpClass()
|
||||
@ -103,229 +87,3 @@ class TestTopology(BaseTopologyTest):
|
||||
self._validate_graph_correctness(graph, 3, 2, entities)
|
||||
finally:
|
||||
self._rollback_to_default()
|
||||
|
||||
def _rollback_to_default(self):
|
||||
self._delete_entities(instance=True, volume=True)
|
||||
api_graph = self.vitrage_client.topology.get()
|
||||
graph = self._create_graph_from_graph_dictionary(api_graph)
|
||||
entities = self._entities_validation_data()
|
||||
self._validate_graph_correctness(graph, 3, 2, entities)
|
||||
|
||||
def _create_entities(self, num_instances=0, num_volumes=0, end_sleep=3):
|
||||
if num_instances > 0:
|
||||
resources = self._create_instances(num_instances)
|
||||
self._wait_for_status(20,
|
||||
self._check_num_instances,
|
||||
num_instances=num_instances)
|
||||
time.sleep(1)
|
||||
|
||||
if num_volumes > 0:
|
||||
self._create_volume_and_attach('volume-1', 1,
|
||||
resources[0].__dict__['id'],
|
||||
'/tmp/vda')
|
||||
self._wait_for_status(20,
|
||||
self._check_num_volumes,
|
||||
num_volumes=1)
|
||||
|
||||
# waiting until all the entities creation were processed by the
|
||||
# entity graph processor
|
||||
time.sleep(end_sleep)
|
||||
|
||||
def _delete_entities(self, instance=False, volume=False):
|
||||
if volume:
|
||||
self._delete_volumes()
|
||||
self._wait_for_status(30,
|
||||
self._check_num_volumes,
|
||||
num_volumes=0)
|
||||
|
||||
if instance:
|
||||
self._delete_instances()
|
||||
self._wait_for_status(20,
|
||||
self._check_num_instances,
|
||||
num_instances=0)
|
||||
|
||||
# waiting until all the entities deletion were processed by the
|
||||
# entity graph processor
|
||||
time.sleep(5)
|
||||
|
||||
def _entities_validation_data(self, cluster_entities=1, cluster_edges=1,
|
||||
zone_entities=1, zone_edges=2,
|
||||
host_entities=1, host_edges=1,
|
||||
instance_entities=0, instance_edges=0,
|
||||
volume_entities=0, volume_edges=0):
|
||||
return [
|
||||
{VProps.TYPE: OPENSTACK_CLUSTER,
|
||||
self.NUM_ENTITIES_PER_TYPE: cluster_entities,
|
||||
self.NUM_EDGES_PER_TYPE: cluster_edges},
|
||||
{VProps.TYPE: NOVA_ZONE_DATASOURCE,
|
||||
self.NUM_ENTITIES_PER_TYPE: zone_entities,
|
||||
self.NUM_EDGES_PER_TYPE: zone_edges},
|
||||
{VProps.TYPE: NOVA_HOST_DATASOURCE,
|
||||
self.NUM_ENTITIES_PER_TYPE: host_entities,
|
||||
self.NUM_EDGES_PER_TYPE: host_edges},
|
||||
{VProps.TYPE: NOVA_INSTANCE_DATASOURCE,
|
||||
self.NUM_ENTITIES_PER_TYPE: instance_entities,
|
||||
self.NUM_EDGES_PER_TYPE: instance_edges},
|
||||
{VProps.TYPE: CINDER_VOLUME_DATASOURCE,
|
||||
self.NUM_ENTITIES_PER_TYPE: volume_entities,
|
||||
self.NUM_EDGES_PER_TYPE: volume_edges}
|
||||
]
|
||||
|
||||
def _validate_graph_correctness(self,
|
||||
graph,
|
||||
num_entities,
|
||||
num_edges,
|
||||
entities):
|
||||
self.assertIsNot(None, graph)
|
||||
self.assertIsNot(None, entities)
|
||||
self.assertEqual(num_entities, graph.num_vertices())
|
||||
self.assertEqual(num_edges, graph.num_edges())
|
||||
|
||||
for entity in entities:
|
||||
query = {
|
||||
VProps.CATEGORY: EntityCategory.RESOURCE,
|
||||
VProps.TYPE: entity[VProps.TYPE],
|
||||
VProps.IS_DELETED: False,
|
||||
VProps.IS_PLACEHOLDER: False
|
||||
}
|
||||
vertices = graph.get_vertices(vertex_attr_filter=query)
|
||||
self.assertEqual(entity[self.NUM_ENTITIES_PER_TYPE], len(vertices))
|
||||
|
||||
num_edges = sum([len(graph.get_edges(vertex.vertex_id))
|
||||
for vertex in vertices])
|
||||
self.assertEqual(entity[self.NUM_EDGES_PER_TYPE], num_edges)
|
||||
|
||||
def _check_num_instances(self, num_instances=0):
|
||||
return len(self.nova_client.servers.list()) == num_instances
|
||||
|
||||
def _check_num_volumes(self, num_volumes=0):
|
||||
return len(self.cinder_client.volumes.list()) == num_volumes
|
||||
|
||||
def _create_volume_and_attach(self, name, size, instance_id, mount_point):
|
||||
volume = self.cinder_client.volumes.create(display_name=name,
|
||||
size=size)
|
||||
time.sleep(3)
|
||||
self.cinder_client.volumes.attach(volume=volume,
|
||||
instance_uuid=instance_id,
|
||||
mountpoint=mount_point)
|
||||
return volume
|
||||
|
||||
def _create_instances(self, num_machines):
|
||||
flavors_list = self.nova_client.flavors.list()
|
||||
images_list = self.nova_client.images.list()
|
||||
|
||||
resources = [self.nova_client.servers.create(
|
||||
name='%s-%s' % ('vm', index),
|
||||
flavor=flavors_list[0],
|
||||
image=images_list[0]) for index in range(num_machines)]
|
||||
|
||||
return resources
|
||||
|
||||
def _delete_instances(self):
|
||||
instances = self.nova_client.servers.list()
|
||||
for instance in instances:
|
||||
try:
|
||||
self.nova_client.servers.delete(instance)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _delete_volumes(self):
|
||||
volumes = self.cinder_client.volumes.list()
|
||||
for volume in volumes:
|
||||
try:
|
||||
self.cinder_client.volumes.detach(volume)
|
||||
self.cinder_client.volumes.force_delete(volume)
|
||||
except Exception:
|
||||
self.cinder_client.volumes.force_delete(volume)
|
||||
|
||||
@staticmethod
|
||||
def _wait_for_status(max_waiting, func, **kwargs):
|
||||
count = 0
|
||||
while count < max_waiting:
|
||||
if func(**kwargs):
|
||||
return True
|
||||
count += 1
|
||||
time.sleep(2)
|
||||
LOG.info("wait_for_status - False ")
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _compare_graphs(api_graph, cli_graph):
|
||||
"""Compare Graph object to graph form terminal """
|
||||
if not api_graph:
|
||||
LOG.error("The topology graph taken from rest api is empty")
|
||||
return False
|
||||
if not cli_graph:
|
||||
LOG.error("The topology graph taken from terminal is empty")
|
||||
return False
|
||||
|
||||
parsed_topology = json.loads(cli_graph)
|
||||
|
||||
sorted_cli_graph = sorted(parsed_topology.items())
|
||||
sorted_api_graph = sorted(api_graph.items())
|
||||
|
||||
for item in sorted_cli_graph[4][1]:
|
||||
item.pop(VProps.UPDATE_TIMESTAMP, None)
|
||||
|
||||
for item in sorted_api_graph[4][1]:
|
||||
item.pop(VProps.UPDATE_TIMESTAMP, None)
|
||||
|
||||
return sorted_cli_graph == sorted_api_graph
|
||||
|
||||
@staticmethod
|
||||
def _create_graph_from_graph_dictionary(api_graph):
|
||||
graph = NXGraph()
|
||||
|
||||
nodes = api_graph['nodes']
|
||||
for i in xrange(len(nodes)):
|
||||
graph.add_vertex(Vertex(str(i), nodes[i]))
|
||||
|
||||
edges = api_graph['links']
|
||||
for i in xrange(len(edges)):
|
||||
graph.add_edge(Edge(str(edges[i]['source']),
|
||||
str(edges[i]['target']),
|
||||
edges[i]['relationship_type']))
|
||||
|
||||
return graph
|
||||
|
||||
def _create_graph_from_tree_dictionary(self,
|
||||
api_graph,
|
||||
graph=None,
|
||||
ancestor=None):
|
||||
children = []
|
||||
graph = NXGraph() if not graph else graph
|
||||
|
||||
if 'children' in api_graph:
|
||||
children = api_graph.copy()['children']
|
||||
del api_graph['children']
|
||||
|
||||
vertex = Vertex(api_graph[VProps.VITRAGE_ID], api_graph)
|
||||
graph.add_vertex(vertex)
|
||||
if ancestor:
|
||||
graph.add_edge(Edge(ancestor[VProps.VITRAGE_ID],
|
||||
vertex[VProps.VITRAGE_ID],
|
||||
'label'))
|
||||
|
||||
for entity in children:
|
||||
self._create_graph_from_tree_dictionary(entity, graph, vertex)
|
||||
|
||||
return graph
|
||||
|
||||
@staticmethod
|
||||
def _graph_query():
|
||||
return '{"and": [{"==": {"category": "RESOURCE"}},' \
|
||||
'{"==": {"is_deleted": false}},' \
|
||||
'{"==": {"is_placeholder": false}},' \
|
||||
'{"or": [{"==": {"type": "openstack.cluster"}},' \
|
||||
'{"==": {"type": "nova.instance"}},' \
|
||||
'{"==": {"type": "nova.host"}},' \
|
||||
'{"==": {"type": "nova.zone"}}]}]}'
|
||||
|
||||
@staticmethod
|
||||
def _tree_query():
|
||||
return '{"and": [{"==": {"category": "RESOURCE"}},' \
|
||||
'{"==": {"is_deleted": false}},' \
|
||||
'{"==": {"is_placeholder": false}},' \
|
||||
'{"or": [{"==": {"type": "openstack.cluster"}},' \
|
||||
'{"==": {"type": "nova.host"}},' \
|
||||
'{"==": {"type": "nova.zone"}}]}]}'
|
||||
|
@ -79,11 +79,8 @@ def run_vitrage_command(command):
|
||||
return None
|
||||
|
||||
|
||||
def run_vitrage_command_with_user(command, user):
|
||||
run_vitrage_command(
|
||||
"cd /openstack/devstack; . openrc " +
|
||||
user + " " + user +
|
||||
"; " + command)
|
||||
def run_vitrage_command_as_admin(command):
|
||||
run_vitrage_command(command)
|
||||
|
||||
|
||||
def run_from_terminal(command):
|
||||
|
Loading…
x
Reference in New Issue
Block a user