[apic_aim] Cleanup default VRF
Delete the per-Tenant default VRF whenever it is no longer needed. Change-Id: Ie057a278d8c17246ca4a41b741fd1e3b455442a9
This commit is contained in:
parent
0f46a0d9d3
commit
ed7dbd8e93
|
@ -112,6 +112,12 @@ class DbMixin(object):
|
|||
vrf_name=vrf.name).
|
||||
all())
|
||||
|
||||
def _is_vrf_used_by_networks(self, session, vrf):
|
||||
return (session.query(NetworkMapping.network_id).
|
||||
filter_by(vrf_tenant_name=vrf.tenant_name,
|
||||
vrf_name=vrf.name).
|
||||
first() is not None)
|
||||
|
||||
def _get_network_bd(self, mapping):
|
||||
return aim_resource.BridgeDomain(
|
||||
tenant_name=mapping.bd_tenant_name,
|
||||
|
|
|
@ -1034,7 +1034,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
aim_ctx, router_topology, router_vrf, vrf,
|
||||
nets_to_notify)
|
||||
router_topo_moved = True
|
||||
# REVISIT: Delete router_vrf if no longer used?
|
||||
self._cleanup_default_vrf(aim_ctx, router_vrf)
|
||||
elif router_shared_net:
|
||||
# Router topology has shared network, so move
|
||||
# interface topology, unless first interface for
|
||||
|
@ -1044,7 +1044,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
self._move_topology(
|
||||
aim_ctx, intf_topology, intf_vrf, vrf,
|
||||
nets_to_notify)
|
||||
# REVISIT: Delete intf_vrf if no longer used?
|
||||
self._cleanup_default_vrf(aim_ctx, intf_vrf)
|
||||
else:
|
||||
# This should never happen.
|
||||
LOG.error("Interface topology %(intf_topology)s and "
|
||||
|
@ -1212,6 +1212,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
intf_vrf = self._map_default_vrf(
|
||||
session, intf_shared_net or network_db)
|
||||
if old_vrf.identity != intf_vrf.identity:
|
||||
intf_vrf = self._ensure_default_vrf(aim_ctx, intf_vrf)
|
||||
self._move_topology(
|
||||
aim_ctx, intf_topology, old_vrf, intf_vrf,
|
||||
nets_to_notify)
|
||||
|
@ -1224,6 +1225,7 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
session,
|
||||
router_shared_net or router_topology.itervalues().next())
|
||||
if old_vrf.identity != router_vrf.identity:
|
||||
router_vrf = self._ensure_default_vrf(aim_ctx, router_vrf)
|
||||
self._move_topology(
|
||||
aim_ctx, router_topology, old_vrf, router_vrf,
|
||||
nets_to_notify)
|
||||
|
@ -1234,6 +1236,8 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
if not router_ids:
|
||||
self._dissassociate_network_from_vrf(
|
||||
aim_ctx, network_db, old_vrf, nets_to_notify)
|
||||
if scope_id == NO_ADDR_SCOPE:
|
||||
self._cleanup_default_vrf(aim_ctx, old_vrf)
|
||||
|
||||
# If external-gateway is set, handle external-connectivity changes.
|
||||
if router_db.gw_port_id:
|
||||
|
@ -2280,6 +2284,11 @@ class ApicMechanismDriver(api_plus.MechanismDriver,
|
|||
vrf = self.aim.create(aim_ctx, attrs)
|
||||
return vrf
|
||||
|
||||
def _cleanup_default_vrf(self, aim_ctx, vrf):
|
||||
if not self._is_vrf_used_by_networks(aim_ctx.db_session, vrf):
|
||||
LOG.info("Deleting default VRF for %s", vrf.tenant_name)
|
||||
self.aim.delete(aim_ctx, vrf)
|
||||
|
||||
# Used by policy driver.
|
||||
def get_bd_for_network(self, session, network):
|
||||
mapping = self._get_network_mapping(session, network['id'])
|
||||
|
|
|
@ -418,14 +418,17 @@ class TestAimMapping(ApicAimTestCase):
|
|||
self.assertIsNotNone(tenant)
|
||||
return tenant
|
||||
|
||||
def _get_vrf(self, vrf_name, tenant_name):
|
||||
def _get_vrf(self, vrf_name, tenant_name, should_exist=True):
|
||||
session = db_api.get_session()
|
||||
aim_ctx = aim_context.AimContext(session)
|
||||
vrf = aim_resource.VRF(tenant_name=tenant_name,
|
||||
name=vrf_name)
|
||||
vrf = self.aim_mgr.get(aim_ctx, vrf)
|
||||
self.assertIsNotNone(vrf)
|
||||
return vrf
|
||||
if should_exist:
|
||||
self.assertIsNotNone(vrf)
|
||||
return vrf
|
||||
else:
|
||||
self.assertIsNone(vrf)
|
||||
|
||||
def _vrf_should_not_exist(self, vrf_name):
|
||||
session = db_api.get_session()
|
||||
|
@ -2256,6 +2259,15 @@ class TestAimMapping(ApicAimTestCase):
|
|||
self._check_router(
|
||||
router, expected_gw_ips, unscoped_project=project)
|
||||
|
||||
def check_default_vrf(project, should_exist):
|
||||
tenant_name = self.name_mapper.project(None, project)
|
||||
vrf = self._get_vrf('DefaultVRF', tenant_name, should_exist)
|
||||
if should_exist:
|
||||
self.assertEqual(tenant_name, vrf.tenant_name)
|
||||
self.assertEqual('DefaultVRF', vrf.name)
|
||||
self.assertEqual('DefaultRoutedVRF', vrf.display_name)
|
||||
self.assertEqual('enforced', vrf.policy_enforcement_pref)
|
||||
|
||||
def check_port_notify(ports=None):
|
||||
if not ports:
|
||||
mock_notif.assert_not_called()
|
||||
|
@ -2289,57 +2301,68 @@ class TestAimMapping(ApicAimTestCase):
|
|||
gw4C = '10.0.4.3'
|
||||
|
||||
# Check initial state with no routing.
|
||||
check_router(rA, [], t1)
|
||||
check_router(rB, [], t1)
|
||||
check_router(rC, [], t1)
|
||||
check_router(rA, [], None)
|
||||
check_router(rB, [], None)
|
||||
check_router(rC, [], None)
|
||||
check_net(net1, sn1, [], [], [gw1A], t1)
|
||||
check_net(net2, sn2, [], [], [gw2A, gw2B], t1)
|
||||
check_net(net3, sn3, [], [], [gw3B, gw3C], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, False)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
# Add subnet 1 to router A.
|
||||
# Add subnet 1 to router A, which should create tenant 1's
|
||||
# default VRF.
|
||||
add_interface(rA, net1, sn1, gw1A, t1)
|
||||
check_port_notify([p1])
|
||||
check_router(rA, [gw1A], t1)
|
||||
check_router(rB, [], t1)
|
||||
check_router(rC, [], t1)
|
||||
check_router(rB, [], None)
|
||||
check_router(rC, [], None)
|
||||
check_net(net1, sn1, [rA], [(gw1A, rA)], [], t1)
|
||||
check_net(net2, sn2, [], [], [gw2A, gw2B], t1)
|
||||
check_net(net3, sn3, [], [], [gw3B, gw3C], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
# Add subnet 2 to router A.
|
||||
add_interface(rA, net2, sn2, gw2A, t1)
|
||||
check_port_notify([p2])
|
||||
check_router(rA, [gw1A, gw2A], t1)
|
||||
check_router(rB, [], t1)
|
||||
check_router(rC, [], t1)
|
||||
check_router(rB, [], None)
|
||||
check_router(rC, [], None)
|
||||
check_net(net1, sn1, [rA], [(gw1A, rA)], [], t1)
|
||||
check_net(net2, sn2, [rA], [(gw2A, rA)], [gw2B], t1)
|
||||
check_net(net3, sn3, [], [], [gw3B, gw3C], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
# Add subnet 2 to router B.
|
||||
add_interface(rB, net2, sn2, gw2B, t1)
|
||||
check_port_notify()
|
||||
check_router(rA, [gw1A, gw2A], t1)
|
||||
check_router(rB, [gw2B], t1)
|
||||
check_router(rC, [], t1)
|
||||
check_router(rC, [], None)
|
||||
check_net(net1, sn1, [rA], [(gw1A, rA)], [], t1)
|
||||
check_net(net2, sn2, [rA, rB], [(gw2A, rA), (gw2B, rB)], [], t1)
|
||||
check_net(net3, sn3, [], [], [gw3B, gw3C], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
# Add subnet 3 to router B.
|
||||
add_interface(rB, net3, sn3, gw3B, t1)
|
||||
check_port_notify([p3])
|
||||
check_router(rA, [gw1A, gw2A], t1)
|
||||
check_router(rB, [gw2B, gw3B], t1)
|
||||
check_router(rC, [], t1)
|
||||
check_router(rC, [], None)
|
||||
check_net(net1, sn1, [rA], [(gw1A, rA)], [], t1)
|
||||
check_net(net2, sn2, [rA, rB], [(gw2A, rA), (gw2B, rB)], [], t1)
|
||||
check_net(net3, sn3, [rB], [(gw3B, rB)], [gw3C], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
# Add subnet 3 to router C.
|
||||
add_interface(rC, net3, sn3, gw3C, t1)
|
||||
|
@ -2351,10 +2374,13 @@ class TestAimMapping(ApicAimTestCase):
|
|||
check_net(net2, sn2, [rA, rB], [(gw2A, rA), (gw2B, rB)], [], t1)
|
||||
check_net(net3, sn3, [rB, rC], [(gw3B, rB), (gw3C, rC)], [], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
# Add shared subnet 4 to router C, which should move router
|
||||
# C's topology (networks 1, 2 and 3 and routers A, B and C) to
|
||||
# tenant 2.
|
||||
# tenant 2, create tenant 2's default VRF, and delete tenant
|
||||
# 1's default VRF.
|
||||
add_interface(rC, net4, sn4, gw4C, t1)
|
||||
check_port_notify([p1, p2, p3])
|
||||
check_router(rA, [gw1A, gw2A], t2)
|
||||
|
@ -2364,9 +2390,12 @@ class TestAimMapping(ApicAimTestCase):
|
|||
check_net(net2, sn2, [rA, rB], [(gw2A, rA), (gw2B, rB)], [], t2)
|
||||
check_net(net3, sn3, [rB, rC], [(gw3B, rB), (gw3C, rC)], [], t2)
|
||||
check_net(net4, sn4, [rC], [(gw4C, rC)], [], t2)
|
||||
check_default_vrf(t1, False)
|
||||
check_default_vrf(t2, True)
|
||||
|
||||
# Remove subnet 3 from router B, which should move router B's
|
||||
# topology (networks 1 and 2 and routers A and B) to tenant 1.
|
||||
# topology (networks 1 and 2 and routers A and B) to tenant 1
|
||||
# and create tenant 1's default VRF.
|
||||
remove_interface(rB, net3, sn3, gw3B, t1)
|
||||
check_port_notify([p1, p2])
|
||||
check_router(rA, [gw1A, gw2A], t1)
|
||||
|
@ -2376,10 +2405,12 @@ class TestAimMapping(ApicAimTestCase):
|
|||
check_net(net2, sn2, [rA, rB], [(gw2A, rA), (gw2B, rB)], [], t1)
|
||||
check_net(net3, sn3, [rC], [(gw3C, rC)], [gw3B], t2)
|
||||
check_net(net4, sn4, [rC], [(gw4C, rC)], [], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, True)
|
||||
|
||||
# Add subnet 3 back to router B, which should move router B's
|
||||
# topology (networks 1 and 2 and routers A and B) to tenant 2
|
||||
# again.
|
||||
# again and delete tenant 1's default VRF.
|
||||
add_interface(rB, net3, sn3, gw3B, t1)
|
||||
check_port_notify([p1, p2])
|
||||
check_router(rA, [gw1A, gw2A], t2)
|
||||
|
@ -2389,9 +2420,12 @@ class TestAimMapping(ApicAimTestCase):
|
|||
check_net(net2, sn2, [rA, rB], [(gw2A, rA), (gw2B, rB)], [], t2)
|
||||
check_net(net3, sn3, [rB, rC], [(gw3B, rB), (gw3C, rC)], [], t2)
|
||||
check_net(net4, sn4, [rC], [(gw4C, rC)], [], t2)
|
||||
check_default_vrf(t1, False)
|
||||
check_default_vrf(t2, True)
|
||||
|
||||
# Remove subnet 2 from router B, which should move network 2's
|
||||
# topology (networks 1 and 2 and router A) back to tenant 1.
|
||||
# topology (networks 1 and 2 and router A) back to tenant 1
|
||||
# and create tenant 1's default VRF
|
||||
remove_interface(rB, net2, sn2, gw2B, t1)
|
||||
check_port_notify([p1, p2])
|
||||
check_router(rA, [gw1A, gw2A], t1)
|
||||
|
@ -2401,9 +2435,12 @@ class TestAimMapping(ApicAimTestCase):
|
|||
check_net(net2, sn2, [rA], [(gw2A, rA)], [gw2B], t1)
|
||||
check_net(net3, sn3, [rB, rC], [(gw3B, rB), (gw3C, rC)], [], t2)
|
||||
check_net(net4, sn4, [rC], [(gw4C, rC)], [], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, True)
|
||||
|
||||
# Add subnet 2 back to router B, which should move network 2's
|
||||
# topology (networks 1 and 2 and router A) to tenant 2 again.
|
||||
# topology (networks 1 and 2 and router A) to tenant 2 again
|
||||
# and delete tenant 1's default VRF.
|
||||
add_interface(rB, net2, sn2, gw2B, t1)
|
||||
check_port_notify([p1, p2])
|
||||
check_router(rA, [gw1A, gw2A], t2)
|
||||
|
@ -2413,6 +2450,90 @@ class TestAimMapping(ApicAimTestCase):
|
|||
check_net(net2, sn2, [rA, rB], [(gw2A, rA), (gw2B, rB)], [], t2)
|
||||
check_net(net3, sn3, [rB, rC], [(gw3B, rB), (gw3C, rC)], [], t2)
|
||||
check_net(net4, sn4, [rC], [(gw4C, rC)], [], t2)
|
||||
check_default_vrf(t1, False)
|
||||
check_default_vrf(t2, True)
|
||||
|
||||
# Remove subnet 4 from router C, which should move network 3's
|
||||
# topology (networks 1, 2 and 3 and routers A and B) to tenant
|
||||
# 1, create tenant 1's default VRF, and delete tenant 2's
|
||||
# default VRF.
|
||||
remove_interface(rC, net4, sn4, gw4C, t1)
|
||||
check_port_notify([p1, p2, p3])
|
||||
check_router(rA, [gw1A, gw2A], t1)
|
||||
check_router(rB, [gw2B, gw3B], t1)
|
||||
check_router(rC, [gw3C], t1)
|
||||
check_net(net1, sn1, [rA], [(gw1A, rA)], [], t1)
|
||||
check_net(net2, sn2, [rA, rB], [(gw2A, rA), (gw2B, rB)], [], t1)
|
||||
check_net(net3, sn3, [rB, rC], [(gw3B, rB), (gw3C, rC)], [], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
# Remove subnet 3 from router C.
|
||||
remove_interface(rC, net3, sn3, gw3C, t1)
|
||||
check_port_notify()
|
||||
check_router(rA, [gw1A, gw2A], t1)
|
||||
check_router(rB, [gw2B, gw3B], t1)
|
||||
check_router(rC, [], None)
|
||||
check_net(net1, sn1, [rA], [(gw1A, rA)], [], t1)
|
||||
check_net(net2, sn2, [rA, rB], [(gw2A, rA), (gw2B, rB)], [], t1)
|
||||
check_net(net3, sn3, [rB], [(gw3B, rB)], [gw3C], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
# Remove subnet 2 from router B.
|
||||
remove_interface(rB, net2, sn2, gw2B, t1)
|
||||
check_port_notify()
|
||||
check_router(rA, [gw1A, gw2A], t1)
|
||||
check_router(rB, [gw3B], t1)
|
||||
check_router(rC, [], None)
|
||||
check_net(net1, sn1, [rA], [(gw1A, rA)], [], t1)
|
||||
check_net(net2, sn2, [rA], [(gw2A, rA)], [gw2B], t1)
|
||||
check_net(net3, sn3, [rB], [(gw3B, rB)], [gw3C], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
# Remove subnet 2 from router A.
|
||||
remove_interface(rA, net2, sn2, gw2A, t1)
|
||||
check_port_notify([p2])
|
||||
check_router(rA, [gw1A], t1)
|
||||
check_router(rB, [gw3B], t1)
|
||||
check_router(rC, [], None)
|
||||
check_net(net1, sn1, [rA], [(gw1A, rA)], [], t1)
|
||||
check_net(net2, sn2, [], [], [gw2A, gw2B], t1)
|
||||
check_net(net3, sn3, [rB], [(gw3B, rB)], [gw3C], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
# Remove subnet 3 from router B.
|
||||
remove_interface(rB, net3, sn3, gw3B, t1)
|
||||
check_port_notify([p3])
|
||||
check_router(rA, [gw1A], t1)
|
||||
check_router(rB, [], None)
|
||||
check_router(rC, [], None)
|
||||
check_net(net1, sn1, [rA], [(gw1A, rA)], [], t1)
|
||||
check_net(net2, sn2, [], [], [gw2A, gw2B], t1)
|
||||
check_net(net3, sn3, [], [], [gw3B, gw3C], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, True)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
# Remove subnet 1 from router A, which should delete tenant
|
||||
# 1's default VRF.
|
||||
remove_interface(rA, net1, sn1, gw1A, t1)
|
||||
check_port_notify([p1])
|
||||
check_router(rA, [], None)
|
||||
check_router(rB, [], None)
|
||||
check_router(rC, [], None)
|
||||
check_net(net1, sn1, [], [], [gw1A], t1)
|
||||
check_net(net2, sn2, [], [], [gw2A, gw2B], t1)
|
||||
check_net(net3, sn3, [], [], [gw3B, gw3C], t1)
|
||||
check_net(net4, sn4, [], [], [gw4C], t2)
|
||||
check_default_vrf(t1, False)
|
||||
check_default_vrf(t2, False)
|
||||
|
||||
def test_address_scope_pre_existing_vrf(self):
|
||||
aim_ctx = aim_context.AimContext(self.db_session)
|
||||
|
|
Loading…
Reference in New Issue