Add update share-type to SDK and CLI
Currently, only the name and description and public access of share-type is set when the share-type is created, and not allowed to be edited after the share-type is created. We can only set extra spec for share-type. But not name or description or public access for share-type. Change-Id: Ia0df0d46e11d0438e16fc910fc377f9dd4e85521 Partially-Implements: blueprint update-share-type-name-or-description Depends-On: https://review.opendev.org/669651
This commit is contained in:
parent
9d802aabdb
commit
cc401e5333
@ -27,7 +27,7 @@ from manilaclient import utils
|
|||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
MAX_VERSION = '2.49'
|
MAX_VERSION = '2.50'
|
||||||
MIN_VERSION = '2.0'
|
MIN_VERSION = '2.0'
|
||||||
DEPRECATED_VERSION = '1.0'
|
DEPRECATED_VERSION = '1.0'
|
||||||
_VERSIONED_METHOD_MAP = {}
|
_VERSIONED_METHOD_MAP = {}
|
||||||
|
@ -211,6 +211,25 @@ class BaseTestCase(base.ClientTestBase):
|
|||||||
cls.method_resources.insert(0, resource)
|
cls.method_resources.insert(0, resource)
|
||||||
return share_type
|
return share_type
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def update_share_type(cls, share_type_id, name=None,
|
||||||
|
is_public=None, client=None,
|
||||||
|
microversion=None, description=None):
|
||||||
|
if client is None:
|
||||||
|
client = cls.get_admin_client()
|
||||||
|
data = {
|
||||||
|
"share_type_id": share_type_id,
|
||||||
|
"microversion": microversion,
|
||||||
|
}
|
||||||
|
if name is not None:
|
||||||
|
data["name"] = name
|
||||||
|
if description is not None:
|
||||||
|
data["description"] = description
|
||||||
|
if is_public is not None:
|
||||||
|
data["is_public"] = is_public
|
||||||
|
share_type = client.update_share_type(**data)
|
||||||
|
return share_type
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create_share_network(cls, name=None, description=None,
|
def create_share_network(cls, name=None, description=None,
|
||||||
neutron_net_id=None,
|
neutron_net_id=None,
|
||||||
|
@ -244,6 +244,41 @@ class ManilaCLIClient(base.CLIClient):
|
|||||||
share_type = utils.details(share_type_raw)
|
share_type = utils.details(share_type_raw)
|
||||||
return share_type
|
return share_type
|
||||||
|
|
||||||
|
def update_share_type(self, share_type_id, name=None,
|
||||||
|
is_public=None, microversion=None,
|
||||||
|
description=None):
|
||||||
|
"""Update share type.
|
||||||
|
|
||||||
|
:param share_type_id: text -- id of share type.
|
||||||
|
:param name: text -- new name of share type, if not set then
|
||||||
|
it will not be updated.
|
||||||
|
:param description: text -- new description of share type.
|
||||||
|
if not set then it will not be updated.
|
||||||
|
:param is_public: bool/str -- boolean or its string alias.
|
||||||
|
new visibility of the share type.If set to True, share
|
||||||
|
type will be available to all projects in the cloud.
|
||||||
|
"""
|
||||||
|
|
||||||
|
cmd = ('type-update %(share_type_id)s ') % {
|
||||||
|
'share_type_id': share_type_id}
|
||||||
|
|
||||||
|
if is_public is not None:
|
||||||
|
if not isinstance(is_public, six.string_types):
|
||||||
|
is_public = six.text_type(is_public)
|
||||||
|
cmd += " --is_public " + is_public
|
||||||
|
|
||||||
|
if description:
|
||||||
|
cmd += " --description " + description
|
||||||
|
elif description == "":
|
||||||
|
cmd += ' --description "" '
|
||||||
|
|
||||||
|
if name:
|
||||||
|
cmd += " --name " + name
|
||||||
|
|
||||||
|
share_type_raw = self.manila(cmd, microversion=microversion)
|
||||||
|
share_type = utils.details(share_type_raw)
|
||||||
|
return share_type
|
||||||
|
|
||||||
@not_found_wrapper
|
@not_found_wrapper
|
||||||
def delete_share_type(self, share_type, microversion=None):
|
def delete_share_type(self, share_type, microversion=None):
|
||||||
"""Deletes share type by its Name or ID."""
|
"""Deletes share type by its Name or ID."""
|
||||||
|
@ -122,6 +122,108 @@ class ShareTypesReadWriteTest(base.BaseTestCase):
|
|||||||
'2.41', True, False, None, None, None, None, None,
|
'2.41', True, False, None, None, None, None, None,
|
||||||
description=data_utils.rand_name('test_share_type_description'))
|
description=data_utils.rand_name('test_share_type_description'))
|
||||||
|
|
||||||
|
@ddt.data(
|
||||||
|
('name_updated_1', 'description_updated', True),
|
||||||
|
('name_updated_2', 'description_updated', False),
|
||||||
|
('name_updated_3', None, None),
|
||||||
|
(None, 'description_updated', None),
|
||||||
|
(None, None, True),
|
||||||
|
(None, None, False),
|
||||||
|
)
|
||||||
|
@ddt.unpack
|
||||||
|
def test_create_update_delete_share_type_2_50(self, new_name,
|
||||||
|
new_description,
|
||||||
|
new_is_public):
|
||||||
|
self.skip_if_microversion_not_supported('2.50')
|
||||||
|
microversion = '2.50'
|
||||||
|
share_type_name = data_utils.rand_name('share_type_update_test')
|
||||||
|
|
||||||
|
# Create share type
|
||||||
|
share_type = self.create_share_type(
|
||||||
|
name=share_type_name,
|
||||||
|
driver_handles_share_servers=False,
|
||||||
|
snapshot_support=None,
|
||||||
|
create_share_from_snapshot=None,
|
||||||
|
revert_to_snapshot=None,
|
||||||
|
mount_snapshot=None,
|
||||||
|
is_public=True,
|
||||||
|
microversion=microversion,
|
||||||
|
extra_specs={},
|
||||||
|
description="share_type_description")
|
||||||
|
|
||||||
|
st_id = share_type['ID']
|
||||||
|
|
||||||
|
# Update share type
|
||||||
|
st_updated = self.update_share_type(st_id, name=new_name,
|
||||||
|
description=new_description,
|
||||||
|
is_public=new_is_public,
|
||||||
|
microversion=microversion)
|
||||||
|
# Verify type name
|
||||||
|
if new_name:
|
||||||
|
self.assertEqual(new_name, st_updated['Name'])
|
||||||
|
|
||||||
|
# Verify type description
|
||||||
|
if new_description:
|
||||||
|
self.assertEqual(new_description, st_updated['Description'])
|
||||||
|
|
||||||
|
# Verify public
|
||||||
|
if new_is_public is not None:
|
||||||
|
self.assertEqual('public' if new_is_public else 'private',
|
||||||
|
st_updated['Visibility'].lower())
|
||||||
|
|
||||||
|
# Delete share type
|
||||||
|
self.admin_client.delete_share_type(st_id, microversion=microversion)
|
||||||
|
|
||||||
|
# Wait for share type deletion
|
||||||
|
self.admin_client.wait_for_share_type_deletion(
|
||||||
|
st_id, microversion=microversion)
|
||||||
|
|
||||||
|
# Verify that it is not listed with common 'type-list' operation.
|
||||||
|
share_types = self.admin_client.list_share_types(
|
||||||
|
list_all=False, microversion=microversion)
|
||||||
|
self.assertFalse(any(st_id == st['ID'] for st in share_types))
|
||||||
|
|
||||||
|
def test_unset_share_type_description_2_50(self):
|
||||||
|
self.skip_if_microversion_not_supported('2.50')
|
||||||
|
microversion = '2.50'
|
||||||
|
share_type_name = data_utils.rand_name('share_type_update_test')
|
||||||
|
|
||||||
|
# Create share type
|
||||||
|
share_type = self.create_share_type(
|
||||||
|
name=share_type_name,
|
||||||
|
driver_handles_share_servers=False,
|
||||||
|
snapshot_support=None,
|
||||||
|
create_share_from_snapshot=None,
|
||||||
|
revert_to_snapshot=None,
|
||||||
|
mount_snapshot=None,
|
||||||
|
is_public=True,
|
||||||
|
microversion=microversion,
|
||||||
|
extra_specs={},
|
||||||
|
description="share_type_description")
|
||||||
|
|
||||||
|
st_id = share_type['ID']
|
||||||
|
|
||||||
|
# Update share type
|
||||||
|
new_description = ""
|
||||||
|
st_updated = self.update_share_type(st_id,
|
||||||
|
description=new_description,
|
||||||
|
microversion=microversion)
|
||||||
|
|
||||||
|
# Verify type description
|
||||||
|
self.assertEqual('None', st_updated['Description'])
|
||||||
|
|
||||||
|
# Delete share type
|
||||||
|
self.admin_client.delete_share_type(st_id, microversion=microversion)
|
||||||
|
|
||||||
|
# Wait for share type deletion
|
||||||
|
self.admin_client.wait_for_share_type_deletion(
|
||||||
|
st_id, microversion=microversion)
|
||||||
|
|
||||||
|
# Verify that it is not listed with common 'type-list' operation.
|
||||||
|
share_types = self.admin_client.list_share_types(
|
||||||
|
list_all=False, microversion=microversion)
|
||||||
|
self.assertFalse(any(st_id == st['ID'] for st in share_types))
|
||||||
|
|
||||||
def _test_create_delete_share_type(self, microversion, is_public, dhss,
|
def _test_create_delete_share_type(self, microversion, is_public, dhss,
|
||||||
spec_snapshot_support,
|
spec_snapshot_support,
|
||||||
spec_create_share_from_snapshot,
|
spec_create_share_from_snapshot,
|
||||||
|
@ -925,8 +925,9 @@ class FakeHTTPClient(fakes.FakeHTTPClient):
|
|||||||
|
|
||||||
def get_types_1234(self, **kw):
|
def get_types_1234(self, **kw):
|
||||||
return (200, {}, {
|
return (200, {}, {
|
||||||
'share_type': {'id': 1,
|
'share_type': {'id': 1234,
|
||||||
'name': 'test-type-1',
|
'name': 'test-type-1234',
|
||||||
|
'share_type_access:is_public': True,
|
||||||
'description': "test share type desc",
|
'description': "test share type desc",
|
||||||
'extra_specs': {'test': 'test'},
|
'extra_specs': {'test': 'test'},
|
||||||
'required_extra_specs': {'test': 'test'}}})
|
'required_extra_specs': {'test': 'test'}}})
|
||||||
|
@ -17,6 +17,7 @@ import itertools
|
|||||||
import mock
|
import mock
|
||||||
|
|
||||||
from manilaclient import api_versions
|
from manilaclient import api_versions
|
||||||
|
from manilaclient import config
|
||||||
from manilaclient import exceptions
|
from manilaclient import exceptions
|
||||||
from manilaclient.tests.unit import utils
|
from manilaclient.tests.unit import utils
|
||||||
from manilaclient.tests.unit.v2 import fakes
|
from manilaclient.tests.unit.v2 import fakes
|
||||||
@ -24,6 +25,10 @@ from manilaclient.v2 import share_types
|
|||||||
|
|
||||||
cs = fakes.FakeClient()
|
cs = fakes.FakeClient()
|
||||||
|
|
||||||
|
CONF = config.CONF
|
||||||
|
|
||||||
|
LATEST_MICROVERSION = CONF.max_api_microversion
|
||||||
|
|
||||||
|
|
||||||
def get_valid_type_create_data_2_0():
|
def get_valid_type_create_data_2_0():
|
||||||
|
|
||||||
@ -430,6 +435,28 @@ class TypesTest(utils.TestCase):
|
|||||||
t.unset_keys(['k'])
|
t.unset_keys(['k'])
|
||||||
cs.assert_called('DELETE', '/types/1/extra_specs/k')
|
cs.assert_called('DELETE', '/types/1/extra_specs/k')
|
||||||
|
|
||||||
|
@ddt.data(*set(('2.50', LATEST_MICROVERSION)))
|
||||||
|
def test_update(self, microversion):
|
||||||
|
manager = self._get_share_types_manager(microversion)
|
||||||
|
self.mock_object(manager, '_update', mock.Mock(return_value="fake"))
|
||||||
|
share_type = 1234
|
||||||
|
name = "updated-test-type-1234"
|
||||||
|
description = "updated test description"
|
||||||
|
is_public_key_name = "share_type_access:is_public"
|
||||||
|
is_public = False
|
||||||
|
expected_body = {
|
||||||
|
"share_type": {
|
||||||
|
"name": name,
|
||||||
|
is_public_key_name: is_public,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = manager.update(
|
||||||
|
share_type, name, is_public, description)
|
||||||
|
expected_body['share_type']['description'] = description
|
||||||
|
manager._update.assert_called_once_with(
|
||||||
|
"/types/%s" % share_type, expected_body, "share_type")
|
||||||
|
self.assertEqual("fake", result)
|
||||||
|
|
||||||
def test_delete(self):
|
def test_delete(self):
|
||||||
cs.share_types.delete(1)
|
cs.share_types.delete(1)
|
||||||
cs.assert_called('DELETE', '/types/1')
|
cs.assert_called('DELETE', '/types/1')
|
||||||
|
@ -101,6 +101,10 @@ class ShareType(common_base.Resource):
|
|||||||
if resp is not None:
|
if resp is not None:
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
def update(self, **kwargs):
|
||||||
|
"""Update this share type."""
|
||||||
|
return self.manager.update(self, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class ShareTypeManager(base.ManagerWithFind):
|
class ShareTypeManager(base.ManagerWithFind):
|
||||||
"""Manage :class:`ShareType` resources."""
|
"""Manage :class:`ShareType` resources."""
|
||||||
@ -164,6 +168,30 @@ class ShareTypeManager(base.ManagerWithFind):
|
|||||||
body["share_type"]["description"] = description
|
body["share_type"]["description"] = description
|
||||||
return self._create("/types", body, "share_type")
|
return self._create("/types", body, "share_type")
|
||||||
|
|
||||||
|
def _do_update(self, share_type, name=None, is_public=None,
|
||||||
|
is_public_keyname="share_type_access:is_public",
|
||||||
|
description=None):
|
||||||
|
"""Update the name and/or description for a share type.
|
||||||
|
|
||||||
|
:param share_type: the ID of the :class: `ShareType` to update.
|
||||||
|
:param name: Descriptive name of the share type.
|
||||||
|
:param description: Description of the share type.
|
||||||
|
:rtype: :class:`ShareType`
|
||||||
|
"""
|
||||||
|
|
||||||
|
body = {
|
||||||
|
"share_type": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if name:
|
||||||
|
body["share_type"]["name"] = name
|
||||||
|
if is_public is not None:
|
||||||
|
body["share_type"][is_public_keyname] = is_public
|
||||||
|
if description or description == "":
|
||||||
|
body["share_type"]["description"] = description
|
||||||
|
return self._update("/types/%s" % common_base.getid(share_type),
|
||||||
|
body, "share_type")
|
||||||
|
|
||||||
@api_versions.wraps("1.0", "2.6")
|
@api_versions.wraps("1.0", "2.6")
|
||||||
def create(self, name, spec_driver_handles_share_servers,
|
def create(self, name, spec_driver_handles_share_servers,
|
||||||
spec_snapshot_support=None, is_public=True, extra_specs=None):
|
spec_snapshot_support=None, is_public=True, extra_specs=None):
|
||||||
@ -221,6 +249,11 @@ class ShareTypeManager(base.ManagerWithFind):
|
|||||||
return self._do_create(name, extra_specs, is_public,
|
return self._do_create(name, extra_specs, is_public,
|
||||||
description=description)
|
description=description)
|
||||||
|
|
||||||
|
@api_versions.wraps("2.50")
|
||||||
|
def update(self, share_type, name=None, is_public=None, description=None):
|
||||||
|
return self._do_update(share_type, name, is_public,
|
||||||
|
description=description)
|
||||||
|
|
||||||
def _handle_spec_driver_handles_share_servers(
|
def _handle_spec_driver_handles_share_servers(
|
||||||
self, extra_specs, spec_driver_handles_share_servers):
|
self, extra_specs, spec_driver_handles_share_servers):
|
||||||
"""Validation and default for DHSS extra spec."""
|
"""Validation and default for DHSS extra spec."""
|
||||||
|
@ -4131,6 +4131,55 @@ def do_type_create(cs, args):
|
|||||||
_print_share_type(stype, show_des=show_des)
|
_print_share_type(stype, show_des=show_des)
|
||||||
|
|
||||||
|
|
||||||
|
@cliutils.arg(
|
||||||
|
'id',
|
||||||
|
metavar='<id>',
|
||||||
|
help="Name or ID of the share type to update.")
|
||||||
|
@cliutils.arg(
|
||||||
|
'--name',
|
||||||
|
metavar='<name>',
|
||||||
|
type=str,
|
||||||
|
help="New name of share type.")
|
||||||
|
@cliutils.arg(
|
||||||
|
'--description',
|
||||||
|
metavar='<description>',
|
||||||
|
type=str,
|
||||||
|
default=None,
|
||||||
|
help="New description of share type.")
|
||||||
|
@cliutils.arg(
|
||||||
|
'--is-public',
|
||||||
|
'--is_public',
|
||||||
|
metavar='<is_public>',
|
||||||
|
action='single_alias',
|
||||||
|
help="New visibility of the share type. If set to True, share type will "
|
||||||
|
"be available to all projects in the cloud.")
|
||||||
|
@api_versions.wraps("2.50")
|
||||||
|
def do_type_update(cs, args):
|
||||||
|
"""Update share type name, description, and/or visibility. (Admin only)."""
|
||||||
|
name = getattr(args, 'name')
|
||||||
|
description = getattr(args, 'description')
|
||||||
|
is_public = getattr(args, 'is_public')
|
||||||
|
if not name and description is None and is_public is None:
|
||||||
|
msg = ("A description and/or non-empty name and/or boolean is_public "
|
||||||
|
"must be supplied to update the respective attributes of the "
|
||||||
|
"share type.")
|
||||||
|
raise exceptions.CommandError(msg)
|
||||||
|
kwargs = {}
|
||||||
|
kwargs['name'] = name
|
||||||
|
if is_public:
|
||||||
|
try:
|
||||||
|
kwargs['is_public'] = strutils.bool_from_string(is_public,
|
||||||
|
strict=True)
|
||||||
|
except ValueError as e:
|
||||||
|
raise exceptions.CommandError("The value of 'is_public' is"
|
||||||
|
" invalid: %s", six.text_type(e))
|
||||||
|
|
||||||
|
kwargs['description'] = description
|
||||||
|
stype = _find_share_type(cs, args.id)
|
||||||
|
stype = stype.update(**kwargs)
|
||||||
|
_print_share_type(stype, show_des=True)
|
||||||
|
|
||||||
|
|
||||||
@cliutils.arg(
|
@cliutils.arg(
|
||||||
'id',
|
'id',
|
||||||
metavar='<id>',
|
metavar='<id>',
|
||||||
|
@ -0,0 +1,6 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
The ``name``, ``description`` and/or ``share_type_access:is_public``
|
||||||
|
attributes of share types can be updated with API version ``2.50``
|
||||||
|
and beyond.
|
Loading…
Reference in New Issue
Block a user