Rollback quota in os_tenant_network

when we call API with 'os_tenant_networks' to delete an existing network
it might fail due to unexpected reason, we should rollback the
quota we reserved otherwise we will face no quota later.

Change-Id: Ic74a7a8df337070f17b1ea6916809fa93880a287
Closes-Bug: 1296489
This commit is contained in:
jichenjc 2014-03-24 15:16:17 +08:00
parent cded075dcf
commit 6169e05a48
2 changed files with 53 additions and 3 deletions

View File

@ -115,6 +115,7 @@ class NetworkController(object):
def delete(self, req, id):
context = req.environ['nova.context']
authorize(context)
reservation = None
try:
if CONF.enable_network_quota:
reservation = QUOTAS.reserve(context, networks=-1)
@ -125,19 +126,27 @@ class NetworkController(object):
LOG.info(_LI("Deleting network with id %s"), id)
def _rollback_quota(reservation):
if CONF.enable_network_quota and reservation:
QUOTAS.rollback(context, reservation)
try:
self.network_api.delete(context, id)
if CONF.enable_network_quota and reservation:
QUOTAS.commit(context, reservation)
response = exc.HTTPAccepted()
except exception.PolicyNotAuthorized as e:
_rollback_quota(reservation)
raise exc.HTTPForbidden(explanation=str(e))
except exception.NetworkInUse as e:
_rollback_quota(reservation)
raise exc.HTTPConflict(explanation=e.format_message())
except exception.NetworkNotFound:
_rollback_quota(reservation)
msg = _("Network not found")
raise exc.HTTPNotFound(explanation=msg)
if CONF.enable_network_quota and reservation:
QUOTAS.commit(context, reservation)
response = exc.HTTPAccepted()
return response
def create(self, req, body):

View File

@ -19,12 +19,14 @@ import datetime
import math
import uuid
import mock
import netaddr
from oslo.config import cfg
import webob
from nova.api.openstack.compute.contrib import networks_associate
from nova.api.openstack.compute.contrib import os_networks as networks
from nova.api.openstack.compute.contrib import os_tenant_networks as tnet
import nova.context
from nova import exception
from nova import test
@ -394,3 +396,42 @@ class NetworksTest(test.NoDBTestCase):
self.assertRaises(webob.exc.HTTPNotImplemented,
controller._disassociate_host_and_project,
req, uuid, {'disassociate': None})
class TenantNetworksTest(test.NoDBTestCase):
def setUp(self):
super(TenantNetworksTest, self).setUp()
self.controller = tnet.NetworkController()
self.flags(enable_network_quota=True)
@mock.patch('nova.quota.QUOTAS.reserve')
@mock.patch('nova.quota.QUOTAS.rollback')
@mock.patch('nova.network.api.API.delete')
def _test_network_delete_exception(self, ex, expex, delete_mock,
rollback_mock, reserve_mock):
req = fakes.HTTPRequest.blank('/v2/1234/os-tenant-networks')
ctxt = req.environ['nova.context']
reserve_mock.return_value = 'rv'
delete_mock.side_effect = ex
self.assertRaises(expex, self.controller.delete, req, 1)
delete_mock.assert_called_once_with(ctxt, 1)
rollback_mock.assert_called_once_with(ctxt, 'rv')
reserve_mock.assert_called_once_with(ctxt, networks=-1)
def test_network_delete_exception_network_not_found(self):
ex = exception.NetworkNotFound(network_id=1)
expex = webob.exc.HTTPNotFound
self._test_network_delete_exception(ex, expex)
def test_network_delete_exception_policy_failed(self):
ex = exception.PolicyNotAuthorized(action='dummy')
expex = webob.exc.HTTPForbidden
self._test_network_delete_exception(ex, expex)
def test_network_delete_exception_network_in_use(self):
ex = exception.NetworkInUse(network_id=1)
expex = webob.exc.HTTPConflict
self._test_network_delete_exception(ex, expex)