# Copyright (C) 2016 VA Linux Systems Japan K.K. # Copyright (C) 2016 Fumihiko Kakuma # All Rights Reserved. # # 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. import collections import threading import time import netaddr from tempest.common import utils from tempest import config from neutron_tempest_plugin.api import base from ryu.tests.integrated.common import docker_base as ctn_base from neutron_dynamic_routing.tests.tempest import bgp_client CONF = config.CONF Scope = collections.namedtuple('Scope', 'name') Pool = collections.namedtuple('Pool', 'name, prefixlen, prefixes') Net = collections.namedtuple('Net', 'name, net, mask, cidr, router') SubNet = collections.namedtuple('SubNet', 'name, cidr, mask') Router = collections.namedtuple('Router', 'name, gw') AS = collections.namedtuple('AS', 'asn, router_id, adv_net') CHECKTIME = 180 CHECKTIME_INFO = 60 CHECKTIME_INT = 1 BRIDGE_TYPE = ctn_base.BRIDGE_TYPE_DOCKER def _setup_client_args(auth_provider): """Set up ServiceClient arguments using config settings. """ service = CONF.network.catalog_type or 'network' region = CONF.network.region or 'regionOne' endpoint_type = CONF.network.endpoint_type build_interval = CONF.network.build_interval build_timeout = CONF.network.build_timeout # The disable_ssl appears in identity disable_ssl_certificate_validation = ( CONF.identity.disable_ssl_certificate_validation) ca_certs = None # Trace in debug section trace_requests = CONF.debug.trace_requests return [auth_provider, service, region, endpoint_type, build_interval, build_timeout, disable_ssl_certificate_validation, ca_certs, trace_requests] class BgpSpeakerScenarioTestJSONBase(base.BaseAdminNetworkTest): def setUp(self): self.addCleanup(self.net_resource_cleanup) super(BgpSpeakerScenarioTestJSONBase, self).setUp() @classmethod def _setup_bgp_non_admin_client(cls): mgr = cls.get_client_manager() auth_provider = mgr.auth_provider client_args = _setup_client_args(auth_provider) cls.bgp_client = bgp_client.BgpSpeakerClientJSON(*client_args) @classmethod def _setup_bgp_admin_client(cls): mgr = cls.get_client_manager(credential_type='admin') auth_provider = mgr.auth_provider client_args = _setup_client_args(auth_provider) cls.bgp_adm_client = bgp_client.BgpSpeakerClientJSON(*client_args) @classmethod def resource_setup(cls): super(BgpSpeakerScenarioTestJSONBase, cls).resource_setup() if not utils.is_extension_enabled('bgp', 'network'): msg = "BGP Speaker extension is not enabled." raise cls.skipException(msg) cls.images = [] cls.containers = [] cls.r_ass = [] cls.r_as_ip = [] cls.bridges = [] cls.admin_routerports = [] cls.admin_floatingips = [] cls.admin_routers = [] cls.admin_router_ip = [] cls.resource_setup_container() cls._setup_bgp_admin_client() cls._setup_bgp_non_admin_client() cls.lock = threading.Lock() @classmethod def resource_cleanup(cls): for ctn in cls.containers: try: ctn.stop() except ctn_base.CommandError: pass ctn.remove() for br in cls.bridges: br.delete() super(BgpSpeakerScenarioTestJSONBase, cls).resource_cleanup() @classmethod def get_subnet(self, start='10.10.1.0', end='10.10.255.0', step=256): subnet_gen = netaddr.iter_iprange(start, end, step=step) i = 1 while True: with self.lock: try: yield (i, str(subnet_gen.next())) except StopIteration: subnet_gen = netaddr.iter_iprange(start, end, step=step) yield (i, str(subnet_gen.next())) i += 1 def net_resource_cleanup(self): for floatingip in self.admin_floatingips: self._try_delete_resource(self.admin_client.delete_floatingip, floatingip['id']) for routerport in self.admin_routerports: self._try_delete_resource( self.admin_client.remove_router_interface_with_subnet_id, routerport['router_id'], routerport['subnet_id']) for router in self.admin_routers: self._try_delete_resource(self.admin_client.delete_router, router['id']) def create_bgp_speaker(self, auto_delete=True, **args): data = {'bgp_speaker': args} bgp_speaker = self.bgp_adm_client.create_bgp_speaker(data) bgp_speaker_id = bgp_speaker['bgp_speaker']['id'] if auto_delete: self.addCleanup(self.bgp_adm_client.delete_bgp_speaker, bgp_speaker_id) return bgp_speaker['bgp_speaker'] def delete_bgp_speaker(self, id): return self.bgp_adm_client.delete_bgp_speaker(id) def create_bgp_peer(self, auto_delete=True, **args): bgp_peer = self.bgp_adm_client.create_bgp_peer({'bgp_peer': args}) bgp_peer_id = bgp_peer['bgp_peer']['id'] if auto_delete: self.addCleanup(self.bgp_adm_client.delete_bgp_peer, bgp_peer_id) return bgp_peer['bgp_peer'] def delete_bgp_peer(self, id): return self.bgp_adm_client.delete_bgp_peer(id) def get_dragent_id(self): agents = self.admin_client.list_agents( agent_type="BGP dynamic routing agent") self.assertTrue(agents['agents'][0]['alive']) return agents['agents'][0]['id'] def add_bgp_speaker_to_dragent(self, agent_id, speaker_id): self.bgp_adm_client.add_bgp_speaker_to_dragent(agent_id, speaker_id) # tnets[[net1, subnet1, router1], [net2, subnet2, router2], ...] def create_bgp_network(self, ip_version, scope, exnet, expool, exsubnet, tpool, tnets): addr_scope = self.create_address_scope(scope.name, ip_version=ip_version) # external network ext_net = self.create_shared_network(**{'router:external': True}) ext_net_id = ext_net['id'] ext_subnetpool = self.create_subnetpool( expool.name, is_admin=True, default_prefixlen=expool.prefixlen, address_scope_id=addr_scope['id'], prefixes=expool.prefixes) self.create_subnet( {'id': ext_net_id}, cidr=netaddr.IPNetwork(exsubnet.cidr), mask_bits=exsubnet.mask, ip_version=ip_version, client=self.admin_client, subnetpool_id=ext_subnetpool['id'], reserve_cidr=False) # tenant network tenant_subnetpool = self.create_subnetpool( tpool.name, default_prefixlen=tpool.prefixlen, address_scope_id=addr_scope['id'], prefixes=tpool.prefixes) for tnet, tsubnet, router in tnets: tenant_net = self.create_network() tenant_subnet = self.create_subnet( {'id': tenant_net['id']}, cidr=netaddr.IPNetwork(tsubnet.cidr), mask_bits=tsubnet.mask, ip_version=ip_version, subnetpool_id=tenant_subnetpool['id'], reserve_cidr=False) # router ext_gw_info = {'network_id': ext_net_id} router_cr = self.admin_client.create_router( router.name, external_gateway_info=ext_gw_info)['router'] self.admin_routers.append(router_cr) self.admin_client.add_router_interface_with_subnet_id( router_cr['id'], tenant_subnet['id']) self.admin_routerports.append({'router_id': router_cr['id'], 'subnet_id': tenant_subnet['id']}) router = self.admin_client.show_router(router_cr['id'])['router'] fixed_ips = router['external_gateway_info']['external_fixed_ips'] self.admin_router_ip.append(fixed_ips[0]['ip_address']) return ext_net_id def create_and_add_peers_to_speaker(self, ext_net_id, speaker_info, peer_infos, auto_delete=True): speaker = self.create_bgp_speaker(auto_delete=auto_delete, **speaker_info) speaker_id = speaker['id'] self.bgp_adm_client.add_bgp_gateway_network(speaker_id, ext_net_id) peer_ids = [] for peer_args in peer_infos: peer = self.create_bgp_peer(auto_delete=auto_delete, **peer_args) peer_id = peer['id'] peer_ids.append(peer_id) self.bgp_adm_client.add_bgp_peer_with_id(speaker_id, peer_id) return (speaker_id, peer_ids) def get_remote_as_state(self, l_as, r_as, expected_state, init_state=ctn_base.BGP_FSM_IDLE, checktime=CHECKTIME, checktime_int=CHECKTIME_INT): neighbor_state = init_state for i in range(0, checktime): neighbor_state = r_as.get_neighbor_state(l_as) if neighbor_state == expected_state: break time.sleep(checktime_int) return neighbor_state def check_remote_as_state(self, l_as, r_as, expected_state, init_state=ctn_base.BGP_FSM_IDLE, checktime=CHECKTIME, checktime_int=CHECKTIME_INT): neighbor_state = self.get_remote_as_state(l_as, r_as, expected_state, init_state=init_state, checktime=checktime, checktime_int=checktime_int) self.assertEqual(neighbor_state, expected_state) def get_remote_as_of_state_ok(self, l_as, r_ass, expected_state, init_state=ctn_base.BGP_FSM_IDLE, checktime=CHECKTIME, checktime_int=CHECKTIME_INT): neighbor_state = init_state ras_list = [] ras_max = len(r_ass) for r_as in r_ass: ras_list.append({'as': r_as, 'check': False}) ok_ras = [] for i in range(0, checktime): for ras in ras_list: if ras['check']: continue neighbor_state = ras['as'].get_neighbor_state(l_as) if neighbor_state == expected_state: ras['check'] = True ok_ras.append(ras['as']) if len(ok_ras) >= ras_max: break time.sleep(checktime_int) return ok_ras def check_multi_remote_as_state(self, l_as, r_ass, expected_state, init_state=ctn_base.BGP_FSM_IDLE, checktime=CHECKTIME, checktime_int=CHECKTIME_INT): ok_ras = self.get_remote_as_of_state_ok( l_as, r_ass, expected_state, init_state=init_state, checktime=checktime, checktime_int=checktime_int) self.assertEqual(len(ok_ras), len(r_ass)) def get_remote_as_rib(self, r_as, prefix, rf, key, expected_item, checktime=CHECKTIME_INFO, checktime_int=CHECKTIME_INT): item = None for i in range(0, checktime): rib = r_as.get_global_rib(prefix=prefix, rf=rf) if rib and key in rib[0]: if expected_item == rib[0][key]: item = rib[0][key] break time.sleep(checktime_int) return item def check_remote_as_rib(self, r_as, prefix, rf, key, expected_item, checktime=CHECKTIME_INFO, checktime_int=CHECKTIME_INT): item = self.get_remote_as_rib(r_as=r_as, prefix=prefix, rf=rf, key=key, expected_item=expected_item, checktime=checktime, checktime_int=checktime_int) self.assertEqual(expected_item, item) def get_remote_as_of_rib_ok(self, r_ass, prefix, rf, key, expected_item, checktime=CHECKTIME_INFO, checktime_int=CHECKTIME_INT): ras_list = [] ras_max = len(r_ass) for r_as in r_ass: ras_list.append({'as': r_as, 'check': False}) ok_ras = [] for i in range(0, checktime): for ras in ras_list: if ras['check']: continue rib = r_as.get_global_rib(prefix=prefix, rf=rf) if rib and key in rib[0]: if expected_item == rib[0][key]: ras['check'] = True ok_ras.append(ras['as']) if len(ok_ras) >= ras_max: break time.sleep(checktime_int) return ok_ras def check_multi_remote_as_rib(self, r_ass, prefix, rf, key, expected_item, checktime=CHECKTIME_INFO, checktime_int=CHECKTIME_INT): ok_ras = self.get_remote_as_of_rib_ok( r_ass=r_ass, prefix=prefix, rf=rf, key=key, expected_item=expected_item, checktime=checktime, checktime_int=checktime_int) self.assertEqual(len(ok_ras), len(r_ass)) def get_next_hop(self, speaker_id, dest_addr): routes = self.bgp_adm_client.get_bgp_advertised_routes(speaker_id) next_hop = '' for route in routes['advertised_routes']: if route['destination'] == dest_addr: next_hop = route['next_hop'] break return next_hop