Handle initialize_connection() exception in volume manager

Due to the fact that several drivers require backend communication to fetch
connection information for a volume, it's possile that these driver throw
exceptions while doing that.  Currently exceptions can bubble up to volume
API not being handled.  This patch logs exception in volume manager and
then raises VolumeBackendAPIException to caller.

Change-Id: Ib3cc152e04ba029dd835a64b0cfb0a77b8a6828e
Closes-bug: 1256804
This commit is contained in:
Zhiteng Huang 2013-12-02 17:05:08 +08:00
parent e40dafd544
commit 17e556acf5
3 changed files with 50 additions and 27 deletions

View File

@ -188,9 +188,14 @@ class VolumeActionsController(wsgi.Controller):
connector = body['os-initialize_connection']['connector']
except KeyError:
raise webob.exc.HTTPBadRequest("Must specify 'connector'")
info = self.volume_api.initialize_connection(context,
volume,
connector)
try:
info = self.volume_api.initialize_connection(context,
volume,
connector)
except exception.VolumeBackendAPIException as error:
msg = _("Unable to fetch connection information from backend.")
raise webob.exc.HTTPInternalServerError(msg)
return {'connection_info': info}
@wsgi.action('os-terminate_connection')

View File

@ -17,6 +17,8 @@
import datetime
import json
import uuid
import mock
import webob
from cinder.api.contrib import volume_actions
@ -65,34 +67,44 @@ class VolumeActionsTest(test.TestCase):
self.assertEqual(res.status_int, 202)
def test_initialize_connection(self):
def fake_initialize_connection(*args, **kwargs):
return {}
self.stubs.Set(volume.API, 'initialize_connection',
fake_initialize_connection)
with mock.patch.object(volume_api.API,
'initialize_connection') as init_conn:
init_conn.return_value = {}
body = {'os-initialize_connection': {'connector': 'fake'}}
req = webob.Request.blank('/v2/fake/volumes/1/action')
req.method = "POST"
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
body = {'os-initialize_connection': {'connector': 'fake'}}
req = webob.Request.blank('/v2/fake/volumes/1/action')
req.method = "POST"
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200)
def test_initialize_connection_without_connector(self):
def fake_initialize_connection(*args, **kwargs):
return {}
self.stubs.Set(volume.API, 'initialize_connection',
fake_initialize_connection)
with mock.patch.object(volume_api.API,
'initialize_connection') as init_conn:
init_conn.return_value = {}
body = {'os-initialize_connection': {}}
req = webob.Request.blank('/v2/fake/volumes/1/action')
req.method = "POST"
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
body = {'os-initialize_connection': {}}
req = webob.Request.blank('/v2/fake/volumes/1/action')
req.method = "POST"
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 400)
def test_initialize_connection_exception(self):
with mock.patch.object(volume_api.API,
'initialize_connection') as init_conn:
init_conn.side_effect = \
exception.VolumeBackendAPIException(data=None)
body = {'os-initialize_connection': {'connector': 'fake'}}
req = webob.Request.blank('/v2/fake/volumes/1/action')
req.method = "POST"
req.body = jsonutils.dumps(body)
req.headers["content-type"] = "application/json"
res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 500)
def test_terminate_connection(self):
def fake_terminate_connection(*args, **kwargs):

View File

@ -708,7 +708,13 @@ class VolumeManager(manager.SchedulerDependentManager):
"""
volume = self.db.volume_get(context, volume_id)
self.driver.validate_connector(connector)
conn_info = self.driver.initialize_connection(volume, connector)
try:
conn_info = self.driver.initialize_connection(volume, connector)
except Exception as err:
err_msg = (_('Unable to fetch connection information from '
'backend: %(err)s') % {'err': str(err)})
LOG.error(err_msg)
raise exception.VolumeBackendAPIException(data=err_msg)
# Add qos_specs to connection info
typeid = volume['volume_type_id']