]> review.fuel-infra Code Review - openstack-build/neutron-build.git/commitdiff
Delete HA network when last HA router is deleted
authorsridhargaddam <sridhar.gaddam@enovance.com>
Thu, 30 Jul 2015 10:54:39 +0000 (10:54 +0000)
committerAssaf Muller <amuller@redhat.com>
Wed, 25 Nov 2015 21:18:05 +0000 (16:18 -0500)
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

neutron/db/l3_hamode_db.py
neutron/tests/unit/db/test_l3_hamode_db.py

index aefc46da282d410f4221f784b803299b9e06451c..9125062fcfc072b2eacfd509ee123975a79f8717 100644 (file)
@@ -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]):
index fbfda4cf05b015cba6f3973b3c24462208772891..e1f3d359aa41cca749cd622861352ad520cf111e 100644 (file)
@@ -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):