Browse Source

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
(cherry picked from commit 853f7d7a74)
tags/7.0.1
sridhargaddam 5 years ago
committed by Ann Kamyshnikova
parent
commit
478012a397
2 changed files with 102 additions and 0 deletions
  1. +33
    -0
      neutron/db/l3_hamode_db.py
  2. +69
    -0
      neutron/tests/unit/db/test_l3_hamode_db.py

+ 33
- 0
neutron/db/l3_hamode_db.py View File

@@ -23,8 +23,11 @@ from sqlalchemy import orm

from neutron.api.v2 import attributes
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
@@ -439,6 +442,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)
@@ -450,6 +468,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 get_ha_router_port_bindings(self, context, router_ids, host=None):
if not router_ids:


+ 69
- 0
neutron/tests/unit/db/test_l3_hamode_db.py View File

@@ -17,6 +17,7 @@ import mock
from oslo_config import cfg
from oslo_utils import timeutils
from oslo_utils import uuidutils
import sqlalchemy as sa

from neutron.api.rpc.handlers import l3_rpc
from neutron.api.v2 import attributes
@@ -503,6 +504,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):



Loading…
Cancel
Save