From 429f2ef71095dd01b34222806486af8e3cedc597 Mon Sep 17 00:00:00 2001 From: Denis Deryabin Date: Mon, 13 Feb 2017 14:19:08 +0300 Subject: [PATCH] add test_diff_proj_same_vn_vm_add_delete Change-Id: Ide6dbcec61ee591e56709c068e47e7bfb29b4d36 --- plugin_test/vapor/requirements.txt | 2 + plugin_test/vapor/vapor/fixtures/contrail.py | 27 ++- .../fixtures/different_tenants_resources.py | 27 +-- .../vapor/vapor/helpers/clients/__init__.py | 2 + .../vapor/helpers/clients/contrail_agent.py | 170 ++++++++++++++++++ .../vapor/helpers/clients/contrail_api.py | 1 + plugin_test/vapor/vapor/settings.py | 19 +- .../vapor/vapor/tests/common/test_base.py | 35 ++++ 8 files changed, 266 insertions(+), 17 deletions(-) create mode 100644 plugin_test/vapor/vapor/helpers/clients/contrail_agent.py diff --git a/plugin_test/vapor/requirements.txt b/plugin_test/vapor/requirements.txt index efa195cc3..830f2b3c9 100644 --- a/plugin_test/vapor/requirements.txt +++ b/plugin_test/vapor/requirements.txt @@ -5,3 +5,5 @@ dpath jmespath==0.9.0 contextlib2==0.5.4; python_version < '3.2' kazoo==2.2.1 +logbook +xmltodict diff --git a/plugin_test/vapor/vapor/fixtures/contrail.py b/plugin_test/vapor/vapor/fixtures/contrail.py index 1aa429aba..df36759bd 100644 --- a/plugin_test/vapor/vapor/fixtures/contrail.py +++ b/plugin_test/vapor/vapor/fixtures/contrail.py @@ -1,15 +1,18 @@ import os +import six import uuid +import pytest +import logbook import pycontrail.client as client -import pytest -import six from six.moves import configparser from six.moves.urllib import parse from vapor import settings from vapor.helpers import clients +LOGGER = logbook.Logger(__name__) + @pytest.fixture def client_contrail(session, contrail_api_endpoint): @@ -23,6 +26,15 @@ def client_contrail_analytics(session, contrail_analytics_endpoint): contrail_analytics_endpoint) +@pytest.fixture +def client_contrail_vrouter_agent(contrail_vrouter_agent_endpoint): + LOGGER.debug('VRouter endpoint: {0}'.format( + contrail_vrouter_agent_endpoint)) + return clients.ContrailVRouterAgentClient( + agent_ip=contrail_vrouter_agent_endpoint['ip'], + agent_port=contrail_vrouter_agent_endpoint['port']) + + def get_nodes_fixture(cmd, scope='function'): """Fixtures to gen nodes by cmd factory.""" @@ -77,7 +89,16 @@ def contrail_analytics_endpoint(contrail_api_endpoint): """Return contrail analytics endpoint.""" parse_result = parse.urlparse(contrail_api_endpoint) return parse_result._replace(netloc="{}:{}".format( - parse_result.hostname, settings.CONTAIL_ANALYTICS_PORT)).geturl() + parse_result.hostname, settings.CONTRAIL_ANALYTICS_PORT)).geturl() + + +@pytest.fixture(scope='module') +def contrail_vrouter_agent_endpoint(contrail_services_http_introspect_ports): + """Return contrail agent endpoint.""" + service_name = 'contrail-vrouter-agent' + ip = contrail_services_http_introspect_ports[service_name]['ips'][0] + port = contrail_services_http_introspect_ports[service_name]['port'] + return {'ip': ip, 'port': port} @pytest.fixture(scope='module') diff --git a/plugin_test/vapor/vapor/fixtures/different_tenants_resources.py b/plugin_test/vapor/vapor/fixtures/different_tenants_resources.py index 98ece128e..a45eeddee 100644 --- a/plugin_test/vapor/vapor/fixtures/different_tenants_resources.py +++ b/plugin_test/vapor/vapor/fixtures/different_tenants_resources.py @@ -135,7 +135,7 @@ def project_2(create_user_with_project): @pytest.fixture -def different_tenants_resources( +def different_tenants_resources(request, project_2, credentials, create_user_with_project, cirros_image, sorted_hypervisors, get_network_steps, get_subnet_steps, get_server_steps, port_steps, get_floating_ip_steps, public_flavor, @@ -149,15 +149,23 @@ def different_tenants_resources( Returns: list: list of AttrDict with created resources """ + default_params = { + 'subnet_cidr': '10.0.0.0/24', + 'base_name': next(utils.generate_ids()), + 'ips': ('10.0.0.11', '10.0.0.21',) + } + default_params.update(getattr(request, 'param', {})) + + subnet_cidr = default_params['subnet_cidr'] + base_name = default_params['base_name'] + ips = default_params['ips'] + hypervisor = sorted_hypervisors[0] host = next( host for host in nova_availability_zone_hosts if hypervisor.hypervisor_hostname.startswith(host)) - subnet_cidr = '10.0.0.0/24' - base_name = next(utils.generate_ids()) - with contextlib.ExitStack() as stack: mrg = ResourceManager(stack, base_name, get_network_steps, @@ -167,16 +175,15 @@ def different_tenants_resources( projects_resources = [] - project_resources = mrg.create(subnet_cidr, '10.0.0.10', cirros_image, + project_resources = mrg.create(subnet_cidr, ips[0], cirros_image, public_flavor, host) projects_resources.append(project_resources) with credentials.change(project_2): - project_resources = mrg.create(subnet_cidr, '10.0.0.20', - cirros_image, public_flavor, host) - + project_resources = mrg.create(subnet_cidr, ips[1], + cirros_image, public_flavor, + host) projects_resources.append(project_resources) - - yield projects_resources + yield projects_resources diff --git a/plugin_test/vapor/vapor/helpers/clients/__init__.py b/plugin_test/vapor/vapor/helpers/clients/__init__.py index 07bdec0f2..97e4ab30e 100644 --- a/plugin_test/vapor/vapor/helpers/clients/__init__.py +++ b/plugin_test/vapor/vapor/helpers/clients/__init__.py @@ -1,7 +1,9 @@ from .contrail_api import ContrailClient from .analytics import ContrailAnalyticsClient +from .contrail_agent import ContrailVRouterAgentClient __all__ = [ 'ContrailClient', 'ContrailAnalyticsClient', + 'ContrailVRouterAgentClient', ] diff --git a/plugin_test/vapor/vapor/helpers/clients/contrail_agent.py b/plugin_test/vapor/vapor/helpers/clients/contrail_agent.py new file mode 100644 index 000000000..40795b534 --- /dev/null +++ b/plugin_test/vapor/vapor/helpers/clients/contrail_agent.py @@ -0,0 +1,170 @@ +import six +import copy +import xmltodict +from collections import OrderedDict + +from vapor.settings import logger + +if six.PY2: + from urllib2 import Request, urlopen +else: + from urllib.request import Request, urlopen + + +__all__ = ['ContrailVRouterAgentClient'] + + +class ClientContrailVRouterAgentBase(object): + def __init__(self, agent_ip, agent_port): + self.ip = agent_ip + self.port = agent_port + + def get_snh_dict_data(self, data): + key = data.keys() + if key[0].find(r'__') == 0: + data = data[key[0]] + data = self.del_unused_key(data) + return_dict = {} + key = data.keys() + for i in key: + return_dict[i] = self.get_data(data[i]) + return return_dict + + def get_resource(self, path): + url = 'http://%s:%s/%s' % (self.ip, self.port, path) + req = Request(url) + try: + response = urlopen(req) + xmldata = response.read() + except Exception as e: + logger.error('get_xml exception: {} url: {}'.format(e, url)) + raise + xml_dict = xmltodict.parse(xmldata) + return xml_dict + + @staticmethod + def del_unused_key(data): + key_list = ['@type', '@identifier', '@size', 'more', + 'Pagination', 'OvsdbPageResp', 'next_batch'] + return OrderedDict({k: v for (k, v) in data.items() + if k not in key_list}) + + def get_data(self, data): + if isinstance(data, list): + data_list = [] + for i in data: + data_dict = self.get_data(i) + data_list.append(data_dict) + return_data = data_list + else: + if '@type' in data: + if data['@type'] == 'sandesh': + sandesh_dict = {} + data = self.del_unused_key(data) + key = data.keys() + for i in key: + sandesh_dict[i] = self.get_data(data[i]) + return_data = sandesh_dict + elif data['@type'] == 'list': + data = self.del_unused_key(data) + key = data.keys() + data = data[key[0]] + return_data = self.get_data(data) + elif data['@type'] == 'struct': + return_list = [] + data = self.del_unused_key(data) + if len(data) == 0: + return '' + keys = data.keys() + for i in keys: + sdata = self.get_data(data[i]) + return_data = sdata + elif data['@type'] in ['i64', 'i32', 'i16', 'u64', 'u32', + 'u16', 'double', 'string', 'bool']: + if '#text' in data: + return_data = data['#text'] + else: + return_data = '' + elif 'element' in data: + return_data = data['#text'] + else: + data_dict = {} + data = self.del_unused_key(data) + for i in data: + data_dict[i] = self.get_data(data[i]) + return_data = data_dict + return return_data + + def find_ifmap_list(self, data): + except_keys = ['@type', '@identifier', '@size', + 'table_size', 'next_batch', 'more'] + for k in data: + if not isinstance(data[k], list): + if k not in except_keys: + return self.find_ifmap_list(data[k]) + else: + temp_list = data[k] + return copy.copy(temp_list) + + def merge_ifmap_list(self, data, next_list): + except_keys = ['@type', '@identifier', '@size', 'table_size', + 'next_batch', 'more'] + for k in data: + if not isinstance(data[k], list): + if k not in except_keys: + return self.merge_ifmap_list(data[k], next_list) + else: + data[k] += next_list + return data + + def get_snhdict(self, path): + data = self.get_resource(path) + all_path = '' + try: + top_key = data.keys() + url = data[top_key[0]]['Pagination']['req']['PageReqData']['all']['#text'] # noqa + all_path = 'Snh_PageReq?x=%s' % url + except KeyError: + pass + try: + top_key = data.keys() + url = data[top_key[0]]['OvsdbPageResp']['req']['OvsdbPageRespData']['all']['#text'] # noqa + all_path = 'Snh_OvsdbPageReq?x=%s' % url + except KeyError: + pass + if all_path != '': + data = self.get_resource(all_path) + keys = data.keys() + if 'next_batch' in data[keys[0]]: + while True: + if 'next_batch' in data[keys[0]]: + old_data = data.copy() + path1 = data[keys[0]]['next_batch']['@link'] + path2 = data[keys[0]]['next_batch']['#text'] + path = 'Snh_%s?x=%s' % (path1,path2) + data = self.get_resource(path) + old_list = self.find_ifmap_list(old_data) + self.merge_ifmap_list(data, old_list) + else: + break + return data + + def get_path_to_dict(self, path): + # Return path directory info by dict + rsp = self.get_snhdict(path) + snh_data = self.get_snh_dict_data(rsp) + return snh_data + + +class ContrailVRouterAgentClient(ClientContrailVRouterAgentBase): + + def get_itfs(self): + data = self.get_path_to_dict('Snh_ItfReq') + return data + + def get_itf_by_name(self, interface_name): + data = self.get_path_to_dict('Snh_ItfReq?x={}'.format(interface_name)) + return data + + + diff --git a/plugin_test/vapor/vapor/helpers/clients/contrail_api.py b/plugin_test/vapor/vapor/helpers/clients/contrail_api.py index fd872aa59..3b3e3c849 100644 --- a/plugin_test/vapor/vapor/helpers/clients/contrail_api.py +++ b/plugin_test/vapor/vapor/helpers/clients/contrail_api.py @@ -1,4 +1,5 @@ from . import base +import urllib class ContrailClient(base.ContrailBaseClient): diff --git a/plugin_test/vapor/vapor/settings.py b/plugin_test/vapor/vapor/settings.py index 19b5c4a54..8e2a2b9d5 100644 --- a/plugin_test/vapor/vapor/settings.py +++ b/plugin_test/vapor/vapor/settings.py @@ -1,8 +1,18 @@ # Project, contrail and OpenStack settings import os - +import sys import yaml +import logbook + +LOG_FILENAME = './vapor.log' +logger = logbook.Logger(__name__) +logger.handlers.append(logbook.FileHandler(LOG_FILENAME, + level='DEBUG', + bubble=True)) +logger.handlers.append(logbook.StreamHandler(sys.stderr, + level='DEBUG', + bubble=True)) BASE_DIR = os.path.dirname(__file__) @@ -17,10 +27,11 @@ KEYSTONE_CREDS = { CONTRAIL_CREDS = {'controller_addr': '192.168.1.127'} -CONTAIL_API_PORT = 8082 -CONTAIL_ANALYTICS_PORT = 8081 +CONTRAIL_ANALYTICS_PORT = 8081 + +NEUTRON_CONTRAIL_PLUGIN_CONFIG_PATH = ( + '/etc/neutron/plugins/opencontrail/ContrailPlugin.ini') -NEUTRON_CONTRAIL_PLUGIN_CONFIG_PATH = '/etc/neutron/plugins/opencontrail/ContrailPlugin.ini' # noqa CONTRAIL_CONFIG_PATH = '/etc/contrail/' # Time between poweroff and start contrail controller node diff --git a/plugin_test/vapor/vapor/tests/common/test_base.py b/plugin_test/vapor/vapor/tests/common/test_base.py index 13a4ddf15..5a924319a 100644 --- a/plugin_test/vapor/vapor/tests/common/test_base.py +++ b/plugin_test/vapor/vapor/tests/common/test_base.py @@ -27,6 +27,7 @@ from vapor.helpers import asserts from vapor.helpers import contrail_status, policy, connectivity from vapor import settings from vapor.helpers import contrail_status, nodes_steps +from vapor.settings import logger def test_network_deleting_with_server(network, server, contrail_api_client): @@ -593,3 +594,37 @@ def test_update_vm_ip(server, subnet, port_steps, server_steps): check=False, **port_dict), raises(neutron_exceptions.BadRequest)) + + +@pytest.mark.parametrize('different_tenants_resources', + [dict(ips=('10.0.0.10', '10.0.0.20'))], + indirect=True) +def test_diff_proj_same_vn_vm_add_delete(different_tenants_resources, + client_contrail_vrouter_agent): + """Test to validate that a VN and VM with the same name and same subnet + can be created in two different projects. + + Test steps: + #. Create 2 different projects. + #. Create a VN with the same name and subnet under each project. + #. Launch a VM under the VN in both the projects. + + Pass criteria: + The label allocated to the VM's should be different. + """ + resources = different_tenants_resources + + itfs = client_contrail_vrouter_agent.get_itfs()['ItfResp'][ + 'itf_list'] + + s1_net_label = next(vrif['label'] for vrif in itfs + if vrif['vm_uuid'] == resources[0].server.id) + + s2_net_label = next(vrif['label'] for vrif in itfs + if vrif['vm_uuid'] == resources[1].server.id) + + logger.debug('label1 = {}; label2 = {}'.format(s1_net_label, + s2_net_label)) + + assert_that(s1_net_label, is_not(equal_to(s2_net_label))) +