Implement OSC share type commands
In this patch we add openstack commands for: share type create share type delete share type set share type unset share type list share type show share type access create share type access list share type access delete These commands can be used to replace all “manila type-” commands. “openstack share type set” combines “manila type-key” with “manila type-update” commands and can be used to set name, description, visibility and extra specs. Change-Id: I10cb6ea800908ebbe48eae7ba8c18680249ff1d2 Partially-implements: bp openstack-client-support
This commit is contained in:
parent
9fc3723de8
commit
e3652b9c1c
@ -97,3 +97,15 @@ STATUS_MANAGE_ERROR = 'manage_error'
|
||||
STATUS_UNMANAGE_ERROR = 'unmanage_error'
|
||||
STATUS_DELETING = 'deleting'
|
||||
STATUS_CREATING = 'creating'
|
||||
|
||||
SNAPSHOT_SUPPORT = 'snapshot_support'
|
||||
CREATE_SHARE_FROM_SNAPSHOT_SUPPORT = 'create_share_from_snapshot_support'
|
||||
REVERT_TO_SNAPSHOT_SUPPORT = 'revert_to_snapshot_support'
|
||||
MOUNT_SNAPSHOT_SUPPORT = 'mount_snapshot_support'
|
||||
|
||||
BOOL_SPECS = (
|
||||
SNAPSHOT_SUPPORT,
|
||||
CREATE_SHARE_FROM_SNAPSHOT_SUPPORT,
|
||||
REVERT_TO_SNAPSHOT_SUPPORT,
|
||||
MOUNT_SNAPSHOT_SUPPORT
|
||||
)
|
||||
|
@ -11,8 +11,11 @@
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import six
|
||||
|
||||
from oslo_utils import strutils
|
||||
|
||||
from manilaclient.common import constants
|
||||
from manilaclient import exceptions
|
||||
|
||||
|
||||
@ -37,6 +40,7 @@ def extract_key_value_options(pairs):
|
||||
|
||||
def format_properties(properties):
|
||||
formatted_data = []
|
||||
|
||||
for item in properties:
|
||||
formatted_data.append("%s : %s" % (item, properties[item]))
|
||||
return "\n".join(formatted_data)
|
||||
@ -57,3 +61,22 @@ def extract_properties(properties):
|
||||
"Parsing error, expected format 'key=value' for " + item
|
||||
)
|
||||
return result_dict
|
||||
|
||||
|
||||
def extract_extra_specs(extra_specs, specs_to_add):
|
||||
for item in specs_to_add:
|
||||
(key, value) = item.split('=', 1)
|
||||
if key in extra_specs:
|
||||
msg = ("Argument '%s' value specified twice." % key)
|
||||
raise exceptions.CommandError(msg)
|
||||
elif key in constants.BOOL_SPECS:
|
||||
if strutils.is_valid_boolstr(value):
|
||||
extra_specs[key] = value.capitalize()
|
||||
else:
|
||||
msg = ("Argument '%s' is of boolean "
|
||||
"type and has invalid value: %s"
|
||||
% (key, six.text_type(value)))
|
||||
raise exceptions.CommandError(msg)
|
||||
else:
|
||||
extra_specs[key] = value
|
||||
return extra_specs
|
||||
|
121
manilaclient/osc/v2/share_type_access.py
Normal file
121
manilaclient/osc/v2/share_type_access.py
Normal file
@ -0,0 +1,121 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import exceptions
|
||||
from osc_lib import utils as oscutils
|
||||
|
||||
from manilaclient.common._i18n import _
|
||||
from manilaclient.common.apiclient import utils as apiutils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ShareTypeAccessAllow(command.Command):
|
||||
"""Add access for share type."""
|
||||
_description = _("Add access for share type")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShareTypeAccessAllow, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'share_type',
|
||||
metavar="<share_type>",
|
||||
help=_("Share type name or ID to add access to")
|
||||
)
|
||||
parser.add_argument(
|
||||
'project_id',
|
||||
metavar="<project_id>",
|
||||
help=_("Project ID to add share type access for")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
share_client = self.app.client_manager.share
|
||||
|
||||
share_type = apiutils.find_resource(
|
||||
share_client.share_types, parsed_args.share_type)
|
||||
|
||||
try:
|
||||
share_client.share_type_access.add_project_access(
|
||||
share_type,
|
||||
parsed_args.project_id)
|
||||
|
||||
except Exception as e:
|
||||
raise exceptions.CommandError(
|
||||
"Failed to add access to share type : %s" % e)
|
||||
|
||||
|
||||
class ListShareTypeAccess(command.Lister):
|
||||
"""Get access list for share type."""
|
||||
_description = _("Get access list for share type")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListShareTypeAccess, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'share_type',
|
||||
metavar="<share_type>",
|
||||
help=_("Share type name or ID to get access list for")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
share_client = self.app.client_manager.share
|
||||
|
||||
share_type = apiutils.find_resource(
|
||||
share_client.share_types, parsed_args.share_type)
|
||||
|
||||
if share_type._info.get('share_type_access:is_public'):
|
||||
raise exceptions.CommandError(
|
||||
'Forbidden to get access list for public share type.')
|
||||
|
||||
data = share_client.share_type_access.list(share_type)
|
||||
|
||||
columns = ['Project_ID']
|
||||
values = (oscutils.get_item_properties(s, columns) for s in data)
|
||||
|
||||
return (columns, values)
|
||||
|
||||
|
||||
class ShareTypeAccessDeny(command.Command):
|
||||
"""Delete access from share type."""
|
||||
_description = _("Delete access from share type")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShareTypeAccessDeny, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'share_type',
|
||||
metavar="<share_type>",
|
||||
help=_("Share type name or ID to delete access from")
|
||||
)
|
||||
parser.add_argument(
|
||||
'project_id',
|
||||
metavar="<project_id>",
|
||||
help=_("Project ID to delete share type access for")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
share_client = self.app.client_manager.share
|
||||
|
||||
share_type = apiutils.find_resource(
|
||||
share_client.share_types, parsed_args.share_type)
|
||||
|
||||
try:
|
||||
share_client.share_type_access.remove_project_access(
|
||||
share_type,
|
||||
parsed_args.project_id)
|
||||
|
||||
except Exception as e:
|
||||
raise exceptions.CommandError(
|
||||
"Failed to remove access from share type : %s" % e)
|
468
manilaclient/osc/v2/share_types.py
Normal file
468
manilaclient/osc/v2/share_types.py
Normal file
@ -0,0 +1,468 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import logging
|
||||
import six
|
||||
|
||||
from osc_lib.command import command
|
||||
from osc_lib import exceptions
|
||||
from osc_lib import utils as oscutils
|
||||
from oslo_utils import strutils
|
||||
|
||||
from manilaclient import api_versions
|
||||
from manilaclient.common._i18n import _
|
||||
from manilaclient.common.apiclient import utils as apiutils
|
||||
from manilaclient.common import constants
|
||||
from manilaclient.osc import utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
ATTRIBUTES = [
|
||||
'id',
|
||||
'name',
|
||||
'visibility',
|
||||
'is_default',
|
||||
'required_extra_specs',
|
||||
'optional_extra_specs',
|
||||
'description'
|
||||
]
|
||||
|
||||
|
||||
def format_share_type(share_type):
|
||||
# share_type_access:is_public (true/false) --> visibility (public/private)
|
||||
is_public = 'share_type_access:is_public'
|
||||
visibility = 'public' if share_type._info.get(is_public) else 'private'
|
||||
share_type._info.pop(is_public, None)
|
||||
|
||||
# optional_extra_specs --> extra_specs without required_extra_specs
|
||||
# required_extra_specs are displayed separately
|
||||
optional_extra_specs = share_type.extra_specs
|
||||
for key in share_type.required_extra_specs.keys():
|
||||
optional_extra_specs.pop(key, None)
|
||||
|
||||
share_type._info.update(
|
||||
{
|
||||
'visibility': visibility,
|
||||
'required_extra_specs': utils.format_properties(
|
||||
share_type.required_extra_specs),
|
||||
'optional_extra_specs': utils.format_properties(
|
||||
optional_extra_specs),
|
||||
}
|
||||
)
|
||||
return share_type
|
||||
|
||||
|
||||
class CreateShareType(command.ShowOne):
|
||||
"""Create new share type."""
|
||||
_description = _(
|
||||
"Create new share type")
|
||||
|
||||
log = logging.getLogger(__name__ + ".CreateShareType")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateShareType, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'name',
|
||||
metavar="<name>",
|
||||
default=None,
|
||||
help=_('Share type name')
|
||||
)
|
||||
parser.add_argument(
|
||||
'spec_driver_handles_share_servers',
|
||||
metavar="<spec_driver_handles_share_servers>",
|
||||
default=None,
|
||||
help=_("Required extra specification. "
|
||||
"Valid values are 'true' and 'false'")
|
||||
)
|
||||
parser.add_argument(
|
||||
"--description",
|
||||
metavar="<description>",
|
||||
default=None,
|
||||
help=_("Share type description. "
|
||||
"Available only for microversion >= 2.41."),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--snapshot-support",
|
||||
metavar="<snapshot_support>",
|
||||
default=None,
|
||||
help=_("Boolean extra spec used for filtering of back ends "
|
||||
"by their capability to create share snapshots."),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--create-share-from-snapshot-support",
|
||||
metavar="<create_share_from_snapshot_support>",
|
||||
default=None,
|
||||
help=_("Boolean extra spec used for filtering of back ends "
|
||||
"by their capability to create shares from snapshots."),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--revert-to-snapshot-support",
|
||||
metavar="<revert_to_snapshot_support>",
|
||||
default=False,
|
||||
help=_("Boolean extra spec used for filtering of back ends "
|
||||
"by their capability to revert shares to snapshots. "
|
||||
"(Default is False)."),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--mount-snapshot-support",
|
||||
metavar="<mount_snapshot_support>",
|
||||
default=False,
|
||||
help=_("Boolean extra spec used for filtering of back ends "
|
||||
"by their capability to mount share snapshots. "
|
||||
"(Default is False)."),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--extra-specs",
|
||||
type=str,
|
||||
nargs='*',
|
||||
metavar='<key=value>',
|
||||
default=None,
|
||||
help=_("Extra specs key and value of share type that will be"
|
||||
" used for share type creation. OPTIONAL: Default=None."
|
||||
" example --extra-specs thin_provisioning='<is> True', "
|
||||
"replication_type=readable."),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--public',
|
||||
metavar="<public>",
|
||||
default=True,
|
||||
help=_('Make type accessible to the public (default true).')
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
share_client = self.app.client_manager.share
|
||||
|
||||
kwargs = {
|
||||
'name': parsed_args.name
|
||||
}
|
||||
try:
|
||||
kwargs['spec_driver_handles_share_servers'] = (
|
||||
strutils.bool_from_string(
|
||||
parsed_args.spec_driver_handles_share_servers,
|
||||
strict=True))
|
||||
except ValueError as e:
|
||||
msg = ("Argument spec_driver_handles_share_servers "
|
||||
"argument is not valid: %s" % six.text_type(e))
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
if parsed_args.description:
|
||||
if share_client.api_version.matches(
|
||||
api_versions.APIVersion("2.41"),
|
||||
api_versions.APIVersion()):
|
||||
kwargs['description'] = parsed_args.description
|
||||
else:
|
||||
raise exceptions.CommandError(
|
||||
"Adding description to share type "
|
||||
"is only available with API microversion >= 2.41")
|
||||
|
||||
if parsed_args.public:
|
||||
kwargs['is_public'] = strutils.bool_from_string(
|
||||
parsed_args.public, default=True)
|
||||
|
||||
extra_specs = {}
|
||||
if parsed_args.extra_specs:
|
||||
for item in parsed_args.extra_specs:
|
||||
(key, value) = item.split('=', 1)
|
||||
if key == 'driver_handles_share_servers':
|
||||
msg = ("'driver_handles_share_servers' "
|
||||
"is already set via positional argument.")
|
||||
raise exceptions.CommandError(msg)
|
||||
else:
|
||||
extra_specs = utils.extract_extra_specs(
|
||||
extra_specs, [item])
|
||||
|
||||
for key in constants.BOOL_SPECS:
|
||||
value = getattr(parsed_args, key)
|
||||
if value:
|
||||
extra_specs = utils.extract_extra_specs(
|
||||
extra_specs, [key + '=' + value])
|
||||
|
||||
kwargs['extra_specs'] = extra_specs
|
||||
|
||||
share_type = share_client.share_types.create(**kwargs)
|
||||
formatted_type = format_share_type(share_type)
|
||||
|
||||
return (ATTRIBUTES, oscutils.get_dict_properties(
|
||||
formatted_type._info, ATTRIBUTES))
|
||||
|
||||
|
||||
class DeleteShareType(command.Command):
|
||||
"""Delete a share type."""
|
||||
_description = _("Delete a share type")
|
||||
|
||||
log = logging.getLogger(__name__ + ".DeleteShareType")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(DeleteShareType, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'share_types',
|
||||
metavar="<share_types>",
|
||||
nargs="+",
|
||||
help=_("Name or ID of the share type(s) to delete")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
share_client = self.app.client_manager.share
|
||||
result = 0
|
||||
|
||||
for share_type in parsed_args.share_types:
|
||||
try:
|
||||
share_type_obj = apiutils.find_resource(
|
||||
share_client.share_types,
|
||||
share_type)
|
||||
|
||||
share_client.share_types.delete(share_type_obj)
|
||||
except Exception as e:
|
||||
result += 1
|
||||
LOG.error(_(
|
||||
"Failed to delete share type with "
|
||||
"name or ID '%(share_type)s': %(e)s"),
|
||||
{'share_type': share_type, 'e': e})
|
||||
|
||||
if result > 0:
|
||||
total = len(parsed_args.share_types)
|
||||
msg = (_("%(result)s of %(total)s share types failed "
|
||||
"to delete.") % {'result': result, 'total': total})
|
||||
raise exceptions.CommandError(msg)
|
||||
|
||||
|
||||
class SetShareType(command.Command):
|
||||
"""Set share type properties."""
|
||||
_description = _("Set share type properties")
|
||||
|
||||
log = logging.getLogger(__name__ + ".SetShareType")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(SetShareType, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'share_type',
|
||||
metavar="<share_type>",
|
||||
help=_("Name or ID of the share type to modify")
|
||||
)
|
||||
parser.add_argument(
|
||||
"--extra-specs",
|
||||
type=str,
|
||||
nargs='*',
|
||||
metavar='<key=value>',
|
||||
default=None,
|
||||
help=_("Extra specs key and value of share type that will be"
|
||||
" used for share type creation. OPTIONAL: Default=None."
|
||||
" example --extra-specs thin_provisioning='<is> True', "
|
||||
"replication_type=readable."),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--public',
|
||||
metavar="<public>",
|
||||
default=None,
|
||||
help=_('New visibility of the share type. If set to True, '
|
||||
'share type will be available to all projects '
|
||||
'in the cloud. '
|
||||
'Available only for microversion >= 2.50')
|
||||
)
|
||||
parser.add_argument(
|
||||
"--description",
|
||||
metavar="<description>",
|
||||
default=None,
|
||||
help=_("New description of share type. "
|
||||
"Available only for microversion >= 2.50"),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--name',
|
||||
metavar="<name>",
|
||||
default=None,
|
||||
help=_('New name of share type. '
|
||||
'Available only for microversion >= 2.50')
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
share_client = self.app.client_manager.share
|
||||
|
||||
share_type = apiutils.find_resource(
|
||||
share_client.share_types, parsed_args.share_type)
|
||||
|
||||
can_update = (
|
||||
share_client.api_version >= api_versions.APIVersion('2.50'))
|
||||
|
||||
kwargs = {}
|
||||
if parsed_args.name is not None:
|
||||
if can_update:
|
||||
kwargs['name'] = parsed_args.name
|
||||
else:
|
||||
raise exceptions.CommandError(
|
||||
"Setting (new) name to share type "
|
||||
"is only available with API microversion >= 2.50")
|
||||
if parsed_args.description is not None:
|
||||
if can_update:
|
||||
kwargs['description'] = parsed_args.description
|
||||
else:
|
||||
raise exceptions.CommandError(
|
||||
"Setting (new) description to share type "
|
||||
"is only available with API microversion >= 2.50")
|
||||
if parsed_args.public is not None:
|
||||
if can_update:
|
||||
kwargs['is_public'] = strutils.bool_from_string(
|
||||
parsed_args.public, default=True)
|
||||
else:
|
||||
raise exceptions.CommandError(
|
||||
"Setting visibility to share type "
|
||||
"is only available with API microversion >= 2.50")
|
||||
if kwargs:
|
||||
share_type.update(**kwargs)
|
||||
|
||||
if parsed_args.extra_specs:
|
||||
extra_specs = utils.extract_extra_specs(
|
||||
extra_specs={},
|
||||
specs_to_add=parsed_args.extra_specs)
|
||||
try:
|
||||
share_type.set_keys(extra_specs)
|
||||
except Exception as e:
|
||||
raise exceptions.CommandError(
|
||||
"Failed to set share type key: %s" % e)
|
||||
|
||||
|
||||
class UnsetShareType(command.Command):
|
||||
"""Unset share type extra specs."""
|
||||
_description = _("Unset share type extra specs")
|
||||
|
||||
log = logging.getLogger(__name__ + ".UnsetShareType")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(UnsetShareType, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'share_type',
|
||||
metavar="<share_type>",
|
||||
help=_("Name or ID of the share type to modify")
|
||||
)
|
||||
parser.add_argument(
|
||||
'extra_specs',
|
||||
metavar='<key>',
|
||||
nargs='+',
|
||||
help=_('Remove extra_specs from this share type'),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
share_client = self.app.client_manager.share
|
||||
|
||||
share_type = apiutils.find_resource(
|
||||
share_client.share_types, parsed_args.share_type)
|
||||
|
||||
if parsed_args.extra_specs:
|
||||
try:
|
||||
share_type.unset_keys(parsed_args.extra_specs)
|
||||
except Exception as e:
|
||||
raise exceptions.CommandError(
|
||||
"Failed to remove share type extra spec: %s" % e)
|
||||
|
||||
|
||||
class ListShareType(command.Lister):
|
||||
"""List Share Types."""
|
||||
_description = _("List share types")
|
||||
|
||||
log = logging.getLogger(__name__ + ".ListShareType")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ListShareType, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'--all',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help=_('Display all share types whatever public or private. '
|
||||
'Default=False. (Admin only)'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--extra-specs',
|
||||
type=str,
|
||||
nargs='*',
|
||||
metavar='<key=value>',
|
||||
default=None,
|
||||
help=_('Filter share types with extra specs (key=value). '
|
||||
'Available only for API microversion >= 2.43. '
|
||||
'OPTIONAL: Default=None.'),
|
||||
)
|
||||
parser.add_argument(
|
||||
'--columns',
|
||||
metavar='<columns>',
|
||||
help=_('Comma separated list of columns to be displayed '
|
||||
'example --columns "id,name".'),
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
share_client = self.app.client_manager.share
|
||||
|
||||
search_opts = {}
|
||||
if parsed_args.extra_specs:
|
||||
if share_client.api_version < api_versions.APIVersion("2.43"):
|
||||
raise exceptions.CommandError(
|
||||
"Filtering by 'extra_specs' is available only with "
|
||||
"API microversion '2.43' and above.")
|
||||
|
||||
search_opts = {
|
||||
'extra_specs': utils.extract_extra_specs(
|
||||
extra_specs={},
|
||||
specs_to_add=parsed_args.extra_specs)
|
||||
}
|
||||
|
||||
share_types = share_client.share_types.list(
|
||||
search_opts=search_opts,
|
||||
show_all=parsed_args.all)
|
||||
|
||||
if parsed_args.columns:
|
||||
columns = parsed_args.columns.split(',')
|
||||
for column in columns:
|
||||
if column not in ATTRIBUTES:
|
||||
msg = ("No column named '%s'. "
|
||||
"Possible columns are: 'id', 'name', 'visibility', "
|
||||
"is_default', 'required_extra_specs', "
|
||||
"'optional_extra_specs', 'description'." % column)
|
||||
raise exceptions.CommandError(msg)
|
||||
else:
|
||||
columns = ATTRIBUTES
|
||||
|
||||
formatted_types = []
|
||||
for share_type in share_types:
|
||||
formatted_types.append(format_share_type(share_type))
|
||||
|
||||
values = (oscutils.get_dict_properties(
|
||||
s._info, columns) for s in formatted_types)
|
||||
|
||||
return (columns, values)
|
||||
|
||||
|
||||
class ShowShareType(command.ShowOne):
|
||||
"""Show a share type."""
|
||||
_description = _("Display share type details")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowShareType, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'share_type',
|
||||
metavar="<share_type>",
|
||||
help=_("Share type to display (name or ID)")
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
share_client = self.app.client_manager.share
|
||||
|
||||
share_type = apiutils.find_resource(
|
||||
share_client.share_types,
|
||||
parsed_args.share_type)
|
||||
|
||||
formatted_type = format_share_type(share_type)
|
||||
|
||||
return (ATTRIBUTES, oscutils.get_dict_properties(
|
||||
formatted_type._info, ATTRIBUTES))
|
@ -31,6 +31,8 @@ class FakeShareClient(object):
|
||||
self.management_url = kwargs['endpoint']
|
||||
self.shares = mock.Mock()
|
||||
self.share_access_rules = mock.Mock()
|
||||
self.share_types = mock.Mock()
|
||||
self.share_type_access = mock.Mock()
|
||||
self.shares.resource_class = osc_fakes.FakeResource(None, {})
|
||||
self.share_export_locations = mock.Mock()
|
||||
self.share_export_locations.resource_class = (
|
||||
@ -199,7 +201,7 @@ class FakeShareType(object):
|
||||
"""Fake one or more share types"""
|
||||
|
||||
@staticmethod
|
||||
def create_one_sharetype(attrs=None):
|
||||
def create_one_sharetype(attrs=None, methods=None):
|
||||
"""Create a fake share type
|
||||
|
||||
:param Dictionary attrs:
|
||||
@ -209,6 +211,7 @@ class FakeShareType(object):
|
||||
"""
|
||||
|
||||
attrs = attrs or {}
|
||||
methods = methods or {}
|
||||
|
||||
share_type_info = {
|
||||
"required_extra_specs": {
|
||||
@ -232,9 +235,49 @@ class FakeShareType(object):
|
||||
share_type_info.update(attrs)
|
||||
share_type = osc_fakes.FakeResource(info=copy.deepcopy(
|
||||
share_type_info),
|
||||
methods=methods,
|
||||
loaded=True)
|
||||
return share_type
|
||||
|
||||
@staticmethod
|
||||
def create_share_types(attrs=None, count=2):
|
||||
"""Create multiple fake share types.
|
||||
|
||||
:param Dictionary attrs:
|
||||
A dictionary with all attributes
|
||||
:param Integer count:
|
||||
The number of share types to be faked
|
||||
:return:
|
||||
A list of FakeResource objects
|
||||
"""
|
||||
|
||||
share_types = []
|
||||
for n in range(0, count):
|
||||
share_types.append(FakeShareType.create_one_sharetype(attrs))
|
||||
|
||||
return share_types
|
||||
|
||||
@staticmethod
|
||||
def get_share_types(share_types=None, count=2):
|
||||
"""Get an iterable MagicMock object with a list of faked types.
|
||||
|
||||
If types list is provided, then initialize the Mock object with the
|
||||
list. Otherwise create one.
|
||||
|
||||
:param List types:
|
||||
A list of FakeResource objects faking types
|
||||
:param Integer count:
|
||||
The number of types to be faked
|
||||
:return
|
||||
An iterable Mock object with side_effect set to a list of faked
|
||||
types
|
||||
"""
|
||||
|
||||
if share_types is None:
|
||||
share_types = FakeShareType.create_share_types(count)
|
||||
|
||||
return mock.Mock(side_effect=share_types)
|
||||
|
||||
|
||||
class FakeShareExportLocation(object):
|
||||
"""Fake one or more export locations"""
|
||||
|
605
manilaclient/tests/unit/osc/v2/test_share_type.py
Normal file
605
manilaclient/tests/unit/osc/v2/test_share_type.py
Normal file
@ -0,0 +1,605 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
from mock import call
|
||||
|
||||
from osc_lib import exceptions
|
||||
from osc_lib import utils as oscutils
|
||||
|
||||
from manilaclient import api_versions
|
||||
from manilaclient.common.apiclient.exceptions import BadRequest
|
||||
from manilaclient.common.apiclient.exceptions import NotFound
|
||||
from manilaclient.osc.v2 import share_types as osc_share_types
|
||||
from manilaclient.tests.unit.osc import osc_utils
|
||||
from manilaclient.tests.unit.osc.v2 import fakes as manila_fakes
|
||||
|
||||
COLUMNS = [
|
||||
'id',
|
||||
'name',
|
||||
'visibility',
|
||||
'is_default',
|
||||
'required_extra_specs',
|
||||
'optional_extra_specs',
|
||||
'description'
|
||||
]
|
||||
|
||||
|
||||
class TestShareType(manila_fakes.TestShare):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShareType, self).setUp()
|
||||
|
||||
self.shares_mock = self.app.client_manager.share.share_types
|
||||
self.shares_mock.reset_mock()
|
||||
self.app.client_manager.share.api_version = api_versions.APIVersion(
|
||||
"2.51")
|
||||
|
||||
|
||||
class TestShareTypeCreate(TestShareType):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShareTypeCreate, self).setUp()
|
||||
|
||||
self.new_share_type = manila_fakes.FakeShareType.create_one_sharetype()
|
||||
self.shares_mock.create.return_value = self.new_share_type
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = osc_share_types.CreateShareType(self.app, None)
|
||||
|
||||
self.data = [
|
||||
self.new_share_type.id,
|
||||
self.new_share_type.name,
|
||||
'public',
|
||||
self.new_share_type.is_default,
|
||||
'driver_handles_share_servers : True',
|
||||
('replication_type : readable\n'
|
||||
'mount_snapshot_support : False\n'
|
||||
'revert_to_snapshot_support : False\n'
|
||||
'create_share_from_snapshot_support : True\n'
|
||||
'snapshot_support : True'),
|
||||
self.new_share_type.description,
|
||||
]
|
||||
|
||||
def test_share_type_create_required_args(self):
|
||||
"""Verifies required arguments."""
|
||||
|
||||
arglist = [
|
||||
self.new_share_type.name,
|
||||
'True'
|
||||
]
|
||||
verifylist = [
|
||||
('name', self.new_share_type.name),
|
||||
('spec_driver_handles_share_servers', 'True')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.shares_mock.create.assert_called_with(
|
||||
extra_specs={},
|
||||
is_public=True,
|
||||
name=self.new_share_type.name,
|
||||
spec_driver_handles_share_servers=True
|
||||
)
|
||||
|
||||
self.assertCountEqual(COLUMNS, columns)
|
||||
self.assertCountEqual(self.data, data)
|
||||
|
||||
def test_share_type_create_missing_required_arg(self):
|
||||
"""Verifies missing required arguments."""
|
||||
|
||||
arglist = [
|
||||
self.new_share_type.name
|
||||
]
|
||||
verifylist = [
|
||||
('name', self.new_share_type.name)
|
||||
]
|
||||
|
||||
self.assertRaises(osc_utils.ParserException,
|
||||
self.check_parser, self.cmd, arglist, verifylist)
|
||||
|
||||
def test_share_type_create_private(self):
|
||||
arglist = [
|
||||
self.new_share_type.name,
|
||||
'True',
|
||||
'--public', 'False'
|
||||
]
|
||||
verifylist = [
|
||||
('name', self.new_share_type.name),
|
||||
('spec_driver_handles_share_servers', 'True'),
|
||||
('public', 'False')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.shares_mock.create.assert_called_with(
|
||||
extra_specs={},
|
||||
is_public=False,
|
||||
name=self.new_share_type.name,
|
||||
spec_driver_handles_share_servers=True
|
||||
)
|
||||
|
||||
self.assertCountEqual(COLUMNS, columns)
|
||||
self.assertCountEqual(self.data, data)
|
||||
|
||||
def test_share_type_create_extra_specs(self):
|
||||
arglist = [
|
||||
self.new_share_type.name,
|
||||
'True',
|
||||
'--extra-specs', 'snapshot_support=true'
|
||||
]
|
||||
verifylist = [
|
||||
('name', self.new_share_type.name),
|
||||
('spec_driver_handles_share_servers', 'True'),
|
||||
('extra_specs', ['snapshot_support=true'])
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.shares_mock.create.assert_called_with(
|
||||
extra_specs={'snapshot_support': 'True'},
|
||||
is_public=True,
|
||||
name=self.new_share_type.name,
|
||||
spec_driver_handles_share_servers=True
|
||||
)
|
||||
|
||||
self.assertCountEqual(COLUMNS, columns)
|
||||
self.assertCountEqual(self.data, data)
|
||||
|
||||
def test_share_type_create_dhss_invalid_value(self):
|
||||
arglist = [
|
||||
self.new_share_type.name,
|
||||
'non_bool_value'
|
||||
]
|
||||
verifylist = [
|
||||
('name', self.new_share_type.name),
|
||||
('spec_driver_handles_share_servers', 'non_bool_value')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_share_type_create_api_version_exception(self):
|
||||
self.app.client_manager.share.api_version = api_versions.APIVersion(
|
||||
"2.40")
|
||||
|
||||
arglist = [
|
||||
self.new_share_type.name,
|
||||
'True',
|
||||
'--description', 'Description'
|
||||
]
|
||||
verifylist = [
|
||||
('name', self.new_share_type.name),
|
||||
('spec_driver_handles_share_servers', 'True'),
|
||||
('description', 'Description')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_share_type_create_dhss_defined_twice(self):
|
||||
arglist = [
|
||||
self.new_share_type.name,
|
||||
'True',
|
||||
'--extra-specs', 'driver_handles_share_servers=true'
|
||||
]
|
||||
verifylist = [
|
||||
('name', self.new_share_type.name),
|
||||
('spec_driver_handles_share_servers', 'True'),
|
||||
('extra_specs', ['driver_handles_share_servers=true'])
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_share_type_create_bool_args(self):
|
||||
arglist = [
|
||||
self.new_share_type.name,
|
||||
'True',
|
||||
'--snapshot-support', 'true'
|
||||
]
|
||||
verifylist = [
|
||||
('name', self.new_share_type.name),
|
||||
('spec_driver_handles_share_servers', 'True'),
|
||||
('snapshot_support', 'true')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.shares_mock.create.assert_called_with(
|
||||
extra_specs={'snapshot_support': 'True'},
|
||||
is_public=True,
|
||||
name=self.new_share_type.name,
|
||||
spec_driver_handles_share_servers=True
|
||||
)
|
||||
|
||||
self.assertCountEqual(COLUMNS, columns)
|
||||
self.assertCountEqual(self.data, data)
|
||||
|
||||
|
||||
class TestShareTypeDelete(TestShareType):
|
||||
|
||||
share_types = manila_fakes.FakeShareType.create_share_types(count=2)
|
||||
|
||||
def setUp(self):
|
||||
super(TestShareTypeDelete, self).setUp()
|
||||
|
||||
self.shares_mock.get = manila_fakes.FakeShareType.get_share_types(
|
||||
self.share_types)
|
||||
self.shares_mock.delete.return_value = None
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = osc_share_types.DeleteShareType(self.app, None)
|
||||
|
||||
def test_share_type_delete_one(self):
|
||||
arglist = [
|
||||
self.share_types[0].id
|
||||
]
|
||||
|
||||
verifylist = [
|
||||
('share_types', [self.share_types[0].id])
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.shares_mock.delete.assert_called_with(self.share_types[0])
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_share_type_delete_multiple(self):
|
||||
arglist = []
|
||||
for t in self.share_types:
|
||||
arglist.append(t.id)
|
||||
verifylist = [
|
||||
('share_types', arglist),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
calls = []
|
||||
for t in self.share_types:
|
||||
calls.append(call(t))
|
||||
self.shares_mock.delete.assert_has_calls(calls)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_delete_share_type_with_exception(self):
|
||||
arglist = [
|
||||
'non_existing_type',
|
||||
]
|
||||
verifylist = [
|
||||
('share_types', arglist),
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.shares_mock.delete.side_effect = exceptions.CommandError()
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
|
||||
class TestShareTypeSet(TestShareType):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShareTypeSet, self).setUp()
|
||||
|
||||
self.share_type = manila_fakes.FakeShareType.create_one_sharetype(
|
||||
methods={'set_keys': None, 'update': None})
|
||||
self.shares_mock.get.return_value = self.share_type
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = osc_share_types.SetShareType(self.app, None)
|
||||
|
||||
def test_share_type_set_extra_specs(self):
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
'--extra-specs', 'snapshot_support=true'
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('extra_specs', ['snapshot_support=true'])
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.share_type.set_keys.assert_called_with(
|
||||
{'snapshot_support': 'True'})
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_share_type_set_name(self):
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
'--name', 'new name'
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('name', 'new name')
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.share_type.update.assert_called_with(
|
||||
name='new name')
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_share_type_set_description(self):
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
'--description', 'new description'
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('description', 'new description')
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.share_type.update.assert_called_with(
|
||||
description='new description')
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_share_type_set_visibility(self):
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
'--public', 'false'
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('public', 'false')
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.share_type.update.assert_called_with(
|
||||
is_public=False)
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_share_type_set_extra_specs_exception(self):
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
'--extra-specs', 'snapshot_support=true'
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('extra_specs', ['snapshot_support=true'])
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.share_type.set_keys.side_effect = BadRequest()
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_share_type_set_api_version_exception(self):
|
||||
self.app.client_manager.share.api_version = api_versions.APIVersion(
|
||||
"2.49")
|
||||
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
'--name', 'new name',
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('name', 'new name'),
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
|
||||
class TestShareTypeUnset(TestShareType):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShareTypeUnset, self).setUp()
|
||||
|
||||
self.share_type = manila_fakes.FakeShareType.create_one_sharetype(
|
||||
methods={'unset_keys': None})
|
||||
self.shares_mock.get.return_value = self.share_type
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = osc_share_types.UnsetShareType(self.app, None)
|
||||
|
||||
def test_share_type_unset_extra_specs(self):
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
'snapshot_support'
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('extra_specs', ['snapshot_support'])
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
self.share_type.unset_keys.assert_called_with(['snapshot_support'])
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_share_type_unset_exception(self):
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
'snapshot_support'
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('extra_specs', ['snapshot_support'])
|
||||
]
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.share_type.unset_keys.side_effect = NotFound()
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
|
||||
class TestShareTypeList(TestShareType):
|
||||
|
||||
share_types = manila_fakes.FakeShareType.create_share_types()
|
||||
|
||||
def setUp(self):
|
||||
super(TestShareTypeList, self).setUp()
|
||||
|
||||
self.shares_mock.list.return_value = self.share_types
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = osc_share_types.ListShareType(self.app, None)
|
||||
|
||||
self.values = (oscutils.get_dict_properties(
|
||||
s._info, COLUMNS) for s in self.share_types)
|
||||
|
||||
def test_share_type_list_no_options(self):
|
||||
arglist = []
|
||||
verifylist = [
|
||||
('all', False)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.shares_mock.list.assert_called_once_with(
|
||||
search_opts={},
|
||||
show_all=False
|
||||
)
|
||||
self.assertEqual(COLUMNS, columns)
|
||||
self.assertEqual(list(self.values), list(data))
|
||||
|
||||
def test_share_type_list_all(self):
|
||||
arglist = [
|
||||
'--all',
|
||||
]
|
||||
verifylist = [
|
||||
('all', True)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.shares_mock.list.assert_called_once_with(
|
||||
search_opts={},
|
||||
show_all=True)
|
||||
self.assertEqual(COLUMNS, columns)
|
||||
self.assertEqual(list(self.values), list(data))
|
||||
|
||||
def test_share_type_list_extra_specs(self):
|
||||
arglist = [
|
||||
'--extra-specs', 'snapshot_support=true'
|
||||
]
|
||||
verifylist = [
|
||||
('extra_specs', ['snapshot_support=true'])
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.shares_mock.list.assert_called_once_with(
|
||||
search_opts={'extra_specs': {'snapshot_support': 'True'}},
|
||||
show_all=False)
|
||||
self.assertEqual(COLUMNS, columns)
|
||||
self.assertEqual(list(self.values), list(data))
|
||||
|
||||
def test_share_type_list_columns(self):
|
||||
arglist = [
|
||||
'--columns', 'id,name'
|
||||
]
|
||||
verifylist = [
|
||||
('columns', 'id,name')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
arg_columns = [
|
||||
'id',
|
||||
'name'
|
||||
]
|
||||
arg_columns_data = (oscutils.get_item_properties(
|
||||
s, arg_columns) for s in self.share_types)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.shares_mock.list.assert_called_once_with(
|
||||
search_opts={},
|
||||
show_all=False)
|
||||
self.assertEqual(arg_columns, columns)
|
||||
self.assertEqual(list(arg_columns_data), list(data))
|
||||
|
||||
def test_share_type_list_api_versions_exception(self):
|
||||
self.app.client_manager.share.api_version = api_versions.APIVersion(
|
||||
"2.42")
|
||||
|
||||
arglist = [
|
||||
'--extra-specs', 'snapshot_support=true'
|
||||
]
|
||||
verifylist = [
|
||||
('extra_specs', ['snapshot_support=true'])
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
def test_share_type_list_columns_invalid_value(self):
|
||||
arglist = [
|
||||
'--columns', 'invalid_column_name'
|
||||
]
|
||||
verifylist = [
|
||||
('columns', 'invalid_column_name')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
|
||||
class TestShareTypeShow(TestShareType):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShareTypeShow, self).setUp()
|
||||
|
||||
self.share_type = manila_fakes.FakeShareType.create_one_sharetype()
|
||||
|
||||
self.shares_mock.get.return_value = self.share_type
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = osc_share_types.ShowShareType(self.app, None)
|
||||
|
||||
self.data = [
|
||||
self.share_type.id,
|
||||
self.share_type.name,
|
||||
'public',
|
||||
self.share_type.is_default,
|
||||
'driver_handles_share_servers : True',
|
||||
('replication_type : readable\n'
|
||||
'mount_snapshot_support : False\n'
|
||||
'revert_to_snapshot_support : False\n'
|
||||
'create_share_from_snapshot_support : True\n'
|
||||
'snapshot_support : True'),
|
||||
self.share_type.description,
|
||||
]
|
||||
|
||||
def test_share_type_show(self):
|
||||
arglist = [
|
||||
self.share_type.id
|
||||
]
|
||||
verifylist = [
|
||||
("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.get.assert_called_with(self.share_type.id)
|
||||
|
||||
self.assertCountEqual(COLUMNS, columns)
|
||||
self.assertCountEqual(self.data, data)
|
194
manilaclient/tests/unit/osc/v2/test_share_type_access.py
Normal file
194
manilaclient/tests/unit/osc/v2/test_share_type_access.py
Normal file
@ -0,0 +1,194 @@
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
#
|
||||
|
||||
from osc_lib import exceptions
|
||||
|
||||
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
|
||||
|
||||
from manilaclient.common.apiclient.exceptions import BadRequest
|
||||
from manilaclient.osc.v2 import share_type_access as osc_share_type_access
|
||||
from manilaclient.tests.unit.osc.v2 import fakes as manila_fakes
|
||||
|
||||
|
||||
class TestShareTypeAccess(manila_fakes.TestShare):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShareTypeAccess, self).setUp()
|
||||
|
||||
self.type_access_mock = (
|
||||
self.app.client_manager.share.share_type_access)
|
||||
|
||||
self.type_access_mock.reset_mock()
|
||||
|
||||
self.share_types_mock = self.app.client_manager.share.share_types
|
||||
self.share_types_mock.reset_mock()
|
||||
|
||||
self.projects_mock = self.app.client_manager.identity.projects
|
||||
self.projects_mock.reset_mock()
|
||||
|
||||
|
||||
class TestShareTypeAccessAllow(TestShareTypeAccess):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShareTypeAccessAllow, self).setUp()
|
||||
|
||||
self.project = identity_fakes.FakeProject.create_one_project()
|
||||
|
||||
self.share_type = manila_fakes.FakeShareType.create_one_sharetype(
|
||||
attrs={'share_type_access:is_public': False})
|
||||
self.share_types_mock.get.return_value = self.share_type
|
||||
|
||||
self.type_access_mock.add_project_access.return_value = None
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = osc_share_type_access.ShareTypeAccessAllow(self.app, None)
|
||||
|
||||
def test_share_type_access_create(self):
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
self.project.id
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('project_id', self.project.id)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.type_access_mock.add_project_access.assert_called_with(
|
||||
self.share_type,
|
||||
self.project.id)
|
||||
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_share_type_access_create_throws_exception(self):
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
'invalid_project_format'
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('project_id', 'invalid_project_format')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.type_access_mock.add_project_access.side_effect = BadRequest()
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
|
||||
class TestShareTypeAccessList(TestShareTypeAccess):
|
||||
|
||||
columns = ['Project_ID']
|
||||
data = (('',), ('',))
|
||||
|
||||
def setUp(self):
|
||||
super(TestShareTypeAccessList, self).setUp()
|
||||
|
||||
self.type_access_mock.list.return_value = (
|
||||
self.columns, self.data)
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = osc_share_type_access.ListShareTypeAccess(self.app, None)
|
||||
|
||||
def test_share_type_access_list(self):
|
||||
share_type = manila_fakes.FakeShareType.create_one_sharetype(
|
||||
attrs={'share_type_access:is_public': False})
|
||||
self.share_types_mock.get.return_value = share_type
|
||||
|
||||
arglist = [
|
||||
share_type.id,
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', share_type.id)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
columns, data = self.cmd.take_action(parsed_args)
|
||||
self.type_access_mock.list.assert_called_once_with(
|
||||
share_type)
|
||||
|
||||
self.assertEqual(self.columns, columns)
|
||||
self.assertEqual(self.data, tuple(data))
|
||||
|
||||
def test_share_type_access_list_public_type(self):
|
||||
share_type = manila_fakes.FakeShareType.create_one_sharetype(
|
||||
attrs={'share_type_access:is_public': True})
|
||||
|
||||
self.share_types_mock.get.return_value = share_type
|
||||
|
||||
arglist = [
|
||||
share_type.id,
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', share_type.id)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
||||
|
||||
|
||||
class TestShareTypeAccessDeny(TestShareTypeAccess):
|
||||
|
||||
def setUp(self):
|
||||
super(TestShareTypeAccessDeny, self).setUp()
|
||||
|
||||
self.project = identity_fakes.FakeProject.create_one_project()
|
||||
|
||||
self.share_type = manila_fakes.FakeShareType.create_one_sharetype(
|
||||
attrs={'share_type_access:is_public': False})
|
||||
self.share_types_mock.get.return_value = self.share_type
|
||||
|
||||
self.type_access_mock.remove_project_access.return_value = None
|
||||
|
||||
# Get the command object to test
|
||||
self.cmd = osc_share_type_access.ShareTypeAccessDeny(self.app, None)
|
||||
|
||||
def test_share_type_access_delete(self):
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
self.project.id
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('project_id', self.project.id)
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
|
||||
result = self.cmd.take_action(parsed_args)
|
||||
|
||||
self.type_access_mock.remove_project_access.assert_called_with(
|
||||
self.share_type,
|
||||
self.project.id)
|
||||
|
||||
self.assertIsNone(result)
|
||||
|
||||
def test_share_type_access_delete_exception(self):
|
||||
arglist = [
|
||||
self.share_type.id,
|
||||
'invalid_project_format'
|
||||
]
|
||||
verifylist = [
|
||||
('share_type', self.share_type.id),
|
||||
('project_id', 'invalid_project_format')
|
||||
]
|
||||
|
||||
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
|
||||
self.type_access_mock.remove_project_access.side_effect = BadRequest()
|
||||
self.assertRaises(
|
||||
exceptions.CommandError, self.cmd.take_action, parsed_args)
|
@ -50,6 +50,15 @@ openstack.share.v2 =
|
||||
share_access_show = manilaclient.osc.v2.share_access_rules:ShowShareAccess
|
||||
share_access_set = manilaclient.osc.v2.share_access_rules:SetShareAccess
|
||||
share_access_unset = manilaclient.osc.v2.share_access_rules:UnsetShareAccess
|
||||
share_type_create = manilaclient.osc.v2.share_types:CreateShareType
|
||||
share_type_delete = manilaclient.osc.v2.share_types:DeleteShareType
|
||||
share_type_set = manilaclient.osc.v2.share_types:SetShareType
|
||||
share_type_unset = manilaclient.osc.v2.share_types:UnsetShareType
|
||||
share_type_list = manilaclient.osc.v2.share_types:ListShareType
|
||||
share_type_show = manilaclient.osc.v2.share_types:ShowShareType
|
||||
share_type_access_create = manilaclient.osc.v2.share_type_access:ShareTypeAccessAllow
|
||||
share_type_access_list = manilaclient.osc.v2.share_type_access:ListShareTypeAccess
|
||||
share_type_access_delete = manilaclient.osc.v2.share_type_access:ShareTypeAccessDeny
|
||||
|
||||
[wheel]
|
||||
universal = 1
|
||||
|
Loading…
Reference in New Issue
Block a user