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
This commit is contained in:
parent
a314f3a38d
commit
f54cba0535
|
@ -493,21 +493,31 @@ 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:
|
|
||||||
|
# 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,
|
if not self._ha_routers_present(context,
|
||||||
router_db.tenant_id):
|
router_db.tenant_id):
|
||||||
self._delete_ha_network(context, ha_network)
|
try:
|
||||||
LOG.info(_LI("HA network %(network)s was deleted as "
|
self._delete_ha_network(context, ha_network)
|
||||||
"no HA routers are present in tenant "
|
except (n_exc.NetworkNotFound,
|
||||||
"%(tenant)s."),
|
orm.exc.ObjectDeletedError):
|
||||||
{'network': ha_network.network_id,
|
LOG.debug(
|
||||||
'tenant': router_db.tenant_id})
|
"HA network for tenant %s was already deleted.",
|
||||||
except n_exc.NetworkNotFound:
|
router_db.tenant_id)
|
||||||
LOG.debug("HA network %s was already deleted.",
|
except sa.exc.InvalidRequestError:
|
||||||
ha_network.network_id)
|
LOG.info(_LI("HA network %s can not be deleted."),
|
||||||
except sa.exc.InvalidRequestError:
|
ha_network.network_id)
|
||||||
LOG.info(_LI("HA network %s can not be deleted."),
|
except n_exc.NetworkInUse:
|
||||||
ha_network.network_id)
|
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 _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]):
|
||||||
|
|
|
@ -16,6 +16,7 @@ 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
|
import sqlalchemy as sa
|
||||||
|
from sqlalchemy import orm
|
||||||
|
|
||||||
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
|
||||||
|
@ -617,23 +618,53 @@ class L3HATestCase(L3HATestFramework):
|
||||||
self.assertNotIn('HA network tenant %s' % router1['tenant_id'],
|
self.assertNotIn('HA network tenant %s' % router1['tenant_id'],
|
||||||
nets_after)
|
nets_after)
|
||||||
|
|
||||||
def test_ha_network_is_not_deleted_if_another_ha_router_is_created(self):
|
def _test_ha_network_is_not_deleted_raise_exception(self, exception):
|
||||||
# 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()
|
router1 = self._create_router()
|
||||||
nets_before = [net['name'] for net in
|
nets_before = [net['name'] for net in
|
||||||
self.core_plugin.get_networks(self.admin_ctx)]
|
self.core_plugin.get_networks(self.admin_ctx)]
|
||||||
self.assertIn('HA network tenant %s' % router1['tenant_id'],
|
self.assertIn('HA network tenant %s' % router1['tenant_id'],
|
||||||
nets_before)
|
nets_before)
|
||||||
with mock.patch.object(self.plugin, '_delete_ha_network',
|
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'])
|
self.plugin.delete_router(self.admin_ctx, router1['id'])
|
||||||
nets_after = [net['name'] for net in
|
nets_after = [net['name'] for net in
|
||||||
self.core_plugin.get_networks(self.admin_ctx)]
|
self.core_plugin.get_networks(self.admin_ctx)]
|
||||||
self.assertIn('HA network tenant %s' % router1['tenant_id'],
|
self.assertIn('HA network tenant %s' % router1['tenant_id'],
|
||||||
nets_after)
|
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):
|
class L3HAModeDbTestCase(L3HATestFramework):
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue