Human readable export location CLI changes
OpenStack CLI option is added to support user friently export location. example command: $ openstack share create nfs 1 --name share_name --mount-point-name custom_export_path partially-implements: bp human-readable-export-locations Depends-On: I72ac7e24ddd4330d76cafd5e7f78bac2b0174883 Change-Id: If896065a74fc4ebabd09b677e5eb0329cecfaab9
This commit is contained in:
parent
5000f1cb1f
commit
b097cec84f
@ -27,7 +27,7 @@ from manilaclient import utils
|
|||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
MAX_VERSION = '2.83'
|
MAX_VERSION = '2.84'
|
||||||
MIN_VERSION = '2.0'
|
MIN_VERSION = '2.0'
|
||||||
DEPRECATED_VERSION = '1.0'
|
DEPRECATED_VERSION = '1.0'
|
||||||
_VERSIONED_METHOD_MAP = {}
|
_VERSIONED_METHOD_MAP = {}
|
||||||
|
@ -188,6 +188,13 @@ class CreateShare(command.ShowOne):
|
|||||||
"possible keys are same_host, different_host."
|
"possible keys are same_host, different_host."
|
||||||
"(repeat option to set multiple hints)"),
|
"(repeat option to set multiple hints)"),
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
'--mount-point-name',
|
||||||
|
metavar="<mount_point_name>",
|
||||||
|
default=None,
|
||||||
|
help=_('Optional custom export location. Available for '
|
||||||
|
'microversion >= 2.84')
|
||||||
|
)
|
||||||
|
|
||||||
return parser
|
return parser
|
||||||
|
|
||||||
@ -232,6 +239,15 @@ class CreateShare(command.ShowOne):
|
|||||||
snapshot_id = snapshot.id
|
snapshot_id = snapshot.id
|
||||||
size = max(size or 0, snapshot.size)
|
size = max(size or 0, snapshot.size)
|
||||||
|
|
||||||
|
mount_point_name = None
|
||||||
|
if parsed_args.mount_point_name:
|
||||||
|
if share_client.api_version < api_versions.APIVersion('2.84'):
|
||||||
|
raise exceptions.CommandError(
|
||||||
|
'Setting share mount point name is '
|
||||||
|
'available only for API microversion >= 2.84')
|
||||||
|
else:
|
||||||
|
mount_point_name = parsed_args.mount_point_name
|
||||||
|
|
||||||
scheduler_hints = {}
|
scheduler_hints = {}
|
||||||
if parsed_args.scheduler_hint:
|
if parsed_args.scheduler_hint:
|
||||||
if share_client.api_version < api_versions.APIVersion('2.65'):
|
if share_client.api_version < api_versions.APIVersion('2.65'):
|
||||||
@ -271,7 +287,8 @@ class CreateShare(command.ShowOne):
|
|||||||
'is_public': parsed_args.public,
|
'is_public': parsed_args.public,
|
||||||
'availability_zone': parsed_args.availability_zone,
|
'availability_zone': parsed_args.availability_zone,
|
||||||
'share_group_id': share_group,
|
'share_group_id': share_group,
|
||||||
'scheduler_hints': scheduler_hints
|
'scheduler_hints': scheduler_hints,
|
||||||
|
'mount_point_name': mount_point_name,
|
||||||
}
|
}
|
||||||
|
|
||||||
share = share_client.shares.create(**body)
|
share = share_client.shares.create(**body)
|
||||||
|
@ -139,6 +139,7 @@ class FakeShare(object):
|
|||||||
"revert_to_snapshot_support": False,
|
"revert_to_snapshot_support": False,
|
||||||
"source_share_group_snapshot_member_id": None,
|
"source_share_group_snapshot_member_id": None,
|
||||||
"scheduler_hints": {},
|
"scheduler_hints": {},
|
||||||
|
"mount_point_name": None,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Overwrite default attributes.
|
# Overwrite default attributes.
|
||||||
|
@ -132,7 +132,8 @@ class TestShareCreate(TestShare):
|
|||||||
share_type=self.share_type.id,
|
share_type=self.share_type.id,
|
||||||
size=self.new_share.size,
|
size=self.new_share.size,
|
||||||
snapshot_id=None,
|
snapshot_id=None,
|
||||||
scheduler_hints={}
|
scheduler_hints={},
|
||||||
|
mount_point_name=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertCountEqual(self.columns, columns)
|
self.assertCountEqual(self.columns, columns)
|
||||||
@ -180,7 +181,8 @@ class TestShareCreate(TestShare):
|
|||||||
share_type=self.share_type.id,
|
share_type=self.share_type.id,
|
||||||
size=self.new_share.size,
|
size=self.new_share.size,
|
||||||
snapshot_id=None,
|
snapshot_id=None,
|
||||||
scheduler_hints={}
|
scheduler_hints={},
|
||||||
|
mount_point_name=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertCountEqual(self.columns, columns)
|
self.assertCountEqual(self.columns, columns)
|
||||||
@ -227,6 +229,49 @@ class TestShareCreate(TestShare):
|
|||||||
snapshot_id=None,
|
snapshot_id=None,
|
||||||
scheduler_hints={'same_host': shares[0].id,
|
scheduler_hints={'same_host': shares[0].id,
|
||||||
'different_host': shares[1].id},
|
'different_host': shares[1].id},
|
||||||
|
mount_point_name=None,
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertCountEqual(self.columns, columns)
|
||||||
|
self.assertCountEqual(self.datalist, data)
|
||||||
|
|
||||||
|
def test_share_create_mount_point_name(self):
|
||||||
|
"""Verifies that the mount point name has been passed correctly."""
|
||||||
|
self.app.client_manager.share.api_version = api_versions.APIVersion(
|
||||||
|
"2.84")
|
||||||
|
|
||||||
|
mount_point_name = "fake_mp"
|
||||||
|
|
||||||
|
arglist = [
|
||||||
|
self.new_share.share_proto,
|
||||||
|
str(self.new_share.size),
|
||||||
|
'--share-type', self.share_type.id,
|
||||||
|
'--mount-point-name', mount_point_name,
|
||||||
|
]
|
||||||
|
verifylist = [
|
||||||
|
('share_proto', self.new_share.share_proto),
|
||||||
|
('size', self.new_share.size),
|
||||||
|
('mount_point_name', mount_point_name),
|
||||||
|
('share_type', self.share_type.id),
|
||||||
|
]
|
||||||
|
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||||
|
|
||||||
|
columns, data = self.cmd.take_action(parsed_args)
|
||||||
|
|
||||||
|
self.shares_mock.create.assert_called_with(
|
||||||
|
availability_zone=None,
|
||||||
|
description=None,
|
||||||
|
is_public=False,
|
||||||
|
metadata={},
|
||||||
|
name=None,
|
||||||
|
share_group_id=None,
|
||||||
|
share_network=None,
|
||||||
|
share_proto=self.new_share.share_proto,
|
||||||
|
share_type=self.share_type.id,
|
||||||
|
size=self.new_share.size,
|
||||||
|
snapshot_id=None,
|
||||||
|
scheduler_hints={},
|
||||||
|
mount_point_name='fake_mp',
|
||||||
)
|
)
|
||||||
|
|
||||||
self.assertCountEqual(self.columns, columns)
|
self.assertCountEqual(self.columns, columns)
|
||||||
@ -269,7 +314,8 @@ class TestShareCreate(TestShare):
|
|||||||
share_type=None,
|
share_type=None,
|
||||||
size=self.new_share.size,
|
size=self.new_share.size,
|
||||||
snapshot_id=self.share_snapshot.id,
|
snapshot_id=self.share_snapshot.id,
|
||||||
scheduler_hints={}
|
scheduler_hints={},
|
||||||
|
mount_point_name=None,
|
||||||
)
|
)
|
||||||
self.assertCountEqual(self.columns, columns)
|
self.assertCountEqual(self.columns, columns)
|
||||||
self.assertCountEqual(self.datalist, data)
|
self.assertCountEqual(self.datalist, data)
|
||||||
@ -305,7 +351,8 @@ class TestShareCreate(TestShare):
|
|||||||
share_type=self.share_type.id,
|
share_type=self.share_type.id,
|
||||||
size=self.new_share.size,
|
size=self.new_share.size,
|
||||||
snapshot_id=None,
|
snapshot_id=None,
|
||||||
scheduler_hints={}
|
scheduler_hints={},
|
||||||
|
mount_point_name=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.shares_mock.get.assert_called_with(self.new_share.id)
|
self.shares_mock.get.assert_called_with(self.new_share.id)
|
||||||
@ -345,7 +392,8 @@ class TestShareCreate(TestShare):
|
|||||||
share_type=self.share_type.id,
|
share_type=self.share_type.id,
|
||||||
size=self.new_share.size,
|
size=self.new_share.size,
|
||||||
snapshot_id=None,
|
snapshot_id=None,
|
||||||
scheduler_hints={}
|
scheduler_hints={},
|
||||||
|
mount_point_name=None,
|
||||||
)
|
)
|
||||||
|
|
||||||
mock_logger.error.assert_called_with(
|
mock_logger.error.assert_called_with(
|
||||||
|
@ -140,6 +140,29 @@ class SharesTest(utils.TestCase):
|
|||||||
availability_zone=availability_zone)
|
availability_zone=availability_zone)
|
||||||
cs.assert_called('POST', '/shares', body)
|
cs.assert_called('POST', '/shares', body)
|
||||||
|
|
||||||
|
@ddt.data({'mount_point_name': 'fake_mount_pt1'},
|
||||||
|
{'mount_point_name': 'fake_mount_pt2'})
|
||||||
|
@ddt.unpack
|
||||||
|
def test_create_share_with_mount_point_name(self, mount_point_name):
|
||||||
|
body = {
|
||||||
|
'share': {
|
||||||
|
'is_public': False,
|
||||||
|
'share_type': None,
|
||||||
|
'name': None,
|
||||||
|
'snapshot_id': None,
|
||||||
|
'description': None,
|
||||||
|
'metadata': {},
|
||||||
|
'share_proto': 'nfs',
|
||||||
|
'share_network_id': None,
|
||||||
|
'size': 1,
|
||||||
|
'availability_zone': None,
|
||||||
|
'scheduler_hints': {},
|
||||||
|
'mount_point_name': mount_point_name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cs.shares.create('nfs', 1, mount_point_name=mount_point_name)
|
||||||
|
cs.assert_called('POST', '/shares', body)
|
||||||
|
|
||||||
@ddt.data(
|
@ddt.data(
|
||||||
type('ShareUUID', (object, ), {'uuid': '1234'}),
|
type('ShareUUID', (object, ), {'uuid': '1234'}),
|
||||||
type('ShareID', (object, ), {'id': '1234'}),
|
type('ShareID', (object, ), {'id': '1234'}),
|
||||||
|
@ -124,7 +124,8 @@ class ShareManager(base.MetadataCapableManager):
|
|||||||
def create(self, share_proto, size, snapshot_id=None, name=None,
|
def create(self, share_proto, size, snapshot_id=None, name=None,
|
||||||
description=None, metadata=None, share_network=None,
|
description=None, metadata=None, share_network=None,
|
||||||
share_type=None, is_public=False, availability_zone=None,
|
share_type=None, is_public=False, availability_zone=None,
|
||||||
share_group_id=None, scheduler_hints=None, return_raw=False):
|
share_group_id=None, scheduler_hints=None, return_raw=False,
|
||||||
|
mount_point_name=None):
|
||||||
"""Create a share.
|
"""Create a share.
|
||||||
|
|
||||||
:param share_proto: text - share protocol for new share available
|
:param share_proto: text - share protocol for new share available
|
||||||
@ -142,6 +143,9 @@ class ShareManager(base.MetadataCapableManager):
|
|||||||
:param scheduler_hints: dict - hints for the scheduler to place share
|
:param scheduler_hints: dict - hints for the scheduler to place share
|
||||||
on most appropriate host e.g. keys are same_host for affinity and
|
on most appropriate host e.g. keys are same_host for affinity and
|
||||||
different_host for anti-affinity
|
different_host for anti-affinity
|
||||||
|
:param mount_point_name: text - share human-readable mount point name.
|
||||||
|
This name will be reflected in export location once
|
||||||
|
share is created.
|
||||||
:rtype: :class:`Share`
|
:rtype: :class:`Share`
|
||||||
"""
|
"""
|
||||||
share_metadata = metadata if metadata is not None else dict()
|
share_metadata = metadata if metadata is not None else dict()
|
||||||
@ -163,6 +167,9 @@ class ShareManager(base.MetadataCapableManager):
|
|||||||
if share_group_id:
|
if share_group_id:
|
||||||
body['share_group_id'] = share_group_id
|
body['share_group_id'] = share_group_id
|
||||||
|
|
||||||
|
if mount_point_name:
|
||||||
|
body['mount_point_name'] = mount_point_name
|
||||||
|
|
||||||
return self._create('/shares', {'share': body}, 'share',
|
return self._create('/shares', {'share': body}, 'share',
|
||||||
return_raw=return_raw)
|
return_raw=return_raw)
|
||||||
|
|
||||||
|
@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- In the 2.84 API version, a new option, ``mount_point_name``, has been
|
||||||
|
introduced to the share creation command. This option allow users
|
||||||
|
to specify a more intuitive ``mount_point_name`` that will be reflected
|
||||||
|
in the share's export location. However, for this feature to be available
|
||||||
|
to users, administrators must first enable an extra-spec in the
|
||||||
|
share type. In addition, administrators need to set an extra-spec named
|
||||||
|
``provisioning:mount_point_prefix``. The Manila service will combine
|
||||||
|
this prefix with the mount point name that user provides during share
|
||||||
|
creation. If the ``provisioning:mount_point_prefix`` is not set for
|
||||||
|
a share type, but ``mount_point_name_support`` is enabled, the share's
|
||||||
|
export location will default to using the project_id as a prefix.
|
||||||
|
Please note that shares created with a project_id prefix cannot be
|
||||||
|
transferred. To move these shares to a different project,
|
||||||
|
an admin must manually unmount them from the current project and mount
|
||||||
|
them to the target project. A new capability, ``mount_point_name_support``,
|
||||||
|
allows the driver to inform the scheduler about its support for the
|
||||||
|
mount_point_name feature.
|
Loading…
Reference in New Issue
Block a user