Volume types need to be specified when creating CG

When creating a consistency group, the scheduler will find a backend that
supports all input volume types. If volume types are not provided, the
default_volume_type in cinder.conf will be used, however, this could cause
inconsistent behavior in a user environment where the default_volume_type
is defined in some places but not in others. This fix removed the use of
default_volume_type for CG creation, added a check to verify that volume
types are provided when creating a CG.

When creating a volume and adding it to a CG, we need to make sure a
volume type is provided as well.

Change-Id: I078d4fdd8d92529e853be16272ad74d1e130f712
Closes-Bug: #1366371
This commit is contained in:
Xing Yang 2014-09-06 13:32:02 -04:00
parent 52df6822f6
commit 9082273305
7 changed files with 240 additions and 136 deletions

View File

@ -125,11 +125,10 @@ class ConsistencyGroupsController(wsgi.Controller):
group = self.consistencygroup_api.get(context, id) group = self.consistencygroup_api.get(context, id)
self.consistencygroup_api.delete(context, group, force) self.consistencygroup_api.delete(context, group, force)
except exception.ConsistencyGroupNotFound: except exception.ConsistencyGroupNotFound:
msg = _("Consistency group could not be found") msg = _("Consistency group %s could not be found.") % id
raise exc.HTTPNotFound(explanation=msg) raise exc.HTTPNotFound(explanation=msg)
except exception.InvalidConsistencyGroup: except exception.InvalidConsistencyGroup as error:
msg = _("Invalid consistency group") raise exc.HTTPBadRequest(explanation=error.msg)
raise exc.HTTPBadRequest(explanation=msg)
return webob.Response(status_int=202) return webob.Response(status_int=202)
@ -176,6 +175,10 @@ class ConsistencyGroupsController(wsgi.Controller):
name = consistencygroup.get('name', None) name = consistencygroup.get('name', None)
description = consistencygroup.get('description', None) description = consistencygroup.get('description', None)
volume_types = consistencygroup.get('volume_types', None) volume_types = consistencygroup.get('volume_types', None)
if not volume_types:
msg = _("volume_types must be provided to create "
"consistency group %(name)s.") % {'name': name}
raise exc.HTTPBadRequest(explanation=msg)
availability_zone = consistencygroup.get('availability_zone', None) availability_zone = consistencygroup.get('availability_zone', None)
LOG.info(_("Creating consistency group %(name)s."), LOG.info(_("Creating consistency group %(name)s."),
@ -184,7 +187,7 @@ class ConsistencyGroupsController(wsgi.Controller):
try: try:
new_consistencygroup = self.consistencygroup_api.create( new_consistencygroup = self.consistencygroup_api.create(
context, name, description, cg_volume_types=volume_types, context, name, description, volume_types,
availability_zone=availability_zone) availability_zone=availability_zone)
except exception.InvalidConsistencyGroup as error: except exception.InvalidConsistencyGroup as error:
raise exc.HTTPBadRequest(explanation=error.msg) raise exc.HTTPBadRequest(explanation=error.msg)

View File

@ -104,27 +104,20 @@ class API(base.Base):
return availability_zone return availability_zone
def create(self, context, name, description, def create(self, context, name, description,
cg_volume_types=None, availability_zone=None): cg_volume_types, availability_zone=None):
check_policy(context, 'create') check_policy(context, 'create')
volume_type_list = None volume_type_list = None
if cg_volume_types: volume_type_list = cg_volume_types.split(',')
volume_type_list = cg_volume_types.split(',')
req_volume_types = [] req_volume_types = []
if volume_type_list: req_volume_types = (self.db.volume_types_get_by_name_or_id(
req_volume_types = (self.db.volume_types_get_by_name_or_id( context, volume_type_list))
context, volume_type_list))
if not req_volume_types:
volume_type = volume_types.get_default_volume_type()
req_volume_types.append(volume_type)
req_volume_type_ids = "" req_volume_type_ids = ""
for voltype in req_volume_types: for voltype in req_volume_types:
if voltype: req_volume_type_ids = (
req_volume_type_ids = ( req_volume_type_ids + voltype.get('id') + ",")
req_volume_type_ids + voltype.get('id') + ",")
if len(req_volume_type_ids) == 0: if len(req_volume_type_ids) == 0:
req_volume_type_ids = None req_volume_type_ids = None

View File

@ -96,18 +96,18 @@ class SchedulerManager(manager.Manager):
context, group_id, context, group_id,
request_spec_list, request_spec_list,
filter_properties_list) filter_properties_list)
except exception.NoValidHost as ex: except exception.NoValidHost:
msg = (_("Could not find a host for consistency group " msg = (_("Could not find a host for consistency group "
"%(group_id)s.") % "%(group_id)s.") %
{'group_id': group_id}) {'group_id': group_id})
LOG.error(msg) LOG.error(msg)
db.consistencygroup_update(context, group_id, db.consistencygroup_update(context, group_id,
{'status': 'error'}) {'status': 'error'})
except Exception as ex: except Exception:
with excutils.save_and_reraise_exception(): with excutils.save_and_reraise_exception():
LOG.error(_("Failed to create consistency group " LOG.exception(_("Failed to create consistency group "
"%(group_id)s.")) "%(group_id)s."),
LOG.exception(ex) {'group_id': group_id})
db.consistencygroup_update(context, group_id, db.consistencygroup_update(context, group_id,
{'status': 'error'}) {'status': 'error'})

