From 6e6e2025d5b7e24b620a7f103d9629c2aedbf76f Mon Sep 17 00:00:00 2001 From: Bob Melander Date: Tue, 24 Jan 2017 12:36:41 +0100 Subject: [PATCH] Adds support for multiple subnets per external network With this patch neutron routers hosted in ASR1k devices can now be attached to external networks that have multiple subnets. The global routers in the ASR1k will always be connected to *all* subnets of an external network regardless if the tenant gateway routers are connected to all those subnets. The patch also adds UTs for the new capability. Addresses: DE3191, DE3092, DE2865, DE2877, DE2882, DE2886 Change-Id: I65775b58361bcfee9ea3d36ff87b9981ba750601 Closes-Bug: #1660988 --- networking_cisco/backwards_compatibility.py | 2 - .../plugins/cisco/cfg_agent/cfg_agent.py | 85 ++ .../device_drivers/asr1k/asr1k_cfg_syncer.py | 189 +-- .../asr1k/asr1k_routing_driver.py | 140 +- .../device_drivers/asr1k/asr1k_snippets.py | 28 + .../service_helpers/routing_svc_helper.py | 105 +- .../service_helpers/routing_svc_helper_aci.py | 11 +- .../cisco/common/cisco_ios_xe_simulator.py | 239 +++ networking_cisco/plugins/cisco/db/l3/ha_db.py | 11 +- .../cisco/db/l3/l3_router_appliance_db.py | 60 +- .../hw_vlan_trunking_driver.py | 5 +- .../plugins/cisco/l3/drivers/__init__.py | 24 + .../drivers/asr1k/asr1k_routertype_driver.py | 75 +- .../l3/drivers/noop_routertype_driver.py | 6 + .../1/neutronclient_multi_subnets_ext_net.txt | 172 +++ .../1/router_dicts_multi_subnets_ext_net.json | 728 ++++++++++ ...running_cfg_0004_multi_subnets_ext_net.txt | 61 + ...running_cfg_0005_multi_subnets_ext_net.txt | 61 + ...nets_ext_net_and_single_subnet_ext_net.txt | 254 ++++ ...ets_ext_net_and_single_subnet_ext_net.json | 1290 +++++++++++++++++ ...nets_ext_net_and_single_subnet_ext_net.txt | 111 ++ ...nets_ext_net_and_single_subnet_ext_net.txt | 111 ++ .../cisco/cfg_agent/test_asr1k_cfg_syncer.py | 234 +-- .../cfg_agent/test_asr1k_routing_driver.py | 60 +- .../cfg_agent/test_routing_svc_helper.py | 191 ++- .../cfg_agent/test_routing_svc_helper_aci.py | 10 + .../test_hw_vlan_trunking_plugging_driver.py | 2 + .../cisco/l3/test_asr1k_routertype_driver.py | 459 +++++- 28 files changed, 4319 insertions(+), 405 deletions(-) create mode 100644 networking_cisco/plugins/cisco/common/cisco_ios_xe_simulator.py create mode 100644 networking_cisco/tests/unit/cisco/cfg_agent/json/1/neutronclient_multi_subnets_ext_net.txt create mode 100644 networking_cisco/tests/unit/cisco/cfg_agent/json/1/router_dicts_multi_subnets_ext_net.json create mode 100644 networking_cisco/tests/unit/cisco/cfg_agent/json/1/running_cfg_0004_multi_subnets_ext_net.txt create mode 100644 networking_cisco/tests/unit/cisco/cfg_agent/json/1/running_cfg_0005_multi_subnets_ext_net.txt create mode 100644 networking_cisco/tests/unit/cisco/cfg_agent/json/2/neutronclient_multi_subnets_ext_net_and_single_subnet_ext_net.txt create mode 100644 networking_cisco/tests/unit/cisco/cfg_agent/json/2/router_dicts_multi_subnets_ext_net_and_single_subnet_ext_net.json create mode 100644 networking_cisco/tests/unit/cisco/cfg_agent/json/2/running_cfg_0004_multi_subnets_ext_net_and_single_subnet_ext_net.txt create mode 100644 networking_cisco/tests/unit/cisco/cfg_agent/json/2/running_cfg_0005_multi_subnets_ext_net_and_single_subnet_ext_net.txt diff --git a/networking_cisco/backwards_compatibility.py b/networking_cisco/backwards_compatibility.py index 4a5ca30..6500ee1 100644 --- a/networking_cisco/backwards_compatibility.py +++ b/networking_cisco/backwards_compatibility.py @@ -72,8 +72,6 @@ else: setattr(constants, 'L3', getattr(svc_constants, 'L3_ROUTER_NAT')) core_opts = base_config.core_opts -#extensions = extensions -#model_base = model_base # Bring in the union of all constants in neutron.common.constants # and neutron_lib.constants. Handle any duplicates by using the diff --git a/networking_cisco/plugins/cisco/cfg_agent/cfg_agent.py b/networking_cisco/plugins/cisco/cfg_agent/cfg_agent.py index ac302c5..375dc74 100755 --- a/networking_cisco/plugins/cisco/cfg_agent/cfg_agent.py +++ b/networking_cisco/plugins/cisco/cfg_agent/cfg_agent.py @@ -524,12 +524,97 @@ def _mock_stuff(): pingable_patcher.start() +# NOTE(bobmel): call mock_ncclient() in main() of cfg_agent.py to run config +# agent with a fake ncclient. That mocked mode of running the config agent is +# useful for end-2-end-like debugging without actual backend hosting devices. +def mock_ncclient(): + import mock + from ncclient.transport import errors as ncc_exc + from networking_cisco.plugins.cisco.common import (cisco_ios_xe_simulator + as cisco_ios_xe) + import os + + def _fake_connect(host, port, username, password, device_params, timeout): + sim = cisco_ios_xe.CiscoIOSXESimulator( + '', host, "255.255.255.0", port, username, password, + device_params, "GigabitEthernet0", timeout) + connection_mock = mock.MagicMock() + connection_mock.edit_config.side_effect = _get_fake_edit_config(sim) + connection_mock.get_config.side_effect = ( + _get_fake_get_config(sim)) + return connection_mock + + def _get_fake_edit_config(simulator): + + def edit_config(config, format='xml', target='candidate', + default_operation=None, test_option=None, + error_option=None): + if not _fake_is_pingable(rc_emul.host_ip): + raise ncc_exc.SSHError('SSH error') + rc_emul.edit_config(config) + print(rc_emul.get_config()) + return ok_xml_obj + + ok_xml_obj = mock.MagicMock() + ok_xml_obj.xml = "" + rc_emul = simulator + return edit_config + + def _get_fake_get_config(simulator): + + def get_running_config(source): + if not _fake_is_pingable(rc_emul.host_ip): + raise ncc_exc.SSHError('SSH error') + head = ('!') + tail = '' + raw_rc = rc_emul.get_config() + return cisco_ios_xe.FakeRunningConfig(head + raw_rc + tail) + + rc_emul = simulator + return get_running_config + + def _fake_is_pingable(ip): + # if a file with a certain name (derived from the 'ip' argument): + # + # /opt/stack/data/neutron/DEAD__10_0_5_8 (ip = 10.0.5.8) + # + # exists then the (faked) hosting device with that IP address + # will appear to NOT respond to pings + path = '/opt/stack/data/neutron' + indicator_filename = path + '/DEAD_' + str(ip).replace('.', '_') + return not os.path.isfile(indicator_filename) + + targets = ['networking_cisco.plugins.cisco.cfg_agent.device_drivers.' + 'csr1kv.csr1kv_routing_driver.manager', + 'networking_cisco.plugins.cisco.cfg_agent.device_drivers.' + 'csr1kv.iosxe_routing_driver.manager'] + ncc_patchers = [] + ncclient_mgr_mock = mock.MagicMock() + ncclient_mgr_mock.connect.side_effect = _fake_connect + + for target in targets: + patcher = mock.patch(target, ncclient_mgr_mock) + patcher.start() + ncc_patchers.append(patcher) + + is_pingable_mock = mock.MagicMock() + is_pingable_mock.side_effect = _fake_is_pingable + pingable_patcher = mock.patch( + 'networking_cisco.plugins.cisco.cfg_agent.device_status._is_pingable', + is_pingable_mock) + pingable_patcher.start() + + def main(manager='networking_cisco.plugins.cisco.cfg_agent.' 'cfg_agent.CiscoCfgAgentWithStateReport'): # NOTE(bobmel): call _mock_stuff() to run config agent with fake ncclient # This mocked mode of running the config agent is useful for end-2-end-like # debugging without actual backend hosting devices. #_mock_stuff() + #mock_ncclient() conf = cfg.CONF conf.register_opts(OPTS, "cfg_agent") config.register_agent_state_opts_helper(conf) diff --git a/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_cfg_syncer.py b/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_cfg_syncer.py index 507996d..84bbe61 100755 --- a/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_cfg_syncer.py +++ b/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_cfg_syncer.py @@ -34,6 +34,8 @@ LOG = logging.getLogger(__name__) ROUTER_ROLE_ATTR = routerrole.ROUTER_ROLE_ATTR +ROUTER_ROLE_HA_REDUNDANCY = cisco_constants.ROUTER_ROLE_HA_REDUNDANCY + NROUTER_REGEX = "nrouter-(\w{6,6})" NROUTER_MULTI_REGION_REGEX = "nrouter-(\w{6,6})-(\w{1,7})" @@ -44,12 +46,12 @@ VRF_REGEX_NEW = "vrf definition " + NROUTER_REGEX VRF_MULTI_REGION_REGEX = "ip vrf " + NROUTER_MULTI_REGION_REGEX VRF_MULTI_REGION_REGEX_NEW = "vrf definition " + NROUTER_MULTI_REGION_REGEX -#INTF_NAME_REGEX = "(PortChannel\d+|\d+Ethernet\d+\/d+\/d+)" - INTF_REGEX = "interface \S+\.(\d+)" -INTF_DESC_REGEX = "\s*description OPENSTACK_NEUTRON_INTF" -INTF_DESC_MULTI_REGION_REGEX = ("\s*description" - " OPENSTACK_NEUTRON_(\w{1,7})_INTF") +INTF_DESC_REGEX = ( + "\s*description OPENSTACK_NEUTRON_INTF|OPENSTACK_NEUTRON_EXTERNAL_INTF") +INTF_DESC_MULTI_REGION_REGEX = ( + "\s*description OPENSTACK_NEUTRON_(\w{1,7})_INTF|" + "OPENSTACK_NEUTRON_EXTERNAL_(\w{1,7})_INTF") VRF_EXT_INTF_REGEX = "\s*ip vrf forwarding .*" VRF_INTF_REGEX = "\s*ip vrf forwarding " + NROUTER_REGEX VRF_INTF_MULTI_REGION_REGEX = ("\s*ip vrf forwarding " + @@ -219,9 +221,13 @@ class ConfigSyncer(object): interface_segment_dict[segment_id] = [] if segment_id not in segment_nat_dict: segment_nat_dict[segment_id] = False - interface['is_external'] = ( - router[ROUTER_ROLE_ATTR] == - cisco_constants.ROUTER_ROLE_GLOBAL) + if (router[ROUTER_ROLE_ATTR] == + cisco_constants.ROUTER_ROLE_GLOBAL): + interface['is_external'] = True + if (segment_id not in self.segment_gw_dict): + self.segment_gw_dict[segment_id] = [interface] + else: + interface['is_external'] = False interface_segment_dict[segment_id].append(interface) # Mark which segments have NAT enabled @@ -235,16 +241,16 @@ class ConfigSyncer(object): cisco_constants.ROUTER_ROLE_GLOBAL): if (gw_segment_id not in self.segment_gw_dict): - self.segment_gw_dict[gw_segment_id] = gw_port + self.segment_gw_dict[gw_segment_id] = [gw_port] if '_interfaces' in router.keys(): interfaces = router['_interfaces'] for intf in interfaces: - if intf['device_owner'] == \ - bc.constants.DEVICE_OWNER_ROUTER_INTF: + if (intf['device_owner'] == + bc.constants.DEVICE_OWNER_ROUTER_INTF): if is_port_v6(intf) is not True: - intf_segment_id = \ - intf['hosting_info']['segmentation_id'] + intf_segment_id = ( + intf['hosting_info']['segmentation_id']) segment_nat_dict[gw_segment_id] = True segment_nat_dict[intf_segment_id] = True @@ -261,7 +267,6 @@ class ConfigSyncer(object): LOG.info(_LI("neutron router db records")) for router_id, router in six.iteritems(router_id_dict): - #LOG.info("ROUTER ID: %s DATA: %s\n\n" % (router_id, router)) LOG.info(_LI("ROUTER_ID: %s"), router_id) LOG.info(_LI("\n")) @@ -451,17 +456,18 @@ class ConfigSyncer(object): continue # Check IPs and netmask - # TODO(sridar) rework this to old model, further - # investigation needed and cleanup. - # pool_info = router['gw_port']['nat_pool_info'] - # pool_ip = pool_info['pool_ip'] - # pool_net = netaddr.IPNetwork(pool_info['pool_cidr']) - pool_ip = str(router['gw_port']['fixed_ips'][0]['ip_address']) - # pool_net = router['gw_port']['subnets'][0]['cidr'] - pool_net = netaddr.IPNetwork( - router['gw_port']['subnets'][0]['cidr']) + if router.get(ROUTER_ROLE_ATTR) == ROUTER_ROLE_HA_REDUNDANCY: + the_port = router['gw_port'][ha.HA_INFO]['ha_port'] + else: + the_port = router['gw_port'] + found = False + for i in range(len(the_port['fixed_ips'])): + pool_ip = str(the_port['fixed_ips'][i]['ip_address']) + if start_ip == pool_ip: + found = True + break - if start_ip != pool_ip: + if found is False: LOG.info(_LI("start IP %(start_ip)s for " "pool does not match %(pool_ip)s, deleting") % {'start_ip': start_ip, 'pool_ip': pool_ip}) @@ -473,6 +479,7 @@ class ConfigSyncer(object): delete_pool_list.append(pool.text) continue + pool_net = netaddr.IPNetwork(the_port['subnets'][i]['cidr']) if netmask != str(pool_net.netmask): LOG.info( _LI("netmask for pool does not match, netmask:%(netmask)s," @@ -557,8 +564,17 @@ class ConfigSyncer(object): continue # Check that nexthop matches gw_ip of external network - gw_ip = gw_port['subnets'][0]['gateway_ip'] - if next_hop.lower() != gw_ip.lower(): + if router.get(ROUTER_ROLE_ATTR) == ROUTER_ROLE_HA_REDUNDANCY: + the_port = router['gw_port'][ha.HA_INFO]['ha_port'] + else: + the_port = router['gw_port'] + found = False + for i in range(len(the_port['subnets'])): + gw_ip = the_port['subnets'][i]['gateway_ip'] + if next_hop.lower() == gw_ip.lower(): + found = True + break + if found is False: LOG.info(_LI("route has incorrect next-hop, deleting")) delete_route_list.append(route.text) continue @@ -644,8 +660,6 @@ class ConfigSyncer(object): # Check that hsrp group name is correct gw_port = router['gw_port'] - #gw_net_id = gw_port['network_id'] - #gw_hsrp_num = self._get_hsrp_grp_num_from_net_id(gw_net_id) gw_hsrp_num = int(gw_port[ha.HA_INFO]['group']) gw_segment_id = int(gw_port['hosting_info']['segmentation_id']) if segment_id != gw_segment_id: @@ -889,14 +903,18 @@ class ConfigSyncer(object): checks running-cfg derived ip_addr and netmask against neutron-db gw_port """ - if (gw_port is not None): - target_ip = gw_port['fixed_ips'][0]['ip_address'] - target_net = netaddr.IPNetwork(gw_port['subnets'][0]['cidr']) - - if (ip_addr != target_ip): + if gw_port is not None: + found = False + for i in range(len(gw_port['fixed_ips'])): + target_ip = gw_port['fixed_ips'][i]['ip_address'] + if ip_addr == target_ip: + found = True + break + if found is False: LOG.info(_LI("Subintf real IP is incorrect, deleting")) return False - if (netmask != str(target_net.netmask)): + target_net = netaddr.IPNetwork(gw_port['subnets'][i]['cidr']) + if netmask != str(target_net.netmask): LOG.info(_LI("Subintf has incorrect netmask, deleting")) return False @@ -904,7 +922,7 @@ class ConfigSyncer(object): return False - def subintf_real_ip_check(self, intf_list, is_external, ip_addr, netmask): + def subintf_real_ip_check(self, intf_list, ip_addr, netmask): for target_intf in intf_list: target_ip = target_intf['fixed_ips'][0]['ip_address'] @@ -972,18 +990,16 @@ class ConfigSyncer(object): def gw_port_hsrp_ip_check(self, gw_port, ip_addr): - if (gw_port is not None): + if gw_port is not None: ha_port = gw_port[ha.HA_INFO]['ha_port'] - - target_ip = ha_port['fixed_ips'][0]['ip_address'] - LOG.info(_LI("target_ip: %(target_ip)s, actual_ip: %(ip_addr)s") % - {'target_ip': target_ip, - 'ip_addr': ip_addr}) - if ip_addr != target_ip: - LOG.info(_LI("HSRP VIP mismatch on gw_port, deleting")) - return False - else: - return True + for fixed_ip in ha_port['fixed_ips']: + target_ip = fixed_ip['ip_address'] + LOG.info(_LI("target_ip: %(target_ip)s, " + "actual_ip: %(ip_addr)s") % + {'target_ip': target_ip, 'ip_addr': ip_addr}) + if ip_addr == target_ip: + return True + LOG.info(_LI("HSRP VIP mismatch on gw_port, deleting")) return False def subintf_hsrp_ip_check(self, intf_list, is_external, ip_addr): @@ -1043,19 +1059,29 @@ class ConfigSyncer(object): def clean_interfaces_ipv4_hsrp_check(self, intf, intf_db_dict): # Check HSRP VIP hsrp_vip_cfg_list = intf.re_search_children(HSRP_V4_VIP_REGEX) - if len(hsrp_vip_cfg_list) < 1: + num_vips = len(hsrp_vip_cfg_list) + num_vips_db = len(intf_db_dict[intf.segment_id][0]['fixed_ips']) + if num_vips < 1: LOG.info(_LI("Interface is missing HSRP VIP, deleting")) return False - - hsrp_vip_cfg = hsrp_vip_cfg_list[0] - match_obj = re.match(HSRP_V4_VIP_REGEX, hsrp_vip_cfg.text) - hsrp_vip_grp_num, hsrp_vip = match_obj.group(1, 2) + elif num_vips != num_vips_db: + LOG.info(_LI("Subintf has wrong number of HSRP VIP addresses (" + "should have %(n_v)d, but has %(n_v_d)d), deleting"), + {'n_v': num_vips, 'n_v_d': num_vips_db}) + return False if intf.is_external: - return self.gw_port_hsrp_ip_check( - intf_db_dict[intf.segment_id], - hsrp_vip) + for hsrp_vip_cfg in hsrp_vip_cfg_list: + match_obj = re.match(HSRP_V4_VIP_REGEX, hsrp_vip_cfg.text) + hsrp_vip_grp_num, hsrp_vip = match_obj.group(1, 2) + if self.gw_port_hsrp_ip_check(intf_db_dict[intf.segment_id][0], + hsrp_vip) is False: + return False + return True else: + hsrp_vip_cfg = hsrp_vip_cfg_list[0] + match_obj = re.match(HSRP_V4_VIP_REGEX, hsrp_vip_cfg.text) + hsrp_vip_grp_num, hsrp_vip = match_obj.group(1, 2) return self.subintf_hsrp_ip_check( intf_db_dict[intf.segment_id], intf.is_external, @@ -1065,23 +1091,32 @@ class ConfigSyncer(object): # Check that real IP address is correct ipv4_addr = intf.re_search_children(INTF_V4_ADDR_REGEX) - if len(ipv4_addr) < 1: + num_addrs = len(ipv4_addr) + num_addrs_db = len(intf_db_dict[intf.segment_id][0]['fixed_ips']) + if num_addrs < 1: LOG.info(_LI("Subintf has no IP address, deleting")) return False - - ipv4_addr_cfg = ipv4_addr[0] - match_obj = re.match(INTF_V4_ADDR_REGEX, ipv4_addr_cfg.text) - ip_addr, netmask = match_obj.group(1, 2) + elif num_addrs != num_addrs_db: + LOG.info(_LI("Subintf has wrong number of addresses (should have " + "%(n_a)d, but has %(n_a_d)d), deleting"), num_addrs, + num_addrs_db) + return False if intf.is_external: - return self.subintf_real_ip_check_gw_port( - intf_db_dict[intf.segment_id], - ip_addr, netmask) + for ipv4_addr_cfg in ipv4_addr: + match_obj = re.match(INTF_V4_ADDR_REGEX, ipv4_addr_cfg.text) + ip_addr, netmask = match_obj.group(1, 2) + if (self.subintf_real_ip_check_gw_port( + intf_db_dict[intf.segment_id][0], ip_addr, netmask) is + False): + return False + return True else: + ipv4_addr_cfg = ipv4_addr[0] + match_obj = re.match(INTF_V4_ADDR_REGEX, ipv4_addr_cfg.text) + ip_addr, netmask = match_obj.group(1, 2) return self.subintf_real_ip_check( - intf_db_dict[intf.segment_id], - intf.is_external, - ip_addr, netmask) + intf_db_dict[intf.segment_id], ip_addr, netmask) def clean_interfaces_ipv6_check(self, intf, intf_segment_dict): # Check that real IP address is correct @@ -1188,11 +1223,10 @@ class ConfigSyncer(object): # Is this an "external network" segment_id? if intf.is_external: - db_intf = self.segment_gw_dict[intf.segment_id] + db_intf = self.segment_gw_dict[intf.segment_id][0] else: db_intf = intf_segment_dict[intf.segment_id][0] - # intf.is_external = db_intf['is_external'] intf.has_ipv6 = is_port_v6(db_intf) # Check VRF config @@ -1251,8 +1285,6 @@ class ConfigSyncer(object): pending_delete_list.append(intf) continue - # self.existing_cfg_dict['interfaces'][intf.segment_id] = intf - correct_grp_num = int(db_intf[ha.HA_INFO]['group']) if intf.is_external: @@ -1262,43 +1294,33 @@ class ConfigSyncer(object): if intf.has_ipv6 is False: if self.clean_interfaces_nat_check(intf, - segment_nat_dict) \ - is False: + segment_nat_dict) is False: pending_delete_list.append(intf) continue - if self.clean_interfaces_ipv4_check(intf, - intf_db) \ - is False: + if self.clean_interfaces_ipv4_check(intf, intf_db) is False: pending_delete_list.append(intf) continue if self.clean_interfaces_ipv4_hsrp_check(intf, - intf_db) \ - is False: + intf_db) is False: pending_delete_list.append(intf) continue else: - if self.clean_interfaces_ipv6_check(intf, intf_db) \ - is False: + if self.clean_interfaces_ipv6_check(intf, intf_db) is False: pending_delete_list.append(intf) continue # Delete if there's any hsrp config with wrong group number - #del_hsrp_cmd = XML_CMD_TAG % (intf.text) hsrp_cfg_list = intf.re_search_children(HSRP_REGEX) needs_hsrp_delete = False for hsrp_cfg in hsrp_cfg_list: hsrp_num = int(hsrp_cfg.re_match(HSRP_REGEX, group=1)) if hsrp_num != correct_grp_num: needs_hsrp_delete = True - #del_hsrp_cmd += XML_CMD_TAG % ("no %s" % (hsrp_cfg.text)) if needs_hsrp_delete: LOG.info(_LI("Bad HSRP config for interface, deleting")) pending_delete_list.append(intf) continue - #confstr = XML_FREEFORM_SNIPPET % (del_hsrp_cmd) - #LOG.info("Deleting bad HSRP config: %s" % (confstr)) - #rpc_obj = conn.edit_config(target='running', config=confstr) self.existing_cfg_dict['interfaces'][intf.segment_id] = intf.text @@ -1307,7 +1329,6 @@ class ConfigSyncer(object): del_cmd = XML_CMD_TAG % ("no %s" % (intf.text)) confstr = XML_FREEFORM_SNIPPET % (del_cmd) LOG.info(_LI("Deleting %s"), (intf.text)) - #LOG.info(confstr) conn.edit_config(target='running', config=confstr) LOG.debug("pending_delete_list (interfaces) = %s" % diff --git a/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_routing_driver.py b/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_routing_driver.py index 8c7af2c..7c186a1 100755 --- a/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_routing_driver.py +++ b/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_routing_driver.py @@ -74,7 +74,8 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): self._edit_running_config(conf_str, 'EMPTY_SNIPPET') def internal_network_added(self, ri, port): - gw_ip = port['subnets'][0]['gateway_ip'] + gw_ip = self._get_item( + port['subnets'], port['ip_info']['subnet_id'], 'id')['gateway_ip'] if self._is_port_v6(port): LOG.debug("Adding IPv6 internal network port: %(port)s for router " "%(r_id)s", {'port': port, 'r_id': ri.id}) @@ -107,7 +108,9 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): if self._is_global_router(ri): self._remove_sub_interface(ext_gw_port) else: - ex_gw_ip = ext_gw_port['subnets'][0]['gateway_ip'] + ex_gw_ip = self._get_item( + ext_gw_port['subnets'], + ext_gw_port['ip_info']['subnet_id'], 'id')['gateway_ip'] if (ex_gw_ip and ext_gw_port['device_owner'] == DEVICE_OWNER_ROUTER_GW): # Remove default route via this network's gateway ip @@ -216,26 +219,32 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): def _handle_external_gateway_added_global_router(self, ri, ext_gw_port): # TODO(bobmel): Get the HA virtual IP correctly - # TODO(sridar): - # This seems to work fine. Keeping this todo until more testing. + # NOTE(sridar): This seems to work fine. Keeping this todo until + # more testing. virtual_gw_port = ext_gw_port[ha.HA_INFO]['ha_port'] - sub_itfc_ip = virtual_gw_port['fixed_ips'][0]['ip_address'] + subnet_id = ext_gw_port['ip_info']['subnet_id'] + sub_itfc_ip = self._get_item(virtual_gw_port['fixed_ips'], + subnet_id)['ip_address'] if self._is_port_v6(ext_gw_port): LOG.debug("Adding IPv6 external network port: %(port)s for global " "router %(r_id)s", {'port': ext_gw_port['id'], 'r_id': ri.id}) self._create_sub_interface_v6(ri, ext_gw_port, True, sub_itfc_ip) else: - LOG.debug("Adding IPv4 external network port: %(port)s for global " - "router %(r_id)s", {'port': ext_gw_port['id'], - 'r_id': ri.id}) + LOG.debug("Adding IPv4 external network port: %(port)s on " + "subnet: (subnet)s for global router %(r_id)s", + {'port': ext_gw_port['id'], 'subnet': subnet_id, + 'r_id': ri.id}) self._create_sub_interface(ri, ext_gw_port, True, sub_itfc_ip) def _handle_external_gateway_added_normal_router(self, ri, ext_gw_port): # Default routes are mapped to tenant router VRFs . Global Router # is not aware of tenant routers with ext network assigned. Thus, # default route must be handled per tenant router. - ex_gw_ip = ext_gw_port['subnets'][0]['gateway_ip'] + ex_gw_ip = self._get_item( + ext_gw_port['subnets'], + ext_gw_port['ip_info']['subnet_id'], 'id')['gateway_ip'] + sub_interface = self._get_interface_name_from_hosting_port(ext_gw_port) vlan_id = self._get_interface_vlan_from_hosting_port(ext_gw_port) if (self._fullsync and @@ -266,11 +275,17 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): LOG.info(_LI("Sub-interface already exists, skipping")) return vrf_name = self._get_vrf_name(ri) - net_mask = netaddr.IPNetwork(port['ip_cidr']).netmask - hsrp_ip = port['fixed_ips'][0]['ip_address'] + net_mask = netaddr.IPNetwork(port['ip_info']['ip_cidr']).netmask + # get port's ip address for the subnet we're processing + hsrp_ip = self._get_item(port['fixed_ips'], + port['ip_info']['subnet_id'])['ip_address'] sub_interface = self._get_interface_name_from_hosting_port(port) - self._do_create_sub_interface(sub_interface, vlan, vrf_name, hsrp_ip, - net_mask, is_external) + if port['ip_info']['is_primary'] is True: + self._do_create_sub_interface( + sub_interface, vlan, vrf_name, hsrp_ip, net_mask, is_external) + else: + # this will only happen for global routers + self._do_set_secondary(sub_interface, hsrp_ip, net_mask) # Always do HSRP if ri.router.get(ha.ENABLED, False): if port.get(ha.HA_INFO) is not None: @@ -281,6 +296,12 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): 'port': port} raise cfg_exc.HAParamsMissingException(**params) + def _do_set_secondary(self, sub_interface, ip, mask): + conf_str = ( + asr1k_snippets.SET_SUBINTERFACE_SECONDARY_IP % ( + sub_interface, ip, mask)) + self._edit_running_config(conf_str, 'SET_SUBINTERFACE_SECONDARY_IP') + def _do_create_sub_interface(self, sub_interface, vlan_id, vrf_name, ip, mask, is_external=False): is_multi_region_enabled = cfg.CONF.multi_region.enable_multi_region @@ -329,41 +350,31 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): def _set_nat_pool(self, ri, gw_port, is_delete): vrf_name = self._get_vrf_name(ri) if ri.router.get(ROUTER_ROLE_ATTR) == ROUTER_ROLE_HA_REDUNDANCY: - pool_ip = gw_port[ha.HA_INFO]['ha_port']['fixed_ips'][0][ - 'ip_address'] - pool_ip_prefix_len = gw_port['fixed_ips'][0]['prefixlen'] + the_port = gw_port[ha.HA_INFO]['ha_port'] else: - pool_ip = gw_port['fixed_ips'][0]['ip_address'] - pool_ip_prefix_len = gw_port['fixed_ips'][0]['prefixlen'] - # TODO(sridar) reverting to old model, needs more investigation - # and cleanup - # pool_info = gw_port['nat_pool_info'] - # pool_ip = pool_info['pool_ip'] + the_port = gw_port + subnet_id = gw_port['ip_info']['subnet_id'] + fixed_ip = self._get_item(the_port['fixed_ips'], subnet_id) + pool_ip = fixed_ip['ip_address'] + pool_ip_prefix_len = fixed_ip['prefixlen'] + #TODO(ebobmel) We need to modify the pool name generation if we + # will have multiple NAT pools per VRF pool_name = "%s_nat_pool" % (vrf_name) - #pool_net = netaddr.IPNetwork(pool_info['pool_cidr']) - #pool_net = netaddr.IPNetwork(gw_port['ip_cidr']) pool_net = "%s/%s" % (pool_ip, pool_ip_prefix_len) pool_net = netaddr.IPNetwork(pool_net) if self._fullsync and pool_ip in self._existing_cfg_dict['pools']: LOG.info(_LI("Pool already exists, skipping")) return - #LOG.debug("SET_NAT_POOL pool netmask: %s, gw_port %s" % ( - # pool_net.netmask, gw_port)) try: if is_delete: conf_str = asr1k_snippets.DELETE_NAT_POOL % ( pool_name, pool_ip, pool_ip, pool_net.netmask) - #self._edit_running_config(conf_str, '%s DELETE_NAT_POOL' % - # self.target_asr['name']) # TODO(update so that hosting device name is passed down) self._edit_running_config(conf_str, 'DELETE_NAT_POOL') - else: conf_str = asr1k_snippets.CREATE_NAT_POOL % ( pool_name, pool_ip, pool_ip, pool_net.netmask) - #self._edit_running_config(conf_str, '%s CREATE_NAT_POOL' % - # self.target_asr['name']) # TODO(update so that hosting device name is passed down) self._edit_running_config(conf_str, 'CREATE_NAT_POOL') #except cfg_exc.CSR1kvConfigException as cse: @@ -376,7 +387,9 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): self._existing_cfg_dict['routes']): LOG.debug("Default route already exists, skipping") return - ext_gw_ip = ext_gw_port['subnets'][0]['gateway_ip'] + ext_gw_ip = self._get_item( + ext_gw_port['subnets'], + ext_gw_port['ip_info']['subnet_id'], 'id')['gateway_ip'] if ext_gw_ip: vrf_name = self._get_vrf_name(ri) out_itfc = self._get_interface_name_from_hosting_port(ext_gw_port) @@ -385,7 +398,9 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): self._edit_running_config(conf_str, 'SET_DEFAULT_ROUTE_WITH_INTF') def _remove_default_route(self, ri, ext_gw_port): - ext_gw_ip = ext_gw_port['subnets'][0]['gateway_ip'] + ext_gw_ip = self._get_item( + ext_gw_port['subnets'], + ext_gw_port['ip_info']['subnet_id'], 'id')['gateway_ip'] if ext_gw_ip: vrf_name = self._get_vrf_name(ri) out_itfc = self._get_interface_name_from_hosting_port(ext_gw_port) @@ -405,29 +420,40 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): priority = ri.router[ha.DETAILS][ha.PRIORITY] port_ha_info = port[ha.HA_INFO] group = port_ha_info['group'] - ip = port_ha_info['ha_port']['fixed_ips'][0]['ip_address'] + subnet_id = port['ip_info']['subnet_id'] + ip = self._get_item(port_ha_info['ha_port']['fixed_ips'], + subnet_id)['ip_address'] vlan = port['hosting_info']['segmentation_id'] if ip and group and priority: vrf_name = self._get_vrf_name(ri) + is_primary = port['ip_info']['is_primary'] sub_interface = self._get_interface_name_from_hosting_port(port) - self._do_set_ha_hsrp(sub_interface, vrf_name, - priority, group, ip, vlan) + self._do_set_ha_hsrp(sub_interface, vrf_name, priority, group, ip, + vlan, is_primary) def _do_set_ha_hsrp(self, sub_interface, vrf_name, priority, group, - ip, vlan): - conf_str = asr1k_snippets.SET_INTC_ASR_HSRP_EXTERNAL % (sub_interface, - group, - priority, - group, ip, - group, group, - group, vlan) - self._edit_running_config(conf_str, 'SET_INTC_ASR_HSRP_EXTERNAL') + ip, vlan, is_primary=True): + if is_primary is True: + conf_str = asr1k_snippets.SET_INTC_ASR_HSRP_EXTERNAL % ( + sub_interface, + group, + priority, + group, ip, + group, group, + group, vlan) + self._edit_running_config(conf_str, 'SET_INTC_ASR_HSRP_EXTERNAL') + else: + conf_str = asr1k_snippets.SET_INTC_ASR_SECONDARY_HSRP_EXTERNAL % ( + sub_interface, + group, ip) + self._edit_running_config(conf_str, + 'SET_INTC_ASR_SECONDARY_HSRP_EXTERNAL') def _create_sub_interface_v6(self, ri, port, is_external=False, gw_ip=""): if self._v6_port_needs_config(port) is not True: return vrf_name = self._get_vrf_name(ri) - ip_cidr = port['ip_cidr'] + ip_cidr = port['ip_info']['ip_cidr'] vlan = self._get_interface_vlan_from_hosting_port(port) sub_interface = self._get_interface_name_from_hosting_port(port) self._do_create_sub_interface_v6(sub_interface, vlan, vrf_name, @@ -486,6 +512,20 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): return False return True + @staticmethod + def _get_item(list_containing_dicts_entries, attribute_value, + attribute_name='subnet_id'): + """Searches a list of dicts and returns the first matching entry + + The dict entry returned contains the attribute 'attribute_name' whose + value equals 'attribute_value'. If no such dict is found in the list + an empty dict is returned. + """ + for item in list_containing_dicts_entries: + if item.get(attribute_name) == attribute_value: + return item + return {} + @staticmethod def _port_is_hsrp(port): hsrp_types = [bc.constants.DEVICE_OWNER_ROUTER_HA_INTF] @@ -496,9 +536,11 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): return (ri.router.get(ROUTER_ROLE_ATTR) == cisco_constants.ROUTER_ROLE_GLOBAL) - @staticmethod - def _is_port_v6(port): - return netaddr.IPNetwork(port['subnets'][0]['cidr']).version == 6 + @classmethod + def _is_port_v6(cls, port): + cidr = cls._get_item(port['subnets'], + port['ip_info']['subnet_id'], 'id')['cidr'] + return netaddr.IPNetwork(cidr).version == 6 @staticmethod def _get_hsrp_grp_num_from_ri(ri): @@ -507,7 +549,7 @@ class ASR1kRoutingDriver(iosxe_driver.IosXeRoutingDriver): def _add_internal_nw_nat_rules(self, ri, port, ext_port): vrf_name = self._get_vrf_name(ri) acl_no = self._generate_acl_num_from_port(port) - internal_cidr = port['ip_cidr'] + internal_cidr = port['ip_info']['ip_cidr'] internal_net = netaddr.IPNetwork(internal_cidr).network net_mask = netaddr.IPNetwork(internal_cidr).hostmask inner_itfc = self._get_interface_name_from_hosting_port(port) diff --git a/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_snippets.py b/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_snippets.py index d43e1d7..8491f18 100755 --- a/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_snippets.py +++ b/networking_cisco/plugins/cisco/cfg_agent/device_drivers/asr1k/asr1k_snippets.py @@ -81,6 +81,20 @@ CREATE_SUBINTERFACE_EXT_REGION_ID_WITH_ID = """ """ +# =================================================== +# Add secondary ip for additional subnets +# $(config)interface GigabitEthernet 2.500 +# $(config)ip address 192.168.0.1 255.255.255.0 secondary +# =================================================== +SET_SUBINTERFACE_SECONDARY_IP = """ + + + interface %s + ip address %s %s secondary + + +""" + # =================================================== # Enable HSRP on a Subinterface # $(config)interface GigabitEthernet0/0/0.314 @@ -129,6 +143,20 @@ SET_INTC_ASR_HSRP_EXTERNAL = """ """ +# =================================================== +# Enable HSRP on a External Network Subinterface secondary IP +# $(config)interface GigabitEthernet0/0/0.314 +# $(config)standby 1621 ip 10.0.3.1 secondary +# =================================================== +SET_INTC_ASR_SECONDARY_HSRP_EXTERNAL = """ + + + interface %s + standby %s ip %s secondary + + +""" + # =========================================================================== # Set Static source translation on an interface # Syntax: ip nat inside source static diff --git a/networking_cisco/plugins/cisco/cfg_agent/service_helpers/routing_svc_helper.py b/networking_cisco/plugins/cisco/cfg_agent/service_helpers/routing_svc_helper.py index 9256df8..a90e720 100755 --- a/networking_cisco/plugins/cisco/cfg_agent/service_helpers/routing_svc_helper.py +++ b/networking_cisco/plugins/cisco/cfg_agent/service_helpers/routing_svc_helper.py @@ -17,6 +17,7 @@ import eventlet import netaddr import pprint as pp +from operator import itemgetter from oslo_config import cfg from oslo_log import log as logging import oslo_messaging @@ -30,6 +31,8 @@ from neutron.common import topics from neutron.common import utils as common_utils from neutron import context as n_context +from neutron_lib import exceptions as n_lib_exc + from networking_cisco._i18n import _, _LE, _LI, _LW from networking_cisco import backwards_compatibility as bc from networking_cisco.plugins.cisco.cfg_agent import cfg_exceptions @@ -54,6 +57,16 @@ SYNC_ROUTERS_MAX_CHUNK_SIZE = 64 SYNC_ROUTERS_MIN_CHUNK_SIZE = 8 +class IPAddressMissingException(n_lib_exc.NeutronException): + message = _("Router port %(port_id)s has no IP address on subnet " + "%(subnet_id)s.") + + +class MultipleIPv4SubnetsException(n_lib_exc.NeutronException): + message = _("There should not be multiple IPv4 subnets %(subnets)s on " + "router port %(port_id)s") + + class RouterInfo(object): """Wrapper class around the (neutron) router dictionary. @@ -726,9 +739,41 @@ class RoutingServiceHelper(object): self._enable_router_interface(ri, port) def _process_new_ports(self, ri, new_ports, ex_gw_port, list_port_ids_up): + #TODO(bmelande): 1. We need to handle the case where an external + # network, to which a global router is connected, + # is given another subnet. The global router must + # then attached to that subnet. That attachment + # does NOT result in a new router port. Instead, it + # is done as an update to an EXISTING router port + # which gets another ip address (from the newly + # added subnet. for p in new_ports: - self._set_subnet_info(p) + # We sort the port's subnets on subnet_id so we can be sure that + # the same ip address is used as primary on the HA master router + # as well as on all HA backup routers. + port_subnets = sorted(p['subnets'], key=itemgetter('id')) + + num_subnets_on_port = len(port_subnets) + LOG.debug("Number of subnets associated with router port = %d" % + num_subnets_on_port) + if (ri.router[ROUTER_ROLE_ATTR] is None and + num_subnets_on_port > 1): + LOG.error(_LE("Ignoring router port with multiple IPv4 " + "subnets associated")) + raise MultipleIPv4SubnetsException( + port_id=p['id'], subnets=pp.pformat(port_subnets)) + + # Configure the primary IP address + self._set_subnet_info(p, port_subnets[0]['id']) self._internal_network_added(ri, p, ex_gw_port) + + # Process the secondary subnets. Only router ports of global + # routers can have multiple ipv4 subnets since we connect such + # routers to external networks using regular router ports. + for p_sn in port_subnets[1:]: + self._set_subnet_info(p, p_sn['id'], is_primary=False) + self._internal_network_added(ri, p, ex_gw_port) + ri.internal_ports.append(p) list_port_ids_up.append(p['id']) @@ -738,13 +783,37 @@ class RoutingServiceHelper(object): ri.internal_ports.remove(p) def _process_gateway_set(self, ri, ex_gw_port, list_port_ids_up): - self._set_subnet_info(ex_gw_port) + # We sort the port's subnets on subnet_id so we can be sure that + # the same ip address is used as primary on the HA master router + # as well as on all HA backup routers. + gw_port_subnets = sorted(ex_gw_port['subnets'], key=itemgetter('id')) + + # Configure the primary IP address + self._set_subnet_info(ex_gw_port, gw_port_subnets[0]['id']) self._external_gateway_added(ri, ex_gw_port) + + # Process the secondary subnets + for gw_p_sn in gw_port_subnets[1:]: + self._set_subnet_info(ex_gw_port, gw_p_sn['id'], is_primary=False) + self._external_gateway_added(ri, ex_gw_port) + list_port_ids_up.append(ex_gw_port['id']) def _process_gateway_cleared(self, ri, ex_gw_port): + # We sort the port's subnets on subnet_id so we can be sure that + # the same ip address is used as primary on the HA master router + # as well as on all HA backup routers. + gw_port_subnets = sorted(ex_gw_port['subnets'], key=itemgetter('id')) + + # Deconfigure the primary IP address + self._set_subnet_info(ex_gw_port, gw_port_subnets[0]['id']) self._external_gateway_removed(ri, ex_gw_port) + # Process the secondary subnets + for gw_p_sn in gw_port_subnets[1:]: + self._set_subnet_info(ex_gw_port, gw_p_sn['id'], is_primary=False) + self._external_gateway_removed(ri, ex_gw_port) + def _add_rid_to_vrf_list(self, ri): # not needed in base service helper pass @@ -1074,26 +1143,14 @@ class RoutingServiceHelper(object): ri.routes = new_routes @staticmethod - def _set_subnet_info(port): - ips = port['fixed_ips'] + def _set_subnet_info(port, subnet_id, is_primary=True): + + ips = [i['ip_address'] for i in port['fixed_ips'] + if i['subnet_id'] == subnet_id] if not ips: - raise Exception(_("Router port %s has no IP address") % port['id']) - if len(ips) > 1: - LOG.error(_LE("Ignoring multiple IPs on router port %s"), - port['id']) - - port_subnets = port['subnets'] - - num_subnets_on_port = len(port_subnets) - LOG.debug("number of subnets associated with port = %d" % - num_subnets_on_port) - # TODO(What should we do if multiple subnets are somehow associated) - # TODO(with a port?) - if (num_subnets_on_port > 1): - LOG.error(_LE("Ignoring port with multiple subnets associated")) - raise Exception(("Multiple subnets configured on port. %s") % - pp.pformat(port_subnets)) - else: - subnet = port_subnets[0] - prefixlen = netaddr.IPNetwork(subnet['cidr']).prefixlen - port['ip_cidr'] = "%s/%s" % (ips[0]['ip_address'], prefixlen) + raise IPAddressMissingException(port_id=port['id'], + subnet_id=subnet_id) + subnet = port['subnets'][0] + prefixlen = netaddr.IPNetwork(subnet['cidr']).prefixlen + port['ip_info'] = {'subnet_id': subnet_id, 'is_primary': is_primary, + 'ip_cidr': "%s/%s" % (ips[0], prefixlen)} diff --git a/networking_cisco/plugins/cisco/cfg_agent/service_helpers/routing_svc_helper_aci.py b/networking_cisco/plugins/cisco/cfg_agent/service_helpers/routing_svc_helper_aci.py index c2c8ef3..3e8e2d5 100644 --- a/networking_cisco/plugins/cisco/cfg_agent/service_helpers/routing_svc_helper_aci.py +++ b/networking_cisco/plugins/cisco/cfg_agent/service_helpers/routing_svc_helper_aci.py @@ -19,8 +19,11 @@ from oslo_log import log as logging from networking_cisco import backwards_compatibility as bc from networking_cisco.plugins.cisco.cfg_agent.service_helpers import ( routing_svc_helper as helper) +from networking_cisco.plugins.cisco.common import (cisco_constants as + c_constants) from networking_cisco.plugins.cisco.extensions import routerrole + ROUTER_ROLE_ATTR = routerrole.ROUTER_ROLE_ATTR LOG = logging.getLogger(__name__) @@ -33,11 +36,15 @@ class RoutingServiceHelperAci(helper.RoutingServiceHelper): self._router_ids_by_vrf = {} self._router_ids_by_vrf_and_ext_net = {} + def _is_global_router(self, ri): + return (ri.router.get(ROUTER_ROLE_ATTR) == + c_constants.ROUTER_ROLE_GLOBAL) + def _process_new_ports(self, ri, new_ports, ex_gw_port, list_port_ids_up): # Only add internal networks if we have an # external gateway -- otherwise we have no parameters # to use to configure the interface (e.g. VRF, IP, etc.) - if ex_gw_port: + if ex_gw_port or self._is_global_router(ri): super(RoutingServiceHelperAci, self)._process_new_ports( ri, new_ports, ex_gw_port, list_port_ids_up) @@ -51,7 +58,7 @@ class RoutingServiceHelperAci(helper.RoutingServiceHelper): # the relevant information (VRF and external network # parameters), which come from the GW port. Go ahead # and remove the interface from our internal state - if gw_port: + if gw_port or self._is_global_router(ri): self._internal_network_removed(ri, p, gw_port) ri.internal_ports.remove(p) diff --git a/networking_cisco/plugins/cisco/common/cisco_ios_xe_simulator.py b/networking_cisco/plugins/cisco/common/cisco_ios_xe_simulator.py new file mode 100644 index 0000000..e608d9f --- /dev/null +++ b/networking_cisco/plugins/cisco/common/cisco_ios_xe_simulator.py @@ -0,0 +1,239 @@ +# Copyright 2016 Cisco Systems, Inc. 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. + +# A tiny and simple Cisco IOS XE running config simulator. +# The intended use is to allow a developer to observe how the running config +# of an IOS XE device evolves as CLI commands are issued. +# +# Simple implies here that no CLI syntax or semantical checks are made so it +# is entirely up to the command issuer to ensure the correctness of the +# commands and their arguments. +# +# Bob Melander (bob.melander@gmail.com) + +import re +import six + +from oslo_utils import timeutils + + +class CiscoIOSXESimulator(object): + + # set of commands to be logged only + log_only_commands = set() + # set of commands bound to immediately preceding line + parent_bound_commands = {'exit-address-family'} + exclamation = {'vrf definition', ' exit-address-family'} + + def __init__(self, path, host_ip, netmask, port, username, password, + device_params, mgmt_interface, timeout): + self.host_ip = host_ip + self.netmask = netmask + self.port = port + self.username = username + self.password = password + self.device_params = device_params + self.mgmt_interface = mgmt_interface + self.timeout = timeout + self.last_update = timeutils.utcnow() + self.rc = self._get_dict() + self._set_default_config() + + def get_config(self): + change_date = timeutils.strtime(self.last_update, '%a %b %d %Y') + change_time = timeutils.strtime(self.last_update, '%H:%M:%S') + intro_lines = ("! Last configuration change at " + change_time + " " + + "UTC " + change_date + " by " + self.username + "\n!\n") + intro_lines += ("hostname ASR-1002X-" + + self.host_ip.replace('.', '_') + "\n!\n") + intro_lines += ("boot-start-marker\nboot system flash " + "bootflash:/asr1002x-simulated.03.16.00.S-ext." + "SPA.bin\nboot-end-marker\n!\n") + rc_data = {'rc_str': intro_lines} + cmds = sorted(self.rc.keys()) + if 'vrf' in cmds: + cmds.remove('vrf') + cmds.insert(0, 'vrf') + #for cmd, args in sorted(six.iteritems(self.rc)): + for cmd in cmds: + args = self.rc[cmd] + line = cmd + self._build_line(rc_data, args, line, 0) + print(rc_data['rc_str']) + return rc_data['rc_str'] + + def edit_config(self, snippet): + command_lines = self._get_command_lines(snippet) + if not command_lines: + return + self._process_next_level(self.rc, self.rc, command_lines, None, True) + self.last_update = timeutils.utcnow() + return True + + def _set_default_config(self): + mgmt_gw_ip = '.'.join((self.host_ip.split('.')[:-1]) + ['1']) + command_chunks = [ + ["vrf definition Mgmt-intf", + "address-family ipv4", + "exit-address-family", + "address-family ipv6", + "exit-address-family"], + ["interface " + self.mgmt_interface, + "vrf forwarding Mgmt-intf", + "ip address " + self.host_ip + " " + self.netmask, + "negotiation auto"], + ["ip tftp source - interface " + self.mgmt_interface], + ["ip route vrf Mgmt - intf 0.0.0.0 0.0.0.0 " + mgmt_gw_ip], + ["ip ssh source - interface " + self.mgmt_interface], + ["ip ssh version 2"] + ] + for commands in command_chunks: + self._process_next_level(self.rc, self.rc, commands, None, True) + + def _build_line(self, rc_data, current, baseline, level): + for string, the_rest in sorted(six.iteritems(current)): + if string == 'EOL': + continue + #line = baseline + line = " " if baseline == "" and level >= 1 else baseline + #line += ' ' + string if line != "" else string + line += ' ' + string if line != "" and line != " " else string + if 'EOL' in the_rest: + #termination = "\n!\n" if self._to_exclamate(line) else "\n" + if self._to_exclamate(line): + termination = "\n !\n" if level >= 1 else "\n!\n" + else: + #termination = " \n" if level == 1 else "\n" + termination = "\n" + rc_data['rc_str'] += line + termination + line = "" + self._build_line(rc_data, the_rest, line, level + 1) + if level == 0: + rc_data['rc_str'] += "!\n" + + def _to_exclamate(self, line): + for statement in self.exclamation: + if line.startswith(statement): + return True + return False + + def _process_next_level(self, parent, current, remaining_lines, + last_processed, is_root=False): + if not remaining_lines: + return + pre, cmd_line = self._get_command_prepending(remaining_lines[0]) + if pre is None: + self._process_set(cmd_line, parent, current, + remaining_lines, last_processed, is_root) + elif pre.lower() == "no": + self._process_unset(cmd_line.split(" "), current) + + def _process_set(self, cmd_line, parent, current, remaining_lines, + last_processed, is_root): + cmd, args = self._get_command_and_args(cmd_line) + if cmd in self.log_only_commands: + self._process_next_level(parent, current, + remaining_lines[1:], last_processed) + return + if cmd in self.parent_bound_commands: + this_one = last_processed.get(cmd) + start = last_processed + else: + this_one = parent.get(cmd) + start = current + if this_one is None: + this_one, current_parent = self._get_successor_and_its_parent( + parent, cmd, start, is_root) + else: + current_parent = start + for arg in args: + next_one, current_parent = self._get_successor_and_its_parent( + current_parent, arg, this_one, is_root) + this_one = next_one + this_one['EOL'] = True + if is_root is True: + current = this_one + self._process_next_level(current_parent, current, remaining_lines[1:], + this_one) + + def _process_unset(self, remaining, current): + if not remaining: + return + arg = remaining[0] + rest = remaining[1:] + if arg in current: + if not rest: + del current[arg] + else: + self._process_unset(rest, current[arg]) + num_items = len(current[arg]) + if num_items == 0: + del current[arg] + + def _get_successor_and_its_parent(self, parent, string, current, is_root): + successor = current.get(string) + if successor is None: + successor = self._get_dict() + current[string] = successor + current_parent = parent if is_root is False else successor + else: + current_parent = current + return successor, current_parent + + def _get_command_lines(self, snippet): + if not snippet: + return [] + lines = snippet.split('\n') + commands = [] + for line in lines: + if self._should_skip_line(line): + continue + cmd = self._get_embedded_command_string(line) + if cmd is not None: + commands.append(cmd) + return commands + + def _should_skip_line(self, line): + if line == "": + return True + if line.find("config>") != -1: + return True + elif line.find("cli-config-data>") != -1: + return True + return False + + def _get_embedded_command_string(self, line): + match_obj = re.match(r'\s*(.*)\s*', line) + if match_obj: + return match_obj.group(1) + return None + + def _get_command_prepending(self, cmd): + match_obj = re.match(r'\s*(no|do) (.*)\s*', cmd) + if match_obj: + return match_obj.group(1), match_obj.group(2) + return None, cmd + + def _get_command_and_args(self, cmd_line): + str_list = cmd_line.split(" ") + return str_list[0], str_list[1:] + + def _get_dict(self): + return {} + + +# A simple Cisco IOS XE CLI simulator +class FakeRunningConfig(object): + def __init__(self, rc): + self._raw = rc diff --git a/networking_cisco/plugins/cisco/db/l3/ha_db.py b/networking_cisco/plugins/cisco/db/l3/ha_db.py index bc89d7f..d51c8a6 100644 --- a/networking_cisco/plugins/cisco/db/l3/ha_db.py +++ b/networking_cisco/plugins/cisco/db/l3/ha_db.py @@ -430,8 +430,13 @@ class HA_db_mixin(object): # Now add gw to redundancy routers rr_ids = [] for r_b_db in router_db.redundancy_bindings: - spec = {EXTERNAL_GW_INFO: copy.copy(router[EXTERNAL_GW_INFO])} - spec[EXTERNAL_GW_INFO].pop('external_fixed_ips', None) + spec = {EXTERNAL_GW_INFO: copy.deepcopy(router[EXTERNAL_GW_INFO])} + if spec[EXTERNAL_GW_INFO]['external_fixed_ips']: + # Ensure ip addresses are not specified as they cannot be + # same as visible router's ip addresses. + for e_fixed_ip in spec[EXTERNAL_GW_INFO]['external_fixed_ips']: + e_fixed_ip.pop('ip_address', None) + #spec[EXTERNAL_GW_INFO].pop('external_fixed_ips', None) spec[ha.ENABLED] = False self._update_router_no_notify( context, r_b_db.redundancy_router_id, {'router': spec}) @@ -682,7 +687,7 @@ class HA_db_mixin(object): return r_ha_g def _get_fixed_ips_subnets(self, fixed_ips): - subnets = copy.copy(fixed_ips) + subnets = copy.deepcopy(fixed_ips) for s in subnets: s.pop('ip_address', None) return subnets diff --git a/networking_cisco/plugins/cisco/db/l3/l3_router_appliance_db.py b/networking_cisco/plugins/cisco/db/l3/l3_router_appliance_db.py index 54b758a..7264182 100644 --- a/networking_cisco/plugins/cisco/db/l3/l3_router_appliance_db.py +++ b/networking_cisco/plugins/cisco/db/l3/l3_router_appliance_db.py @@ -44,7 +44,7 @@ from neutron.extensions import providernet as pr_net from neutron_lib import exceptions as n_exc from networking_cisco import backwards_compatibility as bc -from networking_cisco._i18n import _, _LE, _LI, _LW +from networking_cisco._i18n import _, _LE, _LI from networking_cisco.plugins.cisco.common import cisco_constants from networking_cisco.plugins.cisco.db.device_manager import hd_models from networking_cisco.plugins.cisco.db.l3 import l3_models @@ -67,6 +67,7 @@ VM_CATEGORY = ciscohostingdevicemanager.VM_CATEGORY L3_ROUTER_NAT = bc.constants.L3 HOSTING_DEVICE_ATTR = routerhostingdevice.HOSTING_DEVICE_ATTR ROUTER_ROLE_GLOBAL = cisco_constants.ROUTER_ROLE_GLOBAL +ROUTER_ROLE_LOGICAL_GLOBAL = cisco_constants.ROUTER_ROLE_LOGICAL_GLOBAL ROUTER_ROLE_HA_REDUNDANCY = cisco_constants.ROUTER_ROLE_HA_REDUNDANCY DICT_EXTEND_FUNCTIONS = ['_extend_router_dict_routertype', @@ -1064,13 +1065,17 @@ class L3RouterApplianceDBMixin(extraroute_db.ExtraRoute_dbonly_mixin): @lockutils.synchronized('routerbacklog', 'neutron-') def _process_backlogged_routers(self): - self.ensure_global_router_cleanup() + e_context = n_context.get_admin_context() + for r_type, drv in self._router_drivers.items(): + if drv is not None: + LOG.debug('Calling pre_backlog_processing for router type %s', + r_type) + drv.pre_backlog_processing(e_context) if self._refresh_router_backlog: self._sync_router_backlog() if not self._backlogged_routers: LOG.debug('No routers in backlog %s' % self._backlogged_routers) return - e_context = n_context.get_admin_context() scheduled_routers = [] LOG.info(_LI('Processing router (scheduling) backlog')) # try to reschedule @@ -1111,50 +1116,11 @@ class L3RouterApplianceDBMixin(extraroute_db.ExtraRoute_dbonly_mixin): for ni in self.get_notifiers(e_context, scheduled_routers): if ni['notifier']: ni['notifier'].routers_updated(e_context, ni['routers']) - - def ensure_global_router_cleanup(self): - """TODO: Function to be moved into router type driver. - - This function should be moved into the router type driver. - This will be done when the router type driver api is revised. - """ - e_context = n_context.get_admin_context() - l3plugin = bc.get_plugin(L3_ROUTER_NAT) - filters = {routerrole.ROUTER_ROLE_ATTR: [ROUTER_ROLE_GLOBAL]} - global_routers = l3plugin.get_routers(e_context, filters=filters) - if not global_routers: - LOG.debug("There are no global routers") - return - for gr in global_routers: - filters = { - HOSTING_DEVICE_ATTR: [gr[HOSTING_DEVICE_ATTR]], - routerrole.ROUTER_ROLE_ATTR: [ROUTER_ROLE_HA_REDUNDANCY, None] - } - invert_filters = {'gw_port_id': [None]} - num_rtrs = l3plugin.get_routers_count_extended( - e_context, filters=filters, invert_filters=invert_filters) - LOG.debug("Global router %(name)s[%(id)s] with hosting_device " - "%(hd)s has %(num)d routers with gw_port set on that " - "device", - {'name': gr['name'], 'id': gr['id'], - 'hd': gr[HOSTING_DEVICE_ATTR], 'num': num_rtrs, }) - if num_rtrs == 0: - LOG.warning(_LW("Global router:%(name)s[id:%(id)s] is present " - "for hosting device:%(hd)s but there are no " - "tenant or redundancy routers with gateway set " - "on that hosting device. Proceeding to delete " - "global router."), - {'name': gr['name'], 'id': gr['id'], - 'hd': gr[HOSTING_DEVICE_ATTR]}) - try: - l3plugin.delete_router( - e_context, gr['id'], unschedule=False) - except (exc.ObjectDeletedError, l3.RouterNotFound) as e: - LOG.warning(e) - driver = self._get_router_type_driver( - e_context, gr[routertype.TYPE_ATTR]) - driver._conditionally_remove_logical_global_router( - e_context, gr) + for r_type, drv in self._router_drivers.items(): + if drv is not None: + LOG.debug('Calling post_backlog_processing for router type %s', + r_type) + drv.post_backlog_processing(e_context) def _setup_backlog_handling(self): LOG.debug('Activating periodic backlog processor') diff --git a/networking_cisco/plugins/cisco/device_manager/plugging_drivers/hw_vlan_trunking_driver.py b/networking_cisco/plugins/cisco/device_manager/plugging_drivers/hw_vlan_trunking_driver.py index 556cdb6..dba549b 100644 --- a/networking_cisco/plugins/cisco/device_manager/plugging_drivers/hw_vlan_trunking_driver.py +++ b/networking_cisco/plugins/cisco/device_manager/plugging_drivers/hw_vlan_trunking_driver.py @@ -18,12 +18,15 @@ from oslo_utils import excutils from networking_cisco._i18n import _LE from networking_cisco import backwards_compatibility as bc +from networking_cisco.plugins.cisco.common import cisco_constants from networking_cisco.plugins.cisco.device_manager import config import networking_cisco.plugins.cisco.device_manager.plugging_drivers as plug LOG = logging.getLogger(__name__) DEVICE_OWNER_ROUTER_GW = bc.constants.DEVICE_OWNER_ROUTER_GW +GLOBAL_ROUTER_ROLES = [cisco_constants.ROUTER_ROLE_GLOBAL, + cisco_constants.ROUTER_ROLE_LOGICAL_GLOBAL] class HwVLANTrunkingPlugDriver(plug.PluginSidePluggingDriver): @@ -66,7 +69,7 @@ class HwVLANTrunkingPlugDriver(plug.PluginSidePluggingDriver): def extend_hosting_port_info(self, context, port_db, hosting_device, hosting_info): hosting_info['segmentation_id'] = port_db.hosting_info.segmentation_id - is_external = (port_db.device_owner == DEVICE_OWNER_ROUTER_GW) + is_external = (port_db.networks.external is not None) hosting_info['physical_interface'] = self._get_interface_info( hosting_device['id'], port_db.network_id, is_external) diff --git a/networking_cisco/plugins/cisco/l3/drivers/__init__.py b/networking_cisco/plugins/cisco/l3/drivers/__init__.py index ab848ef..a4b2640 100644 --- a/networking_cisco/plugins/cisco/l3/drivers/__init__.py +++ b/networking_cisco/plugins/cisco/l3/drivers/__init__.py @@ -400,3 +400,27 @@ class L3RouterBaseDriver(object): config agent drivers corresponding to this router type driver. """ return "" + + def pre_backlog_processing(self, context): + """Perform driver specific processing before backlog is processed. + + :param context: admin neutron context + + This function is invoked before the router plugin is processing the + backlog of unscheduled routers. It allows the router type driver to + perform any tasks that should be performed before the backlog is + processed. + """ + pass + + def post_backlog_processing(self, context): + """Perform driver specific processing after backlog is processed. + + :param context: admin neutron context + + This function is invoked after the router plugin has processed the + backlog of unscheduled routers. It allows the router type driver to + perform any tasks that should be performed after the backlog has been + processed. + """ + pass diff --git a/networking_cisco/plugins/cisco/l3/drivers/asr1k/asr1k_routertype_driver.py b/networking_cisco/plugins/cisco/l3/drivers/asr1k/asr1k_routertype_driver.py index 5848a4d..2c27dee 100644 --- a/networking_cisco/plugins/cisco/l3/drivers/asr1k/asr1k_routertype_driver.py +++ b/networking_cisco/plugins/cisco/l3/drivers/asr1k/asr1k_routertype_driver.py @@ -12,8 +12,6 @@ # License for the specific language governing permissions and limitations # under the License. -import copy - from oslo_config import cfg from oslo_log import log as logging from oslo_utils import uuidutils @@ -27,7 +25,7 @@ from neutron.extensions import l3 from neutron_lib import constants as l3_constants from neutron_lib import exceptions as n_exc -from networking_cisco._i18n import _ +from networking_cisco._i18n import _, _LW from networking_cisco import backwards_compatibility as bc from networking_cisco.plugins.cisco.common import cisco_constants from networking_cisco.plugins.cisco.db.l3 import ha_db @@ -197,6 +195,48 @@ class ASR1kL3RouterDriver(drivers.L3RouterBaseDriver): group_id += EXT_HSRP_GRP_OFFSET return group_id + def pre_backlog_processing(self, context): + filters = {routerrole.ROUTER_ROLE_ATTR: [ROUTER_ROLE_GLOBAL]} + global_routers = self._l3_plugin.get_routers(context, filters=filters) + if not global_routers: + LOG.debug("There are no global routers") + return + for gr in global_routers: + filters = { + HOSTING_DEVICE_ATTR: [gr[HOSTING_DEVICE_ATTR]], + routerrole.ROUTER_ROLE_ATTR: [ROUTER_ROLE_HA_REDUNDANCY, None] + } + invert_filters = {'gw_port_id': [None]} + num_rtrs = self._l3_plugin.get_routers_count_extended( + context, filters=filters, invert_filters=invert_filters) + LOG.debug("Global router %(name)s[%(id)s] with hosting_device " + "%(hd)s has %(num)d routers with gw_port set on that " + "device", + {'name': gr['name'], 'id': gr['id'], + 'hd': gr[HOSTING_DEVICE_ATTR], 'num': num_rtrs, }) + if num_rtrs == 0: + LOG.warning( + _LW("Global router:%(name)s[id:%(id)s] is present for " + "hosting device:%(hd)s but there are no tenant or " + "redundancy routers with gateway set on that hosting " + "device. Proceeding to delete global router."), + {'name': gr['name'], 'id': gr['id'], + 'hd': gr[HOSTING_DEVICE_ATTR]}) + self._delete_global_router(context, gr['id']) + filters = { + #TODO(bmelande): Filter on routertype of global router + #routertype.TYPE_ATTR: [routertype_id], + routerrole.ROUTER_ROLE_ATTR: [ROUTER_ROLE_LOGICAL_GLOBAL]} + log_global_routers = self._l3_plugin.get_routers( + context, filters=filters) + if log_global_routers: + log_global_router_id = log_global_routers[0]['id'] + self._delete_global_router(context, log_global_router_id, + logical=True) + + def post_backlog_processing(self, context): + pass + # ---------------- Create workflow functions ----------------- def _conditionally_add_global_router(self, context, tenant_router): @@ -238,7 +278,7 @@ class ASR1kL3RouterDriver(drivers.L3RouterBaseDriver): 'device_id': [global_router['id']], 'device_owner': [port_type]} connected_nets = { - p['network_id'] for p in + p['network_id']: p['fixed_ips'] for p in self._core_plugin.get_ports(context, filters=filters)} if ext_net_id in connected_nets: # already connected to the external network so we're done @@ -255,7 +295,8 @@ class ASR1kL3RouterDriver(drivers.L3RouterBaseDriver): port_type=DEVICE_OWNER_GLOBAL_ROUTER_GW): # When a global router is connected to an external network then a # special type of gateway port is created on that network. Such a - # port is called auxiliary gateway ports. A (logical) global router + # port is called auxiliary gateway ports. It has an ip address on + # each subnet of the external network. A (logical) global router # never has a traditional Neutron gateway port. filters = { 'device_id': [tenant_router['id']], @@ -264,7 +305,7 @@ class ASR1kL3RouterDriver(drivers.L3RouterBaseDriver): # the CIDR of that port's subnet gw_port = self._core_plugin.get_ports(context, filters=filters)[0] - fixed_ips = self._get_fixed_ips_subnets(gw_port['fixed_ips']) + fixed_ips = self._get_fixed_ips_subnets(context, gw_port) global_router_id = global_router['id'] with context.session.begin(subtransactions=True): aux_gw_port = self._core_plugin.create_port(context, { @@ -352,10 +393,9 @@ class ASR1kL3RouterDriver(drivers.L3RouterBaseDriver): context.session.add(r_ha_s_db) return logical_global_router - def _get_fixed_ips_subnets(self, fixed_ips): - subnets = copy.copy(fixed_ips) - for s in subnets: - s.pop('ip_address', None) + def _get_fixed_ips_subnets(self, context, gw_port): + nw = self._core_plugin.get_network(context, gw_port['network_id']) + subnets = [{'subnet_id': s} for s in nw['subnets']] return subnets def _provision_port_ha(self, context, ha_port, router, ha_binding_db=None): @@ -401,6 +441,10 @@ class ASR1kL3RouterDriver(drivers.L3RouterBaseDriver): hd_to_gr_dict = {r[HOSTING_DEVICE_ATTR]: r for r in global_routers} if global_routers: global_router_id = global_routers[0]['id'] + if not tenant_router or not tenant_router[l3.EXTERNAL_GW_INFO]: + # let l3 plugin's periodic backlog processing take care of the + # clean up of the global router + return ext_net_id = tenant_router[l3.EXTERNAL_GW_INFO]['network_id'] routertype_id = tenant_router[routertype.TYPE_ATTR] hd_id = tenant_router[HOSTING_DEVICE_ATTR] @@ -444,7 +488,8 @@ class ASR1kL3RouterDriver(drivers.L3RouterBaseDriver): (num_rtrs == 0 and update_operation is True)): # there are no tenant routers *on ext_net_id* that are serviced by # this global router so it's aux gw port can be deleted - self._delete_auxiliary_gateway_port(context, router_id, ext_net_id) + self._delete_auxiliary_gateway_ports(context, router_id, + ext_net_id) return True return False @@ -463,8 +508,8 @@ class ASR1kL3RouterDriver(drivers.L3RouterBaseDriver): if num_global_rtrs == 0: # there are no global routers *on ext_net_id* that are serviced by # this logical global router so it's aux gw VIP port can be deleted - self._delete_auxiliary_gateway_port(context, log_global_router_id, - ext_net_id) + self._delete_auxiliary_gateway_ports(context, log_global_router_id, + ext_net_id) filters[routerrole.ROUTER_ROLE_ATTR] = [ROUTER_ROLE_GLOBAL] total_num_global_rtrs = self._l3_plugin.get_routers_count( context, filters=filters) @@ -474,7 +519,7 @@ class ASR1kL3RouterDriver(drivers.L3RouterBaseDriver): self._delete_global_router(context, log_global_router_id, True) return False - def _delete_auxiliary_gateway_port( + def _delete_auxiliary_gateway_ports( self, context, router_id, net_id=None, port_type=DEVICE_OWNER_GLOBAL_ROUTER_GW): filters = { @@ -491,7 +536,7 @@ class ASR1kL3RouterDriver(drivers.L3RouterBaseDriver): def _delete_global_router(self, context, global_router_id, logical=False): # ensure we clean up any stale auxiliary gateway ports - self._delete_auxiliary_gateway_port(context, global_router_id) + self._delete_auxiliary_gateway_ports(context, global_router_id) try: if logical is True: # We use parent class method as no special operations beyond diff --git a/networking_cisco/plugins/cisco/l3/drivers/noop_routertype_driver.py b/networking_cisco/plugins/cisco/l3/drivers/noop_routertype_driver.py index 33118bd..861e22a 100644 --- a/networking_cisco/plugins/cisco/l3/drivers/noop_routertype_driver.py +++ b/networking_cisco/plugins/cisco/l3/drivers/noop_routertype_driver.py @@ -76,3 +76,9 @@ class NoopL3RouterDriver(drivers.L3RouterBaseDriver): def delete_floatingip_postcommit(self, context, fip_context): pass + + def pre_backlog_processing(self, context): + pass + + def post_backlog_processing(self, context): + pass diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/json/1/neutronclient_multi_subnets_ext_net.txt b/networking_cisco/tests/unit/cisco/cfg_agent/json/1/neutronclient_multi_subnets_ext_net.txt new file mode 100644 index 0000000..955b2e5 --- /dev/null +++ b/networking_cisco/tests/unit/cisco/cfg_agent/json/1/neutronclient_multi_subnets_ext_net.txt @@ -0,0 +1,172 @@ +(neutron) net-list ++--------------------------------------+---------+-----------------------------------------------------+ +| id | name | subnets | ++--------------------------------------+---------+-----------------------------------------------------+ +| 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | public | 7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41 172.16.6.32/27 | +| | | 05509041-00e0-45c3-bf38-c603911c1ea4 172.17.7.32/27 | +| 02232008-c78c-46b2-b712-678d85def46a | private | 54074049-aaf1-44d2-9843-99cdb10e3212 10.0.3.0/24 | ++--------------------------------------+---------+-----------------------------------------------------+ +(neutron) subnet-list ++--------------------------------------+-----------------+----------------+------------------------------------------------+ +| id | name | cidr | allocation_pools | ++--------------------------------------+-----------------+----------------+------------------------------------------------+ +| 7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41 | public-subnet | 172.16.6.32/27 | {"start": "172.16.6.34", "end": "172.16.6.62"} | +| 54074049-aaf1-44d2-9843-99cdb10e3212 | private-subnet | 10.0.3.0/24 | {"start": "10.0.3.2", "end": "10.0.3.254"} | +| 05509041-00e0-45c3-bf38-c603911c1ea4 | public-subnet-2 | 172.17.7.32/27 | {"start": "172.17.7.34", "end": "172.17.7.62"} | ++--------------------------------------+-----------------+----------------+------------------------------------------------+ +(neutron) router-list ++--------------------------------------+---------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| id | name | external_gateway_info | ++--------------------------------------+---------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 085eba49-7ec9-470a-ac37-e89606eba108 | router1_HA_backup_1 | {"network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", "external_fixed_ips": [{"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": | +| | | "172.16.6.45"}, {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.35"}]} | +| 25ecf24d-a3eb-426f-8871-22d7e78c5944 | Global-router-0000-000000000005 | null | +| 5dd41cc4-7cbd-444f-894b-589531d3686c | router1 | {"network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", "external_fixed_ips": [{"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": | +| | | "172.16.6.44"}, {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.34"}]} | +| 945d631c-0b37-4322-8dbe-c3759a3cac45 | Logical-Global-router | null | +| c5c5eb9e-4451-4936-9125-9a9634cb5d2e | Global-router-0000-000000000004 | null | ++--------------------------------------+---------------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------+ +(neutron) router-port-list router1 ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| id | name | mac_address | fixed_ips | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| 780a2d1a-6cae-4b2e-919e-bb5fb0ee0395 | | fa:16:3e:37:e3:d7 | {"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.44"} | +| | | | {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.34"} | +| 9747b0d0-9380-4674-8cd9-9bc0db62355c | | fa:16:3e:ae:75:c5 | {"subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212", "ip_address": "10.0.3.1"} | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +(neutron) router-show router1 ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Field | Value | ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| admin_state_up | True | +| cisco_ha:details | {"redundancy_routers": [{"priority": 97, "state": "STANDBY", "id": "085eba49-7ec9-470a-ac37-e89606eba108"}], "probe_connectivity": false, "priority": 100, "state": "ACTIVE", | +| | "redundancy_level": 1, "type": "HSRP"} | +| cisco_ha:enabled | True | +| description | | +| external_gateway_info | {"network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", "external_fixed_ips": [{"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.44"}, {"subnet_id": | +| | "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.34"}]} | +| id | 5dd41cc4-7cbd-444f-894b-589531d3686c | +| name | router1 | +| routerhost:hosting_device | 00000000-0000-0000-0000-000000000005 | +| routerrole:role | | +| routertype-aware-scheduler:auto_schedule | True | +| routertype-aware-scheduler:share_hosting_device | True | +| routertype:id | 00000000-0000-0000-0000-000000000003 | +| routes | | +| status | ACTIVE | +| tenant_id | 840995fdaaf44ad4ab972f06fd6fbc13 | ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +(neutron) router-port-list Global-router-0000-000000000005 ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| id | name | mac_address | fixed_ips | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| e678299a-0fbb-43f1-915c-a1c48c676bc6 | | fa:16:3e:04:d1:66 | {"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.48"} | +| | | | {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.38"} | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +(neutron) router-show Global-router-0000-000000000005 ++-------------------------------------------------+--------------------------------------+ +| Field | Value | ++-------------------------------------------------+--------------------------------------+ +| admin_state_up | True | +| cisco_ha:enabled | False | +| description | | +| external_gateway_info | | +| id | 25ecf24d-a3eb-426f-8871-22d7e78c5944 | +| name | Global-router-0000-000000000005 | +| routerhost:hosting_device | 00000000-0000-0000-0000-000000000005 | +| routerrole:role | Global | +| routertype-aware-scheduler:auto_schedule | False | +| routertype-aware-scheduler:share_hosting_device | True | +| routertype:id | 00000000-0000-0000-0000-000000000003 | +| routes | | +| status | ACTIVE | +| tenant_id | | ++-------------------------------------------------+--------------------------------------+ +(neutron) router-show router1_HA_backup_1 ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Field | Value | ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| admin_state_up | True | +| cisco_ha:enabled | False | +| description | | +| external_gateway_info | {"network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", "external_fixed_ips": [{"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.45"}, {"subnet_id": | +| | "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.35"}]} | +| id | 085eba49-7ec9-470a-ac37-e89606eba108 | +| name | router1_HA_backup_1 | +| routerhost:hosting_device | 00000000-0000-0000-0000-000000000004 | +| routerrole:role | HA-Redundancy | +| routertype-aware-scheduler:auto_schedule | True | +| routertype-aware-scheduler:share_hosting_device | True | +| routertype:id | 00000000-0000-0000-0000-000000000003 | +| routes | | +| status | ACTIVE | +| tenant_id | | ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +(neutron) router-port-list router1_HA_backup_1 ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| id | name | mac_address | fixed_ips | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| 121bf217-7224-435a-bb23-fdb9c79b35c1 | | fa:16:3e:33:26:8e | {"subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212", "ip_address": "10.0.3.3"} | +| 53e1c49f-8bad-4dc3-8e19-2202ab08fe53 | | fa:16:3e:fe:b7:79 | {"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.45"} | +| | | | {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.35"} | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +(neutron) router-show router1_HA_backup_1 ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Field | Value | ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| admin_state_up | True | +| cisco_ha:enabled | False | +| description | | +| external_gateway_info | {"network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", "external_fixed_ips": [{"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.45"}, {"subnet_id": | +| | "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.35"}]} | +| id | 085eba49-7ec9-470a-ac37-e89606eba108 | +| name | router1_HA_backup_1 | +| routerhost:hosting_device | 00000000-0000-0000-0000-000000000004 | +| routerrole:role | HA-Redundancy | +| routertype-aware-scheduler:auto_schedule | True | +| routertype-aware-scheduler:share_hosting_device | True | +| routertype:id | 00000000-0000-0000-0000-000000000003 | +| routes | | +| status | ACTIVE | +| tenant_id | | ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +(neutron) router-port-list Global-router-0000-000000000004 ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| id | name | mac_address | fixed_ips | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| 5931d51b-7806-4dd9-a024-2ed1c674782a | | fa:16:3e:40:96:dd | {"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.47"} | +| | | | {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.37"} | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +(neutron) router-show Global-router-0000-000000000004 ++-------------------------------------------------+--------------------------------------+ +| Field | Value | ++-------------------------------------------------+--------------------------------------+ +| admin_state_up | True | +| cisco_ha:enabled | False | +| description | | +| external_gateway_info | | +| id | c5c5eb9e-4451-4936-9125-9a9634cb5d2e | +| name | Global-router-0000-000000000004 | +| routerhost:hosting_device | 00000000-0000-0000-0000-000000000004 | +| routerrole:role | Global | +| routertype-aware-scheduler:auto_schedule | False | +| routertype-aware-scheduler:share_hosting_device | True | +| routertype:id | 00000000-0000-0000-0000-000000000003 | +| routes | | +| status | ACTIVE | +| tenant_id | | ++-------------------------------------------------+--------------------------------------+ +(mysql) select id,device_owner,device_id,network_id from ports; ++--------------------------------------+--------------------------+--------------------------------------+--------------------------------------+ +| port_id | device_owner | device_id | network_id | ++--------------------------------------+--------------------------+--------------------------------------+--------------------------------------+ +| 0b9c4564-9e42-4dfd-ab96-2cabee626aec | network:router_interface | 312cc5db-8749-46fe-82d9-d8492267902d | 02232008-c78c-46b2-b712-678d85def46a | +| 121bf217-7224-435a-bb23-fdb9c79b35c1 | network:router_interface | 085eba49-7ec9-470a-ac37-e89606eba108 | 02232008-c78c-46b2-b712-678d85def46a | +| 3fdf36c5-34a7-4aa3-8508-66b258377a68 | network:router_interface | 945d631c-0b37-4322-8dbe-c3759a3cac45 | 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | +| 53e1c49f-8bad-4dc3-8e19-2202ab08fe53 | network:router_gateway | 085eba49-7ec9-470a-ac37-e89606eba108 | 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | +| 5931d51b-7806-4dd9-a024-2ed1c674782a | network:router_interface | c5c5eb9e-4451-4936-9125-9a9634cb5d2e | 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | +| 780a2d1a-6cae-4b2e-919e-bb5fb0ee0395 | network:router_gateway | 5dd41cc4-7cbd-444f-894b-589531d3686c | 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | +| 9747b0d0-9380-4674-8cd9-9bc0db62355c | network:router_interface | 5dd41cc4-7cbd-444f-894b-589531d3686c | 02232008-c78c-46b2-b712-678d85def46a | +| e678299a-0fbb-43f1-915c-a1c48c676bc6 | network:router_interface | 25ecf24d-a3eb-426f-8871-22d7e78c5944 | 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | ++--------------------------------------+--------------------------+--------------------------------------+--------------------------------------+ + diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/json/1/router_dicts_multi_subnets_ext_net.json b/networking_cisco/tests/unit/cisco/cfg_agent/json/1/router_dicts_multi_subnets_ext_net.json new file mode 100644 index 0000000..946d937 --- /dev/null +++ b/networking_cisco/tests/unit/cisco/cfg_agent/json/1/router_dicts_multi_subnets_ext_net.json @@ -0,0 +1,728 @@ +[{"_interfaces": [{"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T11:27:27", + "description": null, + "device_id": "312cc5db-8749-46fe-82d9-d8492267902d", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.3.2", + "prefixlen": 24, + "subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T11:27:26", + "description": "", + "device_id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.3.1", + "prefixlen": 24, + "subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212"}], + "id": "9747b0d0-9380-4674-8cd9-9bc0db62355c", + "mac_address": "fa:16:3e:ae:75:c5", + "mt": 1450, + "name": "", + "network_id": "02232008-c78c-46b2-b712-678d85def46a", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "10.0.3.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.3.1", + "id": "54074049-aaf1-44d2-9843-99cdb10e3212", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "840995fdaaf44ad4ab972f06fd6fbc13", + "updated_at": "2017-02-28T11:27:26"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:82:59:fb", + "hosting_port_id": "0b9c4564-9e42-4dfd-ab96-2cabee626aec", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/4", + "segmentation_id": 1086}, + "id": "0b9c4564-9e42-4dfd-ab96-2cabee626aec", + "mac_address": "fa:16:3e:82:59:fb", + "mt": 1450, + "name": "", + "network_id": "02232008-c78c-46b2-b712-678d85def46a", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "10.0.3.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.3.1", + "id": "54074049-aaf1-44d2-9843-99cdb10e3212", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:25:56"}], + "admin_state_up": true, + "cisco_ha:details": {"priority": 100, + "probe_connectivity": false, + "redundancy_level": 1, + "redundancy_routers": [{"id": "085eba49-7ec9-470a-ac37-e89606eba108", + "priority": 97, + "state": "STANDBY"}], + "state": "ACTIVE", + "type": "HSRP"}, + "cisco_ha:enabled": true, + "description": "", + "external_gateway_info": {"external_fixed_ips": [{"ip_address": "172.16.6.44", + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.34", + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838"}, + "gw_port": {"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:15", + "description": "", + "device_id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.44", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.34", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:15", + "description": "", + "device_id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.44", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.34", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "id": "780a2d1a-6cae-4b2e-919e-bb5fb0ee0395", + "mac_address": "fa:16:3e:37:e3:d7", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:52:15"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:37:e3:d7", + "hosting_port_id": "780a2d1a-6cae-4b2e-919e-bb5fb0ee0395", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/5", + "segmentation_id": 1056}, + "id": "780a2d1a-6cae-4b2e-919e-bb5fb0ee0395", + "mac_address": "fa:16:3e:37:e3:d7", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:52:15"}, + "gw_port_id": "780a2d1a-6cae-4b2e-919e-bb5fb0ee0395", + "hosting_device": {"admin_state_up": true, + "booting_time": 360, + "created_at": "2017-02-28 11:27:21", + "credentials": {"password": "cisco", + "user_name": "stack"}, + "host_category": "Hardware", + "id": "00000000-0000-0000-0000-000000000005", + "management_ip_address": "10.0.100.7", + "name": "ASR1k template", + "protocol_port": 22, + "service_types": "router", + "status": "ACTIVE", + "template_id": "00000000-0000-0000-0000-000000000003", + "timeout": null}, + "id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "name": "router1", + "router_type": {"cfg_agent_driver": "networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k.asr1k_routing_driver.ASR1kRoutingDriver", + "cfg_agent_service_helper": "networking_cisco.plugins.cisco.cfg_agent.service_helpers.routing_svc_helper.RoutingServiceHelper", + "id": "00000000-0000-0000-0000-000000000003", + "name": "ASR1k_router"}, + "routerhost:hosting_device": "00000000-0000-0000-0000-000000000005", + "routerrole:role": null, + "routertype-aware-scheduler:auto_schedule": true, + "routertype-aware-scheduler:share_hosting_device": true, + "routertype:id": "00000000-0000-0000-0000-000000000003", + "routes": [], + "share_host": true, + "status": "ACTIVE", + "tenant_id": "840995fdaaf44ad4ab972f06fd6fbc13"}, + {"_interfaces": [{"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:18", + "description": null, + "device_id": "c5c5eb9e-4451-4936-9125-9a9634cb5d2e", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.47", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.37", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:18", + "description": null, + "device_id": "945d631c-0b37-4322-8dbe-c3759a3cac45", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.46", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.36", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "id": "3fdf36c5-34a7-4aa3-8508-66b258377a68", + "mac_address": "fa:16:3e:00:d7:f2", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:52:18"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:40:96:dd", + "hosting_port_id": "5931d51b-7806-4dd9-a024-2ed1c674782a", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/2", + "segmentation_id": 1056}, + "id": "5931d51b-7806-4dd9-a024-2ed1c674782a", + "mac_address": "fa:16:3e:40:96:dd", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:52:18"}], + "admin_state_up": true, + "cisco_ha:details": {"priority": 100, + "probe_connectivity": false, + "redundancy_level": 2, + "redundancy_routers": [{"id": "c5c5eb9e-4451-4936-9125-9a9634cb5d2e", + "priority": 100, + "state": "STANDBY"}, + {"id": "25ecf24d-a3eb-426f-8871-22d7e78c5944", + "priority": 103, + "state": "STANDBY"}], + "state": "ACTIVE", + "type": "HSRP"}, + "cisco_ha:enabled": true, + "description": null, + "external_gateway_info": null, + "gw_port_id": null, + "hosting_device": {"admin_state_up": true, + "booting_time": 360, + "created_at": "2017-02-28 11:27:21", + "credentials": {"password": "cisco", + "user_name": "stack"}, + "host_category": "Hardware", + "id": "00000000-0000-0000-0000-000000000004", + "management_ip_address": "10.0.100.6", + "name": "ASR1k template", + "protocol_port": 22, + "service_types": "router", + "status": "ACTIVE", + "template_id": "00000000-0000-0000-0000-000000000003", + "timeout": null}, + "id": "c5c5eb9e-4451-4936-9125-9a9634cb5d2e", + "name": "Global-router-0000-000000000004", + "router_type": {"cfg_agent_driver": "networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k.asr1k_routing_driver.ASR1kRoutingDriver", + "cfg_agent_service_helper": "networking_cisco.plugins.cisco.cfg_agent.service_helpers.routing_svc_helper.RoutingServiceHelper", + "id": "00000000-0000-0000-0000-000000000003", + "name": "ASR1k_router"}, + "routerhost:hosting_device": "00000000-0000-0000-0000-000000000004", + "routerrole:role": "Global", + "routertype-aware-scheduler:auto_schedule": false, + "routertype-aware-scheduler:share_hosting_device": true, + "routertype:id": "00000000-0000-0000-0000-000000000003", + "routes": [], + "share_host": true, + "status": "ACTIVE", + "tenant_id": ""}, + {"_interfaces": [{"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T11:27:27", + "description": null, + "device_id": "085eba49-7ec9-470a-ac37-e89606eba108", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.3.3", + "prefixlen": 24, + "subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T11:27:26", + "description": "", + "device_id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.3.1", + "prefixlen": 24, + "subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212"}], + "id": "9747b0d0-9380-4674-8cd9-9bc0db62355c", + "mac_address": "fa:16:3e:ae:75:c5", + "mt": 1450, + "name": "", + "network_id": "02232008-c78c-46b2-b712-678d85def46a", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "10.0.3.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.3.1", + "id": "54074049-aaf1-44d2-9843-99cdb10e3212", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "840995fdaaf44ad4ab972f06fd6fbc13", + "updated_at": "2017-02-28T11:27:26"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:33:26:8e", + "hosting_port_id": "121bf217-7224-435a-bb23-fdb9c79b35c1", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/2", + "segmentation_id": 1086}, + "id": "121bf217-7224-435a-bb23-fdb9c79b35c1", + "mac_address": "fa:16:3e:33:26:8e", + "mt": 1450, + "name": "", + "network_id": "02232008-c78c-46b2-b712-678d85def46a", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "10.0.3.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.3.1", + "id": "54074049-aaf1-44d2-9843-99cdb10e3212", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:26:04"}], + "admin_state_up": true, + "cisco_ha:details": {"priority": 100, + "probe_connectivity": false, + "redundancy_level": 1, + "redundancy_routers": [{"id": "085eba49-7ec9-470a-ac37-e89606eba108", + "priority": 97, + "state": "STANDBY"}], + "state": "ACTIVE", + "type": "HSRP"}, + "cisco_ha:enabled": true, + "description": "", + "external_gateway_info": {"external_fixed_ips": [{"ip_address": "172.16.6.45", + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.35", + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838"}, + "gw_port": {"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:16", + "description": "", + "device_id": "085eba49-7ec9-470a-ac37-e89606eba108", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.45", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.35", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:15", + "description": "", + "device_id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.44", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.34", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "id": "780a2d1a-6cae-4b2e-919e-bb5fb0ee0395", + "mac_address": "fa:16:3e:37:e3:d7", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:52:15"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:fe:b7:79", + "hosting_port_id": "53e1c49f-8bad-4dc3-8e19-2202ab08fe53", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/2/0/3", + "segmentation_id": 1056}, + "id": "53e1c49f-8bad-4dc3-8e19-2202ab08fe53", + "mac_address": "fa:16:3e:fe:b7:79", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:52:16"}, + "gw_port_id": "53e1c49f-8bad-4dc3-8e19-2202ab08fe53", + "hosting_device": {"admin_state_up": true, + "booting_time": 360, + "created_at": "2017-02-28 11:27:21", + "credentials": {"password": "cisco", + "user_name": "stack"}, + "host_category": "Hardware", + "id": "00000000-0000-0000-0000-000000000004", + "management_ip_address": "10.0.100.6", + "name": "ASR1k template", + "protocol_port": 22, + "service_types": "router", + "status": "ACTIVE", + "template_id": "00000000-0000-0000-0000-000000000003", + "timeout": null}, + "id": "085eba49-7ec9-470a-ac37-e89606eba108", + "name": "router1_HA_backup_1", + "router_type": {"cfg_agent_driver": "networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k.asr1k_routing_driver.ASR1kRoutingDriver", + "cfg_agent_service_helper": "networking_cisco.plugins.cisco.cfg_agent.service_helpers.routing_svc_helper.RoutingServiceHelper", + "id": "00000000-0000-0000-0000-000000000003", + "name": "ASR1k_router"}, + "routerhost:hosting_device": "00000000-0000-0000-0000-000000000004", + "routerrole:role": "HA-Redundancy", + "routertype-aware-scheduler:auto_schedule": true, + "routertype-aware-scheduler:share_hosting_device": true, + "routertype:id": "00000000-0000-0000-0000-000000000003", + "routes": [], + "share_host": true, + "status": "ACTIVE", + "tenant_id": ""}, + {"_interfaces": [{"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:20", + "description": null, + "device_id": "25ecf24d-a3eb-426f-8871-22d7e78c5944", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.48", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.38", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:18", + "description": null, + "device_id": "945d631c-0b37-4322-8dbe-c3759a3cac45", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.46", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.36", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "id": "3fdf36c5-34a7-4aa3-8508-66b258377a68", + "mac_address": "fa:16:3e:00:d7:f2", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:52:18"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:04:d1:66", + "hosting_port_id": "e678299a-0fbb-43f1-915c-a1c48c676bc6", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/4", + "segmentation_id": 1056}, + "id": "e678299a-0fbb-43f1-915c-a1c48c676bc6", + "mac_address": "fa:16:3e:04:d1:66", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:52:20"}], + "admin_state_up": true, + "cisco_ha:details": {"priority": 100, + "probe_connectivity": false, + "redundancy_level": 2, + "redundancy_routers": [{"id": "c5c5eb9e-4451-4936-9125-9a9634cb5d2e", + "priority": 100, + "state": "STANDBY"}, + {"id": "25ecf24d-a3eb-426f-8871-22d7e78c5944", + "priority": 103, + "state": "STANDBY"}], + "state": "ACTIVE", + "type": "HSRP"}, + "cisco_ha:enabled": true, + "description": null, + "external_gateway_info": null, + "gw_port_id": null, + "hosting_device": {"admin_state_up": true, + "booting_time": 360, + "created_at": "2017-02-28 11:27:21", + "credentials": {"password": "cisco", + "user_name": "stack"}, + "host_category": "Hardware", + "id": "00000000-0000-0000-0000-000000000005", + "management_ip_address": "10.0.100.7", + "name": "ASR1k template", + "protocol_port": 22, + "service_types": "router", + "status": "ACTIVE", + "template_id": "00000000-0000-0000-0000-000000000003", + "timeout": null}, + "id": "25ecf24d-a3eb-426f-8871-22d7e78c5944", + "name": "Global-router-0000-000000000005", + "router_type": {"cfg_agent_driver": "networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k.asr1k_routing_driver.ASR1kRoutingDriver", + "cfg_agent_service_helper": "networking_cisco.plugins.cisco.cfg_agent.service_helpers.routing_svc_helper.RoutingServiceHelper", + "id": "00000000-0000-0000-0000-000000000003", + "name": "ASR1k_router"}, + "routerhost:hosting_device": "00000000-0000-0000-0000-000000000005", + "routerrole:role": "Global", + "routertype-aware-scheduler:auto_schedule": false, + "routertype-aware-scheduler:share_hosting_device": true, + "routertype:id": "00000000-0000-0000-0000-000000000003", + "routes": [], + "share_host": true, + "status": "ACTIVE", + "tenant_id": ""}] diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/json/1/running_cfg_0004_multi_subnets_ext_net.txt b/networking_cisco/tests/unit/cisco/cfg_agent/json/1/running_cfg_0004_multi_subnets_ext_net.txt new file mode 100644 index 0000000..e928393 --- /dev/null +++ b/networking_cisco/tests/unit/cisco/cfg_agent/json/1/running_cfg_0004_multi_subnets_ext_net.txt @@ -0,0 +1,61 @@ +! Last configuration change at 08:58:07 UTC Fri Mar 03 2017 by stack +! +vrf definition Mgmt-intf + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family + ! +vrf definition nrouter-085eba + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family + ! +! +interface GigabitEthernet/1/0/2.1086 + description OPENSTACK_NEUTRON_INTF + encapsulation dot1Q 1086 + ip address 10.0.3.3 255.255.255.0 + ip nat inside + standby 1064 ip 10.0.3.1 + standby 1064 name neutron-hsrp-1064-1086 + standby 1064 priority 97 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 + vrf forwarding nrouter-085eba +! +interface GigabitEthernet/2/0/3.1056 + description OPENSTACK_NEUTRON_EXTERNAL_INTF + encapsulation dot1Q 1056 + ip address 172.16.6.47 255.255.255.224 secondary + ip address 172.17.7.37 255.255.255.224 + ip nat outside + standby 1064 ip 172.16.6.46 secondary + standby 1064 ip 172.17.7.36 + standby 1064 name neutron-hsrp-1064-1056 + standby 1064 priority 100 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 +! +interface GigabitEthernet0 + ip address 10.0.100.6 255.255.255.0 + negotiation auto + vrf forwarding Mgmt-intf +! +ip access-list standard neutron_acl_1086_121bf217 + permit 10.0.3.0 0.0.0.255 +! +ip nat inside source list neutron_acl_1086_121bf217 pool nrouter-085eba_nat_pool vrf nrouter-085eba overload +ip nat pool nrouter-085eba_nat_pool 172.16.6.44 172.16.6.44 netmask 255.255.255.224 +ip nat pool nrouter-085eba_nat_pool 172.17.7.34 172.17.7.34 netmask 255.255.255.224 +! +ip route vrf nrouter-085eba 0.0.0.0 0.0.0.0 GigabitEthernet/2/0/3.1056 172.16.6.33 +ip route vrf nrouter-085eba 0.0.0.0 0.0.0.0 GigabitEthernet/2/0/3.1056 172.17.7.33 +! diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/json/1/running_cfg_0005_multi_subnets_ext_net.txt b/networking_cisco/tests/unit/cisco/cfg_agent/json/1/running_cfg_0005_multi_subnets_ext_net.txt new file mode 100644 index 0000000..add2452 --- /dev/null +++ b/networking_cisco/tests/unit/cisco/cfg_agent/json/1/running_cfg_0005_multi_subnets_ext_net.txt @@ -0,0 +1,61 @@ +! Last configuration change at 08:58:07 UTC Fri Mar 03 2017 by stack +! +vrf definition Mgmt-intf + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family + ! +vrf definition nrouter-5dd41c + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family + ! +! +interface GigabitEthernet/1/0/4.1086 + description OPENSTACK_NEUTRON_INTF + encapsulation dot1Q 1086 + ip address 10.0.3.2 255.255.255.0 + ip nat inside + standby 1064 ip 10.0.3.1 + standby 1064 name neutron-hsrp-1064-1086 + standby 1064 priority 100 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 + vrf forwarding nrouter-5dd41c +! +interface GigabitEthernet/1/0/5.1056 + description OPENSTACK_NEUTRON_EXTERNAL_INTF + encapsulation dot1Q 1056 + ip address 172.16.6.48 255.255.255.224 secondary + ip address 172.17.7.38 255.255.255.224 + ip nat outside + standby 1064 ip 172.16.6.46 secondary + standby 1064 ip 172.17.7.36 + standby 1064 name neutron-hsrp-1064-1056 + standby 1064 priority 103 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 +! +interface GigabitEthernet0 + ip address 10.0.100.7 255.255.255.0 + negotiation auto + vrf forwarding Mgmt-intf +! +ip access-list standard neutron_acl_1086_0b9c4564 + permit 10.0.3.0 0.0.0.255 +! +ip nat inside source list neutron_acl_1086_0b9c4564 pool nrouter-5dd41c_nat_pool vrf nrouter-5dd41c overload +ip nat pool nrouter-5dd41c_nat_pool 172.16.6.44 172.16.6.44 netmask 255.255.255.224 +ip nat pool nrouter-5dd41c_nat_pool 172.17.7.34 172.17.7.34 netmask 255.255.255.224 +! +ip route vrf nrouter-5dd41c 0.0.0.0 0.0.0.0 GigabitEthernet/1/0/5.1056 172.16.6.33 +ip route vrf nrouter-5dd41c 0.0.0.0 0.0.0.0 GigabitEthernet/1/0/5.1056 172.17.7.33 +! diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/json/2/neutronclient_multi_subnets_ext_net_and_single_subnet_ext_net.txt b/networking_cisco/tests/unit/cisco/cfg_agent/json/2/neutronclient_multi_subnets_ext_net_and_single_subnet_ext_net.txt new file mode 100644 index 0000000..3f5697e --- /dev/null +++ b/networking_cisco/tests/unit/cisco/cfg_agent/json/2/neutronclient_multi_subnets_ext_net_and_single_subnet_ext_net.txt @@ -0,0 +1,254 @@ +(neutron) net-list ++--------------------------------------+-----------+-----------------------------------------------------+ +| id | name | subnets | ++--------------------------------------+-----------+-----------------------------------------------------+ +| 02232008-c78c-46b2-b712-678d85def46a | private | 54074049-aaf1-44d2-9843-99cdb10e3212 10.0.3.0/24 | +| 7a382985-4c58-4912-beb3-84fcf7d7af77 | public-2 | 7459de26-e9e2-491a-b174-db9f4d7313b8 172.17.8.32/27 | +| 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | public | 7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41 172.16.6.32/27 | +| | | 05509041-00e0-45c3-bf38-c603911c1ea4 172.17.7.32/27 | +| cd04cc62-1799-4727-8f54-a2b4ec1a8bd2 | private-2 | 1af47d42-149e-423f-883f-5369ab11a9a0 10.0.4.0/24 | ++--------------------------------------+-----------+-----------------------------------------------------+ +(neutron) subnet-list ++--------------------------------------+------------------+----------------+------------------------------------------------+ +| id | name | cidr | allocation_pools | ++--------------------------------------+------------------+----------------+------------------------------------------------+ +| 7459de26-e9e2-491a-b174-db9f4d7313b8 | public-2-subnet | 172.17.8.32/27 | {"start": "172.17.8.34", "end": "172.17.8.62"} | +| 1af47d42-149e-423f-883f-5369ab11a9a0 | private-2-subnet | 10.0.4.0/24 | {"start": "10.0.4.2", "end": "10.0.4.254"} | +| 54074049-aaf1-44d2-9843-99cdb10e3212 | private-subnet | 10.0.3.0/24 | {"start": "10.0.3.2", "end": "10.0.3.254"} | +| 05509041-00e0-45c3-bf38-c603911c1ea4 | public-subnet-2 | 172.17.7.32/27 | {"start": "172.17.7.34", "end": "172.17.7.62"} | +| 7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41 | public-subnet | 172.16.6.32/27 | {"start": "172.16.6.34", "end": "172.16.6.62"} | ++--------------------------------------+------------------+----------------+------------------------------------------------+ +(neutron) router-list ++--------------------------------------+---------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| id | name | external_gateway_info | ++--------------------------------------+---------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 085eba49-7ec9-470a-ac37-e89606eba108 | router1_HA_backup_1 | {"network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", "external_fixed_ips": [{"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": | +| | | "172.16.6.45"}, {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.35"}]} | +| 25ecf24d-a3eb-426f-8871-22d7e78c5944 | Global-router-0000-000000000005 | null | +| 5dd41cc4-7cbd-444f-894b-589531d3686c | routerOne | {"network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", "external_fixed_ips": [{"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": | +| | | "172.16.6.44"}, {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.34"}]} | +| 71810702-bcc0-4718-9f62-1f16609084d0 | router2_HA_backup_1 | {"network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", "external_fixed_ips": [{"subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8", "ip_address": | +| | | "172.17.8.37"}]} | +| 945d631c-0b37-4322-8dbe-c3759a3cac45 | Logical-Global-router | null | +| b1e18b85-75ef-49e2-9eda-a5ddce09d777 | router2 | {"network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", "external_fixed_ips": [{"subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8", "ip_address": | +| | | "172.17.8.36"}]} | +| c5c5eb9e-4451-4936-9125-9a9634cb5d2e | Global-router-0000-000000000004 | null | ++--------------------------------------+---------------------------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------+ +(neutron) router-port-list router1 ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| id | name | mac_address | fixed_ips | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| 780a2d1a-6cae-4b2e-919e-bb5fb0ee0395 | | fa:16:3e:37:e3:d7 | {"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.44"} | +| | | | {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.34"} | +| 9747b0d0-9380-4674-8cd9-9bc0db62355c | | fa:16:3e:ae:75:c5 | {"subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212", "ip_address": "10.0.3.1"} | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +(neutron) router-show router1 ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Field | Value | ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| admin_state_up | True | +| cisco_ha:details | {"redundancy_routers": [{"priority": 97, "state": "STANDBY", "id": "085eba49-7ec9-470a-ac37-e89606eba108"}], "probe_connectivity": false, "priority": 100, "state": "ACTIVE", | +| | "redundancy_level": 1, "type": "HSRP"} | +| cisco_ha:enabled | True | +| description | | +| external_gateway_info | {"network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", "external_fixed_ips": [{"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.44"}, {"subnet_id": | +| | "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.34"}]} | +| id | 5dd41cc4-7cbd-444f-894b-589531d3686c | +| name | router1 | +| routerhost:hosting_device | 00000000-0000-0000-0000-000000000005 | +| routerrole:role | | +| routertype-aware-scheduler:auto_schedule | True | +| routertype-aware-scheduler:share_hosting_device | True | +| routertype:id | 00000000-0000-0000-0000-000000000003 | +| routes | | +| status | ACTIVE | +| tenant_id | 840995fdaaf44ad4ab972f06fd6fbc13 | ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +(neutron) router-port-list router2_HA_backup_1 ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| id | name | mac_address | fixed_ips | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| 050aee56-f6a8-496a-a1af-2c7a57ca93d1 | | fa:16:3e:58:cb:03 | {"subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8", "ip_address": "172.17.8.37"} | +| e626fe6a-ee02-4453-8b81-59ba5efe92f8 | | fa:16:3e:0e:51:cc | {"subnet_id": "1af47d42-149e-423f-883f-5369ab11a9a0", "ip_address": "10.0.4.3"} | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +(neutron) router-show router2_HA_backup_1 ++-------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Field | Value | ++-------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| admin_state_up | True | +| cisco_ha:enabled | False | +| description | | +| external_gateway_info | {"network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", "external_fixed_ips": [{"subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8", "ip_address": "172.17.8.37"}]} | +| id | 71810702-bcc0-4718-9f62-1f16609084d0 | +| name | router2_HA_backup_1 | +| routerhost:hosting_device | 00000000-0000-0000-0000-000000000005 | +| routerrole:role | HA-Redundancy | +| routertype-aware-scheduler:auto_schedule | True | +| routertype-aware-scheduler:share_hosting_device | True | +| routertype:id | 00000000-0000-0000-0000-000000000003 | +| routes | | +| status | ACTIVE | +| tenant_id | | ++-------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +(neutron) router-port-list Global-router-0000-000000000005 ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| id | name | mac_address | fixed_ips | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| 2a66a97a-3b53-4847-88b5-4fdeba6d42c7 | | fa:16:3e:c0:28:2b | {"subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8", "ip_address": "172.17.8.39"} | +| e678299a-0fbb-43f1-915c-a1c48c676bc6 | | fa:16:3e:04:d1:66 | {"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.48"} | +| | | | {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.38"} | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +(neutron) router-show Global-router-0000-000000000005 ++-------------------------------------------------+--------------------------------------+ +| Field | Value | ++-------------------------------------------------+--------------------------------------+ +| admin_state_up | True | +| cisco_ha:enabled | False | +| description | | +| external_gateway_info | | +| id | 25ecf24d-a3eb-426f-8871-22d7e78c5944 | +| name | Global-router-0000-000000000005 | +| routerhost:hosting_device | 00000000-0000-0000-0000-000000000005 | +| routerrole:role | Global | +| routertype-aware-scheduler:auto_schedule | False | +| routertype-aware-scheduler:share_hosting_device | True | +| routertype:id | 00000000-0000-0000-0000-000000000003 | +| routes | | +| status | ACTIVE | +| tenant_id | | ++-------------------------------------------------+--------------------------------------+ +(neutron) router-port-list router1_HA_backup_1 ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| id | name | mac_address | fixed_ips | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| 121bf217-7224-435a-bb23-fdb9c79b35c1 | | fa:16:3e:33:26:8e | {"subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212", "ip_address": "10.0.3.3"} | +| 53e1c49f-8bad-4dc3-8e19-2202ab08fe53 | | fa:16:3e:fe:b7:79 | {"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.45"} | +| | | | {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.35"} | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +(neutron) router-show router1_HA_backup_1 ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Field | Value | ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| admin_state_up | True | +| cisco_ha:enabled | False | +| description | | +| external_gateway_info | {"network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", "external_fixed_ips": [{"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.45"}, {"subnet_id": | +| | "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.35"}]} | +| id | 085eba49-7ec9-470a-ac37-e89606eba108 | +| name | router1_HA_backup_1 | +| routerhost:hosting_device | 00000000-0000-0000-0000-000000000004 | +| routerrole:role | HA-Redundancy | +| routertype-aware-scheduler:auto_schedule | True | +| routertype-aware-scheduler:share_hosting_device | True | +| routertype:id | 00000000-0000-0000-0000-000000000003 | +| routes | | +| status | ACTIVE | +| tenant_id | | ++-------------------------------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +(neutron) router-port-list router2 ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| id | name | mac_address | fixed_ips | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| 3582f930-df68-421d-b62e-e7dbcc424deb | | fa:16:3e:ee:95:e4 | {"subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8", "ip_address": "172.17.8.36"} | +| 8f6ec549-a879-4893-8cac-fab3911c8e45 | | fa:16:3e:07:76:1c | {"subnet_id": "1af47d42-149e-423f-883f-5369ab11a9a0", "ip_address": "10.0.4.1"} | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +(neutron) router-show router2 ++-------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Field | Value | ++-------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| admin_state_up | True | +| cisco_ha:details | {"redundancy_routers": [{"priority": 97, "state": "STANDBY", "id": "71810702-bcc0-4718-9f62-1f16609084d0"}], "probe_connectivity": false, "priority": 100, "state": "ACTIVE", | +| | "redundancy_level": 1, "type": "HSRP"} | +| cisco_ha:enabled | True | +| description | | +| external_gateway_info | {"network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", "external_fixed_ips": [{"subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8", "ip_address": "172.17.8.36"}]} | +| id | b1e18b85-75ef-49e2-9eda-a5ddce09d777 | +| name | router2 | +| routerhost:hosting_device | 00000000-0000-0000-0000-000000000004 | +| routerrole:role | | +| routertype-aware-scheduler:auto_schedule | True | +| routertype-aware-scheduler:share_hosting_device | True | +| routertype:id | 00000000-0000-0000-0000-000000000003 | +| routes | | +| status | ACTIVE | +| tenant_id | 840995fdaaf44ad4ab972f06fd6fbc13 | ++-------------------------------------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +(neutron) router-port-list Global-router-0000-000000000004 ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| id | name | mac_address | fixed_ips | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +| 5931d51b-7806-4dd9-a024-2ed1c674782a | | fa:16:3e:40:96:dd | {"subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", "ip_address": "172.16.6.47"} | +| | | | {"subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4", "ip_address": "172.17.7.37"} | ++--------------------------------------+------+-------------------+------------------------------------------------------------------------------------+ +(neutron) router-show Global-router-0000-000000000004 ++-------------------------------------------------+--------------------------------------+ +| Field | Value | ++-------------------------------------------------+--------------------------------------+ +| admin_state_up | True | +| cisco_ha:enabled | False | +| description | | +| external_gateway_info | | +| id | c5c5eb9e-4451-4936-9125-9a9634cb5d2e | +| name | Global-router-0000-000000000004 | +| routerhost:hosting_device | 00000000-0000-0000-0000-000000000004 | +| routerrole:role | Global | +| routertype-aware-scheduler:auto_schedule | False | +| routertype-aware-scheduler:share_hosting_device | True | +| routertype:id | 00000000-0000-0000-0000-000000000003 | +| routes | | +| status | ACTIVE | +| tenant_id | | ++-------------------------------------------------+--------------------------------------+ +mysql> select id,device_owner,device_id,network_id from ports; ++--------------------------------------+--------------------------+--------------------------------------+--------------------------------------+ +| id | device_owner | device_id | network_id | ++--------------------------------------+--------------------------+--------------------------------------+--------------------------------------+ +| 050aee56-f6a8-496a-a1af-2c7a57ca93d1 | network:router_gateway | 71810702-bcc0-4718-9f62-1f16609084d0 | 7a382985-4c58-4912-beb3-84fcf7d7af77 | +| 0b9c4564-9e42-4dfd-ab96-2cabee626aec | network:router_interface | 312cc5db-8749-46fe-82d9-d8492267902d | 02232008-c78c-46b2-b712-678d85def46a | +| 121bf217-7224-435a-bb23-fdb9c79b35c1 | network:router_interface | 085eba49-7ec9-470a-ac37-e89606eba108 | 02232008-c78c-46b2-b712-678d85def46a | +| 2a66a97a-3b53-4847-88b5-4fdeba6d42c7 | network:router_interface | 25ecf24d-a3eb-426f-8871-22d7e78c5944 | 7a382985-4c58-4912-beb3-84fcf7d7af77 | +| 3582f930-df68-421d-b62e-e7dbcc424deb | network:router_gateway | b1e18b85-75ef-49e2-9eda-a5ddce09d777 | 7a382985-4c58-4912-beb3-84fcf7d7af77 | +| 3ad3a3d6-1533-4572-8e13-c655f8f7a701 | network:router_interface | 945d631c-0b37-4322-8dbe-c3759a3cac45 | 7a382985-4c58-4912-beb3-84fcf7d7af77 | +| 3fdf36c5-34a7-4aa3-8508-66b258377a68 | network:router_interface | 945d631c-0b37-4322-8dbe-c3759a3cac45 | 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | +| 53e1c49f-8bad-4dc3-8e19-2202ab08fe53 | network:router_gateway | 085eba49-7ec9-470a-ac37-e89606eba108 | 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | +| 5931d51b-7806-4dd9-a024-2ed1c674782a | network:router_interface | c5c5eb9e-4451-4936-9125-9a9634cb5d2e | 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | +| 780a2d1a-6cae-4b2e-919e-bb5fb0ee0395 | network:router_gateway | 5dd41cc4-7cbd-444f-894b-589531d3686c | 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | +| 8850d162-03ee-4b63-8d5a-632ef2e538d9 | network:router_interface | 125973e6-42dd-4e9a-8eed-38cb21b8b30f | cd04cc62-1799-4727-8f54-a2b4ec1a8bd2 | +| 8f6ec549-a879-4893-8cac-fab3911c8e45 | network:router_interface | b1e18b85-75ef-49e2-9eda-a5ddce09d777 | cd04cc62-1799-4727-8f54-a2b4ec1a8bd2 | +| 9747b0d0-9380-4674-8cd9-9bc0db62355c | network:router_interface | 5dd41cc4-7cbd-444f-894b-589531d3686c | 02232008-c78c-46b2-b712-678d85def46a | +| e626fe6a-ee02-4453-8b81-59ba5efe92f8 | network:router_interface | 71810702-bcc0-4718-9f62-1f16609084d0 | cd04cc62-1799-4727-8f54-a2b4ec1a8bd2 | +| e678299a-0fbb-43f1-915c-a1c48c676bc6 | network:router_interface | 25ecf24d-a3eb-426f-8871-22d7e78c5944 | 9d81f2da-eb8b-4c61-b247-ca3fe85a7838 | +| f06164a0-8d91-4a7e-bcde-ab9a7887c978 | | | 02232008-c78c-46b2-b712-678d85def46a | +| fe89f2e3-a07a-4ae9-ad9b-b5090ddac1d1 | network:router_interface | c5c5eb9e-4451-4936-9125-9a9634cb5d2e | 7a382985-4c58-4912-beb3-84fcf7d7af77 | ++--------------------------------------+--------------------------+--------------------------------------+--------------------------------------+ +17 rows in set (0.00 sec) +(neutron) port-show private-port-1 ++-----------------------+---------------------------------------------------------------------------------+ +| Field | Value | ++-----------------------+---------------------------------------------------------------------------------+ +| admin_state_up | True | +| allowed_address_pairs | | +| binding:host_id | | +| binding:profile | {} | +| binding:vif_details | {} | +| binding:vif_type | unbound | +| binding:vnic_type | normal | +| created_at | 2017-03-07T12:08:30 | +| description | | +| device_id | | +| device_owner | | +| extra_dhcp_opts | | +| fixed_ips | {"subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212", "ip_address": "10.0.3.4"} | +| id | f06164a0-8d91-4a7e-bcde-ab9a7887c978 | +| mac_address | fa:16:3e:7b:45:2b | +| name | private-port-1 | +| network_id | 02232008-c78c-46b2-b712-678d85def46a | +| port_security_enabled | True | +| security_groups | f52fa760-8849-4612-a592-3714166c20c3 | +| status | DOWN | +| tenant_id | 840995fdaaf44ad4ab972f06fd6fbc13 | +| updated_at | 2017-03-07T13:01:55 | ++-----------------------+---------------------------------------------------------------------------------+ + + + diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/json/2/router_dicts_multi_subnets_ext_net_and_single_subnet_ext_net.json b/networking_cisco/tests/unit/cisco/cfg_agent/json/2/router_dicts_multi_subnets_ext_net_and_single_subnet_ext_net.json new file mode 100644 index 0000000..c357114 --- /dev/null +++ b/networking_cisco/tests/unit/cisco/cfg_agent/json/2/router_dicts_multi_subnets_ext_net_and_single_subnet_ext_net.json @@ -0,0 +1,1290 @@ +[{"_interfaces": [{"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T11:27:27", + "description": null, + "device_id": "312cc5db-8749-46fe-82d9-d8492267902d", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.3.2", + "prefixlen": 24, + "subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T11:27:26", + "description": "", + "device_id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.3.1", + "prefixlen": 24, + "subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212"}], + "id": "9747b0d0-9380-4674-8cd9-9bc0db62355c", + "mac_address": "fa:16:3e:ae:75:c5", + "mt": 1450, + "name": "", + "network_id": "02232008-c78c-46b2-b712-678d85def46a", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "10.0.3.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.3.1", + "id": "54074049-aaf1-44d2-9843-99cdb10e3212", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "840995fdaaf44ad4ab972f06fd6fbc13", + "updated_at": "2017-02-28T11:27:26"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:82:59:fb", + "hosting_port_id": "0b9c4564-9e42-4dfd-ab96-2cabee626aec", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/4", + "segmentation_id": 1086}, + "id": "0b9c4564-9e42-4dfd-ab96-2cabee626aec", + "mac_address": "fa:16:3e:82:59:fb", + "mt": 1450, + "name": "", + "network_id": "02232008-c78c-46b2-b712-678d85def46a", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "10.0.3.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.3.1", + "id": "54074049-aaf1-44d2-9843-99cdb10e3212", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:25:56"}], + "admin_state_up": true, + "cisco_ha:details": {"priority": 100, + "probe_connectivity": false, + "redundancy_level": 1, + "redundancy_routers": [{"id": "085eba49-7ec9-470a-ac37-e89606eba108", + "priority": 97, + "state": "STANDBY"}], + "state": "ACTIVE", + "type": "HSRP"}, + "cisco_ha:enabled": true, + "description": "", + "external_gateway_info": {"external_fixed_ips": [{"ip_address": "172.16.6.44", + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.34", + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838"}, + "gw_port": {"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:15", + "description": "", + "device_id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.44", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.34", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:15", + "description": "", + "device_id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.44", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.34", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "id": "780a2d1a-6cae-4b2e-919e-bb5fb0ee0395", + "mac_address": "fa:16:3e:37:e3:d7", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T13:18:29"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:37:e3:d7", + "hosting_port_id": "780a2d1a-6cae-4b2e-919e-bb5fb0ee0395", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/5", + "segmentation_id": 1056}, + "id": "780a2d1a-6cae-4b2e-919e-bb5fb0ee0395", + "mac_address": "fa:16:3e:37:e3:d7", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T13:18:29"}, + "gw_port_id": "780a2d1a-6cae-4b2e-919e-bb5fb0ee0395", + "hosting_device": {"admin_state_up": true, + "booting_time": 360, + "created_at": "2017-02-28 11:27:21", + "credentials": {"password": "cisco", + "user_name": "stack"}, + "host_category": "Hardware", + "id": "00000000-0000-0000-0000-000000000005", + "management_ip_address": "10.0.100.7", + "name": "ASR1k template", + "protocol_port": 22, + "service_types": "router", + "status": "ACTIVE", + "template_id": "00000000-0000-0000-0000-000000000003", + "timeout": null}, + "id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "name": "routerOne", + "router_type": {"cfg_agent_driver": "networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k.asr1k_routing_driver.ASR1kRoutingDriver", + "cfg_agent_service_helper": "networking_cisco.plugins.cisco.cfg_agent.service_helpers.routing_svc_helper.RoutingServiceHelper", + "id": "00000000-0000-0000-0000-000000000003", + "name": "ASR1k_router"}, + "routerhost:hosting_device": "00000000-0000-0000-0000-000000000005", + "routerrole:role": null, + "routertype-aware-scheduler:auto_schedule": true, + "routertype-aware-scheduler:share_hosting_device": true, + "routertype:id": "00000000-0000-0000-0000-000000000003", + "routes": [], + "share_host": true, + "status": "ACTIVE", + "tenant_id": "840995fdaaf44ad4ab972f06fd6fbc13"}, + {"_interfaces": [{"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:57:12", + "description": null, + "device_id": "71810702-bcc0-4718-9f62-1f16609084d0", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.4.3", + "prefixlen": 24, + "subnet_id": "1af47d42-149e-423f-883f-5369ab11a9a0"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:57:09", + "description": "", + "device_id": "b1e18b85-75ef-49e2-9eda-a5ddce09d777", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.4.1", + "prefixlen": 24, + "subnet_id": "1af47d42-149e-423f-883f-5369ab11a9a0"}], + "id": "8f6ec549-a879-4893-8cac-fab3911c8e45", + "mac_address": "fa:16:3e:07:76:1c", + "mt": 1450, + "name": "", + "network_id": "cd04cc62-1799-4727-8f54-a2b4ec1a8bd2", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "10.0.4.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.4.1", + "id": "1af47d42-149e-423f-883f-5369ab11a9a0", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "840995fdaaf44ad4ab972f06fd6fbc13", + "updated_at": "2017-03-07T12:57:09"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:0e:51:cc", + "hosting_port_id": "e626fe6a-ee02-4453-8b81-59ba5efe92f8", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/4", + "segmentation_id": 1050}, + "id": "e626fe6a-ee02-4453-8b81-59ba5efe92f8", + "mac_address": "fa:16:3e:0e:51:cc", + "mt": 1450, + "name": "", + "network_id": "cd04cc62-1799-4727-8f54-a2b4ec1a8bd2", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "10.0.4.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.4.1", + "id": "1af47d42-149e-423f-883f-5369ab11a9a0", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-03-07T12:57:13"}], + "admin_state_up": true, + "cisco_ha:details": {"priority": 100, + "probe_connectivity": false, + "redundancy_level": 1, + "redundancy_routers": [{"id": "71810702-bcc0-4718-9f62-1f16609084d0", + "priority": 97, + "state": "STANDBY"}], + "state": "ACTIVE", + "type": "HSRP"}, + "cisco_ha:enabled": true, + "description": "", + "external_gateway_info": {"external_fixed_ips": [{"ip_address": "172.17.8.37", + "subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8"}], + "network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77"}, + "gw_port": {"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:18:57", + "description": "", + "device_id": "71810702-bcc0-4718-9f62-1f16609084d0", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.17.8.37", + "prefixlen": 27, + "subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:18:35", + "description": "", + "device_id": "b1e18b85-75ef-49e2-9eda-a5ddce09d777", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.17.8.36", + "prefixlen": 27, + "subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8"}], + "id": "3582f930-df68-421d-b62e-e7dbcc424deb", + "mac_address": "fa:16:3e:ee:95:e4", + "mt": 1450, + "name": "", + "network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.17.8.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.8.33", + "id": "7459de26-e9e2-491a-b174-db9f4d7313b8", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-03-07T12:42:47"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:58:cb:03", + "hosting_port_id": "050aee56-f6a8-496a-a1af-2c7a57ca93d1", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/5", + "segmentation_id": 1018}, + "id": "050aee56-f6a8-496a-a1af-2c7a57ca93d1", + "mac_address": "fa:16:3e:58:cb:03", + "mt": 1450, + "name": "", + "network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.17.8.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.8.33", + "id": "7459de26-e9e2-491a-b174-db9f4d7313b8", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-03-07T12:42:47"}, + "gw_port_id": "050aee56-f6a8-496a-a1af-2c7a57ca93d1", + "hosting_device": {"admin_state_up": true, + "booting_time": 360, + "created_at": "2017-02-28 11:27:21", + "credentials": {"password": "cisco", + "user_name": "stack"}, + "host_category": "Hardware", + "id": "00000000-0000-0000-0000-000000000005", + "management_ip_address": "10.0.100.7", + "name": "ASR1k template", + "protocol_port": 22, + "service_types": "router", + "status": "ACTIVE", + "template_id": "00000000-0000-0000-0000-000000000003", + "timeout": null}, + "id": "71810702-bcc0-4718-9f62-1f16609084d0", + "name": "router2_HA_backup_1", + "router_type": {"cfg_agent_driver": "networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k.asr1k_routing_driver.ASR1kRoutingDriver", + "cfg_agent_service_helper": "networking_cisco.plugins.cisco.cfg_agent.service_helpers.routing_svc_helper.RoutingServiceHelper", + "id": "00000000-0000-0000-0000-000000000003", + "name": "ASR1k_router"}, + "routerhost:hosting_device": "00000000-0000-0000-0000-000000000005", + "routerrole:role": "HA-Redundancy", + "routertype-aware-scheduler:auto_schedule": true, + "routertype-aware-scheduler:share_hosting_device": true, + "routertype:id": "00000000-0000-0000-0000-000000000003", + "routes": [], + "share_host": true, + "status": "ACTIVE", + "tenant_id": ""}, + {"_interfaces": [{"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T11:27:27", + "description": null, + "device_id": "085eba49-7ec9-470a-ac37-e89606eba108", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.3.3", + "prefixlen": 24, + "subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T11:27:26", + "description": "", + "device_id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.3.1", + "prefixlen": 24, + "subnet_id": "54074049-aaf1-44d2-9843-99cdb10e3212"}], + "id": "9747b0d0-9380-4674-8cd9-9bc0db62355c", + "mac_address": "fa:16:3e:ae:75:c5", + "mt": 1450, + "name": "", + "network_id": "02232008-c78c-46b2-b712-678d85def46a", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "10.0.3.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.3.1", + "id": "54074049-aaf1-44d2-9843-99cdb10e3212", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "840995fdaaf44ad4ab972f06fd6fbc13", + "updated_at": "2017-02-28T11:27:26"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:33:26:8e", + "hosting_port_id": "121bf217-7224-435a-bb23-fdb9c79b35c1", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/2", + "segmentation_id": 1086}, + "id": "121bf217-7224-435a-bb23-fdb9c79b35c1", + "mac_address": "fa:16:3e:33:26:8e", + "mt": 1450, + "name": "", + "network_id": "02232008-c78c-46b2-b712-678d85def46a", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "10.0.3.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.3.1", + "id": "54074049-aaf1-44d2-9843-99cdb10e3212", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:26:04"}], + "admin_state_up": true, + "cisco_ha:details": {"priority": 100, + "probe_connectivity": false, + "redundancy_level": 1, + "redundancy_routers": [{"id": "085eba49-7ec9-470a-ac37-e89606eba108", + "priority": 97, + "state": "STANDBY"}], + "state": "ACTIVE", + "type": "HSRP"}, + "cisco_ha:enabled": true, + "description": "", + "external_gateway_info": {"external_fixed_ips": [{"ip_address": "172.16.6.45", + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.35", + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838"}, + "gw_port": {"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:16", + "description": "", + "device_id": "085eba49-7ec9-470a-ac37-e89606eba108", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.45", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.35", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:15", + "description": "", + "device_id": "5dd41cc4-7cbd-444f-894b-589531d3686c", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.44", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.34", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "id": "780a2d1a-6cae-4b2e-919e-bb5fb0ee0395", + "mac_address": "fa:16:3e:37:e3:d7", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T13:18:29"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:fe:b7:79", + "hosting_port_id": "53e1c49f-8bad-4dc3-8e19-2202ab08fe53", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/2/0/3", + "segmentation_id": 1056}, + "id": "53e1c49f-8bad-4dc3-8e19-2202ab08fe53", + "mac_address": "fa:16:3e:fe:b7:79", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T13:18:29"}, + "gw_port_id": "53e1c49f-8bad-4dc3-8e19-2202ab08fe53", + "hosting_device": {"admin_state_up": true, + "booting_time": 360, + "created_at": "2017-02-28 11:27:21", + "credentials": {"password": "cisco", + "user_name": "stack"}, + "host_category": "Hardware", + "id": "00000000-0000-0000-0000-000000000004", + "management_ip_address": "10.0.100.6", + "name": "ASR1k template", + "protocol_port": 22, + "service_types": "router", + "status": "ACTIVE", + "template_id": "00000000-0000-0000-0000-000000000003", + "timeout": null}, + "id": "085eba49-7ec9-470a-ac37-e89606eba108", + "name": "router1_HA_backup_1", + "router_type": {"cfg_agent_driver": "networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k.asr1k_routing_driver.ASR1kRoutingDriver", + "cfg_agent_service_helper": "networking_cisco.plugins.cisco.cfg_agent.service_helpers.routing_svc_helper.RoutingServiceHelper", + "id": "00000000-0000-0000-0000-000000000003", + "name": "ASR1k_router"}, + "routerhost:hosting_device": "00000000-0000-0000-0000-000000000004", + "routerrole:role": "HA-Redundancy", + "routertype-aware-scheduler:auto_schedule": true, + "routertype-aware-scheduler:share_hosting_device": true, + "routertype:id": "00000000-0000-0000-0000-000000000003", + "routes": [], + "share_host": true, + "status": "ACTIVE", + "tenant_id": ""}, + {"_interfaces": [{"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:19:10", + "description": null, + "device_id": "25ecf24d-a3eb-426f-8871-22d7e78c5944", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.17.8.39", + "prefixlen": 27, + "subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:19:07", + "description": null, + "device_id": "945d631c-0b37-4322-8dbe-c3759a3cac45", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.17.8.38", + "prefixlen": 27, + "subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8"}], + "id": "3ad3a3d6-1533-4572-8e13-c655f8f7a701", + "mac_address": "fa:16:3e:36:cf:68", + "mt": 1450, + "name": "", + "network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.17.8.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.8.33", + "id": "7459de26-e9e2-491a-b174-db9f4d7313b8", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-03-07T12:19:07"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:c0:28:2b", + "hosting_port_id": "2a66a97a-3b53-4847-88b5-4fdeba6d42c7", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/5", + "segmentation_id": 1018}, + "id": "2a66a97a-3b53-4847-88b5-4fdeba6d42c7", + "mac_address": "fa:16:3e:c0:28:2b", + "mt": 1450, + "name": "", + "network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.17.8.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.8.33", + "id": "7459de26-e9e2-491a-b174-db9f4d7313b8", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-03-07T12:42:48"}, + {"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:20", + "description": null, + "device_id": "25ecf24d-a3eb-426f-8871-22d7e78c5944", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.48", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.38", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:18", + "description": null, + "device_id": "945d631c-0b37-4322-8dbe-c3759a3cac45", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.46", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.36", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "id": "3fdf36c5-34a7-4aa3-8508-66b258377a68", + "mac_address": "fa:16:3e:00:d7:f2", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:52:18"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:04:d1:66", + "hosting_port_id": "e678299a-0fbb-43f1-915c-a1c48c676bc6", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/5", + "segmentation_id": 1056}, + "id": "e678299a-0fbb-43f1-915c-a1c48c676bc6", + "mac_address": "fa:16:3e:04:d1:66", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T13:18:30"}], + "admin_state_up": true, + "cisco_ha:details": {"priority": 100, + "probe_connectivity": false, + "redundancy_level": 8, + "redundancy_routers": [{"id": "c5c5eb9e-4451-4936-9125-9a9634cb5d2e", + "priority": 100, + "state": "STANDBY"}, + {"id": "25ecf24d-a3eb-426f-8871-22d7e78c5944", + "priority": 103, + "state": "STANDBY"}], + "state": "ACTIVE", + "type": "HSRP"}, + "cisco_ha:enabled": true, + "description": null, + "external_gateway_info": null, + "gw_port_id": null, + "hosting_device": {"admin_state_up": true, + "booting_time": 360, + "created_at": "2017-02-28 11:27:21", + "credentials": {"password": "cisco", + "user_name": "stack"}, + "host_category": "Hardware", + "id": "00000000-0000-0000-0000-000000000005", + "management_ip_address": "10.0.100.7", + "name": "ASR1k template", + "protocol_port": 22, + "service_types": "router", + "status": "ACTIVE", + "template_id": "00000000-0000-0000-0000-000000000003", + "timeout": null}, + "id": "25ecf24d-a3eb-426f-8871-22d7e78c5944", + "name": "Global-router-0000-000000000005", + "router_type": {"cfg_agent_driver": "networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k.asr1k_routing_driver.ASR1kRoutingDriver", + "cfg_agent_service_helper": "networking_cisco.plugins.cisco.cfg_agent.service_helpers.routing_svc_helper.RoutingServiceHelper", + "id": "00000000-0000-0000-0000-000000000003", + "name": "ASR1k_router"}, + "routerhost:hosting_device": "00000000-0000-0000-0000-000000000005", + "routerrole:role": "Global", + "routertype-aware-scheduler:auto_schedule": false, + "routertype-aware-scheduler:share_hosting_device": true, + "routertype:id": "00000000-0000-0000-0000-000000000003", + "routes": [], + "share_host": true, + "status": "ACTIVE", + "tenant_id": ""}, + {"_interfaces": [{"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:18", + "description": null, + "device_id": "c5c5eb9e-4451-4936-9125-9a9634cb5d2e", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.47", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.37", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-02-28T12:52:18", + "description": null, + "device_id": "945d631c-0b37-4322-8dbe-c3759a3cac45", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.16.6.46", + "prefixlen": 27, + "subnet_id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41"}, + {"ip_address": "172.17.7.36", + "prefixlen": 27, + "subnet_id": "05509041-00e0-45c3-bf38-c603911c1ea4"}], + "id": "3fdf36c5-34a7-4aa3-8508-66b258377a68", + "mac_address": "fa:16:3e:00:d7:f2", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T12:52:18"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:40:96:dd", + "hosting_port_id": "5931d51b-7806-4dd9-a024-2ed1c674782a", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/2/0/3", + "segmentation_id": 1056}, + "id": "5931d51b-7806-4dd9-a024-2ed1c674782a", + "mac_address": "fa:16:3e:40:96:dd", + "mt": 1450, + "name": "", + "network_id": "9d81f2da-eb8b-4c61-b247-ca3fe85a7838", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.17.7.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.7.33", + "id": "05509041-00e0-45c3-bf38-c603911c1ea4", + "ipv6_ra_mode": null, + "subnetpool_id": null}, + {"cidr": "172.16.6.32/27", + "dns_nameservers": [], + "gateway_ip": "172.16.6.33", + "id": "7b3f7882-867e-4e6c-a9b3-a8f6ce3abd41", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-02-28T13:18:30"}, + {"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:19:27", + "description": null, + "device_id": "c5c5eb9e-4451-4936-9125-9a9634cb5d2e", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.17.8.40", + "prefixlen": 27, + "subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:19:07", + "description": null, + "device_id": "945d631c-0b37-4322-8dbe-c3759a3cac45", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.17.8.38", + "prefixlen": 27, + "subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8"}], + "id": "3ad3a3d6-1533-4572-8e13-c655f8f7a701", + "mac_address": "fa:16:3e:36:cf:68", + "mt": 1450, + "name": "", + "network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "172.17.8.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.8.33", + "id": "7459de26-e9e2-491a-b174-db9f4d7313b8", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-03-07T12:19:07"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:d2:8f:48", + "hosting_port_id": "fe89f2e3-a07a-4ae9-ad9b-b5090ddac1d1", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/2/0/3", + "segmentation_id": 1018}, + "id": "fe89f2e3-a07a-4ae9-ad9b-b5090ddac1d1", + "mac_address": "fa:16:3e:d2:8f:48", + "mt": 1450, + "name": "", + "network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.17.8.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.8.33", + "id": "7459de26-e9e2-491a-b174-db9f4d7313b8", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-03-07T12:42:47"}], + "admin_state_up": true, + "cisco_ha:details": {"priority": 100, + "probe_connectivity": false, + "redundancy_level": 8, + "redundancy_routers": [{"id": "c5c5eb9e-4451-4936-9125-9a9634cb5d2e", + "priority": 100, + "state": "STANDBY"}, + {"id": "25ecf24d-a3eb-426f-8871-22d7e78c5944", + "priority": 103, + "state": "STANDBY"}], + "state": "ACTIVE", + "type": "HSRP"}, + "cisco_ha:enabled": true, + "description": null, + "external_gateway_info": null, + "gw_port_id": null, + "hosting_device": {"admin_state_up": true, + "booting_time": 360, + "created_at": "2017-02-28 11:27:21", + "credentials": {"password": "cisco", + "user_name": "stack"}, + "host_category": "Hardware", + "id": "00000000-0000-0000-0000-000000000004", + "management_ip_address": "10.0.100.6", + "name": "ASR1k template", + "protocol_port": 22, + "service_types": "router", + "status": "ACTIVE", + "template_id": "00000000-0000-0000-0000-000000000003", + "timeout": null}, + "id": "c5c5eb9e-4451-4936-9125-9a9634cb5d2e", + "name": "Global-router-0000-000000000004", + "router_type": {"cfg_agent_driver": "networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k.asr1k_routing_driver.ASR1kRoutingDriver", + "cfg_agent_service_helper": "networking_cisco.plugins.cisco.cfg_agent.service_helpers.routing_svc_helper.RoutingServiceHelper", + "id": "00000000-0000-0000-0000-000000000003", + "name": "ASR1k_router"}, + "routerhost:hosting_device": "00000000-0000-0000-0000-000000000004", + "routerrole:role": "Global", + "routertype-aware-scheduler:auto_schedule": false, + "routertype-aware-scheduler:share_hosting_device": true, + "routertype:id": "00000000-0000-0000-0000-000000000003", + "routes": [], + "share_host": true, + "status": "ACTIVE", + "tenant_id": ""}, + {"_interfaces": [{"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:57:11", + "description": null, + "device_id": "125973e6-42dd-4e9a-8eed-38cb21b8b30f", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.4.2", + "prefixlen": 24, + "subnet_id": "1af47d42-149e-423f-883f-5369ab11a9a0"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:57:09", + "description": "", + "device_id": "b1e18b85-75ef-49e2-9eda-a5ddce09d777", + "device_owner": "network:router_interface", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "10.0.4.1", + "prefixlen": 24, + "subnet_id": "1af47d42-149e-423f-883f-5369ab11a9a0"}], + "id": "8f6ec549-a879-4893-8cac-fab3911c8e45", + "mac_address": "fa:16:3e:07:76:1c", + "mt": 1450, + "name": "", + "network_id": "cd04cc62-1799-4727-8f54-a2b4ec1a8bd2", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "10.0.4.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.4.1", + "id": "1af47d42-149e-423f-883f-5369ab11a9a0", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "840995fdaaf44ad4ab972f06fd6fbc13", + "updated_at": "2017-03-07T12:57:09"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:30:b2:f5", + "hosting_port_id": "8850d162-03ee-4b63-8d5a-632ef2e538d9", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/1/0/2", + "segmentation_id": 1050}, + "id": "8850d162-03ee-4b63-8d5a-632ef2e538d9", + "mac_address": "fa:16:3e:30:b2:f5", + "mt": 1450, + "name": "", + "network_id": "cd04cc62-1799-4727-8f54-a2b4ec1a8bd2", + "port_security_enabled": false, + "security_groups": [], + "status": "DOWN", + "subnets": [{"cidr": "10.0.4.0/24", + "dns_nameservers": [], + "gateway_ip": "10.0.4.1", + "id": "1af47d42-149e-423f-883f-5369ab11a9a0", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-03-07T12:57:11"}], + "admin_state_up": true, + "cisco_ha:details": {"priority": 100, + "probe_connectivity": false, + "redundancy_level": 1, + "redundancy_routers": [{"id": "71810702-bcc0-4718-9f62-1f16609084d0", + "priority": 97, + "state": "STANDBY"}], + "state": "ACTIVE", + "type": "HSRP"}, + "cisco_ha:enabled": true, + "description": "", + "external_gateway_info": {"external_fixed_ips": [{"ip_address": "172.17.8.36", + "subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8"}], + "network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77"}, + "gw_port": {"address_scopes": {"4": null, "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:18:35", + "description": "", + "device_id": "b1e18b85-75ef-49e2-9eda-a5ddce09d777", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.17.8.36", + "prefixlen": 27, + "subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8"}], + "ha_info": {"group": "1064", + "ha_port": {"address_scopes": {"4": null, + "6": null}, + "admin_state_up": true, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "created_at": "2017-03-07T12:18:35", + "description": "", + "device_id": "b1e18b85-75ef-49e2-9eda-a5ddce09d777", + "device_owner": "network:router_gateway", + "dns_name": null, + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{"ip_address": "172.17.8.36", + "prefixlen": 27, + "subnet_id": "7459de26-e9e2-491a-b174-db9f4d7313b8"}], + "id": "3582f930-df68-421d-b62e-e7dbcc424deb", + "mac_address": "fa:16:3e:ee:95:e4", + "mt": 1450, + "name": "", + "network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.17.8.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.8.33", + "id": "7459de26-e9e2-491a-b174-db9f4d7313b8", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-03-07T12:42:47"}, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP"}, + "hosting_info": {"hosting_mac": "fa:16:3e:ee:95:e4", + "hosting_port_id": "3582f930-df68-421d-b62e-e7dbcc424deb", + "hosting_port_name": "", + "physical_interface": "GigabitEthernet/2/0/3", + "segmentation_id": 1018}, + "id": "3582f930-df68-421d-b62e-e7dbcc424deb", + "mac_address": "fa:16:3e:ee:95:e4", + "mt": 1450, + "name": "", + "network_id": "7a382985-4c58-4912-beb3-84fcf7d7af77", + "port_security_enabled": false, + "security_groups": [], + "status": "ACTIVE", + "subnets": [{"cidr": "172.17.8.32/27", + "dns_nameservers": [], + "gateway_ip": "172.17.8.33", + "id": "7459de26-e9e2-491a-b174-db9f4d7313b8", + "ipv6_ra_mode": null, + "subnetpool_id": null}], + "tenant_id": "", + "updated_at": "2017-03-07T12:42:47"}, + "gw_port_id": "3582f930-df68-421d-b62e-e7dbcc424deb", + "hosting_device": {"admin_state_up": true, + "booting_time": 360, + "created_at": "2017-02-28 11:27:21", + "credentials": {"password": "cisco", + "user_name": "stack"}, + "host_category": "Hardware", + "id": "00000000-0000-0000-0000-000000000004", + "management_ip_address": "10.0.100.6", + "name": "ASR1k template", + "protocol_port": 22, + "service_types": "router", + "status": "ACTIVE", + "template_id": "00000000-0000-0000-0000-000000000003", + "timeout": null}, + "id": "b1e18b85-75ef-49e2-9eda-a5ddce09d777", + "name": "router2", + "router_type": {"cfg_agent_driver": "networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k.asr1k_routing_driver.ASR1kRoutingDriver", + "cfg_agent_service_helper": "networking_cisco.plugins.cisco.cfg_agent.service_helpers.routing_svc_helper.RoutingServiceHelper", + "id": "00000000-0000-0000-0000-000000000003", + "name": "ASR1k_router"}, + "routerhost:hosting_device": "00000000-0000-0000-0000-000000000004", + "routerrole:role": null, + "routertype-aware-scheduler:auto_schedule": true, + "routertype-aware-scheduler:share_hosting_device": true, + "routertype:id": "00000000-0000-0000-0000-000000000003", + "routes": [], + "share_host": true, + "status": "ACTIVE", + "tenant_id": "840995fdaaf44ad4ab972f06fd6fbc13"}] diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/json/2/running_cfg_0004_multi_subnets_ext_net_and_single_subnet_ext_net.txt b/networking_cisco/tests/unit/cisco/cfg_agent/json/2/running_cfg_0004_multi_subnets_ext_net_and_single_subnet_ext_net.txt new file mode 100644 index 0000000..97d3428 --- /dev/null +++ b/networking_cisco/tests/unit/cisco/cfg_agent/json/2/running_cfg_0004_multi_subnets_ext_net_and_single_subnet_ext_net.txt @@ -0,0 +1,111 @@ +! Last configuration change at 13:03:29 UTC Tue Mar 07 2017 by stack +! +hostname ASR-1002X-10_0_100_6 +! +boot-start-marker +boot system flash bootflash:/asr1002x-simulated.03.16.00.S-ext.SPA.bin +boot-end-marker +! +vrf definition Mgmt-intf + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family + ! +vrf definition nrouter-085eba + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family + ! +vrf definition nrouter-b1e18b + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family + ! +! +interface GigabitEthernet/1/0/2.1050 + description OPENSTACK_NEUTRON_INTF + encapsulation dot1Q 1050 + ip address 10.0.4.2 255.255.255.0 + ip nat inside + standby 1064 ip 10.0.4.1 + standby 1064 name neutron-hsrp-1064-1050 + standby 1064 priority 100 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 + vrf forwarding nrouter-b1e18b +! +interface GigabitEthernet/1/0/2.1086 + description OPENSTACK_NEUTRON_INTF + encapsulation dot1Q 1086 + ip address 10.0.3.3 255.255.255.0 + ip nat inside + standby 1064 ip 10.0.3.1 + standby 1064 name neutron-hsrp-1064-1086 + standby 1064 priority 97 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 + vrf forwarding nrouter-085eba +! +interface GigabitEthernet/2/0/3.1018 + description OPENSTACK_NEUTRON_EXTERNAL_INTF + encapsulation dot1Q 1018 + ip address 172.17.8.40 255.255.255.224 + ip nat outside + standby 1064 ip 172.17.8.38 + standby 1064 name neutron-hsrp-1064-1018 + standby 1064 priority 100 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 +! +interface GigabitEthernet/2/0/3.1056 + description OPENSTACK_NEUTRON_EXTERNAL_INTF + encapsulation dot1Q 1056 + ip address 172.16.6.47 255.255.255.224 secondary + ip address 172.17.7.37 255.255.255.224 + ip nat outside + standby 1064 ip 172.16.6.46 secondary + standby 1064 ip 172.17.7.36 + standby 1064 name neutron-hsrp-1064-1056 + standby 1064 priority 100 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 +! +interface GigabitEthernet0 + ip address 10.0.100.6 255.255.255.0 + negotiation auto + vrf forwarding Mgmt-intf +! +ip access-list standard neutron_acl_1050_8850d162 + permit 10.0.4.0 0.0.0.255 +ip access-list standard neutron_acl_1086_121bf217 + permit 10.0.3.0 0.0.0.255 +! +ip nat inside source list neutron_acl_1050_8850d162 pool nrouter-b1e18b_nat_pool vrf nrouter-b1e18b overload +ip nat inside source list neutron_acl_1086_121bf217 pool nrouter-085eba_nat_pool vrf nrouter-085eba overload +ip nat pool nrouter-085eba_nat_pool 172.16.6.44 172.16.6.44 netmask 255.255.255.224 +ip nat pool nrouter-085eba_nat_pool 172.17.7.34 172.17.7.34 netmask 255.255.255.224 +ip nat pool nrouter-b1e18b_nat_pool 172.17.8.36 172.17.8.36 netmask 255.255.255.224 +! +ip route vrf Mgmt - intf 0.0.0.0 0.0.0.0 10.0.100.1 +ip route vrf nrouter-085eba 0.0.0.0 0.0.0.0 GigabitEthernet/2/0/3.1056 172.16.6.33 +ip route vrf nrouter-085eba 0.0.0.0 0.0.0.0 GigabitEthernet/2/0/3.1056 172.17.7.33 +ip route vrf nrouter-b1e18b 0.0.0.0 0.0.0.0 GigabitEthernet/2/0/3.1018 172.17.8.33 +! +ip ssh source - interface GigabitEthernet0 +ip ssh version 2 +! +ip tftp source - interface GigabitEthernet0 +! diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/json/2/running_cfg_0005_multi_subnets_ext_net_and_single_subnet_ext_net.txt b/networking_cisco/tests/unit/cisco/cfg_agent/json/2/running_cfg_0005_multi_subnets_ext_net_and_single_subnet_ext_net.txt new file mode 100644 index 0000000..862791d --- /dev/null +++ b/networking_cisco/tests/unit/cisco/cfg_agent/json/2/running_cfg_0005_multi_subnets_ext_net_and_single_subnet_ext_net.txt @@ -0,0 +1,111 @@ +! Last configuration change at 13:03:29 UTC Tue Mar 07 2017 by stack +! +hostname ASR-1002X-10_0_100_7 +! +boot-start-marker +boot system flash bootflash:/asr1002x-simulated.03.16.00.S-ext.SPA.bin +boot-end-marker +! +vrf definition Mgmt-intf + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family + ! +vrf definition nrouter-5dd41c + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family + ! +vrf definition nrouter-718107 + ! + address-family ipv4 + exit-address-family + ! + address-family ipv6 + exit-address-family + ! +! +interface GigabitEthernet/1/0/4.1050 + description OPENSTACK_NEUTRON_INTF + encapsulation dot1Q 1050 + ip address 10.0.4.3 255.255.255.0 + ip nat inside + standby 1064 ip 10.0.4.1 + standby 1064 name neutron-hsrp-1064-1050 + standby 1064 priority 97 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 + vrf forwarding nrouter-718107 +! +interface GigabitEthernet/1/0/4.1086 + description OPENSTACK_NEUTRON_INTF + encapsulation dot1Q 1086 + ip address 10.0.3.2 255.255.255.0 + ip nat inside + standby 1064 ip 10.0.3.1 + standby 1064 name neutron-hsrp-1064-1086 + standby 1064 priority 100 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 + vrf forwarding nrouter-5dd41c +! +interface GigabitEthernet/1/0/5.1018 + description OPENSTACK_NEUTRON_EXTERNAL_INTF + encapsulation dot1Q 1018 + ip address 172.17.8.39 255.255.255.224 + ip nat outside + standby 1064 ip 172.17.8.38 + standby 1064 name neutron-hsrp-1064-1018 + standby 1064 priority 103 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 +! +interface GigabitEthernet/1/0/5.1056 + description OPENSTACK_NEUTRON_EXTERNAL_INTF + encapsulation dot1Q 1056 + ip address 172.16.6.48 255.255.255.224 secondary + ip address 172.17.7.38 255.255.255.224 + ip nat outside + standby 1064 ip 172.16.6.46 secondary + standby 1064 ip 172.17.7.36 + standby 1064 name neutron-hsrp-1064-1056 + standby 1064 priority 103 + standby 1064 timers 1 3 + standby delay minimum 30 reload 60 + standby version 2 +! +interface GigabitEthernet0 + ip address 10.0.100.7 255.255.255.0 + negotiation auto + vrf forwarding Mgmt-intf +! +ip access-list standard neutron_acl_1050_e626fe6a + permit 10.0.4.0 0.0.0.255 +ip access-list standard neutron_acl_1086_0b9c4564 + permit 10.0.3.0 0.0.0.255 +! +ip nat inside source list neutron_acl_1050_e626fe6a pool nrouter-718107_nat_pool vrf nrouter-718107 overload +ip nat inside source list neutron_acl_1086_0b9c4564 pool nrouter-5dd41c_nat_pool vrf nrouter-5dd41c overload +ip nat pool nrouter-5dd41c_nat_pool 172.16.6.44 172.16.6.44 netmask 255.255.255.224 +ip nat pool nrouter-5dd41c_nat_pool 172.17.7.34 172.17.7.34 netmask 255.255.255.224 +ip nat pool nrouter-718107_nat_pool 172.17.8.36 172.17.8.36 netmask 255.255.255.224 +! +ip route vrf Mgmt - intf 0.0.0.0 0.0.0.0 10.0.100.1 +ip route vrf nrouter-5dd41c 0.0.0.0 0.0.0.0 GigabitEthernet/1/0/5.1056 172.16.6.33 +ip route vrf nrouter-5dd41c 0.0.0.0 0.0.0.0 GigabitEthernet/1/0/5.1056 172.17.7.33 +ip route vrf nrouter-718107 0.0.0.0 0.0.0.0 GigabitEthernet/1/0/5.1018 172.17.8.33 +! +ip ssh source - interface GigabitEthernet0 +ip ssh version 2 +! +ip tftp source - interface GigabitEthernet0 +! diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/test_asr1k_cfg_syncer.py b/networking_cisco/tests/unit/cisco/cfg_agent/test_asr1k_cfg_syncer.py index 8cbb758..3a6380a 100644 --- a/networking_cisco/tests/unit/cisco/cfg_agent/test_asr1k_cfg_syncer.py +++ b/networking_cisco/tests/unit/cisco/cfg_agent/test_asr1k_cfg_syncer.py @@ -12,16 +12,17 @@ # License for the specific language governing permissions and limitations # under the License. +import os + import mock from neutron.tests import base from oslo_config import cfg +from oslo_serialization import jsonutils from networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k import ( asr1k_cfg_syncer) - from networking_cisco.plugins.cisco.cfg_agent.device_drivers.asr1k import ( asr1k_routing_driver as driver) - from networking_cisco.plugins.cisco.common.htparser import HTParser @@ -1261,6 +1262,93 @@ NEUTRON_DB = [ "tenant_id": "ecf8697e8dc04fef8be7c7f9c3594de9" }, { + "_interfaces": [ + { + "admin_state_up": True, + "allowed_address_pairs": [], + "binding:host_id": "asr1k-k7-controller-1-R2", + "binding:profile": {}, + "binding:vif_details": { + "ovs_hybrid_plug": True, + "port_filter": True + }, + "binding:vif_type": "ovs", + "binding:vnic_type": "normal", + "device_id": "213fd355-78c3-44cc-bd6e-492b9ade2602", + "device_owner": "network:router_interface", + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [ + { + "ip_address": "172.16.0.105", + "prefixlen": 16, + "subnet_id": "8f9c885d-a2ad-4fff-8127-2d4b3af6015b" + } + ], + "ha_info": { + "group": "1064", + "ha_port": { + "admin_state_up": True, + "allowed_address_pairs": [], + "binding:host_id": "", + "binding:profile": {}, + "binding:vif_details": {}, + "binding:vif_type": "unbound", + "binding:vnic_type": "normal", + "device_id": "a2617b46-78ef-49ba-95b5-0f3ff90f1f91", + "device_owner": "network:router_interface", + "extra_dhcp_opts": [], + "extra_subnets": [], + "fixed_ips": [{ + "ip_address": "172.16.0.104", + "prefixlen": 16, + "subnet_id": "8f9c885d-a2ad-4fff-8127-2d4b3af6015b" + }], + "id": "b768491c-4b76-492f-a0ee-56bc50867a07", + "mac_address": "fa:16:3e:77:ae:bb", + "name": "", + "network_id": "7a38a5fd-3ad9-4952-ab08-4def22407269", + "security_groups": [], + "status": "DOWN", + "subnets": [ + { + "cidr": "172.16.0.0/16", + "gateway_ip": "172.16.0.1", + "id": "8f9c885d-a2ad-4fff-8127-2d4b3af6015b", + "ipv6_ra_mode": None + } + ], + "tenant_id": "" + }, + "other_config": "", + "timers_config": "", + "tracking_config": "", + "type": "HSRP" + }, + "hosting_info": { + "hosting_mac": "fa:16:3e:97:ec:f2", + "hosting_port_id": "527b7bc0-d6ba-4d07-932a-60e96da86173", + "hosting_port_name": "", + "physical_interface": "Port-channel10", + "segmentation_id": 3000 + }, + "id": "527b7bc0-d6ba-4d07-932a-60e96da86173", + "mac_address": "fa:16:3e:97:ec:f2", + "name": "", + "network_id": "7a38a5fd-3ad9-4952-ab08-4def22407269", + "security_groups": [], + "status": "ACTIVE", + "subnets": [ + { + "cidr": "172.16.0.0/16", + "gateway_ip": "172.16.0.1", + "id": "8f9c885d-a2ad-4fff-8127-2d4b3af6015b", + "ipv6_ra_mode": None + } + ], + "tenant_id": "" + } + ], "admin_state_up": True, "cisco_ha:details": { "priority": 100, @@ -1291,94 +1379,7 @@ NEUTRON_DB = [ ], "network_id": "7a38a5fd-3ad9-4952-ab08-4def22407269" }, - "gw_port": { - "admin_state_up": True, - "allowed_address_pairs": [], - "binding:host_id": "asr1k-k7-controller-1-R2", - "binding:profile": {}, - "binding:vif_details": { - "ovs_hybrid_plug": True, - "port_filter": True - }, - "binding:vif_type": "ovs", - "binding:vnic_type": "normal", - "device_id": "213fd355-78c3-44cc-bd6e-492b9ade2602", - "device_owner": "network:router_gateway", - "extra_dhcp_opts": [], - "extra_subnets": [], - "fixed_ips": [ - { - "ip_address": "172.16.0.105", - "prefixlen": 16, - "subnet_id": "8f9c885d-a2ad-4fff-8127-2d4b3af6015b" - } - ], - "ha_info": { - "group": "1064", - "ha_port": { - "admin_state_up": True, - "allowed_address_pairs": [], - "binding:host_id": "", - "binding:profile": {}, - "binding:vif_details": {}, - "binding:vif_type": "unbound", - "binding:vnic_type": "normal", - "device_id": "a2617b46-78ef-49ba-95b5-0f3ff90f1f91", - "device_owner": "network:router_gateway", - "extra_dhcp_opts": [], - "extra_subnets": [], - "fixed_ips": [ - { - "ip_address": "172.16.0.104", - "prefixlen": 16, - "subnet_id": "8f9c885d-a2ad-4fff-8127-2d4b3af6015b" - } - ], - "id": "b768491c-4b76-492f-a0ee-56bc50867a07", - "mac_address": "fa:16:3e:77:ae:bb", - "name": "", - "network_id": "7a38a5fd-3ad9-4952-ab08-4def22407269", - "security_groups": [], - "status": "DOWN", - "subnets": [ - { - "cidr": "172.16.0.0/16", - "gateway_ip": "172.16.0.1", - "id": "8f9c885d-a2ad-4fff-8127-2d4b3af6015b", - "ipv6_ra_mode": None - } - ], - "tenant_id": "" - }, - "other_config": "", - "timers_config": "", - "tracking_config": "", - "type": "HSRP" - }, - "hosting_info": { - "hosting_mac": "fa:16:3e:97:ec:f2", - "hosting_port_id": "527b7bc0-d6ba-4d07-932a-60e96da86173", - "hosting_port_name": "", - "physical_interface": "Port-channel10", - "segmentation_id": 3000 - }, - "id": "527b7bc0-d6ba-4d07-932a-60e96da86173", - "mac_address": "fa:16:3e:97:ec:f2", - "name": "", - "network_id": "7a38a5fd-3ad9-4952-ab08-4def22407269", - "security_groups": [], - "status": "ACTIVE", - "subnets": [ - { - "cidr": "172.16.0.0/16", - "gateway_ip": "172.16.0.1", - "id": "8f9c885d-a2ad-4fff-8127-2d4b3af6015b", - "ipv6_ra_mode": None - } - ], - "tenant_id": "" - }, - "gw_port_id": "527b7bc0-d6ba-4d07-932a-60e96da86173", + "gw_port_id": None, "hosting_device": { "admin_state_up": True, "booting_time": 360, @@ -1432,9 +1433,8 @@ class ASR1kCfgSyncer(base.BaseTestCase): self.hosting_device_info = { 'id': '00000000-0000-0000-0000-000000000003'} self.driver = mock.Mock() - self.config_syncer = asr1k_cfg_syncer.ConfigSyncer(self.router_db_info, - self.driver, - self.hosting_device_info) + self.config_syncer = asr1k_cfg_syncer.ConfigSyncer( + self.router_db_info, self.driver, self.hosting_device_info) def test_delete_invalid_cfg_empty_routers_list(self): """ @@ -1655,3 +1655,51 @@ class ASR1kCfgSyncer(base.BaseTestCase): parsed_cfg) self.assertEqual([], invalid_cfg) + + def _test_clean_router_multi_ext_net(self, routers_dict_filename, + running_cfg_filename, hd_id, + expected_invalid_cfg=None): + if expected_invalid_cfg is None: + expected_invalid_cfg = [] + path = os.path.dirname(os.path.abspath(__file__)) + '/' + with open(path + routers_dict_filename) as routers_dict_file: + r_dict_txt = routers_dict_file.read() + routers_dict = jsonutils.loads(r_dict_txt) + with open(path + running_cfg_filename) as running_config_file: + running_cfg = running_config_file.read() + hosting_device_info = {'id': hd_id} + config_syncer = asr1k_cfg_syncer.ConfigSyncer( + routers_dict, self.driver, hosting_device_info) + config_syncer.get_running_config = mock.Mock( + return_value=running_cfg) + invalid_cfg = config_syncer.delete_invalid_cfg() + self.assertEqual(expected_invalid_cfg, invalid_cfg) + + def test_clean_router_with_two_subnet_gw(self): + self._test_clean_router_multi_ext_net( + 'json/1/router_dicts_multi_subnets_ext_net.json', + 'json/1/running_cfg_0005_multi_subnets_ext_net.txt', + '00000000-0000-0000-0000-000000000005') + + def test_clean_ha_backup_router_with_two_subnet_gw(self): + self._test_clean_router_multi_ext_net( + 'json/1/router_dicts_multi_subnets_ext_net.json', + 'json/1/running_cfg_0004_multi_subnets_ext_net.txt', + '00000000-0000-0000-0000-000000000004') + + def test_clean_routers_with_two_subnet_gw_and_single_subnet_gw(self): + self._test_clean_router_multi_ext_net( + 'json/2/router_dicts_multi_subnets_ext_net_and_' + 'single_subnet_ext_net.json', + 'json/2/running_cfg_0005_multi_subnets_ext_net_and_' + 'single_subnet_ext_net.txt', + '00000000-0000-0000-0000-000000000005') + + def test_clean_ha_backup_routers_with_two_subnet_gw_and_single_subnet_gw( + self): + self._test_clean_router_multi_ext_net( + 'json/2/router_dicts_multi_subnets_ext_net_and_' + 'single_subnet_ext_net.json', + 'json/2/running_cfg_0004_multi_subnets_ext_net_and_' + 'single_subnet_ext_net.txt', + '00000000-0000-0000-0000-000000000004') diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/test_asr1k_routing_driver.py b/networking_cisco/tests/unit/cisco/cfg_agent/test_asr1k_routing_driver.py index b855ae8..98d6e63 100644 --- a/networking_cisco/tests/unit/cisco/cfg_agent/test_asr1k_routing_driver.py +++ b/networking_cisco/tests/unit/cisco/cfg_agent/test_asr1k_routing_driver.py @@ -76,21 +76,25 @@ class ASR1kRoutingDriver(base.BaseTestCase): self.ex_gw_cidr = '20.0.0.30/24' self.ex_gw_ip_mask = '255.255.255.0' self.ex_gw_ha_group = 1500 + sn_id = _uuid() self.ex_gw_ha_info = {'group': self.ex_gw_ha_group, 'ha_port': { 'fixed_ips': [{ + 'subnet_id': sn_id, 'ip_address': self.ex_gw_ip_vip, 'prefixlen': self.ex_gw_prefixlen}]}} self.ex_gw_gateway_ip = '20.0.0.1' self.vlan_ext = 317 self.phy_infc = 'GigabitEthernet0/0/0' - self.ex_gw_port = {'id': _uuid(), 'network_id': _uuid(), + 'ip_info': {'subnet_id': sn_id, + 'is_primary': True, + 'ip_cidr': self.ex_gw_cidr}, 'fixed_ips': [{'ip_address': self.ex_gw_ip, 'prefixlen': self.ex_gw_prefixlen, - 'subnet_id': _uuid()}], - 'subnets': [{'cidr': self.ex_gw_cidr, + 'subnet_id': sn_id}], + 'subnets': [{'id': sn_id, 'cidr': self.ex_gw_cidr, 'gateway_ip': self.ex_gw_gateway_ip}], 'device_owner': bc.constants.DEVICE_OWNER_ROUTER_GW, 'mac_address': 'ca:fe:de:ad:be:ef', @@ -109,21 +113,25 @@ class ASR1kRoutingDriver(base.BaseTestCase): self.gw_ip_vip = '10.0.3.1' self.gw_ip_mask = '255.255.255.0' self.gw_ha_group = 1621 + sn_id = _uuid() self.gw_ha_info = {'group': self.gw_ha_group, 'ha_port': { 'fixed_ips': [{ + 'subnet_id': sn_id, 'ip_address': self.gw_ip_vip, 'prefixlen': self.gw_prefixlen}]}} self.port = {'id': PORT_ID, - 'ip_cidr': self.gw_ip_cidr, - 'fixed_ips': [{'ip_address': self.gw_ip}], - 'subnets': [{'cidr': self.gw_ip_cidr, + 'ip_info': {'subnet_id': sn_id, + 'is_primary': True, + 'ip_cidr': self.gw_ip_cidr}, + 'fixed_ips': [{'ip_address': self.gw_ip, + 'subnet_id': sn_id}], + 'subnets': [{'id': sn_id, 'cidr': self.gw_ip_cidr, 'gateway_ip': self.gw_ip}], 'hosting_info': { 'physical_interface': self.phy_infc, 'segmentation_id': self.vlan_int}, - HA_INFO: self.gw_ha_info - } + HA_INFO: self.gw_ha_info} int_ports = [self.port] self.floating_ip = '20.0.0.35' self.fixed_ip = '10.0.3.5' @@ -165,8 +173,7 @@ class ASR1kRoutingDriver(base.BaseTestCase): 'state': 'ACTIVE', 'type': 'HSRP'} self.global_router[ha.DETAILS] = self.cisco_ha_details_global - self.global_router['gw_port'][HA_INFO]['ha_port']['fixed_ips'][0][ - 'ip_address'] = self.ex_gw_ip_vip + self.global_router['gw_port'] = None self.ri_global = routing_svc_helper.RouterInfo( FAKE_ID, self.global_router) self.ri_global.internal_ports = int_ports @@ -246,6 +253,20 @@ class ASR1kRoutingDriver(base.BaseTestCase): self.assert_edit_run_cfg( snippets.SET_INTC_ASR_HSRP_EXTERNAL, cfg_args_hsrp) + def test_internal_network_added_global_router_secondary_subnet(self): + self.port['ip_info']['is_primary'] = False + self.global_router[bc.constants.INTERFACE_KEY][0]['ip_info'][ + 'is_primary'] = False + self.driver.internal_network_added(self.ri_global, self.port) + sub_interface = self.phy_infc + '.' + str(self.vlan_int) + cfg_args_sub = (sub_interface, self.gw_ip, self.gw_ip_mask) + self.assert_edit_run_cfg( + snippets.SET_SUBINTERFACE_SECONDARY_IP, cfg_args_sub) + + cfg_args_hsrp = (sub_interface, self.gw_ha_group, self.gw_ip_vip) + self.assert_edit_run_cfg( + snippets.SET_INTC_ASR_SECONDARY_HSRP_EXTERNAL, cfg_args_hsrp) + def test_internal_network_added_global_router_with_multi_region(self): cfg.CONF.set_override('enable_multi_region', True, 'multi_region') is_multi_region_enabled = cfg.CONF.multi_region.enable_multi_region @@ -265,6 +286,25 @@ class ASR1kRoutingDriver(base.BaseTestCase): self.assert_edit_run_cfg( snippets.SET_INTC_ASR_HSRP_EXTERNAL, cfg_args_hsrp) + def test_internal_network_added_global_router_with_multi_region_sec_sn( + self): + cfg.CONF.set_override('enable_multi_region', True, 'multi_region') + is_multi_region_enabled = cfg.CONF.multi_region.enable_multi_region + self.assertEqual(True, is_multi_region_enabled) + + self.port['ip_info']['is_primary'] = False + self.global_router[bc.constants.INTERFACE_KEY][0]['ip_info'][ + 'is_primary'] = False + self.driver.internal_network_added(self.ri_global, self.port) + sub_interface = self.phy_infc + '.' + str(self.vlan_int) + cfg_args_sub = (sub_interface, self.gw_ip, self.gw_ip_mask) + self.assert_edit_run_cfg( + snippets.SET_SUBINTERFACE_SECONDARY_IP, cfg_args_sub) + + cfg_args_hsrp = (sub_interface, self.gw_ha_group, self.gw_ip_vip) + self.assert_edit_run_cfg( + snippets.SET_INTC_ASR_SECONDARY_HSRP_EXTERNAL, cfg_args_hsrp) + def _make_test_router_non_ha(self): self.ri.router[ha.ENABLED] = False del self.ri.router[ha.DETAILS] diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/test_routing_svc_helper.py b/networking_cisco/tests/unit/cisco/cfg_agent/test_routing_svc_helper.py index 2e2f72b..bd50c98 100644 --- a/networking_cisco/tests/unit/cisco/cfg_agent/test_routing_svc_helper.py +++ b/networking_cisco/tests/unit/cisco/cfg_agent/test_routing_svc_helper.py @@ -37,25 +37,43 @@ HOST = 'myhost' FAKE_ID = _uuid() -def prepare_router_data(enable_snat=None, num_internal_ports=1): +def prepare_router_data(enable_snat=None, num_internal_ports=1, + num_subnets=1, is_global=False): router_id = _uuid() + ext_fixed_ips = [] + ext_subnets = [] + sn_ids = sorted([_uuid() for i in range(num_subnets)]) + for i in range(num_subnets): + sn_id = sn_ids[i] + ext_fixed_ips.append({'ip_address': '19.4.%s.4' % i, + 'subnet_id': sn_id}) + ext_subnets.append({'id': sn_id, 'cidr': '19.4.%s.0/24' % i, + 'gateway_ip': '19.4.%s.1' % i}) ex_gw_port = {'id': _uuid(), 'network_id': _uuid(), 'admin_state_up': True, - 'fixed_ips': [{'ip_address': '19.4.4.4', - 'subnet_id': _uuid()}], - 'subnets': [{'cidr': '19.4.4.0/24', - 'gateway_ip': '19.4.4.1'}]} + 'fixed_ips': ext_fixed_ips, + 'subnets': ext_subnets} int_ports = [] - for i in range(num_internal_ports): + num_internal_subnets = 1 if is_global is False else num_subnets + for j in range(num_internal_ports): + k = 35 + j + int_fixed_ips = [] + int_subnets = [] + sn_ids = sorted([_uuid() for i in range(num_internal_subnets)]) + for i in range(num_internal_subnets): + sn_id = sn_ids[i] + int_fixed_ips.append({'ip_address': '%s.4.%s.4' % (k, i), + 'subnet_id': sn_id}) + int_subnets.append({'id': sn_id, 'cidr': '%s.4.%s.0/24' % (k, i), + 'gateway_ip': '%s.4.%s.1' % (k, i)}) int_ports.append({'id': _uuid(), 'network_id': _uuid(), 'admin_state_up': True, - 'fixed_ips': [{'ip_address': '35.4.%s.4' % i, - 'subnet_id': _uuid()}], + 'fixed_ips': int_fixed_ips, 'mac_address': 'ca:fe:de:ad:be:ef', - 'subnets': [{'cidr': '35.4.%s.0/24' % i, - 'gateway_ip': '35.4.%s.1' % i}]}) + 'subnets': int_subnets}) + hosting_device = {'id': _uuid(), "name": "CSR1kv_template", "booting_time": 300, @@ -72,10 +90,14 @@ def prepare_router_data(enable_snat=None, num_internal_ports=1): 'admin_state_up': True, bc.constants.INTERFACE_KEY: int_ports, 'routes': [], - 'gw_port': ex_gw_port, 'hosting_device': hosting_device, - 'router_type': '', - routerrole.ROUTER_ROLE_ATTR: None} + 'router_type': ''} + if is_global is True: + router['gw_port'] = None + router[routerrole.ROUTER_ROLE_ATTR] = c_constants.ROUTER_ROLE_GLOBAL + else: + router['gw_port'] = ex_gw_port + router[routerrole.ROUTER_ROLE_ATTR] = None if enable_snat is not None: router['enable_snat'] = enable_snat return router, int_ports @@ -126,12 +148,13 @@ class TestBasicRoutingOperations(base.BaseTestCase): self.conf = cfg.ConfigOpts() self.conf.register_opts(bc.core_opts) self.conf.register_opts(cfg_agent.OPTS, "cfg_agent") + sn_id = _uuid() self.ex_gw_port = {'id': _uuid(), 'network_id': _uuid(), 'admin_state_up': True, 'fixed_ips': [{'ip_address': '19.4.4.4', - 'subnet_id': _uuid()}], - 'subnets': [{'cidr': '19.4.4.0/24', + 'subnet_id': sn_id}], + 'subnets': [{'id': sn_id, 'cidr': '19.4.4.0/24', 'gateway_ip': '19.4.4.1'}]} self.hosting_device = {'id': "100", 'name': "CSR1kv_template", @@ -221,6 +244,27 @@ class TestBasicRoutingOperations(base.BaseTestCase): self.assertRaises(SessionCloseError, self.routing_helper._process_router, ri) + def test_process_router_throw_no_ip_address_on_subnet_error(self): + router, ports = prepare_router_data() + # change subnet_id to something that does not exist + router['gw_port']['subnets'][0]['id'] = 'fake_uuid' + ri = routing_svc_helper.RouterInfo(router['id'], router) + self.assertRaises(routing_svc_helper.IPAddressMissingException, + self.routing_helper._process_router, ri) + + def _test_process_router_throw_multiple_ipv4_subnets_error(self): + router, ports = prepare_router_data(num_subnets=2, is_global=True) + # make router a regular one which triggers the error condition + router[routerrole.ROUTER_ROLE_ATTR] = None + ri = routing_svc_helper.RouterInfo(router['id'], router) + return ri, router + + def test_process_router_throw_multiple_ipv4_subnets_error(self): + ri, router = ( + self._test_process_router_throw_multiple_ipv4_subnets_error()) + self.assertRaises(routing_svc_helper.MultipleIPv4SubnetsException, + self.routing_helper._process_router, ri) + def _test_router_admin_port_state(self, router, ri, ex_gw_port): # change the router admin_state_up to false router['admin_state_up'] = False @@ -252,9 +296,30 @@ class TestBasicRoutingOperations(base.BaseTestCase): self.assertFalse(self.routing_helper._disable_router_interface.called) self._reset_mocks() - def test_process_router(self, test_admin_state=True): - router, ports = prepare_router_data() - #Setup mock for call to proceess floating ips + # msn means that the router has an external gateway with multiple subnets + def _test_process_msn_router(self, num_ext_subnets=3, + test_admin_state=True): + + def _verify_ip_info(the_mock): + self.assertEqual(num_ext_subnets, len(the_mock.ip_infos)) + self.assertTrue(the_mock.ip_infos[0]['is_primary']) + self.assertEqual('19.4.0.4/24', the_mock.ip_infos[0]['ip_cidr']) + for i in range(1, num_ext_subnets): + self.assertFalse(the_mock.ip_infos[i]['is_primary']) + self.assertEqual('19.4.%s.4/24' % i, + the_mock.ip_infos[i]['ip_cidr']) + + # need these helpers to verify that ip_info is correct + def _ext_gw_added(ri, ex_gw_port): + self.routing_helper._external_gateway_added.ip_infos.append( + copy.deepcopy(ex_gw_port['ip_info'])) + + def _ext_gw_removed(ri, ex_gw_port): + self.routing_helper._external_gateway_removed.ip_infos.append( + copy.deepcopy(ex_gw_port['ip_info'])) + + router, ports = prepare_router_data(num_subnets=num_ext_subnets) + # Setup mock for call to process floating ips self.routing_helper._process_router_floating_ips = mock.Mock() fake_floatingips1 = {'floatingips': [ {'id': _uuid(), @@ -262,17 +327,18 @@ class TestBasicRoutingOperations(base.BaseTestCase): 'fixed_ip_address': '7.7.7.7', 'port_id': _uuid()}]} ri = routing_svc_helper.RouterInfo(router['id'], router=router) + self.routing_helper._external_gateway_added.ip_infos = [] + self.routing_helper._external_gateway_added.side_effect = _ext_gw_added # Process with initial values self.routing_helper._process_router(ri) ex_gw_port = ri.router.get('gw_port') # Assert that process_floating_ips, internal_network & external network # added were all called with the right params - self.routing_helper._process_router_floating_ips.assert_called_with( - ri, ex_gw_port) - self.routing_helper._internal_network_added.assert_called_with( + (self.routing_helper._process_router_floating_ips + .assert_called_once_with(ri, ex_gw_port)) + self.routing_helper._internal_network_added.assert_called_once_with( ri, ports[0], ex_gw_port) - self.routing_helper._external_gateway_added.assert_called_with( - ri, ex_gw_port) + _verify_ip_info(self.routing_helper._external_gateway_added) self._reset_mocks() # remap floating IP to a new fixed ip fake_floatingips2 = copy.deepcopy(fake_floatingips1) @@ -283,8 +349,8 @@ class TestBasicRoutingOperations(base.BaseTestCase): # was only called. self.routing_helper._process_router(ri) ex_gw_port = ri.router.get('gw_port') - self.routing_helper._process_router_floating_ips.assert_called_with( - ri, ex_gw_port) + (self.routing_helper._process_router_floating_ips + .assert_called_once_with(ri, ex_gw_port)) self.assertFalse(self.routing_helper._internal_network_added.called) self.assertFalse(self.routing_helper._external_gateway_added.called) self._reset_mocks() @@ -294,8 +360,8 @@ class TestBasicRoutingOperations(base.BaseTestCase): # process_floating_ips and external_network remove was called self.routing_helper._process_router(ri) ex_gw_port = ri.router.get('gw_port') - self.routing_helper._process_router_floating_ips.assert_called_with( - ri, ex_gw_port) + (self.routing_helper._process_router_floating_ips + .assert_called_once_with(ri, ex_gw_port)) self.assertFalse(self.routing_helper._internal_network_added.called) self.assertFalse(self.routing_helper._external_gateway_added.called) self._reset_mocks() @@ -310,18 +376,79 @@ class TestBasicRoutingOperations(base.BaseTestCase): ri.router = router # Keep a copy of the ex_gw_port before its gone after processing. ex_gw_port = ri.ex_gw_port + self.routing_helper._external_gateway_removed.ip_infos = [] + self.routing_helper._external_gateway_removed.side_effect = ( + _ext_gw_removed) # Process router and verify that internal and external network removed # were called and floating_ips_process was called self.routing_helper._process_router(ri) self.assertFalse(self.routing_helper. _process_router_floating_ips.called) self.assertFalse(self.routing_helper._external_gateway_added.called) - self.assertTrue(self.routing_helper._internal_network_removed.called) - self.assertTrue(self.routing_helper._external_gateway_removed.called) - self.routing_helper._internal_network_removed.assert_called_with( + self.routing_helper._internal_network_removed.assert_called_once_with( ri, ports[0], ex_gw_port) - self.routing_helper._external_gateway_removed.assert_called_with( - ri, ex_gw_port) + _verify_ip_info(self.routing_helper._external_gateway_removed) + + def test_process_router(self, test_admin_state=True): + self._test_process_msn_router(num_ext_subnets=1, + test_admin_state=test_admin_state) + + def test_process_msn_router(self): + self._test_process_msn_router() + + def _test_process_global_msn_router(self, num_ext_subnets=3): + + def _verify_ip_info(the_mock): + self.assertEqual(num_ext_subnets, len(the_mock.ip_infos)) + self.assertTrue(the_mock.ip_infos[0]['is_primary']) + self.assertEqual('35.4.0.4/24', the_mock.ip_infos[0]['ip_cidr']) + for i in range(1, num_ext_subnets): + self.assertFalse(the_mock.ip_infos[i]['is_primary']) + self.assertEqual('35.4.%s.4/24' % i, + the_mock.ip_infos[i]['ip_cidr']) + + # need these helpers to verify that ip_info is correct + def _int_nw_added(ri, port, ex_gw_port): + self.assertIsNone(ex_gw_port) + self.routing_helper._internal_network_added.ip_infos.append( + copy.deepcopy(port['ip_info'])) + + router, ports = prepare_router_data(num_subnets=num_ext_subnets, + is_global=True) + # Setup mock for call to process floating ips + self.routing_helper._process_router_floating_ips = mock.Mock() + ri = routing_svc_helper.RouterInfo(router['id'], router=router) + self.routing_helper._internal_network_added.ip_infos = [] + self.routing_helper._internal_network_added.side_effect = _int_nw_added + # Process with initial values + self.routing_helper._process_router(ri) + self.assertFalse(self.routing_helper. + _process_router_floating_ips.called) + self.assertFalse(self.routing_helper._external_gateway_added.called) + _verify_ip_info(self.routing_helper._internal_network_added) + self._reset_mocks() + + # now no ports so state is torn down + del router[bc.constants.INTERFACE_KEY] + # Update router_info object + ri.router = router + + # Process router and verify that internal and external network removed + # were called and floating_ips_process was called + self.routing_helper._process_router(ri) + self.assertFalse(self.routing_helper. + _process_router_floating_ips.called) + self.assertFalse(self.routing_helper._external_gateway_added.called) + self.assertFalse(self.routing_helper._external_gateway_removed.called) + self.assertFalse(self.routing_helper._internal_network_added.called) + self.routing_helper._internal_network_removed.assert_called_once_with( + ri, ports[0], None) + + def test_process_global_router(self): + self._test_process_global_msn_router(num_ext_subnets=1,) + + def test_process_global_msn_router(self): + self._test_process_global_msn_router() def test_routing_table_update(self): router = self.router diff --git a/networking_cisco/tests/unit/cisco/cfg_agent/test_routing_svc_helper_aci.py b/networking_cisco/tests/unit/cisco/cfg_agent/test_routing_svc_helper_aci.py index 056074b..305ffe6 100644 --- a/networking_cisco/tests/unit/cisco/cfg_agent/test_routing_svc_helper_aci.py +++ b/networking_cisco/tests/unit/cisco/cfg_agent/test_routing_svc_helper_aci.py @@ -80,10 +80,20 @@ class TestBasicRoutingOperationsAci(helper.TestBasicRoutingOperations): self.driver = self._mock_driver_and_hosting_device( self.routing_helper) + def test_process_router_throw_multiple_ipv4_subnets_error(self): + ri, router = ( + self._test_process_router_throw_multiple_ipv4_subnets_error()) + router['gw_port'] = {'id': ''} + self.assertRaises(svc_helper.MultipleIPv4SubnetsException, + self.routing_helper._process_router, ri) + def test_process_router(self): super(TestBasicRoutingOperationsAci, self).test_process_router(test_admin_state=False) + def test_process_msn_router(self): + self._test_process_msn_router(test_admin_state=False) + def test_process_router_2_rids_1_vrf(self): driver = self._mock_driver_and_hosting_device(self.routing_helper) router1, ports = helper.prepare_router_data() diff --git a/networking_cisco/tests/unit/cisco/device_manager/test_hw_vlan_trunking_plugging_driver.py b/networking_cisco/tests/unit/cisco/device_manager/test_hw_vlan_trunking_plugging_driver.py index 01d2571..867fa58 100644 --- a/networking_cisco/tests/unit/cisco/device_manager/test_hw_vlan_trunking_plugging_driver.py +++ b/networking_cisco/tests/unit/cisco/device_manager/test_hw_vlan_trunking_plugging_driver.py @@ -146,6 +146,7 @@ class TestHwVLANTrunkingPlugDriver( fake_port_db_obj.hosting_info = mock.MagicMock() fake_port_db_obj.hosting_info.segmentation_id = 50 fake_port_db_obj.device_owner = bc.constants.DEVICE_OWNER_ROUTER_INTF + fake_port_db_obj.networks.external = None hosting_device = {'id': '00000000-0000-0000-0000-000000000002'} tenant_id = 'tenant_uuid1' ctx = context.Context('', tenant_id, is_admin=True) @@ -162,6 +163,7 @@ class TestHwVLANTrunkingPlugDriver( fake_port_db_obj.hosting_info = mock.MagicMock() fake_port_db_obj.hosting_info.segmentation_id = 40 fake_port_db_obj.device_owner = bc.constants.DEVICE_OWNER_ROUTER_GW + fake_port_db_obj.networks.external = {'external': True} hosting_device = {'id': '00000000-0000-0000-0000-000000000002'} tenant_id = 'tenant_uuid1' ctx = context.Context('', tenant_id, is_admin=True) diff --git a/networking_cisco/tests/unit/cisco/l3/test_asr1k_routertype_driver.py b/networking_cisco/tests/unit/cisco/l3/test_asr1k_routertype_driver.py index 879f5ed..1ccdf11 100644 --- a/networking_cisco/tests/unit/cisco/l3/test_asr1k_routertype_driver.py +++ b/networking_cisco/tests/unit/cisco/l3/test_asr1k_routertype_driver.py @@ -63,6 +63,9 @@ class Asr1kRouterTypeDriverTestCase( router_type = 'Nexus_ToR_Neutron_router' def _verify_global_router(self, role, hd_id, ext_net_ids): + # The 'ext_net_ids' argument is a dict where key is ext_net_id and + # value is a list of subnet_ids that the global router should be + # connected to if role == ROUTER_ROLE_LOGICAL_GLOBAL or hd_id is None: q_p = '%s=%s' % (ROUTER_ROLE_ATTR, role) else: @@ -85,10 +88,18 @@ class Asr1kRouterTypeDriverTestCase( DEVICE_OWNER_GLOBAL_ROUTER_GW) aux_gw_ports = self._list('ports', query_params=q_p)['ports'] self.assertEqual(len(ext_net_ids), len(aux_gw_ports)) - ids = copy.copy(ext_net_ids) + ids = copy.deepcopy(ext_net_ids) + # check that there are ports on each external network for aux_gw_port in aux_gw_ports: self.assertIn(aux_gw_port['network_id'], ids) - ids.remove(aux_gw_port['network_id']) + self.assertEqual(len(aux_gw_port['fixed_ips']), + len(ids[aux_gw_port['network_id']])) + # check that port has ip on correct subnets + for ips in aux_gw_port['fixed_ips']: + self.assertIn(ips['subnet_id'], + ids[aux_gw_port['network_id']]) + ids[aux_gw_port['network_id']].remove(ips['subnet_id']) + ids.pop(aux_gw_port['network_id']) return router['id'] def _verify_routers(self, router_ids, ext_net_ids, hd_id=None, @@ -134,16 +145,21 @@ class Asr1kRouterTypeDriverTestCase( self.network(tenant_id=tenant_id_2) as n_external_2: ext_net_1_id = n_external_1['network']['id'] self._set_net_external(ext_net_1_id) - self._create_subnet(self.fmt, ext_net_1_id, cidr='10.0.1.0/24', - tenant_id=tenant_id_1) + sn_1 = self._make_subnet( + self.fmt, n_external_1, '10.0.1.1', cidr='10.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + ext_net_ids = {ext_net_1_id: [sn_1['id']]} + ext_gw_1 = {'network_id': ext_net_1_id} if same_ext_net is False: ext_net_2_id = n_external_2['network']['id'] self._set_net_external(ext_net_2_id) - self._create_subnet(self.fmt, ext_net_2_id, cidr='10.0.2.0/24', - tenant_id=tenant_id_2) + sn_2 = self._make_subnet( + self.fmt, n_external_2, '10.0.2.1', cidr='10.0.2.0/24', + tenant_id=tenant_id_2)['subnet'] + ext_gw_2_subnets = [sn_2['id']] else: ext_net_2_id = ext_net_1_id - ext_gw_1 = {'network_id': ext_net_1_id} + ext_gw_2_subnets = [sn_1['id']] ext_gw_2 = {'network_id': ext_net_2_id} with self.router( tenant_id=tenant_id_1, external_gateway_info=ext_gw_1, @@ -153,14 +169,14 @@ class Asr1kRouterTypeDriverTestCase( r1_after = self._show('routers', r1['id'])['router'] hd_id = r1_after[HOSTING_DEVICE_ATTR] # should have one global router now - self._verify_routers({r1['id']}, {ext_net_1_id}, hd_id) + self._verify_routers({r1['id']}, ext_net_ids, hd_id) with self.router( tenant_id=tenant_id_2, external_gateway_info=ext_gw_1, set_context=set_context) as router2: r2 = router2['router'] self.l3_plugin._process_backlogged_routers() # should still have only one global router - self._verify_routers({r1['id'], r2['id']}, {ext_net_1_id}, + self._verify_routers({r1['id'], r2['id']}, ext_net_ids, hd_id) with self.router(name='router2', tenant_id=tenant_id_2, external_gateway_info=ext_gw_2, @@ -169,9 +185,9 @@ class Asr1kRouterTypeDriverTestCase( self.l3_plugin._process_backlogged_routers() # should still have only one global router but now with # one extra auxiliary gateway port + ext_net_ids[ext_net_2_id] = ext_gw_2_subnets self._verify_routers( - {r1['id'], r2['id'], r3['id']}, - {ext_net_1_id, ext_net_2_id}, hd_id) + {r1['id'], r2['id'], r3['id']}, ext_net_ids, hd_id) # single tenant and single external network def test_create_gateway_router(self): @@ -202,12 +218,89 @@ class Asr1kRouterTypeDriverTestCase( self._test_create_gateway_router(True, same_tenant=False, same_ext_net=False) + # msn - multiple subnets (on a single neutron external network) + def _test_create_msn_gateway_router(self, set_context=False, + same_tenant=True, same_ext_net=True): + tenant_id_1 = _uuid() + tenant_id_2 = tenant_id_1 if same_tenant is True else _uuid() + with self.network(tenant_id=tenant_id_1) as msn_n_external_1,\ + self.network(tenant_id=tenant_id_2) as n_external_2: + msn_ext_net_1_id = msn_n_external_1['network']['id'] + self._set_net_external(msn_ext_net_1_id) + sn_1 = self._make_subnet( + self.fmt, msn_n_external_1, '10.0.1.1', cidr='10.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + sn_2 = self._make_subnet( + self.fmt, msn_n_external_1, '20.0.1.1', cidr='20.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + ext_gw_1_subnets = [sn_1['id'], sn_2['id']] + ext_net_ids = {msn_ext_net_1_id: ext_gw_1_subnets} + ext_gw_1 = { + 'network_id': msn_ext_net_1_id, + 'external_fixed_ips': [{'subnet_id': sid} + for sid in ext_gw_1_subnets]} + if same_ext_net is False: + ext_net_2_id = n_external_2['network']['id'] + self._set_net_external(ext_net_2_id) + sn_3 = self._make_subnet( + self.fmt, n_external_2, '10.0.2.1', cidr='10.0.2.0/24', + tenant_id=tenant_id_2)['subnet'] + ext_gw_2_subnets = [sn_3['id']] + ext_gw_2 = {'network_id': ext_net_2_id, + 'external_fixed_ips': [{'subnet_id': sn_3['id']}]} + else: + ext_net_2_id = msn_ext_net_1_id + ext_gw_2_subnets = ext_gw_1_subnets + ext_gw_2 = ext_gw_1 + with self.router( + tenant_id=tenant_id_1, external_gateway_info=ext_gw_1, + set_context=set_context) as router1: + r1 = router1['router'] + self.l3_plugin._process_backlogged_routers() + r1_after = self._show('routers', r1['id'])['router'] + hd_id = r1_after[HOSTING_DEVICE_ATTR] + # should have one global router now + self._verify_routers({r1['id']}, ext_net_ids, hd_id) + with self.router( + tenant_id=tenant_id_2, external_gateway_info=ext_gw_1, + set_context=set_context) as router2: + r2 = router2['router'] + self.l3_plugin._process_backlogged_routers() + # should still have only one global router + self._verify_routers({r1['id'], r2['id']}, ext_net_ids, + hd_id) + with self.router(name='router2', tenant_id=tenant_id_2, + external_gateway_info=ext_gw_2, + set_context=set_context) as router3: + r3 = router3['router'] + self.l3_plugin._process_backlogged_routers() + # should still have only one global router but now with + # one extra auxiliary gateway port + ext_net_ids[ext_net_2_id] = ext_gw_2_subnets + self._verify_routers( + {r1['id'], r2['id'], r3['id']}, + ext_net_ids, hd_id) + + # single tenant and single external network with two subnets + def test_create_msn_gateway_router(self): + self._test_create_msn_gateway_router() + + def test_create_msn_gateway_router_dt(self): + self._test_create_msn_gateway_router(same_tenant=False) + + def test_create_msn_gateway_router_den(self): + self._test_create_msn_gateway_router(same_ext_net=False) + + def test_create_msn_gateway_router_dt_den(self): + self._test_create_msn_gateway_router(same_tenant=False, + same_ext_net=False) + def _test_create_router_adds_no_global_router(self, set_context=False): with self.router(set_context=set_context) as router: r = router['router'] self.l3_plugin._process_backlogged_routers() # should have no global routers - self._verify_routers({r['id']}, set(), None) + self._verify_routers({r['id']}, {}, None) def test_create_router_adds_no_global_router(self): self._test_create_router_adds_no_global_router() @@ -222,8 +315,10 @@ class Asr1kRouterTypeDriverTestCase( with self.network(tenant_id=tenant_id_1) as n_external_1: ext_net_1_id = n_external_1['network']['id'] self._set_net_external(ext_net_1_id) - self._create_subnet(self.fmt, ext_net_1_id, cidr='10.0.1.0/24', - tenant_id=tenant_id_1) + sn_1 = self._make_subnet( + self.fmt, n_external_1, '10.0.1.1', cidr='10.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + ext_net_ids = {ext_net_1_id: [sn_1['id']]} ext_gw_1 = {'network_id': ext_net_1_id} with self.router( tenant_id=tenant_id_1, external_gateway_info=ext_gw_1, @@ -238,8 +333,7 @@ class Asr1kRouterTypeDriverTestCase( # backlog processing will trigger one routers_updated # notification containing r1 and r2 self.l3_plugin._process_backlogged_routers() - self._verify_routers({r1['id'], r2['id']}, {ext_net_1_id}, - hd_id) + self._verify_routers({r1['id'], r2['id']}, ext_net_ids, hd_id) def test_create_router_adds_no_aux_gw_port_to_global_router(self): self._test_create_router_adds_no_aux_gw_port_to_global_router() @@ -265,16 +359,21 @@ class Asr1kRouterTypeDriverTestCase( self.network(tenant_id=tenant_id_2) as n_external_2: ext_net_1_id = n_external_1['network']['id'] self._set_net_external(ext_net_1_id) - self._create_subnet(self.fmt, ext_net_1_id, cidr='10.0.1.0/24', - tenant_id=tenant_id_1) + sn_1 = self._make_subnet( + self.fmt, n_external_1, '10.0.1.1', cidr='10.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + ext_net_ids = {ext_net_1_id: [sn_1['id']]} + ext_gw_1 = {'network_id': ext_net_1_id} if same_ext_net is False: ext_net_2_id = n_external_2['network']['id'] self._set_net_external(ext_net_2_id) - self._create_subnet(self.fmt, ext_net_2_id, cidr='10.0.2.0/24', - tenant_id=tenant_id_2) + sn_2 = self._make_subnet( + self.fmt, n_external_2, '10.0.2.1', cidr='10.0.2.0/24', + tenant_id=tenant_id_2)['subnet'] + ext_gw_2_subnets = [sn_2['id']] else: ext_net_2_id = ext_net_1_id - ext_gw_1 = {'network_id': ext_net_1_id} + ext_gw_2_subnets = [sn_1['id']] ext_gw_2 = {'network_id': ext_net_2_id} with self.router(tenant_id=tenant_id_1, set_context=set_context) as router1, \ @@ -287,7 +386,6 @@ class Asr1kRouterTypeDriverTestCase( self.l3_plugin._process_backlogged_routers() # should have no global router yet r_ids = {r1['id'], r2['id']} - ext_net_ids = {ext_net_1_id} self._verify_routers(r_ids, ext_net_ids) r_spec = {'router': {l3.EXTERNAL_GW_INFO: ext_gw_1}} r1_after = self._update('routers', r1['id'], r_spec)['router'] @@ -298,7 +396,7 @@ class Asr1kRouterTypeDriverTestCase( self._update('routers', r2['id'], r_spec)['router'] # should still have only one global router but now with # one extra auxiliary gateway port - ext_net_ids = {ext_net_1_id, ext_net_2_id} + ext_net_ids[ext_net_2_id] = ext_gw_2_subnets self._verify_routers(r_ids, ext_net_ids, hd_id, [1, 3]) def test_update_router_set_gateway(self): @@ -327,6 +425,90 @@ class Asr1kRouterTypeDriverTestCase( self._test_update_router_set_gateway(True, same_tenant=False, same_ext_net=False) + def _test_update_router_set_msn_gateway( + self, set_context=False, same_tenant=True, same_ext_net=True): + tenant_id_1 = _uuid() + tenant_id_2 = tenant_id_1 if same_tenant is True else _uuid() + with self.network(tenant_id=tenant_id_1) as msn_n_external_1, \ + self.network(tenant_id=tenant_id_2) as n_external_2: + msn_ext_net_1_id = msn_n_external_1['network']['id'] + self._set_net_external(msn_ext_net_1_id) + sn_1 = self._make_subnet( + self.fmt, msn_n_external_1, '10.0.1.1', cidr='10.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + sn_2 = self._make_subnet( + self.fmt, msn_n_external_1, '20.0.1.1', cidr='20.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + ext_net_ids = {msn_ext_net_1_id: [sn_1['id'], sn_2['id']]} + ext_gw_1 = { + 'network_id': msn_ext_net_1_id, + 'external_fixed_ips': [{'subnet_id': sn_1['id']}]} + if same_ext_net is False: + ext_net_2_id = n_external_2['network']['id'] + self._set_net_external(ext_net_2_id) + sn_3 = self._make_subnet( + self.fmt, n_external_2, '10.0.2.1', cidr='10.0.2.0/24', + tenant_id=tenant_id_2)['subnet'] + ext_gw_2_subnets = [sn_3['id']] + ext_gw_2 = {'network_id': ext_net_2_id, + 'external_fixed_ips': [{'subnet_id': sn_3['id']}]} + else: + ext_net_2_id = msn_ext_net_1_id + ext_gw_2_subnets = ext_net_ids[msn_ext_net_1_id] + ext_gw_2 = ext_gw_1 + with self.router(tenant_id=tenant_id_1, + set_context=set_context) as router1, \ + self.router(name='router2', tenant_id=tenant_id_2, + set_context=set_context) as router2: + r1 = router1['router'] + r2 = router2['router'] + # backlog processing will trigger one routers_updated + # notification containing r1 and r2 + self.l3_plugin._process_backlogged_routers() + # should have no global router yet + r_ids = {r1['id'], r2['id']} + self._verify_routers(r_ids, ext_net_ids) + r_spec = {'router': {l3.EXTERNAL_GW_INFO: ext_gw_1}} + r1_after = self._update('routers', r1['id'], r_spec)['router'] + res_ips = r1_after[l3.EXTERNAL_GW_INFO]['external_fixed_ips'] + self.assertEqual(1, len(res_ips)) + self.assertEqual(sn_1['id'], res_ips[0]['subnet_id']) + hd_id = r1_after[HOSTING_DEVICE_ATTR] + # should now have one global router + self._verify_routers(r_ids, ext_net_ids, hd_id, [1]) + ext_gw_1_2 = {'network_id': msn_ext_net_1_id, + 'external_fixed_ips': [{'subnet_id': sn_1['id']}, + {'subnet_id': sn_2['id']}]} + r_spec = {'router': {l3.EXTERNAL_GW_INFO: ext_gw_1_2}} + r1_final = self._update('routers', r1['id'], r_spec)['router'] + res_ips = r1_final[l3.EXTERNAL_GW_INFO]['external_fixed_ips'] + self.assertEqual(2, len(res_ips)) + self.assertIn(res_ips[0]['subnet_id'], + ext_net_ids[msn_ext_net_1_id]) + self.assertIn(res_ips[1]['subnet_id'], + ext_net_ids[msn_ext_net_1_id]) + # should now have one global router + self._verify_routers(r_ids, ext_net_ids, hd_id, [1]) + r_spec = {'router': {l3.EXTERNAL_GW_INFO: ext_gw_2}} + self._update('routers', r2['id'], r_spec)['router'] + # should still have only one global router but now with + # one extra auxiliary gateway port + ext_net_ids[ext_net_2_id] = ext_gw_2_subnets + self._verify_routers(r_ids, ext_net_ids, hd_id, [1, 3]) + + def test_update_router_set_msn_gateway(self): + self._test_update_router_set_msn_gateway() + + def test_update_router_set_msn_gateway_dt(self): + self._test_update_router_set_msn_gateway(same_tenant=False) + + def test_update_router_set_msn_gateway_den(self): + self._test_update_router_set_msn_gateway(same_ext_net=False) + + def test_update_router_set_msn_gateway_dt_den(self): + self._test_update_router_set_msn_gateway(same_tenant=False, + same_ext_net=False) + def _test_router_update_unset_gw_or_delete( self, set_context=False, same_tenant=True, same_ext_net=True, update_operation=True): @@ -336,16 +518,22 @@ class Asr1kRouterTypeDriverTestCase( self.network(tenant_id=tenant_id_1) as n_external_2: ext_net_1_id = n_external_1['network']['id'] self._set_net_external(ext_net_1_id) - self._create_subnet(self.fmt, ext_net_1_id, cidr='10.0.1.0/24', - tenant_id=tenant_id_1) + sn_1 = self._make_subnet( + self.fmt, n_external_1, '10.0.1.1', cidr='10.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + ext_net_ids = {ext_net_1_id: [sn_1['id']]} + ext_gw_1 = {'network_id': ext_net_1_id} if same_ext_net is False: ext_net_2_id = n_external_2['network']['id'] self._set_net_external(ext_net_2_id) - self._create_subnet(self.fmt, ext_net_2_id, cidr='10.0.2.0/24', - tenant_id=tenant_id_2) + sn_2 = self._make_subnet( + self.fmt, n_external_2, '10.0.2.1', cidr='10.0.2.0/24', + tenant_id=tenant_id_2)['subnet'] + ext_gw_2_subnets = [sn_2['id']] else: ext_net_2_id = ext_net_1_id - ext_gw_1 = {'network_id': ext_net_1_id} + ext_gw_2_subnets = [sn_1['id']] + ext_net_ids[ext_net_2_id] = ext_gw_2_subnets ext_gw_2 = {'network_id': ext_net_2_id} with self.router(tenant_id=tenant_id_1, external_gateway_info=ext_gw_1, @@ -361,7 +549,6 @@ class Asr1kRouterTypeDriverTestCase( r1_after = self._show('routers', r1['id'])['router'] hd_id = r1_after[HOSTING_DEVICE_ATTR] r_ids = {r1['id'], r2['id']} - ext_net_ids = {ext_net_1_id, ext_net_2_id} # should have one global router now self._verify_routers(r_ids, ext_net_ids, hd_id, [0, 1]) if update_operation is True: @@ -370,8 +557,9 @@ class Asr1kRouterTypeDriverTestCase( else: self._delete('routers', r1['id']) r_ids = {r2['id']} - ext_net_ids = {ext_net_2_id} # should still have one global router + if same_ext_net is False: + ext_net_ids.pop(ext_net_1_id) self._verify_routers(r_ids, ext_net_ids, hd_id, [0, 1]) if update_operation is True: self._update('routers', r2['id'], r_spec) @@ -379,6 +567,7 @@ class Asr1kRouterTypeDriverTestCase( self._delete('routers', r2['id']) r_ids = {} # should have no global router now + ext_net_ids.pop(ext_net_2_id, None) self._verify_routers(r_ids, ext_net_ids) def test_router_update_unset_gw(self): @@ -407,6 +596,88 @@ class Asr1kRouterTypeDriverTestCase( self._test_router_update_unset_gw_or_delete(True, same_tenant=False, same_ext_net=False) + def _test_router_update_unset_msn_gw( + self, set_context=False, same_tenant=True, same_ext_net=True): + tenant_id_1 = _uuid() + tenant_id_2 = tenant_id_1 if same_tenant is True else _uuid() + with self.network(tenant_id=tenant_id_1) as msn_n_external_1, \ + self.network(tenant_id=tenant_id_1) as n_external_2: + msn_ext_net_1_id = msn_n_external_1['network']['id'] + self._set_net_external(msn_ext_net_1_id) + sn_1 = self._make_subnet( + self.fmt, msn_n_external_1, '10.0.1.1', cidr='10.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + sn_2 = self._make_subnet( + self.fmt, msn_n_external_1, '20.0.1.1', cidr='20.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + ext_gw_1_subnets = [sn_1['id'], sn_2['id']] + ext_net_ids = {msn_ext_net_1_id: ext_gw_1_subnets} + ext_gw_1 = { + 'network_id': msn_ext_net_1_id, + 'external_fixed_ips': [{'subnet_id': sid} + for sid in ext_gw_1_subnets]} + if same_ext_net is False: + ext_net_2_id = n_external_2['network']['id'] + self._set_net_external(ext_net_2_id) + sn_3 = self._make_subnet( + self.fmt, n_external_2, '10.0.2.1', cidr='10.0.2.0/24', + tenant_id=tenant_id_2)['subnet'] + ext_gw_2_subnets = [sn_3['id']] + ext_gw_2 = {'network_id': ext_net_2_id, + 'external_fixed_ips': [{'subnet_id': sn_3['id']}]} + else: + ext_net_2_id = msn_ext_net_1_id + ext_gw_2_subnets = ext_gw_1_subnets + ext_gw_2 = ext_gw_1 + ext_net_ids[ext_net_2_id] = ext_gw_2_subnets + with self.router(tenant_id=tenant_id_1, + external_gateway_info=ext_gw_1, + set_context=set_context) as router1,\ + self.router(name='router2', tenant_id=tenant_id_2, + external_gateway_info=ext_gw_2, + set_context=set_context) as router2: + r1 = router1['router'] + r2 = router2['router'] + # backlog processing will trigger one routers_updated + # notification containing r1 and r2 + self.l3_plugin._process_backlogged_routers() + r1_after = self._show('routers', r1['id'])['router'] + hd_id = r1_after[HOSTING_DEVICE_ATTR] + r_ids = {r1['id'], r2['id']} + # should have one global router now + self._verify_routers(r_ids, ext_net_ids, hd_id, [0, 1]) + ext_gw_1['external_fixed_ips'] = [{'subnet_id': sn_1['id']}] + r_spec = {'router': {l3.EXTERNAL_GW_INFO: ext_gw_1}} + r1_after_2 = self._update('routers', r1['id'], + r_spec)['router'] + res_ips = r1_after_2[l3.EXTERNAL_GW_INFO]['external_fixed_ips'] + self.assertEqual(1, len(res_ips)) + self.assertEqual(sn_1['id'], res_ips[0]['subnet_id']) + # should still have one global router + self._verify_routers(r_ids, ext_net_ids, hd_id, [0, 1]) + r_spec = {'router': {l3.EXTERNAL_GW_INFO: None}} + self._update('routers', r1['id'], r_spec) + # should still have one global router + if same_ext_net is False: + ext_net_ids.pop(msn_ext_net_1_id) + self._verify_routers(r_ids, ext_net_ids, hd_id, [0, 1]) + self._update('routers', r2['id'], r_spec) + # should have no global router now + self._verify_routers(r_ids, ext_net_ids) + + def test_router_update_unset_msn_gw(self): + self._test_router_update_unset_msn_gw() + + def test_router_update_unset_msn_gw_dt(self): + self._test_router_update_unset_msn_gw(same_tenant=False) + + def test_router_update_unset_msn_gw_den(self): + self._test_router_update_unset_msn_gw(same_ext_net=False) + + def test_router_update_unset_msn_gw_dt_den(self): + self._test_router_update_unset_msn_gw(same_tenant=False, + same_ext_net=False) + def _test_delete_gateway_router(self, set_context=False, same_tenant=True, same_ext_net=True): self._test_router_update_unset_gw_or_delete( @@ -437,6 +708,80 @@ class Asr1kRouterTypeDriverTestCase( self._test_delete_gateway_router(True, same_tenant=False, same_ext_net=False) + def _test_delete_msn_gateway_router(self, set_context=False, + same_tenant=True, same_ext_net=True): + tenant_id_1 = _uuid() + tenant_id_2 = tenant_id_1 if same_tenant is True else _uuid() + with self.network(tenant_id=tenant_id_1) as msn_n_external_1, \ + self.network(tenant_id=tenant_id_1) as n_external_2: + msn_ext_net_1_id = msn_n_external_1['network']['id'] + self._set_net_external(msn_ext_net_1_id) + sn_1 = self._make_subnet( + self.fmt, msn_n_external_1, '10.0.1.1', cidr='10.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + sn_2 = self._make_subnet( + self.fmt, msn_n_external_1, '20.0.1.1', cidr='20.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + ext_gw_1_subnets = [sn_1['id'], sn_2['id']] + ext_net_ids = {msn_ext_net_1_id: ext_gw_1_subnets} + ext_gw_1 = { + 'network_id': msn_ext_net_1_id, + 'external_fixed_ips': [{'subnet_id': sid} + for sid in ext_gw_1_subnets]} + if same_ext_net is False: + ext_net_2_id = n_external_2['network']['id'] + self._set_net_external(ext_net_2_id) + sn_3 = self._make_subnet( + self.fmt, n_external_2, '10.0.2.1', cidr='10.0.2.0/24', + tenant_id=tenant_id_2)['subnet'] + ext_gw_2_subnets = [sn_3['id']] + ext_gw_2 = {'network_id': ext_net_2_id, + 'external_fixed_ips': [{'subnet_id': sn_3['id']}]} + else: + ext_net_2_id = msn_ext_net_1_id + ext_gw_2_subnets = ext_gw_1_subnets + ext_gw_2 = ext_gw_1 + ext_net_ids[ext_net_2_id] = ext_gw_2_subnets + with self.router(tenant_id=tenant_id_1, + external_gateway_info=ext_gw_1, + set_context=set_context) as router1,\ + self.router(name='router2', tenant_id=tenant_id_2, + external_gateway_info=ext_gw_2, + set_context=set_context) as router2: + r1 = router1['router'] + r2 = router2['router'] + # backlog processing will trigger one routers_updated + # notification containing r1 and r2 + self.l3_plugin._process_backlogged_routers() + r1_after = self._show('routers', r1['id'])['router'] + hd_id = r1_after[HOSTING_DEVICE_ATTR] + r_ids = {r1['id'], r2['id']} + # should have one global router now + self._verify_routers(r_ids, ext_net_ids, hd_id, [0, 1]) + self._delete('routers', r1['id']) + r_ids = {r2['id']} + # should still have one global router + if same_ext_net is False: + ext_net_ids.pop(msn_ext_net_1_id) + self._verify_routers(r_ids, ext_net_ids, hd_id, [0, 1]) + self._delete('routers', r2['id']) + r_ids = {} + # should have no global router now + self._verify_routers(r_ids, ext_net_ids) + + def test_delete_msn_gateway_router(self): + self._test_delete_msn_gateway_router() + + def test_delete_msn_gateway_router_dt(self): + self._test_delete_msn_gateway_router(same_tenant=False) + + def test_delete_msn_gateway_router_den(self): + self._test_delete_msn_gateway_router(same_ext_net=False) + + def test_delete_msn_gateway_router_dt_den(self): + self._test_delete_msn_gateway_router(same_tenant=False, + same_ext_net=False) + def _test_router_interface_add_refused_for_unsupported_topology( self, num_expected_ports=2, set_context=False, same_tenant=True): tenant_id_1 = _uuid() @@ -518,6 +863,9 @@ class Asr1kHARouterTypeDriverTestCase( def _verify_routers(self, router_ids, ext_net_ids, hd_id=None, call_indices=None): + # The 'ext_net_ids' argument is a dict where key is ext_net_id and + # value is a list of subnet_ids that the global router should be + # connected to # tenant routers q_p = '%s=None' % ROUTER_ROLE_ATTR r_ids = {r['id'] for r in self._list( @@ -574,6 +922,9 @@ class L3CfgAgentAsr1kRouterTypeDriverTestCase( super(L3CfgAgentAsr1kRouterTypeDriverTestCase, self).tearDown() def _verify_global_router(self, role, hd_id, ext_net_ids): + # The 'ext_net_ids' argument is a dict where key is ext_net_id and + # value is a list of subnet_ids that the global router should be + # connected to if hd_id is None: q_p = '%s=%s' % (ROUTER_ROLE_ATTR, role) else: @@ -593,10 +944,17 @@ class L3CfgAgentAsr1kRouterTypeDriverTestCase( DEVICE_OWNER_GLOBAL_ROUTER_GW) aux_gw_ports = self._list('ports', query_params=q_p)['ports'] self.assertEqual(len(ext_net_ids), len(aux_gw_ports)) - ids = copy.copy(ext_net_ids) + ids = copy.deepcopy(ext_net_ids) for aux_gw_port in aux_gw_ports: self.assertIn(aux_gw_port['network_id'], ids) - ids.remove(aux_gw_port['network_id']) + self.assertEqual(len(aux_gw_port['fixed_ips']), + len(ids[aux_gw_port['network_id']])) + # check that port has ip on correct subnets + for ips in aux_gw_port['fixed_ips']: + self.assertIn(ips['subnet_id'], + ids[aux_gw_port['network_id']]) + ids[aux_gw_port['network_id']].remove(ips['subnet_id']) + ids.pop(aux_gw_port['network_id']) return router def _verify_ha_settings(self, router, expected_ha): @@ -628,6 +986,9 @@ class L3CfgAgentAsr1kRouterTypeDriverTestCase( ha_port['fixed_ips'][0]['ip_address']) def _verify_sync_data(self, router, router_ids, ext_net_ids): + # The 'ext_net_ids' argument is a dict where key is ext_net_id and + # value is a list of subnet_ids that the global router should be + # connected to hd_id = router[HOSTING_DEVICE_ATTR] id_r_ha_backup = router[ha.DETAILS][ha.REDUNDANCY_ROUTERS][0]['id'] router_ha_backup = self._show('routers', id_r_ha_backup)['router'] @@ -675,21 +1036,34 @@ class L3CfgAgentAsr1kRouterTypeDriverTestCase( 'allocated_vlan': 5}) tenant_id_1 = _uuid() tenant_id_2 = tenant_id_1 if same_tenant is True else _uuid() - with self.network(tenant_id=tenant_id_1) as n_external_1, \ + with self.network(tenant_id=tenant_id_1) as msn_n_external_1, \ self.network(tenant_id=tenant_id_1) as n_external_2: - ext_net_1_id = n_external_1['network']['id'] - self._set_net_external(ext_net_1_id) - self._create_subnet(self.fmt, ext_net_1_id, cidr='10.0.1.0/24', - tenant_id=tenant_id_1) + msn_ext_net_1_id = msn_n_external_1['network']['id'] + self._set_net_external(msn_ext_net_1_id) + sn_1 = self._make_subnet( + self.fmt, msn_n_external_1, '10.0.1.1', cidr='10.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + sn_2 = self._make_subnet( + self.fmt, msn_n_external_1, '20.0.1.1', cidr='20.0.1.0/24', + tenant_id=tenant_id_1)['subnet'] + ext_net_ids = {msn_ext_net_1_id: [sn_1['id'], sn_2['id']]} + ext_gw_1 = { + 'network_id': msn_ext_net_1_id, + 'external_fixed_ips': [{'subnet_id': sn_1['id']}]} if same_ext_net is False: ext_net_2_id = n_external_2['network']['id'] self._set_net_external(ext_net_2_id) - self._create_subnet(self.fmt, ext_net_2_id, cidr='10.0.2.0/24', - tenant_id=tenant_id_2) + sn_3 = self._make_subnet( + self.fmt, n_external_2, '10.0.2.1', cidr='10.0.2.0/24', + tenant_id=tenant_id_2)['subnet'] + ext_gw_2_subnets = [sn_3['id']] + ext_gw_2 = {'network_id': ext_net_2_id, + 'external_fixed_ips': [{'subnet_id': sn_3['id']}]} else: - ext_net_2_id = ext_net_1_id - ext_gw_1 = {'network_id': ext_net_1_id} - ext_gw_2 = {'network_id': ext_net_2_id} + ext_net_2_id = msn_ext_net_1_id + ext_gw_2_subnets = ext_net_ids[msn_ext_net_1_id] + ext_gw_2 = ext_gw_1 + ext_net_ids[ext_net_2_id] = ext_gw_2_subnets with self.router(tenant_id=tenant_id_1, external_gateway_info=ext_gw_1, set_context=set_context) as router1, \ @@ -705,7 +1079,6 @@ class L3CfgAgentAsr1kRouterTypeDriverTestCase( self.l3_plugin._process_backlogged_routers() r1_after = self._show('routers', r1['id'])['router'] r_ids = [r1['id'], r2['id'], r3['id']] - ext_net_ids = {ext_net_1_id, ext_net_2_id} self._verify_sync_data(r1_after, r_ids, ext_net_ids) def test_l3_cfg_agent_query_global_router_info(self):