Add RouterPort binding to ha interface creation

The L3 HA interface cleanup routines during router deletion were
occuring after the parent router resource was deleted. This meant
that if they failed to delete, they would be orphaned since the
parent router was already gone.

This order of router delete and then HA delete was intentional
because deleting them before calling the parent router delete
function would cause them to be deleted before the checks to see
if the router was in use. If the router was in use, the HA interface
would be removed and would leave an HA router in an inconsitent state.
(See I956d0094ae6e2412e859d79feeb4003941d2bb4b for details)

This patch just has the L3 HA code add a RouterPort binding for the
HA interfaces. This allows the parent router_delete call to delete the
HA interfaces automatically after doing the in-use check but before
deleting the actual router.

In order to avoid a migration in a back-port, this is compatible with
previously created routers as well by continuing to call
_delete_ha_interfaces after the parent router is deleted. This means
that any routers created before this patch will potentially leave
orphans that will have to be manually deleted via the port API.

Closes-Bug: #1540271
Change-Id: Ifd3e007aaf2a2ed8123275aa3a9f540838e3c003
This commit is contained in:
Kevin Benton 2016-04-09 12:15:56 -07:00
parent ca57c9fe8f
commit 0074b943d6
2 changed files with 20 additions and 0 deletions

View File

@ -36,6 +36,7 @@ from neutron.common import utils as n_utils
from neutron.db import agents_db
from neutron.db.availability_zone import router as router_az_db
from neutron.db import common_db_mixin
from neutron.db import l3_db
from neutron.db import l3_dvr_db
from neutron.db.l3_dvr_db import is_distributed_router
from neutron.db import model_base
@ -340,6 +341,10 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin,
def _create_ha_port_binding(self, context, router_id, port_id):
try:
with context.session.begin():
routerportbinding = l3_db.RouterPort(
port_id=port_id, router_id=router_id,
port_type=constants.DEVICE_OWNER_ROUTER_HA_INTF)
context.session.add(routerportbinding)
portbinding = L3HARouterAgentPortBinding(port_id=port_id,
router_id=router_id)
context.session.add(portbinding)
@ -584,6 +589,12 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin,
if ha_network:
self._delete_vr_id_allocation(
context, ha_network, router_db.extra_attributes.ha_vr_id)
# NOTE(kevinbenton): normally the ha interfaces should have
# been automatically removed by the super delete_router call.
# However, that only applies to interfaces created after fix
# Ifd3e007aaf2a2ed8123275aa3a9f540838e3c003 which added the
# RouterPort relationship to ha interfaces. Legacy interfaces
# will be cleaned up by this.
self._delete_ha_interfaces(context, router_db.id)
# always attempt to cleanup the network as the router is

View File

@ -807,6 +807,15 @@ class L3HATestCase(L3HATestFramework):
self.plugin.get_number_of_agents_for_scheduling,
self.admin_ctx)
def test_ha_ports_deleted_in_parent_router_removal(self):
router1 = self._create_router()
# router cleanup should no longer depend on this function for
# newly created routers.
self.plugin._delete_ha_interfaces = mock.Mock()
self.plugin.delete_router(self.admin_ctx, router1['id'])
self.assertEqual([], self.core_plugin.get_ports(
self.admin_ctx, filters={'device_id': [router1['id']]}))
def test_ha_network_deleted_if_no_ha_router_present_two_tenants(self):
# Create two routers in different tenants.
router1 = self._create_router()