diff --git a/plugin_test/vapor/vapor/fixtures/contrail.py b/plugin_test/vapor/vapor/fixtures/contrail.py index e177bfd6a..592fffcde 100644 --- a/plugin_test/vapor/vapor/fixtures/contrail.py +++ b/plugin_test/vapor/vapor/fixtures/contrail.py @@ -28,12 +28,17 @@ def client_contrail_analytics(session): @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 client_contrail_vrouter_agents(contrail_vrouter_agent_endpoints): + endpoints = contrail_vrouter_agent_endpoints + port = endpoints['port'] + _clients = {} + for node in endpoints['nodes']: + LOGGER.debug('VRouter `{node}` endpoint: {ip}:{port}'.format( + node=node['fqdn'], ip=node['ip'], port=port)) + _clients[node['fqdn']] = clients.ContrailVRouterAgentClient( + agent_ip=node['ip'], agent_port=endpoints['port']) + + return _clients def get_nodes_fixture(cmd, scope='function'): @@ -86,18 +91,53 @@ def contrail_api_endpoint(os_faults_steps): @pytest.fixture(scope='module') -def contrail_vrouter_agent_endpoint(contrail_services_http_introspect_ports): - """Return contrail agent endpoint.""" +def contrail_vrouter_agent_endpoints(contrail_services_http_introspect_ports): + """Return contrail agent endpoints info. + + Return format: + { + 'port': 8100, + 'nodes': [ + { + 'ip': '1.22.3.4', + 'fqdn': 'cmp001.mcp.local' + }, + { + 'ip': '1.22.3.5', + 'fqdn': 'cmp002.mcp.local' + } + ] + } + """ service_name = 'contrail-vrouter-agent' - ip = contrail_services_http_introspect_ports[service_name]['nodes'][0][ - 'ip'] - port = contrail_services_http_introspect_ports[service_name]['port'] - return {'ip': ip, 'port': port} + return contrail_services_http_introspect_ports[service_name] @pytest.fixture(scope='module') def contrail_services_http_introspect_ports(os_faults_steps, contrail_nodes): - """Return contrail services ips and ports.""" + """Return contrail services ips and ports. + + Return format: + { + 'contrail-vrouter-agent':{ + 'port': 8100, + 'nodes': [ + { + 'ip': '1.22.3.4', + 'fqdn': 'cmp001.mcp.local' + }, + { + 'ip': '1.22.3.5', + 'fqdn': 'cmp002.mcp.local' + } + ] + }, + 'contrail-opserver': {...}, + .... + + } + + """ default_ports = { 'contrail-config-nodemgr': 8100, diff --git a/plugin_test/vapor/vapor/helpers/clients/contrail_agent.py b/plugin_test/vapor/vapor/helpers/clients/contrail_agent.py index 1d25cff0b..c73c74a6b 100644 --- a/plugin_test/vapor/vapor/helpers/clients/contrail_agent.py +++ b/plugin_test/vapor/vapor/helpers/clients/contrail_agent.py @@ -1,15 +1,10 @@ -import six import copy + +from six.moves.urllib import request 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'] @@ -20,21 +15,16 @@ class ClientContrailVRouterAgentBase(object): self.port = agent_port def get_snh_dict_data(self, data): - key = data.keys() - if key[0].find(r'__') == 0: - data = data[key[0]] + key = next(iter(data.keys())) + if key.startswith(r'__'): + data = data[key] 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 + return {k: self.get_data(v) for k, v in data.items()} def get_resource(self, path): url = 'http://%s:%s/%s' % (self.ip, self.port, path) - req = Request(url) try: - response = urlopen(req) + response = request.urlopen(url) xmldata = response.read() except Exception as e: logger.error('get_xml exception: {} url: {}'.format(e, url)) @@ -46,38 +36,35 @@ class ClientContrailVRouterAgentBase(object): 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}) + return {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) + for item in data: + data_dict = self.get_data(item) 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 + return_data = {k: self.get_data(v) + for k, v in data.items()} elif data['@type'] == 'list': data = self.del_unused_key(data) - key = data.keys() - data = data[key[0]] + key = next(iter(data.keys())) + data = data[key] return_data = self.get_data(data) elif data['@type'] == 'struct': + is_list = '@size' in data 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 + value = next(iter(data.values())) + if is_list and not (isinstance(value, list)): + value = [value] + return_data = self.get_data(value) elif data['@type'] in ['i64', 'i32', 'i16', 'u64', 'u32', 'u16', 'double', 'string', 'bool']: if '#text' in data: @@ -87,11 +74,8 @@ class ClientContrailVRouterAgentBase(object): 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_data = {k: self.get_data(v) for k, v in data.items()} return return_data def find_ifmap_list(self, data): @@ -118,34 +102,32 @@ class ClientContrailVRouterAgentBase(object): def get_snhdict(self, path): data = self.get_resource(path) - all_path = '' + # Check all data link + all_path = None try: - top_key = data.keys() - url = data[top_key[0]]['Pagination']['req']['PageReqData']['all']['#text'] # noqa + top_key = next(iter(data.keys())) + url = data[top_key]['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 + top_key = next(iter(data.keys())) + url = data[top_key]['OvsdbPageResp']['req']['OvsdbPageRespData']['all']['#text'] # noqa all_path = 'Snh_OvsdbPageReq?x=%s' % url except KeyError: pass - if all_path != '': + 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 + # Check pagination + key = next(iter(data.keys())) + while 'next_batch' in data[key]: + old_data = data.copy() + path1 = data[key]['next_batch']['@link'] + path2 = data[key]['next_batch']['#text'] + path = 'Snh_%s?x=%s' % (path1, path2) + data = self.get_resource(path) + old_list = self.find_ifmap_list(old_data) + data = self.merge_ifmap_list(data, old_list) return data def get_path_to_dict(self, path): @@ -164,3 +146,7 @@ class ContrailVRouterAgentClient(ClientContrailVRouterAgentBase): def get_itf_by_name(self, interface_name): data = self.get_path_to_dict('Snh_ItfReq?x={}'.format(interface_name)) return data + + def get_sg_list(self): + data = self.get_path_to_dict('Snh_SgListReq') + return data diff --git a/plugin_test/vapor/vapor/tests/common/test_base.py b/plugin_test/vapor/vapor/tests/common/test_base.py index eb95ccfb2..e2e6f3f82 100644 --- a/plugin_test/vapor/vapor/tests/common/test_base.py +++ b/plugin_test/vapor/vapor/tests/common/test_base.py @@ -647,7 +647,8 @@ def test_update_vm_ip(server, subnet, port_steps, server_steps): [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): + client_contrail_vrouter_agents, + os_faults_steps): """Test to validate that a VN and VM with the same name and same subnet can be created in two different projects. @@ -661,7 +662,13 @@ def test_diff_proj_same_vn_vm_add_delete(different_tenants_resources, """ resources = different_tenants_resources - itfs = client_contrail_vrouter_agent.get_itfs()['ItfResp'][ + compute_host = getattr(resources[0].server, + stepler_config.SERVER_ATTR_HOST) + compute_fqdn = os_faults_steps.get_fqdn_by_host_name(compute_host) + + vrouter_agent_client = client_contrail_vrouter_agents[compute_fqdn] + + itfs = vrouter_agent_client.get_itfs()['ItfResp'][ 'itf_list'] s1_net_label = next(vrif['label'] for vrif in itfs diff --git a/plugin_test/vapor/vapor/tests/common/test_security_group.py b/plugin_test/vapor/vapor/tests/common/test_security_group.py index 88595e858..de091cfb1 100644 --- a/plugin_test/vapor/vapor/tests/common/test_security_group.py +++ b/plugin_test/vapor/vapor/tests/common/test_security_group.py @@ -13,7 +13,8 @@ import time import attrdict -from hamcrest import assert_that, equal_to # noqa: H301 +from hamcrest import (assert_that, equal_to, only_contains, + has_entries) # noqa: H301 from pycontrail import types import pytest from stepler import config as stepler_config @@ -448,3 +449,36 @@ def test_add_remove_security_group_with_active_flow( ifaces[0], tcp_filter) connectivity.check_packets_on_iface(os_faults_steps, computes[1], ifaces[1], udp_filter) + + +def test_security_group_on_vrouter( + server, security_group, client_contrail_vrouter_agents, + os_faults_steps, neutron_create_security_group): + """Check that server's compute vRouter "know" about security groups. + + Steps: + #. Create server with security group + #. Check that security group uuid is present on server's vRouter agent + /Snh_SgListReq reply + #. Create new security group + #. Add created security group to server + #. Check that new security group uuid is present on server's vRouter + agent /Snh_SgListReq reply + """ + compute_host = getattr(server, stepler_config.SERVER_ATTR_HOST) + compute_fqdn = os_faults_steps.get_fqdn_by_host_name(compute_host) + vrouter_agent = client_contrail_vrouter_agents[compute_fqdn] + + sg_list = vrouter_agent.get_sg_list()['SgListResp']['sg_list'] + assert_that( + sg_list, only_contains(has_entries(sg_uuid=security_group['id']))) + + new_security_group = neutron_create_security_group( + next(utils.generate_ids())) + server.add_security_group(new_security_group['id']) + + sg_list = vrouter_agent.get_sg_list()['SgListResp']['sg_list'] + assert_that(sg_list, + only_contains( + has_entries(sg_uuid=security_group['id']), + has_entries(sg_uuid=new_security_group['id'])))