From: sridhargaddam Date: Thu, 30 Jul 2015 10:54:39 +0000 (+0000) Subject: Delete HA network when last HA router is deleted X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=853f7d7a74a2281b0cd34c337362e73635e501a2;p=openstack-build%2Fneutron-build.git 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 Change-Id: I1d50b973aed4148857ac3d2bbee0d38e2e199783 --- diff --git a/neutron/db/l3_hamode_db.py b/neutron/db/l3_hamode_db.py index aefc46da2..9125062fc 100644 --- a/neutron/db/l3_hamode_db.py +++ b/neutron/db/l3_hamode_db.py @@ -26,6 +26,8 @@ from neutron.common import constants from neutron.common import exceptions as n_exc from neutron.common import utils as n_utils 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 model_base 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 + 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): router_db = self._get_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( context, ha_network, router_db.extra_attributes.ha_vr_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): for agent in self.get_l3_agents_hosting_routers(context, [router_id]): diff --git a/neutron/tests/unit/db/test_l3_hamode_db.py b/neutron/tests/unit/db/test_l3_hamode_db.py index fbfda4cf0..e1f3d359a 100644 --- a/neutron/tests/unit/db/test_l3_hamode_db.py +++ b/neutron/tests/unit/db/test_l3_hamode_db.py @@ -15,6 +15,7 @@ import mock from oslo_config import cfg from oslo_utils import uuidutils +import sqlalchemy as sa from neutron.api.rpc.handlers import l3_rpc from neutron.api.v2 import attributes @@ -566,6 +567,74 @@ class L3HATestCase(L3HATestFramework): self.plugin.get_number_of_agents_for_scheduling, 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):