Catch known exceptions during deleting last HA router
In some scenarios, for instance rally test create_and_delete_routers,
it will get some exceptions, such as the network in use exception,
during the router deleting api call, but actually the router has
been deleted. There has race between HA router create and delete,
if set more api and rpc worker race raises exception more frequently.
Because the inconsistent error message was not useful for user,
this patch will catch those know exceptions ObjectDeletedError,
NetworkInUse when user delete last HA router.
At the same time, when user create the first HA router, but because
of the failure of HA network creation, the router will be deleted,
then the deleting HA network will raise AttributeError, this patch
also move HA network deleting procedure under ha_network exist check
block.
Change-Id: I8cda00c1e7caffc4dfb20a817a11c60736855bb5
Closes-Bug: #1523780
Related-Bug: #1367157
(cherry picked from commit f54cba0535
)
This commit is contained in:
parent
4270a6f5a1
commit
ff021e7e4c
|
@ -468,21 +468,31 @@ 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:
|
||||
|
||||
# In case that create HA router failed because of the failure
|
||||
# in HA network creation. So here put this deleting HA network
|
||||
# procedure under 'if ha_network' block.
|
||||
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)
|
||||
try:
|
||||
self._delete_ha_network(context, ha_network)
|
||||
except (n_exc.NetworkNotFound,
|
||||
orm.exc.ObjectDeletedError):
|
||||
LOG.debug(
|
||||
"HA network for tenant %s was already deleted.",
|
||||
router_db.tenant_id)
|
||||
except sa.exc.InvalidRequestError:
|
||||
LOG.info(_LI("HA network %s can not be deleted."),
|
||||
ha_network.network_id)
|
||||
except n_exc.NetworkInUse:
|
||||
LOG.debug("HA network %s is still in use.",
|
||||
ha_network.network_id)
|
||||
else:
|
||||
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})
|
||||
|
||||
def get_ha_router_port_bindings(self, context, router_ids, host=None):
|
||||
if not router_ids:
|
||||
|
|
|
@ -18,10 +18,12 @@ from oslo_config import cfg
|
|||
from oslo_utils import timeutils
|
||||
from oslo_utils import uuidutils
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy import orm
|
||||
|
||||
from neutron.api.rpc.handlers import l3_rpc
|
||||
from neutron.api.v2 import attributes
|
||||
from neutron.common import constants
|
||||
from neutron.common import exceptions as n_exc
|
||||
from neutron import context
|
||||
from neutron.db import agents_db
|
||||
from neutron.db import common_db_mixin
|
||||
|
@ -574,23 +576,53 @@ class L3HATestCase(L3HATestFramework):
|
|||
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.
|
||||
def _test_ha_network_is_not_deleted_raise_exception(self, exception):
|
||||
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):
|
||||
side_effect=exception):
|
||||
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)
|
||||
|
||||
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.
|
||||
self._test_ha_network_is_not_deleted_raise_exception(
|
||||
sa.exc.InvalidRequestError)
|
||||
|
||||
def test_ha_network_is_not_deleted_if_network_in_use(self):
|
||||
self._test_ha_network_is_not_deleted_raise_exception(
|
||||
n_exc.NetworkInUse(net_id="foo_net_id"))
|
||||
|
||||
def test_ha_network_is_not_deleted_if_db_deleted_error(self):
|
||||
self._test_ha_network_is_not_deleted_raise_exception(
|
||||
orm.exc.ObjectDeletedError(None))
|
||||
|
||||
def test_ha_router_create_failed_no_ha_network_delete(self):
|
||||
tenant_id = "foo_tenant_id"
|
||||
nets_before = self.core_plugin.get_networks(self.admin_ctx)
|
||||
self.assertNotIn('HA network tenant %s' % tenant_id,
|
||||
nets_before)
|
||||
|
||||
# Unable to create HA network
|
||||
with mock.patch.object(self.core_plugin, 'create_network',
|
||||
side_effect=n_exc.NoNetworkAvailable):
|
||||
self.assertRaises(n_exc.NoNetworkAvailable,
|
||||
self._create_router,
|
||||
True,
|
||||
tenant_id)
|
||||
nets_after = self.core_plugin.get_networks(self.admin_ctx)
|
||||
self.assertEqual(nets_before, nets_after)
|
||||
self.assertNotIn('HA network tenant %s' % tenant_id,
|
||||
nets_after)
|
||||
|
||||
|
||||
class L3HAModeDbTestCase(L3HATestFramework):
|
||||
|
||||
|
|
Loading…
Reference in New Issue