Merge "[AIM] Support sharing of L3Outs"
This commit is contained in:
commit
c61fa15ad7
|
@ -62,3 +62,8 @@ class PreExistingSVICannotBeConnectedToRouter(exceptions.BadRequest):
|
|||
|
||||
class OnlyOneSubnetInSVINetwork(exceptions.BadRequest):
|
||||
message = _("Only one subnet is allowed in SVI network.")
|
||||
|
||||
|
||||
class ExternalSubnetOverlapInL3Out(exceptions.BadRequest):
|
||||
message = _("External subnet CIDR %(cidr)s overlaps with existing "
|
||||
"subnets in APIC L3Outside %(l3out)s.")
|
||||
|
|
|
@ -112,6 +112,30 @@ class ExtensionDbMixin(object):
|
|||
res_dict[cisco_apic.EXTERNAL_CIDRS],
|
||||
network_id=network_id)
|
||||
|
||||
def get_network_ids_by_ext_net_dn(self, session, dn, lock_update=False):
|
||||
ids = session.query(NetworkExtensionDb.network_id).filter_by(
|
||||
external_network_dn=dn)
|
||||
if lock_update:
|
||||
ids = ids.with_lockmode('update')
|
||||
return [i[0] for i in ids]
|
||||
|
||||
def get_network_ids_by_l3out_dn(self, session, dn, lock_update=False):
|
||||
ids = session.query(NetworkExtensionDb.network_id).filter(
|
||||
NetworkExtensionDb.external_network_dn.like(dn + "/%"))
|
||||
if lock_update:
|
||||
ids = ids.with_lockmode('update')
|
||||
return [i[0] for i in ids]
|
||||
|
||||
def get_external_cidrs_by_ext_net_dn(self, session, dn, lock_update=False):
|
||||
ctab = NetworkExtensionCidrDb
|
||||
ntab = NetworkExtensionDb
|
||||
cidrs = session.query(ctab.cidr).join(
|
||||
ntab, ntab.network_id == ctab.network_id).filter(
|
||||
ntab.external_network_dn == dn).distinct()
|
||||
if lock_update:
|
||||
cidrs = cidrs.with_lockmode('update')
|
||||
return [c[0] for c in cidrs]
|
||||
|
||||
def get_subnet_extn_db(self, session, subnet_id):
|
||||
db_obj = (session.query(SubnetExtensionDb).filter_by(
|
||||
subnet_id=subnet_id).first())
|
||||
|
|
|
@ -452,8 +452,13 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
|
||||
ns.create_l3outside(aim_ctx, l3out, vmm_domains=domains)
|
||||
ns.create_external_network(aim_ctx, ext_net)
|
||||
ns.update_external_cidrs(aim_ctx, ext_net,
|
||||
current[cisco_apic.EXTERNAL_CIDRS])
|
||||
# Get external CIDRs for all external networks that share
|
||||
# this APIC external network.
|
||||
ext_db = extension_db.ExtensionDbMixin()
|
||||
cidrs = sorted(
|
||||
ext_db.get_external_cidrs_by_ext_net_dn(session, ext_net.dn,
|
||||
lock_update=True))
|
||||
ns.update_external_cidrs(aim_ctx, ext_net, cidrs)
|
||||
|
||||
for resource in ns.get_l3outside_resources(aim_ctx, l3out):
|
||||
if isinstance(resource, aim_resource.BridgeDomain):
|
||||
|
@ -554,7 +559,13 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
old = sorted(original[cisco_apic.EXTERNAL_CIDRS])
|
||||
new = sorted(current[cisco_apic.EXTERNAL_CIDRS])
|
||||
if old != new:
|
||||
ns.update_external_cidrs(aim_ctx, ext_net, new)
|
||||
# Get external CIDRs for all external networks that share
|
||||
# this APIC external network.
|
||||
ext_db = extension_db.ExtensionDbMixin()
|
||||
cidrs = sorted(
|
||||
ext_db.get_external_cidrs_by_ext_net_dn(
|
||||
session, ext_net.dn, lock_update=True))
|
||||
ns.update_external_cidrs(aim_ctx, ext_net, cidrs)
|
||||
# TODO(amitbose) Propagate name updates to AIM
|
||||
|
||||
def delete_network_precommit(self, context):
|
||||
|
@ -568,10 +579,22 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
l3out, ext_net, ns = self._get_aim_nat_strategy(current)
|
||||
if not ext_net:
|
||||
return # Unmanaged external network
|
||||
ns.delete_external_network(aim_ctx, ext_net)
|
||||
# TODO(amitbose) delete L3out only if no other Neutron
|
||||
# network is using the L3out
|
||||
ns.delete_l3outside(aim_ctx, l3out)
|
||||
extn_db = extension_db.ExtensionDbMixin()
|
||||
# REVISIT: lock_update=True is needed to handle races. Find
|
||||
# alternative solutions since Neutron discourages using such
|
||||
# queries.
|
||||
other_nets = set(
|
||||
extn_db.get_network_ids_by_ext_net_dn(session, ext_net.dn,
|
||||
lock_update=True))
|
||||
other_nets.discard(current['id'])
|
||||
if not other_nets:
|
||||
ns.delete_external_network(aim_ctx, ext_net)
|
||||
other_nets = set(
|
||||
extn_db.get_network_ids_by_l3out_dn(session, l3out.dn,
|
||||
lock_update=True))
|
||||
other_nets.discard(current['id'])
|
||||
if not other_nets:
|
||||
ns.delete_l3outside(aim_ctx, l3out)
|
||||
elif self._is_svi(current):
|
||||
l3out, ext_net, _ = self._get_aim_external_stuff(current)
|
||||
aim_l3out = self.aim.get(aim_ctx, l3out)
|
||||
|
@ -657,6 +680,19 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
network_db)
|
||||
if not ext_net:
|
||||
return # Unmanaged external network
|
||||
# Check subnet overlap with subnets from other Neutron
|
||||
# external networks that map to the same APIC L3Out
|
||||
ext_db = extension_db.ExtensionDbMixin()
|
||||
other_nets = set(
|
||||
ext_db.get_network_ids_by_l3out_dn(session, l3out.dn,
|
||||
lock_update=True))
|
||||
other_nets.discard(network_id)
|
||||
cidrs = (session.query(models_v2.Subnet.cidr).filter(
|
||||
models_v2.Subnet.network_id.in_(other_nets)).all())
|
||||
cidrs = netaddr.IPSet([c[0] for c in cidrs])
|
||||
if cidrs & netaddr.IPSet([current['cidr']]):
|
||||
raise exceptions.ExternalSubnetOverlapInL3Out(
|
||||
cidr=current['cidr'], l3out=l3out.dn)
|
||||
ns.create_subnet(aim_ctx, l3out,
|
||||
self._subnet_to_gw_ip_mask(current))
|
||||
|
||||
|
@ -2782,9 +2818,12 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
if old_network:
|
||||
_, ext_net, ns = self._get_aim_nat_strategy(old_network)
|
||||
if ext_net:
|
||||
# Find Neutron networks that share the APIC external network.
|
||||
eqv_nets = ext_db.get_network_ids_by_ext_net_dn(
|
||||
session, ext_net.dn, lock_update=True)
|
||||
rtr_old = [r for r in rtr_dbs
|
||||
if (r.gw_port_id and
|
||||
r.gw_port.network_id == old_network['id'])]
|
||||
r.gw_port.network_id in eqv_nets)]
|
||||
prov = set()
|
||||
cons = set()
|
||||
for r in rtr_old:
|
||||
|
@ -2799,9 +2838,12 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
if new_network:
|
||||
_, ext_net, ns = self._get_aim_nat_strategy(new_network)
|
||||
if ext_net:
|
||||
# Find Neutron networks that share the APIC external network.
|
||||
eqv_nets = ext_db.get_network_ids_by_ext_net_dn(
|
||||
session, ext_net.dn, lock_update=True)
|
||||
rtr_new = [r for r in rtr_dbs
|
||||
if (r.gw_port_id and
|
||||
r.gw_port.network_id == new_network['id'])]
|
||||
r.gw_port.network_id in eqv_nets)]
|
||||
prov = set()
|
||||
cons = set()
|
||||
for r in rtr_new:
|
||||
|
|
|
@ -2930,13 +2930,13 @@ class TestAimMapping(ApicAimTestCase):
|
|||
|
||||
class TestSyncState(ApicAimTestCase):
|
||||
@staticmethod
|
||||
def _get_synced_status(self, context, resource, create_if_absent=True):
|
||||
def _get_synced_status(self, context, resource, **kwargs):
|
||||
status = aim_status.AciStatus.SYNCED
|
||||
return aim_status.AciStatus(resource_root=resource.root,
|
||||
sync_status=status)
|
||||
|
||||
@staticmethod
|
||||
def _get_pending_status_for_type(resource, type, create_if_absent=True):
|
||||
def _get_pending_status_for_type(resource, type, **kwargs):
|
||||
status = (isinstance(resource, type) and
|
||||
aim_status.AciStatus.SYNC_PENDING or
|
||||
aim_status.AciStatus.SYNCED)
|
||||
|
@ -2944,7 +2944,7 @@ class TestSyncState(ApicAimTestCase):
|
|||
sync_status=status)
|
||||
|
||||
@staticmethod
|
||||
def _get_failed_status_for_type(resource, type, create_if_absent=True):
|
||||
def _get_failed_status_for_type(resource, type, **kwargs):
|
||||
status = (isinstance(resource, type) and
|
||||
aim_status.AciStatus.SYNC_FAILED or
|
||||
aim_status.AciStatus.SYNC_PENDING)
|
||||
|
@ -3196,6 +3196,7 @@ class TestSyncState(ApicAimTestCase):
|
|||
|
||||
subnet = self._show('subnets', subnet['id'])['subnet']
|
||||
self.assertEqual(expected_state, subnet['apic:synchronization_state'])
|
||||
self._delete("subnets", subnet['id'])
|
||||
|
||||
def test_external_subnet(self):
|
||||
with mock.patch('aim.aim_manager.AimManager.get_status',
|
||||
|
@ -3206,7 +3207,7 @@ class TestSyncState(ApicAimTestCase):
|
|||
for expected_status, status_func in [
|
||||
('build', TestSyncState._get_pending_status_for_type),
|
||||
('error', TestSyncState._get_failed_status_for_type)]:
|
||||
def get_status(self, context, resource, create_if_absent=True):
|
||||
def get_status(self, context, resource, **kwargs):
|
||||
return status_func(resource, aim_resource.Subnet)
|
||||
with mock.patch('aim.aim_manager.AimManager.get_status',
|
||||
get_status):
|
||||
|
@ -4815,7 +4816,7 @@ class TestExternalConnectivityBase(object):
|
|||
self._make_subnet(
|
||||
self.fmt, {'network': ext_net1}, '100.100.100.1',
|
||||
'100.100.100.0/24')
|
||||
ext_net2 = self._make_ext_network('ext-net1',
|
||||
ext_net2 = self._make_ext_network('ext-net2',
|
||||
dn=self.dn_t1_l2_n2)
|
||||
self._make_subnet(
|
||||
self.fmt, {'network': ext_net2}, '200.200.200.1',
|
||||
|
@ -4894,7 +4895,7 @@ class TestExternalConnectivityBase(object):
|
|||
def test_router_gateway(self):
|
||||
self._do_test_router_gateway(use_addr_scope=False)
|
||||
|
||||
def test_router_gateway_addr_scope(self,):
|
||||
def test_router_gateway_addr_scope(self):
|
||||
self._do_test_router_gateway(use_addr_scope=True)
|
||||
|
||||
def test_router_with_unmanaged_external_network(self):
|
||||
|
@ -4921,7 +4922,8 @@ class TestExternalConnectivityBase(object):
|
|||
self._router_interface_action('remove', router['id'], sub1['id'], None)
|
||||
self.mock_ns.disconnect_vrf.assert_not_called()
|
||||
|
||||
def _do_test_multiple_router(self, use_addr_scope=False):
|
||||
def _do_test_multiple_router(self, use_addr_scope=False,
|
||||
shared_l3out=False):
|
||||
cv = self.mock_ns.connect_vrf
|
||||
dv = self.mock_ns.disconnect_vrf
|
||||
|
||||
|
@ -4951,17 +4953,18 @@ class TestExternalConnectivityBase(object):
|
|||
ext_nets = []
|
||||
a_ext_nets = []
|
||||
for x in range(0, 2):
|
||||
ext_net = self._make_ext_network('ext-net%d' % x,
|
||||
dn='uni/tn-%s/out-l%d/instP-n%d' % (self.t1_aname, x, x))
|
||||
dn = (self.dn_t1_l1_n1 if shared_l3out else
|
||||
'uni/tn-%s/out-l%d/instP-n%d' % (self.t1_aname, x, x))
|
||||
ext_net = self._make_ext_network('ext-net%d' % x, dn=dn)
|
||||
self._make_subnet(
|
||||
self.fmt, {'network': ext_net}, '100.%d.100.1' % x,
|
||||
'100.%d.100.0/24' % x)
|
||||
ext_nets.append(ext_net['id'])
|
||||
a_ext_net = aim_resource.ExternalNetwork(
|
||||
tenant_name=self.t1_aname,
|
||||
l3out_name='l%d' % x, name='n%d' % x)
|
||||
a_ext_net = aim_resource.ExternalNetwork.from_dn(dn)
|
||||
a_ext_nets.append(a_ext_net)
|
||||
self.fix_l3out_vrf(self.t1_aname, 'l%d' % x, a_vrf.name)
|
||||
# Note: With shared_l3out=True, a_ext_net[0] and a_ext_net[1] are one
|
||||
# and the same APIC external network
|
||||
|
||||
routers = []
|
||||
contracts = []
|
||||
|
@ -4988,16 +4991,26 @@ class TestExternalConnectivityBase(object):
|
|||
|
||||
self.mock_ns.reset_mock()
|
||||
self._add_external_gateway_to_router(routers[1], ext_nets[1])
|
||||
a_ext_nets[1].provided_contract_names = [contracts[1]]
|
||||
a_ext_nets[1].consumed_contract_names = [contracts[1]]
|
||||
if shared_l3out:
|
||||
a_ext_nets[1].provided_contract_names = sorted(contracts)
|
||||
a_ext_nets[1].consumed_contract_names = sorted(contracts)
|
||||
else:
|
||||
a_ext_nets[1].provided_contract_names = [contracts[1]]
|
||||
a_ext_nets[1].consumed_contract_names = [contracts[1]]
|
||||
cv.assert_called_once_with(mock.ANY, a_ext_nets[1], a_vrf)
|
||||
|
||||
self.mock_ns.reset_mock()
|
||||
self._router_interface_action('remove', routers[0], sub1['id'], None)
|
||||
a_ext_nets[0].provided_contract_names = []
|
||||
a_ext_nets[0].consumed_contract_names = []
|
||||
dv.assert_called_once_with(mock.ANY, a_ext_nets[0], a_vrf)
|
||||
cv.assert_not_called()
|
||||
if shared_l3out:
|
||||
a_ext_nets[0].provided_contract_names = [contracts[1]]
|
||||
a_ext_nets[0].consumed_contract_names = [contracts[1]]
|
||||
cv.assert_called_once_with(mock.ANY, a_ext_nets[0], a_vrf)
|
||||
dv.assert_not_called()
|
||||
else:
|
||||
a_ext_nets[0].provided_contract_names = []
|
||||
a_ext_nets[0].consumed_contract_names = []
|
||||
dv.assert_called_once_with(mock.ANY, a_ext_nets[0], a_vrf)
|
||||
cv.assert_not_called()
|
||||
|
||||
self.mock_ns.reset_mock()
|
||||
self._router_interface_action('remove', routers[1], sub1['id'], None)
|
||||
|
@ -5011,6 +5024,14 @@ class TestExternalConnectivityBase(object):
|
|||
def test_multiple_router_addr_scope(self):
|
||||
self._do_test_multiple_router(use_addr_scope=True)
|
||||
|
||||
def test_multiple_router_shared_l3out(self):
|
||||
self._do_test_multiple_router(use_addr_scope=False,
|
||||
shared_l3out=True)
|
||||
|
||||
def test_multiple_router_addr_scope_shared_l3out(self):
|
||||
self._do_test_multiple_router(use_addr_scope=True,
|
||||
shared_l3out=True)
|
||||
|
||||
def test_floatingip(self):
|
||||
net1 = self._make_network(self.fmt, 'pvt-net1', True)['network']
|
||||
sub1 = self._make_subnet(
|
||||
|
@ -5377,6 +5398,111 @@ class TestExternalConnectivityBase(object):
|
|||
def test_external_network_host_domains(self):
|
||||
self._test_external_network_lifecycle_with_domains(create_hds=True)
|
||||
|
||||
def test_shared_l3out_external_cidr(self):
|
||||
net1 = self._make_ext_network('net1',
|
||||
dn=self.dn_t1_l1_n1,
|
||||
cidrs=['1.2.3.0/20', '20.10.0.0/16',
|
||||
'4.4.4.0/24'])
|
||||
a_ext_net = aim_resource.ExternalNetwork.from_dn(self.dn_t1_l1_n1)
|
||||
self.mock_ns.update_external_cidrs.assert_called_once_with(
|
||||
mock.ANY, a_ext_net, ['1.2.3.0/20', '20.10.0.0/16', '4.4.4.0/24'])
|
||||
|
||||
self.mock_ns.reset_mock()
|
||||
self._make_ext_network('net2',
|
||||
dn=self.dn_t1_l1_n1,
|
||||
cidrs=['50.60.0.0/28', '1.2.3.0/20'])
|
||||
self.mock_ns.update_external_cidrs.assert_called_once_with(
|
||||
mock.ANY, a_ext_net,
|
||||
['1.2.3.0/20', '20.10.0.0/16', '4.4.4.0/24', '50.60.0.0/28'])
|
||||
|
||||
self.mock_ns.reset_mock()
|
||||
net1 = self._update('networks', net1['id'],
|
||||
{'network': {CIDR: ['4.3.3.0/30', '20.10.0.0/16']}})['network']
|
||||
self.mock_ns.update_external_cidrs.assert_called_once_with(
|
||||
mock.ANY, a_ext_net,
|
||||
['1.2.3.0/20', '20.10.0.0/16', '4.3.3.0/30', '50.60.0.0/28'])
|
||||
|
||||
def test_shared_l3out_network_delete(self):
|
||||
# Test reference counting of shared L3outs
|
||||
|
||||
net1 = self._make_ext_network('net1', dn=self.dn_t1_l1_n1)
|
||||
a_l3out = aim_resource.L3Outside(tenant_name=self.t1_aname, name='l1')
|
||||
a_ext_net = aim_resource.ExternalNetwork(
|
||||
tenant_name=self.t1_aname, l3out_name='l1', name='n1')
|
||||
self.mock_ns.create_l3outside.assert_called_once_with(
|
||||
mock.ANY, a_l3out, vmm_domains=[])
|
||||
self.mock_ns.create_external_network.assert_called_once_with(
|
||||
mock.ANY, a_ext_net)
|
||||
|
||||
# create second network that shares APIC l3out and external-network
|
||||
self.mock_ns.reset_mock()
|
||||
net2 = self._make_ext_network('net2', dn=self.dn_t1_l1_n1)
|
||||
self.mock_ns.create_l3outside.assert_called_once_with(
|
||||
mock.ANY, a_l3out, vmm_domains=[])
|
||||
self.mock_ns.create_external_network.assert_called_once_with(
|
||||
mock.ANY, a_ext_net)
|
||||
|
||||
# create third network that shares APIC l3out only
|
||||
self.mock_ns.reset_mock()
|
||||
net3 = self._make_ext_network(
|
||||
'net3', dn=('uni/tn-%s/out-l1/instP-n2' % self.t1_aname))
|
||||
a_ext_net3 = aim_resource.ExternalNetwork(
|
||||
tenant_name=self.t1_aname, l3out_name='l1', name='n2')
|
||||
self.mock_ns.create_l3outside.assert_called_once_with(
|
||||
mock.ANY, a_l3out, vmm_domains=[])
|
||||
self.mock_ns.create_external_network.assert_called_once_with(
|
||||
mock.ANY, a_ext_net3)
|
||||
|
||||
# delete net2
|
||||
self.mock_ns.reset_mock()
|
||||
self._delete('networks', net2['id'])
|
||||
self.mock_ns.delete_l3outside.assert_not_called()
|
||||
self.mock_ns.delete_external_network.assert_not_called()
|
||||
|
||||
# delete net1
|
||||
self.mock_ns.reset_mock()
|
||||
self._delete('networks', net1['id'])
|
||||
self.mock_ns.delete_l3outside.assert_not_called()
|
||||
self.mock_ns.delete_external_network.assert_called_once_with(
|
||||
mock.ANY, a_ext_net)
|
||||
|
||||
# delete net3
|
||||
self.mock_ns.reset_mock()
|
||||
self._delete('networks', net3['id'])
|
||||
self.mock_ns.delete_l3outside.assert_called_once_with(
|
||||
mock.ANY, a_l3out)
|
||||
self.mock_ns.delete_external_network.assert_called_once_with(
|
||||
mock.ANY, a_ext_net3)
|
||||
|
||||
def test_shared_l3out_external_subnet_overlap(self):
|
||||
net1 = self._make_ext_network('net1', dn=self.dn_t1_l1_n1)
|
||||
self._make_subnet(
|
||||
self.fmt, {'network': net1}, '100.100.100.1',
|
||||
'100.100.100.0/24')
|
||||
|
||||
net2 = self._make_ext_network('net2', dn=self.dn_t1_l1_n1)
|
||||
self._make_subnet(
|
||||
self.fmt, {'network': net2}, '200.200.200.1',
|
||||
'200.200.200.0/24')
|
||||
|
||||
res = self._create_subnet(self.fmt,
|
||||
net_id=net2['id'],
|
||||
cidr="100.100.100.128/28",
|
||||
gateway_ip="100.100.100.129",
|
||||
expected_res_status=400)
|
||||
res = self.deserialize(self.fmt, res)
|
||||
self.assertEqual('ExternalSubnetOverlapInL3Out',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
res = self._create_subnet(self.fmt,
|
||||
net_id=net1['id'],
|
||||
cidr="200.200.0.0/16",
|
||||
gateway_ip="200.200.0.129",
|
||||
expected_res_status=400)
|
||||
res = self.deserialize(self.fmt, res)
|
||||
self.assertEqual('ExternalSubnetOverlapInL3Out',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
|
||||
class TestExternalDistributedNat(TestExternalConnectivityBase,
|
||||
ApicAimTestCase):
|
||||
|
|
|
@ -4195,7 +4195,7 @@ class TestImplicitExternalSegment(AIMBaseTestCase):
|
|||
|
||||
def _create_default_es(self, **kwargs):
|
||||
es_sub = self._make_ext_subnet(
|
||||
'net1', '90.90.0.0/16',
|
||||
'net1', kwargs.pop('subnet_cidr', '90.90.0.0/16'),
|
||||
tenant_id=(kwargs.get('tenant_id') or self._tenant_id),
|
||||
dn=self._dn_t1_l1_n1)
|
||||
return self.create_external_segment(name=self._default_es_name,
|
||||
|
@ -4244,11 +4244,12 @@ class TestImplicitExternalSegment(AIMBaseTestCase):
|
|||
self.assertEqual(1, len(l3p['external_segments']))
|
||||
|
||||
# Verify only one visible ES can exist
|
||||
res = self._create_default_es(expected_res_status=400)
|
||||
res = self._create_default_es(expected_res_status=400,
|
||||
subnet_cidr='10.10.0.0/28')
|
||||
self.assertEqual('DefaultExternalSegmentAlreadyExists',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
def test_impicit_lifecycle(self):
|
||||
def test_implicit_lifecycle(self):
|
||||
self._test_implicit_lifecycle()
|
||||
|
||||
def test_implicit_lifecycle_shared(self):
|
||||
|
@ -4268,7 +4269,8 @@ class TestImplicitExternalSegment(AIMBaseTestCase):
|
|||
self.assertEqual(1, len(ep['external_segments']))
|
||||
|
||||
res = self._create_default_es(expected_res_status=400,
|
||||
tenant_id='anothertenant')
|
||||
tenant_id='anothertenant',
|
||||
subnet_cidr='10.10.0.0/28')
|
||||
self.assertEqual('DefaultExternalSegmentAlreadyExists',
|
||||
res['NeutronError']['type'])
|
||||
|
||||
|
@ -4566,7 +4568,7 @@ class TestNatPool(AIMBaseTestCase):
|
|||
sub_id = nat_pool['subnet_id']
|
||||
|
||||
sub2 = self._make_ext_subnet('net1', '192.167.0.0/24',
|
||||
dn='uni/tn-t1/out-l1/instP-n2')
|
||||
dn='uni/tn-t1/out-l2/instP-n2')
|
||||
es2 = self.create_external_segment(
|
||||
name="nondefault", subnet_id=sub2['id'],
|
||||
external_routes=routes,
|
||||
|
|
Loading…
Reference in New Issue