View File

@ -26,6 +26,7 @@ import webob
import cinder.consistencygroup import cinder.consistencygroup
from cinder import context from cinder import context
from cinder import db from cinder import db
from cinder.i18n import _
from cinder import test from cinder import test
from cinder.tests.api import fakes from cinder.tests.api import fakes
@ -73,14 +74,15 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body) res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 200) self.assertEqual(200, res.status_int)
self.assertEqual(res_dict['consistencygroup']['availability_zone'], self.assertEqual('az1',
'az1') res_dict['consistencygroup']['availability_zone'])
self.assertEqual(res_dict['consistencygroup']['description'], self.assertEqual('this is a test consistency group',
'this is a test consistency group') res_dict['consistencygroup']['description'])
self.assertEqual(res_dict['consistencygroup']['name'], self.assertEqual('test_consistencygroup',
'test_consistencygroup') res_dict['consistencygroup']['name'])
self.assertEqual(res_dict['consistencygroup']['status'], 'creating') self.assertEqual('creating',
res_dict['consistencygroup']['status'])
db.consistencygroup_destroy(context.get_admin_context(), db.consistencygroup_destroy(context.get_admin_context(),
consistencygroup_id) consistencygroup_id)
@ -93,11 +95,11 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
req.headers['Content-Type'] = 'application/xml' req.headers['Content-Type'] = 'application/xml'
req.headers['Accept'] = 'application/xml' req.headers['Accept'] = 'application/xml'
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200) self.assertEqual(200, res.status_int)
dom = minidom.parseString(res.body) dom = minidom.parseString(res.body)
consistencygroup = dom.getElementsByTagName('consistencygroup') consistencygroup = dom.getElementsByTagName('consistencygroup')
name = consistencygroup.item(0).getAttribute('name') name = consistencygroup.item(0).getAttribute('name')
self.assertEqual(name.strip(), "test_consistencygroup") self.assertEqual("test_consistencygroup", name.strip())
db.consistencygroup_destroy( db.consistencygroup_destroy(
context.get_admin_context(), context.get_admin_context(),
consistencygroup_id) consistencygroup_id)
@ -109,10 +111,10 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body) res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 404) self.assertEqual(404, res.status_int)
self.assertEqual(res_dict['itemNotFound']['code'], 404) self.assertEqual(404, res_dict['itemNotFound']['code'])
self.assertEqual(res_dict['itemNotFound']['message'], self.assertEqual('ConsistencyGroup 9999 could not be found.',
'ConsistencyGroup 9999 could not be found.') res_dict['itemNotFound']['message'])
def test_list_consistencygroups_json(self): def test_list_consistencygroups_json(self):
consistencygroup_id1 = self._create_consistencygroup() consistencygroup_id1 = self._create_consistencygroup()
@ -125,19 +127,19 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body) res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 200) self.assertEqual(200, res.status_int)
self.assertEqual(res_dict['consistencygroups'][0]['id'], self.assertEqual(consistencygroup_id1,
consistencygroup_id1) res_dict['consistencygroups'][0]['id'])
self.assertEqual(res_dict['consistencygroups'][0]['name'], self.assertEqual('test_consistencygroup',
'test_consistencygroup') res_dict['consistencygroups'][0]['name'])
self.assertEqual(res_dict['consistencygroups'][1]['id'], self.assertEqual(consistencygroup_id2,
consistencygroup_id2) res_dict['consistencygroups'][1]['id'])
self.assertEqual(res_dict['consistencygroups'][1]['name'], self.assertEqual('test_consistencygroup',
'test_consistencygroup') res_dict['consistencygroups'][1]['name'])
self.assertEqual(res_dict['consistencygroups'][2]['id'], self.assertEqual(consistencygroup_id3,
consistencygroup_id3) res_dict['consistencygroups'][2]['id'])
self.assertEqual(res_dict['consistencygroups'][2]['name'], self.assertEqual('test_consistencygroup',
'test_consistencygroup') res_dict['consistencygroups'][2]['name'])
db.consistencygroup_destroy(context.get_admin_context(), db.consistencygroup_destroy(context.get_admin_context(),
consistencygroup_id3) consistencygroup_id3)
@ -157,16 +159,16 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
req.headers['Accept'] = 'application/xml' req.headers['Accept'] = 'application/xml'
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200) self.assertEqual(200, res.status_int)
dom = minidom.parseString(res.body) dom = minidom.parseString(res.body)
consistencygroup_list = dom.getElementsByTagName('consistencygroup') consistencygroup_list = dom.getElementsByTagName('consistencygroup')
self.assertEqual(consistencygroup_list.item(0).getAttribute('id'), self.assertEqual(consistencygroup_id1,
consistencygroup_id1) consistencygroup_list.item(0).getAttribute('id'))
self.assertEqual(consistencygroup_list.item(1).getAttribute('id'), self.assertEqual(consistencygroup_id2,
consistencygroup_id2) consistencygroup_list.item(1).getAttribute('id'))
self.assertEqual(consistencygroup_list.item(2).getAttribute('id'), self.assertEqual(consistencygroup_id3,
consistencygroup_id3) consistencygroup_list.item(2).getAttribute('id'))
db.consistencygroup_destroy(context.get_admin_context(), db.consistencygroup_destroy(context.get_admin_context(),
consistencygroup_id3) consistencygroup_id3)
@ -187,39 +189,39 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body) res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 200) self.assertEqual(200, res.status_int)
self.assertEqual(res_dict['consistencygroups'][0]['availability_zone'], self.assertEqual('az1',
'az1') res_dict['consistencygroups'][0]['availability_zone'])
self.assertEqual(res_dict['consistencygroups'][0]['description'], self.assertEqual('this is a test consistency group',
'this is a test consistency group') res_dict['consistencygroups'][0]['description'])
self.assertEqual(res_dict['consistencygroups'][0]['name'], self.assertEqual('test_consistencygroup',
'test_consistencygroup') res_dict['consistencygroups'][0]['name'])
self.assertEqual(res_dict['consistencygroups'][0]['id'], self.assertEqual(consistencygroup_id1,
consistencygroup_id1) res_dict['consistencygroups'][0]['id'])
self.assertEqual(res_dict['consistencygroups'][0]['status'], self.assertEqual('creating',
'creating') res_dict['consistencygroups'][0]['status'])
self.assertEqual(res_dict['consistencygroups'][1]['availability_zone'], self.assertEqual('az1',
'az1') res_dict['consistencygroups'][1]['availability_zone'])
self.assertEqual(res_dict['consistencygroups'][1]['description'], self.assertEqual('this is a test consistency group',
'this is a test consistency group') res_dict['consistencygroups'][1]['description'])
self.assertEqual(res_dict['consistencygroups'][1]['name'], self.assertEqual('test_consistencygroup',
'test_consistencygroup') res_dict['consistencygroups'][1]['name'])
self.assertEqual(res_dict['consistencygroups'][1]['id'], self.assertEqual(consistencygroup_id2,
consistencygroup_id2) res_dict['consistencygroups'][1]['id'])
self.assertEqual(res_dict['consistencygroups'][1]['status'], self.assertEqual('creating',
'creating') res_dict['consistencygroups'][1]['status'])
self.assertEqual(res_dict['consistencygroups'][2]['availability_zone'], self.assertEqual('az1',
'az1') res_dict['consistencygroups'][2]['availability_zone'])
self.assertEqual(res_dict['consistencygroups'][2]['description'], self.assertEqual('this is a test consistency group',
'this is a test consistency group') res_dict['consistencygroups'][2]['description'])
self.assertEqual(res_dict['consistencygroups'][2]['name'], self.assertEqual('test_consistencygroup',
'test_consistencygroup') res_dict['consistencygroups'][2]['name'])
self.assertEqual(res_dict['consistencygroups'][2]['id'], self.assertEqual(consistencygroup_id3,
consistencygroup_id3) res_dict['consistencygroups'][2]['id'])
self.assertEqual(res_dict['consistencygroups'][2]['status'], self.assertEqual('creating',
'creating') res_dict['consistencygroups'][2]['status'])
db.consistencygroup_destroy(context.get_admin_context(), db.consistencygroup_destroy(context.get_admin_context(),
consistencygroup_id3) consistencygroup_id3)
@ -239,54 +241,57 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
req.headers['Accept'] = 'application/xml' req.headers['Accept'] = 'application/xml'
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 200) self.assertEqual(200, res.status_int)
dom = minidom.parseString(res.body) dom = minidom.parseString(res.body)
consistencygroup_detail = dom.getElementsByTagName('consistencygroup') consistencygroup_detail = dom.getElementsByTagName('consistencygroup')
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(0).getAttribute('availability_zone'), 'az1',
'az1') consistencygroup_detail.item(0).getAttribute('availability_zone'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(0).getAttribute('description'), 'this is a test consistency group',
'this is a test consistency group') consistencygroup_detail.item(0).getAttribute('description'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(0).getAttribute('name'), 'test_consistencygroup',
'test_consistencygroup') consistencygroup_detail.item(0).getAttribute('name'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(0).getAttribute('id'), consistencygroup_id1,
consistencygroup_id1) consistencygroup_detail.item(0).getAttribute('id'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(0).getAttribute('status'), 'creating') 'creating',
consistencygroup_detail.item(0).getAttribute('status'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(1).getAttribute('availability_zone'), 'az1',
'az1') consistencygroup_detail.item(1).getAttribute('availability_zone'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(1).getAttribute('description'), 'this is a test consistency group',
'this is a test consistency group') consistencygroup_detail.item(1).getAttribute('description'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(1).getAttribute('name'), 'test_consistencygroup',
'test_consistencygroup') consistencygroup_detail.item(1).getAttribute('name'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(1).getAttribute('id'), consistencygroup_id2,
consistencygroup_id2) consistencygroup_detail.item(1).getAttribute('id'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(1).getAttribute('status'), 'creating') 'creating',
consistencygroup_detail.item(1).getAttribute('status'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(2).getAttribute('availability_zone'), 'az1',
'az1') consistencygroup_detail.item(2).getAttribute('availability_zone'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(2).getAttribute('description'), 'this is a test consistency group',
'this is a test consistency group') consistencygroup_detail.item(2).getAttribute('description'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(2).getAttribute('name'), 'test_consistencygroup',
'test_consistencygroup') consistencygroup_detail.item(2).getAttribute('name'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(2).getAttribute('id'), consistencygroup_id3,
consistencygroup_id3) consistencygroup_detail.item(2).getAttribute('id'))
self.assertEqual( self.assertEqual(
consistencygroup_detail.item(2).getAttribute('status'), 'creating') 'creating',
consistencygroup_detail.item(2).getAttribute('status'))
db.consistencygroup_destroy(context.get_admin_context(), db.consistencygroup_destroy(context.get_admin_context(),
consistencygroup_id3) consistencygroup_id3)
@ -297,7 +302,14 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
def test_create_consistencygroup_json(self): def test_create_consistencygroup_json(self):
group_id = "1" group_id = "1"
# Create volume type
vol_type = 'test'
db.volume_type_create(context.get_admin_context(),
{'name': vol_type, 'extra_specs': {}})
body = {"consistencygroup": {"name": "cg1", body = {"consistencygroup": {"name": "cg1",
"volume_types": vol_type,
"description": "description":
"Consistency Group 1", }} "Consistency Group 1", }}
req = webob.Request.blank('/v2/fake/consistencygroups') req = webob.Request.blank('/v2/fake/consistencygroups')
@ -307,7 +319,7 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body) res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 202) self.assertEqual(202, res.status_int)
self.assertIn('id', res_dict['consistencygroup']) self.assertIn('id', res_dict['consistencygroup'])
db.consistencygroup_destroy(context.get_admin_context(), group_id) db.consistencygroup_destroy(context.get_admin_context(), group_id)
@ -322,11 +334,11 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body) res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400) self.assertEqual(400, res.status_int)
self.assertEqual(res_dict['badRequest']['code'], 400) self.assertEqual(400, res_dict['badRequest']['code'])
self.assertEqual(res_dict['badRequest']['message'], self.assertEqual('The server could not comply with the request since'
'The server could not comply with the request since' ' it is either malformed or otherwise incorrect.',
' it is either malformed or otherwise incorrect.') res_dict['badRequest']['message'])
def test_delete_consistencygroup_available(self): def test_delete_consistencygroup_available(self):
consistencygroup_id = self._create_consistencygroup(status='available') consistencygroup_id = self._create_consistencygroup(status='available')
@ -338,10 +350,10 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
req.body = json.dumps(body) req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
self.assertEqual(res.status_int, 202) self.assertEqual(202, res.status_int)
self.assertEqual(self._get_consistencygroup_attrib(consistencygroup_id, self.assertEqual('deleting',
'status'), self._get_consistencygroup_attrib(consistencygroup_id,
'deleting') 'status'))
db.consistencygroup_destroy(context.get_admin_context(), db.consistencygroup_destroy(context.get_admin_context(),
consistencygroup_id) consistencygroup_id)
@ -354,10 +366,10 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body) res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 404) self.assertEqual(404, res.status_int)
self.assertEqual(res_dict['itemNotFound']['code'], 404) self.assertEqual(404, res_dict['itemNotFound']['code'])
self.assertEqual(res_dict['itemNotFound']['message'], self.assertEqual('Consistency group 9999 could not be found.',
'Consistency group could not be found') res_dict['itemNotFound']['message'])
def test_delete_consistencygroup_with_Invalidconsistencygroup(self): def test_delete_consistencygroup_with_Invalidconsistencygroup(self):
consistencygroup_id = self._create_consistencygroup(status='invalid') consistencygroup_id = self._create_consistencygroup(status='invalid')
@ -370,10 +382,11 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
res = req.get_response(fakes.wsgi_app()) res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body) res_dict = json.loads(res.body)
self.assertEqual(res.status_int, 400) self.assertEqual(400, res.status_int)
self.assertEqual(res_dict['badRequest']['code'], 400) self.assertEqual(400, res_dict['badRequest']['code'])
self.assertEqual(res_dict['badRequest']['message'], msg = (_('Invalid ConsistencyGroup: Consistency group status must be '
'Invalid consistency group') 'available or error, but current status is: invalid'))
self.assertEqual(msg, res_dict['badRequest']['message'])
db.consistencygroup_destroy(context.get_admin_context(), db.consistencygroup_destroy(context.get_admin_context(),
consistencygroup_id) consistencygroup_id)
@ -425,3 +438,21 @@ class ConsistencyGroupsAPITestCase(test.TestCase):
context.get_admin_context(read_deleted='yes'), context.get_admin_context(read_deleted='yes'),
cg['id']) cg['id'])
self.assertEqual(cg['status'], 'deleted') self.assertEqual(cg['status'], 'deleted')
def test_create_consistencygroup_failed_no_volume_type(self):
name = 'cg1'
body = {"consistencygroup": {"name": name,
"description":
"Consistency Group 1", }}
req = webob.Request.blank('/v2/fake/consistencygroups')
req.method = 'POST'
req.headers['Content-Type'] = 'application/json'
req.body = json.dumps(body)
res = req.get_response(fakes.wsgi_app())
res_dict = json.loads(res.body)
self.assertEqual(400, res.status_int)
self.assertEqual(400, res_dict['badRequest']['code'])
msg = (_('volume_types must be provided to create '
'consistency group %s.') % name)
self.assertEqual(msg, res_dict['badRequest']['message'])

