Add the ability to update type public status
Currently, the v2 volume type update api doesn't support updating volume type's public status. All volume types created are public by default if not specified. It is not possible to update an existing volume_type is_public status. It is necessary to add updating public status for volume type. If a volume type updated from public to private, the volumes previously created with this type will not be affected, but the user without access will not be able to create volume with this type anymore. APIImpact: Add 'is_public' for v2 type update api. Implements blueprint: volume-types-public-update Change-Id: I4a5b2cf8f747c87908a09835a5edb8873c4e946b
This commit is contained in:
parent
1bbae62b3d
commit
f92d71219e
|
@ -112,6 +112,7 @@ class VolumeTypesManageController(wsgi.Controller):
|
|||
vol_type = body['volume_type']
|
||||
description = vol_type.get('description')
|
||||
name = vol_type.get('name')
|
||||
is_public = vol_type.get('is_public')
|
||||
|
||||
# Name and description can not be both None.
|
||||
# If name specified, name can not be empty.
|
||||
|
@ -123,6 +124,11 @@ class VolumeTypesManageController(wsgi.Controller):
|
|||
msg = _("Specify either volume type name and/or description.")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
if is_public is not None and not utils.is_valid_boolstr(is_public):
|
||||
msg = _("Invalid value '%s' for is_public. Accepted values: "
|
||||
"True or False.") % is_public
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
if name:
|
||||
utils.check_string_length(name, 'Type name',
|
||||
min_length=1, max_length=255)
|
||||
|
@ -132,7 +138,8 @@ class VolumeTypesManageController(wsgi.Controller):
|
|||
min_length=0, max_length=255)
|
||||
|
||||
try:
|
||||
volume_types.update(context, id, name, description)
|
||||
volume_types.update(context, id, name, description,
|
||||
is_public=is_public)
|
||||
# Get the updated
|
||||
vol_type = volume_types.get_volume_type(context, id)
|
||||
req.cache_resource(vol_type, name='types')
|
||||
|
|
|
@ -22,6 +22,7 @@ class ViewBuilder(common.ViewBuilder):
|
|||
"""Trim away extraneous volume type attributes."""
|
||||
trimmed = dict(id=volume_type.get('id'),
|
||||
name=volume_type.get('name'),
|
||||
is_public=volume_type.get('is_public'),
|
||||
extra_specs=volume_type.get('extra_specs'),
|
||||
description=volume_type.get('description'))
|
||||
return trimmed if brief else dict(volume_type=trimmed)
|
||||
|
|
|
@ -2302,6 +2302,10 @@ def volume_type_update(context, volume_type_id, values):
|
|||
if values['description'] is None:
|
||||
del values['description']
|
||||
|
||||
# No is_public change
|
||||
if values['is_public'] is None:
|
||||
del values['is_public']
|
||||
|
||||
# No name change
|
||||
if values['name'] is None:
|
||||
del values['name']
|
||||
|
|
|
@ -36,9 +36,10 @@ def stub_volume_type(id):
|
|||
extra_specs=specs)
|
||||
|
||||
|
||||
def stub_volume_type_updated(id):
|
||||
def stub_volume_type_updated(id, is_public=True):
|
||||
return dict(id=id,
|
||||
name='vol_type_%s_%s' % (six.text_type(id), six.text_type(id)),
|
||||
is_public=is_public,
|
||||
description='vol_type_desc_%s_%s' % (
|
||||
six.text_type(id), six.text_type(id)))
|
||||
|
||||
|
@ -84,14 +85,6 @@ def return_volume_types_create_duplicate_type(context,
|
|||
raise exception.VolumeTypeExists(id=name)
|
||||
|
||||
|
||||
def return_volume_types_update(context, id, name, description):
|
||||
pass
|
||||
|
||||
|
||||
def return_volume_types_update_fail(context, id, name, description):
|
||||
raise exception.VolumeTypeUpdateFailed(id=id)
|
||||
|
||||
|
||||
def stub_volume_type_updated_name_only(id):
|
||||
return dict(id=id,
|
||||
name='vol_type_%s_%s' % (six.text_type(id), six.text_type(id)),
|
||||
|
@ -104,11 +97,7 @@ def stub_volume_type_updated_name_after_delete(id):
|
|||
description='vol_type_desc_%s' % six.text_type(id))
|
||||
|
||||
|
||||
def return_volume_types_update_exist(context, id, name, description):
|
||||
raise exception.VolumeTypeExists(id=id, name=name)
|
||||
|
||||
|
||||
def return_volume_types_get_volume_type_updated(context, id):
|
||||
def return_volume_types_get_volume_type_updated(id, is_public=True):
|
||||
if id == "777":
|
||||
raise exception.VolumeTypeNotFound(volume_type_id=id)
|
||||
if id == '888':
|
||||
|
@ -119,7 +108,7 @@ def return_volume_types_get_volume_type_updated(context, id):
|
|||
return stub_volume_type_updated_name_after_delete(int(id))
|
||||
|
||||
# anything else
|
||||
return stub_volume_type_updated(int(id))
|
||||
return stub_volume_type_updated(int(id), is_public=is_public)
|
||||
|
||||
|
||||
def return_volume_types_get_by_name(context, name):
|
||||
|
@ -273,14 +262,15 @@ class VolumeTypesManageApiTest(test.TestCase):
|
|||
body = {'volume_type': 'string'}
|
||||
self._create_volume_type_bad_body(body=body)
|
||||
|
||||
def test_update(self):
|
||||
self.stubs.Set(volume_types, 'update',
|
||||
return_volume_types_update)
|
||||
self.stubs.Set(volume_types, 'get_volume_type',
|
||||
return_volume_types_get_volume_type_updated)
|
||||
@mock.patch('cinder.volume.volume_types.update')
|
||||
@mock.patch('cinder.volume.volume_types.get_volume_type')
|
||||
def test_update(self, mock_get, mock_update):
|
||||
mock_get.return_value = return_volume_types_get_volume_type_updated(
|
||||
'1', is_public=False)
|
||||
|
||||
body = {"volume_type": {"name": "vol_type_1_1",
|
||||
"description": "vol_type_desc_1_1"}}
|
||||
"description": "vol_type_desc_1_1",
|
||||
"is_public": False}}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/types/1')
|
||||
req.method = 'PUT'
|
||||
|
||||
|
@ -289,7 +279,8 @@ class VolumeTypesManageApiTest(test.TestCase):
|
|||
self.assertEqual(1, len(self.notifier.notifications))
|
||||
self._check_test_results(res_dict,
|
||||
{'expected_desc': 'vol_type_desc_1_1',
|
||||
'expected_name': 'vol_type_1_1'})
|
||||
'expected_name': 'vol_type_1_1',
|
||||
'is_public': False})
|
||||
|
||||
@mock.patch('cinder.volume.volume_types.update')
|
||||
@mock.patch('cinder.volume.volume_types.get_volume_type')
|
||||
|
@ -325,11 +316,11 @@ class VolumeTypesManageApiTest(test.TestCase):
|
|||
self.assertRaises(exception.InvalidInput,
|
||||
self.controller._update, req, '1', body)
|
||||
|
||||
def test_update_non_exist(self):
|
||||
self.stubs.Set(volume_types, 'update',
|
||||
return_volume_types_update)
|
||||
self.stubs.Set(volume_types, 'get_volume_type',
|
||||
return_volume_types_get_volume_type)
|
||||
@mock.patch('cinder.volume.volume_types.get_volume_type')
|
||||
@mock.patch('cinder.volume.volume_types.update')
|
||||
def test_update_non_exist(self, mock_update, mock_get_volume_type):
|
||||
mock_get_volume_type.side_effect = exception.VolumeTypeNotFound(
|
||||
volume_type_id=777)
|
||||
|
||||
body = {"volume_type": {"name": "vol_type_1_1",
|
||||
"description": "vol_type_desc_1_1"}}
|
||||
|
@ -341,11 +332,11 @@ class VolumeTypesManageApiTest(test.TestCase):
|
|||
self.controller._update, req, '777', body)
|
||||
self.assertEqual(1, len(self.notifier.notifications))
|
||||
|
||||
def test_update_db_fail(self):
|
||||
self.stubs.Set(volume_types, 'update',
|
||||
return_volume_types_update_fail)
|
||||
self.stubs.Set(volume_types, 'get_volume_type',
|
||||
return_volume_types_get_volume_type)
|
||||
@mock.patch('cinder.volume.volume_types.get_volume_type')
|
||||
@mock.patch('cinder.volume.volume_types.update')
|
||||
def test_update_db_fail(self, mock_update, mock_get_volume_type):
|
||||
mock_update.side_effect = exception.VolumeTypeUpdateFailed(id='1')
|
||||
mock_get_volume_type.return_value = stub_volume_type(1)
|
||||
|
||||
body = {"volume_type": {"name": "vol_type_1_1",
|
||||
"description": "vol_type_desc_1_1"}}
|
||||
|
@ -374,11 +365,11 @@ class VolumeTypesManageApiTest(test.TestCase):
|
|||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller._update, req, '1', body)
|
||||
|
||||
def test_update_only_name(self):
|
||||
self.stubs.Set(volume_types, 'update',
|
||||
return_volume_types_update)
|
||||
self.stubs.Set(volume_types, 'get_volume_type',
|
||||
return_volume_types_get_volume_type_updated)
|
||||
@mock.patch('cinder.volume.volume_types.update')
|
||||
@mock.patch('cinder.volume.volume_types.get_volume_type')
|
||||
def test_update_only_name(self, mock_get, mock_update):
|
||||
mock_get.return_value = return_volume_types_get_volume_type_updated(
|
||||
'999')
|
||||
|
||||
body = {"volume_type": {"name": "vol_type_999_999"}}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/types/999')
|
||||
|
@ -391,11 +382,11 @@ class VolumeTypesManageApiTest(test.TestCase):
|
|||
{'expected_name': 'vol_type_999_999',
|
||||
'expected_desc': 'vol_type_desc_999'})
|
||||
|
||||
def test_update_only_description(self):
|
||||
self.stubs.Set(volume_types, 'update',
|
||||
return_volume_types_update)
|
||||
self.stubs.Set(volume_types, 'get_volume_type',
|
||||
return_volume_types_get_volume_type_updated)
|
||||
@mock.patch('cinder.volume.volume_types.update')
|
||||
@mock.patch('cinder.volume.volume_types.get_volume_type')
|
||||
def test_update_only_description(self, mock_get, mock_update):
|
||||
mock_get.return_value = return_volume_types_get_volume_type_updated(
|
||||
'888')
|
||||
|
||||
body = {"volume_type": {"description": "vol_type_desc_888_888"}}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/types/888')
|
||||
|
@ -408,11 +399,23 @@ class VolumeTypesManageApiTest(test.TestCase):
|
|||
{'expected_name': 'vol_type_888',
|
||||
'expected_desc': 'vol_type_desc_888_888'})
|
||||
|
||||
def test_rename_existing_name(self):
|
||||
self.stubs.Set(volume_types, 'update',
|
||||
return_volume_types_update_exist)
|
||||
self.stubs.Set(volume_types, 'get_volume_type',
|
||||
return_volume_types_get_volume_type_updated)
|
||||
def test_update_invalid_is_public(self):
|
||||
body = {"volume_type": {"name": "test",
|
||||
"description": "something",
|
||||
"is_public": "fake"}}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/types/1')
|
||||
req.method = 'PUT'
|
||||
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller._update, req, '1', body)
|
||||
|
||||
@mock.patch('cinder.volume.volume_types.update')
|
||||
@mock.patch('cinder.volume.volume_types.get_volume_type')
|
||||
def test_rename_existing_name(self, mock_get, mock_update):
|
||||
mock_update.side_effect = exception.VolumeTypeExists(
|
||||
id="666", name="vol_type_666")
|
||||
mock_get.return_value = return_volume_types_get_volume_type_updated(
|
||||
'666')
|
||||
# first attempt fail
|
||||
body = {"volume_type": {"name": "vol_type_666"}}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/types/666')
|
||||
|
@ -434,10 +437,7 @@ class VolumeTypesManageApiTest(test.TestCase):
|
|||
self.assertEqual(1, len(self.notifier.notifications))
|
||||
|
||||
# update again
|
||||
self.stubs.Set(volume_types, 'update',
|
||||
return_volume_types_update)
|
||||
self.stubs.Set(volume_types, 'get_volume_type',
|
||||
return_volume_types_get_volume_type_updated)
|
||||
mock_update.side_effect = mock.MagicMock()
|
||||
body = {"volume_type": {"name": "vol_type_666_666"}}
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/types/666')
|
||||
req.method = 'PUT'
|
||||
|
@ -457,3 +457,6 @@ class VolumeTypesManageApiTest(test.TestCase):
|
|||
if expected_results.get('expected_name'):
|
||||
self.assertEqual(expected_results['expected_name'],
|
||||
results['volume_type']['name'])
|
||||
if expected_results.get('is_public') is not None:
|
||||
self.assertEqual(expected_results['is_public'],
|
||||
results['volume_type']['is_public'])
|
||||
|
|
|
@ -128,6 +128,7 @@ class VolumeTypesApiTest(test.TestCase):
|
|||
expected_volume_type = dict(name='new_type',
|
||||
extra_specs={},
|
||||
description=None,
|
||||
is_public=None,
|
||||
id=42)
|
||||
self.assertDictMatch(output['volume_type'], expected_volume_type)
|
||||
|
||||
|
@ -154,6 +155,7 @@ class VolumeTypesApiTest(test.TestCase):
|
|||
expected_volume_type = dict(name='new_type',
|
||||
extra_specs={},
|
||||
id=42 + i,
|
||||
is_public=None,
|
||||
description=None)
|
||||
self.assertDictMatch(output['volume_types'][i],
|
||||
expected_volume_type)
|
||||
|
|
|
@ -153,6 +153,7 @@ class VolumeTypesApiTest(test.TestCase):
|
|||
raw_volume_type = dict(
|
||||
name='new_type',
|
||||
description='new_type_desc',
|
||||
is_public=True,
|
||||
deleted=False,
|
||||
created_at=now,
|
||||
updated_at=now,
|
||||
|
@ -168,6 +169,7 @@ class VolumeTypesApiTest(test.TestCase):
|
|||
expected_volume_type = dict(
|
||||
name='new_type',
|
||||
description='new_type_desc',
|
||||
is_public=True,
|
||||
extra_specs={},
|
||||
id=42,
|
||||
)
|
||||
|
@ -183,6 +185,7 @@ class VolumeTypesApiTest(test.TestCase):
|
|||
dict(
|
||||
name='new_type',
|
||||
description='new_type_desc',
|
||||
is_public=True,
|
||||
deleted=False,
|
||||
created_at=now,
|
||||
updated_at=now,
|
||||
|
@ -200,6 +203,7 @@ class VolumeTypesApiTest(test.TestCase):
|
|||
expected_volume_type = dict(
|
||||
name='new_type',
|
||||
description='new_type_desc',
|
||||
is_public=True,
|
||||
extra_specs={},
|
||||
id=42 + i
|
||||
)
|
||||
|
|
|
@ -57,7 +57,7 @@ def create(context,
|
|||
return type_ref
|
||||
|
||||
|
||||
def update(context, id, name, description):
|
||||
def update(context, id, name, description, is_public=None):
|
||||
"""Update volume type by id."""
|
||||
if id is None:
|
||||
msg = _("id cannot be None")
|
||||
|
@ -66,7 +66,8 @@ def update(context, id, name, description):
|
|||
type_updated = db.volume_type_update(context,
|
||||
id,
|
||||
dict(name=name,
|
||||
description=description))
|
||||
description=description,
|
||||
is_public=is_public))
|
||||
except db_exc.DBError:
|
||||
LOG.exception(_LE('DB error:'))
|
||||
raise exception.VolumeTypeUpdateFailed(id=id)
|
||||
|
|
Loading…
Reference in New Issue