Merge "add test_diff_proj_same_vn_vm_add_delete"
This commit is contained in:
commit
8d697733f2
|
@ -5,3 +5,5 @@ dpath
|
||||||
jmespath==0.9.0
|
jmespath==0.9.0
|
||||||
contextlib2==0.5.4; python_version < '3.2'
|
contextlib2==0.5.4; python_version < '3.2'
|
||||||
kazoo==2.2.1
|
kazoo==2.2.1
|
||||||
|
logbook
|
||||||
|
xmltodict
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
import os
|
import os
|
||||||
|
import six
|
||||||
import uuid
|
import uuid
|
||||||
|
import pytest
|
||||||
|
import logbook
|
||||||
|
|
||||||
import pycontrail.client as client
|
import pycontrail.client as client
|
||||||
import pytest
|
|
||||||
import six
|
|
||||||
from six.moves import configparser
|
from six.moves import configparser
|
||||||
from six.moves.urllib import parse
|
from six.moves.urllib import parse
|
||||||
|
|
||||||
from vapor import settings
|
from vapor import settings
|
||||||
from vapor.helpers import clients
|
from vapor.helpers import clients
|
||||||
|
|
||||||
|
LOGGER = logbook.Logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def client_contrail(session, contrail_api_endpoint):
|
def client_contrail(session, contrail_api_endpoint):
|
||||||
|
@ -23,6 +26,15 @@ def client_contrail_analytics(session, contrail_analytics_endpoint):
|
||||||
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'):
|
def get_nodes_fixture(cmd, scope='function'):
|
||||||
"""Fixtures to gen nodes by cmd factory."""
|
"""Fixtures to gen nodes by cmd factory."""
|
||||||
|
|
||||||
|
@ -77,7 +89,16 @@ def contrail_analytics_endpoint(contrail_api_endpoint):
|
||||||
"""Return contrail analytics endpoint."""
|
"""Return contrail analytics endpoint."""
|
||||||
parse_result = parse.urlparse(contrail_api_endpoint)
|
parse_result = parse.urlparse(contrail_api_endpoint)
|
||||||
return parse_result._replace(netloc="{}:{}".format(
|
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')
|
@pytest.fixture(scope='module')
|
||||||
|
|
|
@ -135,7 +135,7 @@ def project_2(create_user_with_project):
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def different_tenants_resources(
|
def different_tenants_resources(request,
|
||||||
project_2, credentials, create_user_with_project, cirros_image,
|
project_2, credentials, create_user_with_project, cirros_image,
|
||||||
sorted_hypervisors, get_network_steps, get_subnet_steps,
|
sorted_hypervisors, get_network_steps, get_subnet_steps,
|
||||||
get_server_steps, port_steps, get_floating_ip_steps, public_flavor,
|
get_server_steps, port_steps, get_floating_ip_steps, public_flavor,
|
||||||
|
@ -149,15 +149,23 @@ def different_tenants_resources(
|
||||||
Returns:
|
Returns:
|
||||||
list: list of AttrDict with created resources
|
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]
|
hypervisor = sorted_hypervisors[0]
|
||||||
|
|
||||||
host = next(
|
host = next(
|
||||||
host for host in nova_availability_zone_hosts
|
host for host in nova_availability_zone_hosts
|
||||||
if hypervisor.hypervisor_hostname.startswith(host))
|
if hypervisor.hypervisor_hostname.startswith(host))
|
||||||
|
|
||||||
subnet_cidr = '10.0.0.0/24'
|
|
||||||
base_name = next(utils.generate_ids())
|
|
||||||
|
|
||||||
with contextlib.ExitStack() as stack:
|
with contextlib.ExitStack() as stack:
|
||||||
|
|
||||||
mrg = ResourceManager(stack, base_name, get_network_steps,
|
mrg = ResourceManager(stack, base_name, get_network_steps,
|
||||||
|
@ -167,16 +175,15 @@ def different_tenants_resources(
|
||||||
|
|
||||||
projects_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)
|
public_flavor, host)
|
||||||
|
|
||||||
projects_resources.append(project_resources)
|
projects_resources.append(project_resources)
|
||||||
|
|
||||||
with credentials.change(project_2):
|
with credentials.change(project_2):
|
||||||
|
|
||||||
project_resources = mrg.create(subnet_cidr, '10.0.0.20',
|
project_resources = mrg.create(subnet_cidr, ips[1],
|
||||||
cirros_image, public_flavor, host)
|
cirros_image, public_flavor,
|
||||||
|
host)
|
||||||
projects_resources.append(project_resources)
|
projects_resources.append(project_resources)
|
||||||
|
yield projects_resources
|
||||||
yield projects_resources
|
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
from .contrail_api import ContrailClient
|
from .contrail_api import ContrailClient
|
||||||
from .analytics import ContrailAnalyticsClient
|
from .analytics import ContrailAnalyticsClient
|
||||||
|
from .contrail_agent import ContrailVRouterAgentClient
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
'ContrailClient',
|
'ContrailClient',
|
||||||
'ContrailAnalyticsClient',
|
'ContrailAnalyticsClient',
|
||||||
|
'ContrailVRouterAgentClient',
|
||||||
]
|
]
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from . import base
|
from . import base
|
||||||
|
import urllib
|
||||||
|
|
||||||
|
|
||||||
class ContrailClient(base.ContrailBaseClient):
|
class ContrailClient(base.ContrailBaseClient):
|
||||||
|
|
|
@ -1,8 +1,18 @@
|
||||||
# Project, contrail and OpenStack settings
|
# Project, contrail and OpenStack settings
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import sys
|
||||||
import yaml
|
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__)
|
BASE_DIR = os.path.dirname(__file__)
|
||||||
|
|
||||||
|
@ -17,10 +27,11 @@ KEYSTONE_CREDS = {
|
||||||
|
|
||||||
CONTRAIL_CREDS = {'controller_addr': '192.168.1.127'}
|
CONTRAIL_CREDS = {'controller_addr': '192.168.1.127'}
|
||||||
|
|
||||||
CONTAIL_API_PORT = 8082
|
CONTRAIL_ANALYTICS_PORT = 8081
|
||||||
CONTAIL_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/'
|
CONTRAIL_CONFIG_PATH = '/etc/contrail/'
|
||||||
|
|
||||||
# Time between poweroff and start contrail controller node
|
# Time between poweroff and start contrail controller node
|
||||||
|
|
|
@ -27,6 +27,7 @@ from vapor.helpers import asserts
|
||||||
from vapor.helpers import contrail_status, policy, connectivity
|
from vapor.helpers import contrail_status, policy, connectivity
|
||||||
from vapor import settings
|
from vapor import settings
|
||||||
from vapor.helpers import contrail_status, nodes_steps
|
from vapor.helpers import contrail_status, nodes_steps
|
||||||
|
from vapor.settings import logger
|
||||||
|
|
||||||
|
|
||||||
def test_network_deleting_with_server(network, server, contrail_api_client):
|
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,
|
check=False,
|
||||||
**port_dict),
|
**port_dict),
|
||||||
raises(neutron_exceptions.BadRequest))
|
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)))
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue