Delete HA network when last HA router is deleted

Currently when the last HA router of a tenant is deleted the HA network
belonging to this tenant is not removed. While running tempest aganist an
OpenStack setup where tenant VLANs (with small VLAN range) is used we hit
the limits are tempest tests start to fail as we cannot create new networks.
This patch addresses this issue by deleting the HA network when the last HA
router is deleted for the tenant.

Closes-Bug: #1367157

Co-Authored-By: Ann Kamyshnikova<akamyshnikova@mirantis.com>

Change-Id: I1d50b973aed4148857ac3d2bbee0d38e2e199783
This commit is contained in:
sridhargaddam 2015-07-30 10:54:39 +00:00 committed by Assaf Muller
parent 6c0841e8e2
commit 853f7d7a74
2 changed files with 101 additions and 0 deletions

View File

@ -26,6 +26,8 @@ from neutron.common import constants
from neutron.common import exceptions as n_exc from neutron.common import exceptions as n_exc
from neutron.common import utils as n_utils from neutron.common import utils as n_utils
from neutron.db import agents_db from neutron.db import agents_db
from neutron.db import l3_attrs_db
from neutron.db import l3_db
from neutron.db import l3_dvr_db from neutron.db import l3_dvr_db
from neutron.db import model_base from neutron.db import model_base
from neutron.db import models_v2 from neutron.db import models_v2
@ -460,6 +462,21 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin):
return router_db return router_db
def _delete_ha_network(self, context, net):
admin_ctx = context.elevated()
self._core_plugin.delete_network(admin_ctx, net.network_id)
def _ha_routers_present(self, context, tenant_id):
ha = True
routers = context.session.query(l3_db.Router).filter(
l3_db.Router.tenant_id == tenant_id).subquery()
ha_routers = context.session.query(
l3_attrs_db.RouterExtraAttributes).join(
routers,
l3_attrs_db.RouterExtraAttributes.router_id == routers.c.id
).filter(l3_attrs_db.RouterExtraAttributes.ha == ha).first()
return ha_routers is not None
def delete_router(self, context, id): def delete_router(self, context, id):
router_db = self._get_router(context, id) router_db = self._get_router(context, id)
super(L3_HA_NAT_db_mixin, self).delete_router(context, id) super(L3_HA_NAT_db_mixin, self).delete_router(context, id)
@ -471,6 +488,21 @@ class L3_HA_NAT_db_mixin(l3_dvr_db.L3_NAT_with_dvr_db_mixin):
self._delete_vr_id_allocation( self._delete_vr_id_allocation(
context, ha_network, router_db.extra_attributes.ha_vr_id) context, ha_network, router_db.extra_attributes.ha_vr_id)
self._delete_ha_interfaces(context, router_db.id) self._delete_ha_interfaces(context, router_db.id)
try:
if not self._ha_routers_present(context,
router_db.tenant_id):
self._delete_ha_network(context, ha_network)
LOG.info(_LI("HA network %(network)s was deleted as "
"no HA routers are present in tenant "
"%(tenant)s."),
{'network': ha_network.network_id,
'tenant': router_db.tenant_id})
except n_exc.NetworkNotFound:
LOG.debug("HA network %s was already deleted.",
ha_network.network_id)
except sa.exc.InvalidRequestError:
LOG.info(_LI("HA network %s can not be deleted."),
ha_network.network_id)
def _unbind_ha_router(self, context, router_id): def _unbind_ha_router(self, context, router_id):
for agent in self.get_l3_agents_hosting_routers(context, [router_id]): for agent in self.get_l3_agents_hosting_routers(context, [router_id]):

View File

@ -15,6 +15,7 @@
import mock import mock
from oslo_config import cfg from oslo_config import cfg
from oslo_utils import uuidutils from oslo_utils import uuidutils
import sqlalchemy as sa
from neutron.api.rpc.handlers import l3_rpc from neutron.api.rpc.handlers import l3_rpc
from neutron.api.v2 import attributes from neutron.api.v2 import attributes
@ -566,6 +567,74 @@ class L3HATestCase(L3HATestFramework):
self.plugin.get_number_of_agents_for_scheduling, self.plugin.get_number_of_agents_for_scheduling,
self.admin_ctx) self.admin_ctx)
def test_ha_network_deleted_if_no_ha_router_present_two_tenants(self):
# Create two routers in different tenants.
router1 = self._create_router()
router2 = self._create_router(tenant_id='tenant2')
nets_before = [net['name'] for net in
self.core_plugin.get_networks(self.admin_ctx)]
# Check that HA networks created for each tenant
self.assertIn('HA network tenant %s' % router1['tenant_id'],
nets_before)
self.assertIn('HA network tenant %s' % router2['tenant_id'],
nets_before)
# Delete router1
self.plugin.delete_router(self.admin_ctx, router1['id'])
nets_after = [net['name'] for net in
self.core_plugin.get_networks(self.admin_ctx)]
# Check that HA network for tenant1 is deleted and for tenant2 is not.
self.assertNotIn('HA network tenant %s' % router1['tenant_id'],
nets_after)
self.assertIn('HA network tenant %s' % router2['tenant_id'],
nets_after)
def test_ha_network_is_not_delete_if_ha_router_is_present(self):
# Create 2 routers in one tenant and check if one is deleted, HA
# network still exists.
router1 = self._create_router()
router2 = self._create_router()
nets_before = [net['name'] for net in
self.core_plugin.get_networks(self.admin_ctx)]
self.assertIn('HA network tenant %s' % router1['tenant_id'],
nets_before)
self.plugin.delete_router(self.admin_ctx, router2['id'])
nets_after = [net['name'] for net in
self.core_plugin.get_networks(self.admin_ctx)]
self.assertIn('HA network tenant %s' % router1['tenant_id'],
nets_after)
def test_ha_network_delete_ha_and_non_ha_router(self):
# Create HA and non-HA router. Check after deletion HA router HA
# network is deleted.
router1 = self._create_router(ha=False)
router2 = self._create_router()
nets_before = [net['name'] for net in
self.core_plugin.get_networks(self.admin_ctx)]
self.assertIn('HA network tenant %s' % router1['tenant_id'],
nets_before)
self.plugin.delete_router(self.admin_ctx, router2['id'])
nets_after = [net['name'] for net in
self.core_plugin.get_networks(self.admin_ctx)]
self.assertNotIn('HA network tenant %s' % router1['tenant_id'],
nets_after)
def test_ha_network_is_not_deleted_if_another_ha_router_is_created(self):
# If another router was created during deletion of current router,
# _delete_ha_network will fail with InvalidRequestError. Check that HA
# network won't be deleted.
router1 = self._create_router()
nets_before = [net['name'] for net in
self.core_plugin.get_networks(self.admin_ctx)]
self.assertIn('HA network tenant %s' % router1['tenant_id'],
nets_before)
with mock.patch.object(self.plugin, '_delete_ha_network',
side_effect=sa.exc.InvalidRequestError):
self.plugin.delete_router(self.admin_ctx, router1['id'])
nets_after = [net['name'] for net in
self.core_plugin.get_networks(self.admin_ctx)]
self.assertIn('HA network tenant %s' % router1['tenant_id'],
nets_after)
class L3HAModeDbTestCase(L3HATestFramework): class L3HAModeDbTestCase(L3HATestFramework):