View File

@ -115,6 +115,36 @@ class VolumeApiTest(test.TestCase):
'encrypted': False}} 'encrypted': False}}
self.assertEqual(res_dict, ex) self.assertEqual(res_dict, ex)
def test_volume_create_with_consistencygroup_invalid_type(self):
ctxt = context.RequestContext('fake', 'fake', auth_token=True)
vol_type = db.volume_type_create(
context.get_admin_context(),
dict(name=CONF.default_volume_type, extra_specs={})
)
db_vol_type = db.volume_type_get(context.get_admin_context(),
vol_type.id)
cg = {
'id': '1',
'name': 'cg1',
'volume_type_id': db_vol_type['id'],
}
fake_type = {
'id': '9999',
'name': 'fake',
}
vol_api = volume_api.API()
self.assertRaises(exception.InvalidInput,
vol_api.create,
ctxt, 1, 'vol1', 'volume 1',
consistencygroup=cg)
self.assertRaises(exception.InvalidInput,
vol_api.create,
ctxt, 1, 'vol1', 'volume 1',
volume_type=fake_type,
consistencygroup=cg)
def test_volume_create_with_type(self): def test_volume_create_with_type(self):
vol_type = db.volume_type_create( vol_type = db.volume_type_create(
context.get_admin_context(), context.get_admin_context(),

View File

@ -22,7 +22,10 @@ import mock
from oslo.config import cfg from oslo.config import cfg
from cinder import context from cinder import context
from cinder import db
from cinder import exception from cinder import exception
from cinder.i18n import _
from cinder.openstack.common import log as logging
from cinder.scheduler import driver from cinder.scheduler import driver
from cinder.scheduler import filter_scheduler from cinder.scheduler import filter_scheduler
from cinder.scheduler import manager from cinder.scheduler import manager
@ -188,6 +191,46 @@ class SchedulerManagerTestCase(test.TestCase):
{'status': 'in-use'}) {'status': 'in-use'})
self.manager.driver.find_retype_host = orig_retype self.manager.driver.find_retype_host = orig_retype
def test_create_consistencygroup_exceptions(self):
with mock.patch.object(filter_scheduler.FilterScheduler,
'schedule_create_consistencygroup') as mock_cg:
original_driver = self.manager.driver
self.manager.driver = filter_scheduler.FilterScheduler
LOG = logging.getLogger('cinder.scheduler.manager')
self.stubs.Set(LOG, 'error', mock.Mock())
self.stubs.Set(LOG, 'exception', mock.Mock())
self.stubs.Set(db, 'consistencygroup_update', mock.Mock())
ex = exception.CinderException('test')
mock_cg.side_effect = ex
group_id = '1'
self.assertRaises(exception.CinderException,
self.manager.create_consistencygroup,
self.context,
'volume',
group_id)
LOG.exception.assert_called_once_with(_(
"Failed to create consistency group "
"%(group_id)s."), {'group_id': group_id})
db.consistencygroup_update.assert_called_once_with(
self.context, group_id, {'status': 'error'})
mock_cg.reset_mock()
LOG.exception.reset_mock()
db.consistencygroup_update.reset_mock()
mock_cg.side_effect = exception.NoValidHost(
reason="No weighed hosts available")
self.manager.create_consistencygroup(
self.context, 'volume', group_id)
LOG.error.assert_called_once_with(_(
"Could not find a host for consistency group "
"%(group_id)s.") % {'group_id': group_id})
db.consistencygroup_update.assert_called_once_with(
self.context, group_id, {'status': 'error'})
self.manager.driver = original_driver
class SchedulerTestCase(test.TestCase): class SchedulerTestCase(test.TestCase):
"""Test case for base scheduler driver class.""" """Test case for base scheduler driver class."""

View File

@ -155,11 +155,15 @@ class API(base.Base):
scheduler_hints=None, backup_source_volume=None, scheduler_hints=None, backup_source_volume=None,
source_replica=None, consistencygroup=None): source_replica=None, consistencygroup=None):
if volume_type and consistencygroup: if consistencygroup:
if not volume_type:
msg = _("volume_type must be provided when creating "
"a volume in a consistency group.")
raise exception.InvalidInput(reason=msg)
cg_voltypeids = consistencygroup.get('volume_type_id') cg_voltypeids = consistencygroup.get('volume_type_id')
if volume_type.get('id') not in cg_voltypeids: if volume_type.get('id') not in cg_voltypeids:
msg = _("Invalid volume_type provided (requested type " msg = _("Invalid volume_type provided (requested type "
"must be supported by this consistency group.") "must be supported by this consistency group).")
raise exception.InvalidInput(reason=msg) raise exception.InvalidInput(reason=msg)
if source_volume and volume_type: if source_volume and volume_type: