diff --git a/doc/source/cli/osc/v2/index.rst b/doc/source/cli/osc/v2/index.rst index 7ac5ce529..5eafb9feb 100644 --- a/doc/source/cli/osc/v2/index.rst +++ b/doc/source/cli/osc/v2/index.rst @@ -177,7 +177,10 @@ share groups ============ .. autoprogram-cliff:: openstack.share.v2 - :command: share group [!t]* + :command: share group [!ts]* + +.. autoprogram-cliff:: openstack.share.v2 + :command: share group set ================= share group types @@ -185,3 +188,10 @@ share group types .. autoprogram-cliff:: openstack.share.v2 :command: share group type * + +===================== +share group snapshots +===================== + + .. autoprogram-cliff:: openstack.share.v2 + :command: share group snapshot * diff --git a/manilaclient/osc/v2/share_group_snapshots.py b/manilaclient/osc/v2/share_group_snapshots.py new file mode 100644 index 000000000..1680d490d --- /dev/null +++ b/manilaclient/osc/v2/share_group_snapshots.py @@ -0,0 +1,442 @@ +# 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.cli import parseractions +from osc_lib.command import command +from osc_lib import exceptions +from osc_lib import utils +from osc_lib import utils as osc_utils + +from manilaclient.common._i18n import _ + +LOG = logging.getLogger(__name__) + + +class CreateShareGroupSnapshot(command.ShowOne): + """Create a share group snapshot.""" + _description = _( + "Create a share group snapshot of the given share group") + + def get_parser(self, prog_name): + parser = super( + CreateShareGroupSnapshot, self).get_parser(prog_name) + parser.add_argument( + "share_group", + metavar="", + help=_("Name or ID of the share group.") + ) + parser.add_argument( + "--name", + metavar="", + default=None, + help=_("Optional share group snapshot name. (Default=None)") + ) + parser.add_argument( + "--description", + metavar="", + default=None, + help=_("Optional share group snapshot description. " + "(Default=None)") + ) + parser.add_argument( + '--wait', + action='store_true', + default=False, + help=_('Wait for share group snapshot creation') + ) + return parser + + def take_action(self, parsed_args): + share_client = self.app.client_manager.share + + share_group = osc_utils.find_resource( + share_client.share_groups, + parsed_args.share_group) + + share_group_snapshot = share_client.share_group_snapshots.create( + share_group, + name=parsed_args.name, + description=parsed_args.description, + ) + if parsed_args.wait: + if not osc_utils.wait_for_status( + status_f=share_client.share_group_snapshots.get, + res_id=share_group_snapshot.id, + success_status=['available'] + ): + LOG.error(_("ERROR: Share group snapshot is in error state.")) + + share_group_snapshot = osc_utils.find_resource( + share_client.share_group_snapshots, + share_group_snapshot.id) + + data = share_group_snapshot._info + data.pop('links', None) + data.pop('members', None) + + return self.dict2columns(data) + + +class DeleteShareGroupSnapshot(command.Command): + """Delete one or more share group snapshots.""" + _description = _("Delete one or more share group snapshot") + + def get_parser(self, prog_name): + parser = super(DeleteShareGroupSnapshot, self).get_parser(prog_name) + parser.add_argument( + "share_group_snapshot", + metavar="", + nargs="+", + help=_("Name or ID of the group snapshot(s) to delete") + ) + parser.add_argument( + "--force", + action='store_true', + default=False, + help=_("Attempt to force delete the share group snapshot(s) " + "(Default=False) (Admin only).") + ) + parser.add_argument( + "--wait", + action='store_true', + default=False, + help=_("Wait for share group snapshot deletion") + ) + return parser + + def take_action(self, parsed_args): + share_client = self.app.client_manager.share + result = 0 + + for share_group_snapshot in parsed_args.share_group_snapshot: + try: + share_group_snapshot_obj = osc_utils.find_resource( + share_client.share_group_snapshots, + share_group_snapshot) + + share_client.share_group_snapshots.delete( + share_group_snapshot_obj, + force=parsed_args.force) + + if parsed_args.wait: + if not osc_utils.wait_for_delete( + manager=share_client.share_group_snapshots, + res_id=share_group_snapshot_obj.id): + result += 1 + + except Exception as e: + result += 1 + LOG.error( + 'Failed to delete a share group snapshot with ' + f'name or ID {share_group_snapshot}: {e}') + + if result > 0: + total = len(parsed_args.share_group_snapshot) + msg = (f'{result} of {total} share group snapshots failed ' + 'to delete.') + raise exceptions.CommandError(msg) + + +class ShowShareGroupSnapshot(command.ShowOne): + """Display a share group snapshot""" + _description = _( + "Show details about a share group snapshot") + + def get_parser(self, prog_name): + parser = super(ShowShareGroupSnapshot, self).get_parser(prog_name) + parser.add_argument( + "share_group_snapshot", + metavar="", + help=_("Name or ID of the share group snapshot to display") + ) + return parser + + def take_action(self, parsed_args): + share_client = self.app.client_manager.share + + share_group_snapshot = osc_utils.find_resource( + share_client.share_group_snapshots, + parsed_args.share_group_snapshot) + + data = share_group_snapshot._info + data.pop('links', None) + data.pop('members', None) + + return self.dict2columns(data) + + +class SetShareGroupSnapshot(command.Command): + """Set share group snapshot properties.""" + _description = _("Set share group snapshot properties") + + def get_parser(self, prog_name): + parser = super(SetShareGroupSnapshot, self).get_parser(prog_name) + parser.add_argument( + "share_group_snapshot", + metavar="", + help=_('Name or ID of the snapshot to set a property for') + ) + parser.add_argument( + "--name", + metavar="", + default=None, + help=_("Set a name to the snapshot.") + ) + parser.add_argument( + "--description", + metavar="", + default=None, + help=_("Set a description to the snapshot.") + ) + parser.add_argument( + "--status", + metavar="", + choices=['available', 'error', 'creating', + 'deleting', 'error_deleting'], + help=_("Explicitly set the state of a share group snapshot" + "(Admin only). " + "Options include : available, error, creating, " + "deleting, error_deleting.") + ) + return parser + + def take_action(self, parsed_args): + share_client = self.app.client_manager.share + result = 0 + + share_group_snapshot = osc_utils.find_resource( + share_client.share_group_snapshots, + parsed_args.share_group_snapshot) + + kwargs = {} + + if parsed_args.name is not None: + kwargs['name'] = parsed_args.name + if parsed_args.description is not None: + kwargs['description'] = parsed_args.description + + if kwargs: + try: + share_client.share_group_snapshots.update( + share_group_snapshot, + **kwargs + ) + except Exception as e: + result += 1 + LOG.error('Failed to set name or desciption for ' + 'share group snapshot with ID ' + f'{share_group_snapshot.id}: {e}') + + if parsed_args.status: + try: + share_client.share_group_snapshots.reset_state( + share_group_snapshot, + parsed_args.status + ) + except Exception as e: + result += 1 + LOG.error('Failed to set status for ' + 'share group snapshot with ID ' + f'{share_group_snapshot.id}: {e}') + + if result > 0: + raise exceptions.CommandError(_( + "One or more of the set operations failed")) + + +class UnsetShareGroupSnapshot(command.Command): + """Unset a share group snapshot property.""" + _description = _("Unset a share group snapshot property") + + def get_parser(self, prog_name): + parser = super(UnsetShareGroupSnapshot, self).get_parser(prog_name) + parser.add_argument( + "share_group_snapshot", + metavar="", + help=_("Name or ID of the group snapshot to unset a property of") + ) + parser.add_argument( + "--name", + action='store_true', + help=_("Unset share group snapshot name."), + ) + parser.add_argument( + "--description", + action='store_true', + help=_("Unset share group snapshot description."), + ) + return parser + + def take_action(self, parsed_args): + share_client = self.app.client_manager.share + + share_group_snapshot = osc_utils.find_resource( + share_client.share_group_snapshots, + parsed_args.share_group_snapshot) + + kwargs = {} + if parsed_args.name: + # the SDK unsets name if it is an empty string + kwargs['name'] = '' + if parsed_args.description: + # the SDK unsets description if it is an empty string + kwargs['description'] = '' + if kwargs: + try: + share_client.share_group_snapshots.update( + share_group_snapshot, + **kwargs + ) + except Exception as e: + raise exceptions.CommandError( + 'Failed to unset name or description for ' + f'share group snapshot : {e}') + + +class ListShareGroupSnapshot(command.Lister): + """List share group snapshots.""" + _description = _("List share group snapshots") + + def get_parser(self, prog_name): + parser = super(ListShareGroupSnapshot, self).get_parser(prog_name) + parser.add_argument( + "--all-projects", + action='store_true', + default=False, + help=_("Display information from all projects (Admin only).") + ) + parser.add_argument( + "--name", + metavar="", + default=None, + help=_("Filter results by name.") + ) + parser.add_argument( + "--status", + metavar="", + default=None, + help=_("Filter results by status.") + ) + parser.add_argument( + "--share-group", + metavar="", + default=None, + help=_("Filter results by share group name or ID.") + ) + parser.add_argument( + "--limit", + metavar="", + type=int, + default=None, + action=parseractions.NonNegativeAction, + help=_("Limit the number of share groups returned") + ) + parser.add_argument( + "--marker", + metavar="", + help=_("The last share group snapshot ID of the " + "previous page") + ) + parser.add_argument( + '--sort', + metavar="[:]", + default='name:asc', + help=_("Sort output by selected keys and directions(asc or desc) " + "(default: name:asc), multiple keys and directions can be " + "specified separated by comma") + ) + parser.add_argument( + "--detailed", + action="store_true", + help=_("Show detailed information about share group snapshot. ") + ) + return parser + + def take_action(self, parsed_args): + share_client = self.app.client_manager.share + + share_group_id = None + if parsed_args.share_group: + share_group_id = osc_utils.find_resource( + share_client.share_groups, + parsed_args.share_group).id + + columns = [ + 'ID', + 'Name', + 'Status', + 'Description', + ] + + search_opts = { + 'all_tenants': parsed_args.all_projects, + 'name': parsed_args.name, + 'status': parsed_args.status, + 'share_group_id': share_group_id, + 'limit': parsed_args.limit, + 'offset': parsed_args.marker, + } + + if parsed_args.detailed: + columns.extend([ + 'Created At', + 'Share Group ID', + ]) + + if parsed_args.all_projects: + columns.append('Project ID') + + share_group_snapshots = share_client.share_group_snapshots.list( + search_opts=search_opts) + + share_group_snapshots = utils.sort_items( + share_group_snapshots, parsed_args.sort, str) + + data = ( + osc_utils.get_dict_properties(share_group_snapshot._info, columns) + for share_group_snapshot in share_group_snapshots + ) + + return (columns, data) + + +class ListShareGroupSnapshotMembers(command.Lister): + """List members for share group snapshot.""" + _description = _("List members of share group snapshot") + + def get_parser(self, prog_name): + parser = super( + ListShareGroupSnapshotMembers, self).get_parser(prog_name) + parser.add_argument( + "share_group_snapshot", + metavar="", + help=_("Name or ID of the group snapshot to list members for") + ) + return parser + + def take_action(self, parsed_args): + share_client = self.app.client_manager.share + + columns = ['Share ID', 'Size'] + + share_group_snapshot = osc_utils.find_resource( + share_client.share_group_snapshots, + parsed_args.share_group_snapshot) + + data = ( + osc_utils.get_dict_properties(member, columns) + for member in share_group_snapshot._info.get('members', []) + ) + + return (columns, data) diff --git a/manilaclient/tests/unit/osc/v2/fakes.py b/manilaclient/tests/unit/osc/v2/fakes.py index d02abae4f..67e9cfcc1 100644 --- a/manilaclient/tests/unit/osc/v2/fakes.py +++ b/manilaclient/tests/unit/osc/v2/fakes.py @@ -37,6 +37,7 @@ class FakeShareClient(object): self.quotas = mock.Mock() self.quota_classes = mock.Mock() self.share_snapshots = mock.Mock() + self.share_group_snapshots = mock.Mock() self.share_snapshot_export_locations = mock.Mock() self.share_snapshot_instances = mock.Mock() self.share_replicas = mock.Mock() @@ -1290,3 +1291,55 @@ class FakeShareGroupType(object): share_group_types = FakeShareGroupType.share_group_types(count) return mock.Mock(side_effect=share_group_types) + + +class FakeShareGroupSnapshot(object): + """Fake a share group snapshot""" + + @staticmethod + def create_one_share_group_snapshot(attrs=None, methods=None): + """Create a fake share group snapshot + + :param Dictionary attrs: + A dictionary with all attributes + :return: + A FakeResource object, with project_id, resource and so on + """ + + attrs = attrs or {} + methods = methods or {} + + share_group_snapshot = { + 'status': 'available', + 'share_group_id': 'share-group-id-' + uuid.uuid4().hex, + 'name': None, + 'created_at': datetime.datetime.now().isoformat(), + "project_id": 'project-id-' + uuid.uuid4().hex, + 'id': 'share-group-snapshot-id-' + uuid.uuid4().hex, + 'description': None + } + + share_group_snapshot.update(attrs) + share_group_snapshot = osc_fakes.FakeResource(info=copy.deepcopy( + share_group_snapshot), + methods=methods, + loaded=True) + return share_group_snapshot + + @staticmethod + def create_share_group_snapshots(attrs=None, count=2): + """Create multiple fake share group snapshot. + + :param Dictionary attrs: + A dictionary with all attributes + :param Integer count: + The number of share group snapshot to be faked + :return: + A list of FakeResource objects + """ + + share_group_snapshots = [] + for n in range(0, count): + share_group_snapshots.append( + FakeShareGroupSnapshot.create_one_share_group_snapshot(attrs)) + return share_group_snapshots diff --git a/manilaclient/tests/unit/osc/v2/test_share_group_snapshots.py b/manilaclient/tests/unit/osc/v2/test_share_group_snapshots.py new file mode 100644 index 000000000..ca7c233e7 --- /dev/null +++ b/manilaclient/tests/unit/osc/v2/test_share_group_snapshots.py @@ -0,0 +1,671 @@ +# 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 uuid + +from osc_lib import exceptions +from osc_lib import utils as oscutils + +from unittest import mock + +from manilaclient import api_versions +from manilaclient.osc.v2 import ( + share_group_snapshots as osc_share_group_snapshots) +from manilaclient.tests.unit.osc import osc_utils +from manilaclient.tests.unit.osc.v2 import fakes as manila_fakes + +LOG = logging.getLogger(__name__) + + +class TestShareGroupSnapshot(manila_fakes.TestShare): + + def setUp(self): + super(TestShareGroupSnapshot, self).setUp() + + self.groups_mock = self.app.client_manager.share.share_groups + self.groups_mock.reset_mock() + + self.group_snapshot_mocks = ( + self.app.client_manager.share.share_group_snapshots) + self.group_snapshot_mocks.reset_mock() + + self.app.client_manager.share.api_version = api_versions.APIVersion( + api_versions.MAX_VERSION) + + +class TestCreateShareGroupSnapshot(TestShareGroupSnapshot): + + def setUp(self): + super(TestCreateShareGroupSnapshot, self).setUp() + + self.share_group = ( + manila_fakes.FakeShareGroup.create_one_share_group() + ) + self.groups_mock.get.return_value = self.share_group + + self.share_group_snapshot = ( + manila_fakes.FakeShareGroupSnapshot + .create_one_share_group_snapshot() + ) + self.group_snapshot_mocks.create.return_value = ( + self.share_group_snapshot) + self.group_snapshot_mocks.get.return_value = ( + self.share_group_snapshot) + + self.cmd = osc_share_group_snapshots.CreateShareGroupSnapshot( + self.app, None) + + self.data = tuple(self.share_group_snapshot._info.values()) + self.columns = tuple(self.share_group_snapshot._info.keys()) + + def test_share_group_snapshot_create_missing_args(self): + arglist = [] + verifylist = [] + + self.assertRaises( + osc_utils.ParserException, + self.check_parser, self.cmd, arglist, verifylist) + + def test_share_group_snapshot_create(self): + arglist = [ + self.share_group.id + ] + verifylist = [ + ('share_group', self.share_group.id) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.create.assert_called_with( + self.share_group, + name=None, + description=None + ) + + self.assertCountEqual(self.columns, columns) + self.assertCountEqual(self.data, data) + + def test_share_group_snapshot_create_options(self): + arglist = [ + self.share_group.id, + '--name', self.share_group_snapshot.name, + '--description', self.share_group_snapshot.description + ] + verifylist = [ + ('share_group', self.share_group.id), + ('name', self.share_group_snapshot.name), + ('description', self.share_group_snapshot.description) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.create.assert_called_with( + self.share_group, + name=self.share_group_snapshot.name, + description=self.share_group_snapshot.description, + ) + + self.assertCountEqual(self.columns, columns) + self.assertCountEqual(self.data, data) + + def test_share_group_snapshot_create_wait(self): + arglist = [ + self.share_group.id, + '--wait' + ] + verifylist = [ + ('share_group', self.share_group.id), + ('wait', True) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + with mock.patch('osc_lib.utils.wait_for_status', return_value=True): + self.group_snapshot_mocks.create.assert_called_with( + self.share_group, + name=None, + description=None, + ) + self.group_snapshot_mocks.get.assert_called_with( + self.share_group_snapshot.id) + self.assertCountEqual(self.columns, columns) + self.assertCountEqual(self.data, data) + + @mock.patch('manilaclient.osc.v2.share_group_snapshots.LOG') + def test_share_group_snapshot_create_wait_exception(self, mock_logger): + arglist = [ + self.share_group.id, + '--wait' + ] + verifylist = [ + ('share_group', self.share_group.id), + ('wait', True) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + with mock.patch('osc_lib.utils.wait_for_status', return_value=False): + columns, data = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.create.assert_called_with( + self.share_group, + name=None, + description=None, + ) + + mock_logger.error.assert_called_with( + "ERROR: Share group snapshot is in error state.") + + self.group_snapshot_mocks.get.assert_called_with( + self.share_group_snapshot.id) + self.assertCountEqual(self.columns, columns) + self.assertCountEqual(self.data, data) + + +class TestDeleteShareGroupSnapshot(TestShareGroupSnapshot): + + def setUp(self): + super(TestDeleteShareGroupSnapshot, self).setUp() + + self.share_group_snapshot = ( + manila_fakes.FakeShareGroupSnapshot + .create_one_share_group_snapshot()) + self.group_snapshot_mocks.get.return_value = ( + self.share_group_snapshot) + + self.cmd = osc_share_group_snapshots.DeleteShareGroupSnapshot( + self.app, None) + + def test_share_group_snapshot_delete_missing_args(self): + arglist = [] + verifylist = [] + + self.assertRaises(osc_utils.ParserException, + self.check_parser, self.cmd, arglist, verifylist) + + def test_share_group_snapshot_delete(self): + arglist = [ + self.share_group_snapshot.id + ] + verifylist = [ + ('share_group_snapshot', [self.share_group_snapshot.id]) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.delete.assert_called_with( + self.share_group_snapshot, + force=False) + self.assertIsNone(result) + + def test_share_group_snapshot_delete_force(self): + arglist = [ + self.share_group_snapshot.id, + '--force' + ] + verifylist = [ + ('share_group_snapshot', [self.share_group_snapshot.id]), + ('force', True) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.delete.assert_called_with( + self.share_group_snapshot, + force=True) + self.assertIsNone(result) + + def test_share_group_snapshot_delete_multiple(self): + share_group_snapshots = ( + manila_fakes.FakeShareGroupSnapshot. + create_share_group_snapshots(count=2)) + arglist = [ + share_group_snapshots[0].id, + share_group_snapshots[1].id + ] + verifylist = [ + ('share_group_snapshot', [share_group_snapshots[0].id, ( + share_group_snapshots[1].id)]) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.assertEqual(self.group_snapshot_mocks.delete.call_count, + len(share_group_snapshots)) + self.assertIsNone(result) + + def test_share_group_snapshot_delete_exception(self): + arglist = [ + self.share_group_snapshot.id + ] + verifylist = [ + ('share_group_snapshot', [self.share_group_snapshot.id]) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.group_snapshot_mocks.delete.side_effect = ( + exceptions.CommandError()) + self.assertRaises(exceptions.CommandError, + self.cmd.take_action, + parsed_args) + + def test_share_group_snapshot_delete_wait(self): + arglist = [ + self.share_group_snapshot.id, + '--wait' + ] + verifylist = [ + ('share_group_snapshot', [self.share_group_snapshot.id]), + ('wait', True) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + with mock.patch('osc_lib.utils.wait_for_delete', return_value=True): + result = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.delete.assert_called_with( + self.share_group_snapshot, + force=False) + self.group_snapshot_mocks.get.assert_called_with( + self.share_group_snapshot.id) + self.assertIsNone(result) + + def test_share_group_snapshot_delete_wait_exception(self): + arglist = [ + self.share_group_snapshot.id, + '--wait' + ] + verifylist = [ + ('share_group_snapshot', [self.share_group_snapshot.id]), + ('wait', True) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + with mock.patch('osc_lib.utils.wait_for_delete', return_value=False): + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, + parsed_args + ) + + +class TestShowShareGroupSnapshot(TestShareGroupSnapshot): + + def setUp(self): + super(TestShowShareGroupSnapshot, self).setUp() + + self.share_group_snapshot = ( + manila_fakes.FakeShareGroupSnapshot + .create_one_share_group_snapshot()) + self.group_snapshot_mocks.get.return_value = ( + self.share_group_snapshot) + + self.cmd = osc_share_group_snapshots.ShowShareGroupSnapshot( + self.app, None) + + self.data = tuple(self.share_group_snapshot._info.values()) + self.columns = tuple(self.share_group_snapshot._info.keys()) + + def test_share_group_snapshot_show_missing_args(self): + arglist = [] + verifylist = [] + + self.assertRaises( + osc_utils.ParserException, + self.check_parser, self.cmd, arglist, verifylist) + + def test_share_group_show(self): + arglist = [ + self.share_group_snapshot.id + ] + verifylist = [ + ('share_group_snapshot', self.share_group_snapshot.id) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.get.assert_called_with( + self.share_group_snapshot.id + ) + + self.assertCountEqual(self.columns, columns) + self.assertCountEqual(self.data, data) + + +class TestSetShareGroupSnapshot(TestShareGroupSnapshot): + + def setUp(self): + super(TestSetShareGroupSnapshot, self).setUp() + + self.share_group_snapshot = ( + manila_fakes.FakeShareGroupSnapshot + .create_one_share_group_snapshot()) + self.group_snapshot_mocks.get.return_value = ( + self.share_group_snapshot) + + self.cmd = osc_share_group_snapshots.SetShareGroupSnapshot( + self.app, None) + + self.data = tuple(self.share_group_snapshot._info.values()) + self.columns = tuple(self.share_group_snapshot._info.keys()) + + def test_set_share_group_snapshot_name_description(self): + group_snapshot_name = 'group-snapshot-name-' + uuid.uuid4().hex + group_snapshot_description = ( + 'group-snapshot-description-' + uuid.uuid4().hex) + arglist = [ + self.share_group_snapshot.id, + '--name', group_snapshot_name, + '--description', group_snapshot_description + ] + verifylist = [ + ('share_group_snapshot', self.share_group_snapshot.id), + ('name', group_snapshot_name), + ('description', group_snapshot_description) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.update.assert_called_with( + self.share_group_snapshot, + name=parsed_args.name, + description=parsed_args.description) + self.assertIsNone(result) + + def test_set_share_group_snapshot_status(self): + arglist = [ + self.share_group_snapshot.id, + '--status', 'available' + ] + verifylist = [ + ('share_group_snapshot', self.share_group_snapshot.id), + ('status', 'available') + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.reset_state.assert_called_with( + self.share_group_snapshot, + 'available') + self.assertIsNone(result) + + def test_set_share_group_snapshot_exception(self): + arglist = [ + self.share_group_snapshot.id, + '--status', 'available' + ] + verifylist = [ + ('share_group_snapshot', self.share_group_snapshot.id), + ('status', 'available') + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.group_snapshot_mocks.reset_state.side_effect = Exception() + + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, + parsed_args) + + +class TestUnsetShareGroupSnapshot(TestShareGroupSnapshot): + + def setUp(self): + super(TestUnsetShareGroupSnapshot, self).setUp() + + self.share_group_snapshot = ( + manila_fakes.FakeShareGroupSnapshot + .create_one_share_group_snapshot()) + self.group_snapshot_mocks.get.return_value = ( + self.share_group_snapshot) + + self.cmd = osc_share_group_snapshots.UnsetShareGroupSnapshot( + self.app, None) + + def test_unset_share_group_snapshot_name_description(self): + arglist = [ + self.share_group_snapshot.id, + '--name', + '--description' + ] + verifylist = [ + ('share_group_snapshot', self.share_group_snapshot.id), + ('name', True), + ('description', True) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.update.assert_called_with( + self.share_group_snapshot, + name='', + description='') + self.assertIsNone(result) + + def test_unset_share_group_snapshot_name_exception(self): + arglist = [ + self.share_group_snapshot.id, + '--name', + ] + verifylist = [ + ('share_group_snapshot', self.share_group_snapshot.id), + ('name', True), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + self.group_snapshot_mocks.update.side_effect = Exception() + + self.assertRaises( + exceptions.CommandError, + self.cmd.take_action, + parsed_args) + + +class TestListShareGroupSnapshot(TestShareGroupSnapshot): + + columns = [ + 'ID', + 'Name', + 'Status', + 'Description', + ] + + def setUp(self): + super(TestListShareGroupSnapshot, self).setUp() + + self.share_group = ( + manila_fakes.FakeShareGroup.create_one_share_group() + ) + self.groups_mock.get.return_value = self.share_group + + self.share_group_snapshot = ( + manila_fakes.FakeShareGroupSnapshot + .create_one_share_group_snapshot({ + 'share_group_id': self.share_group.id + })) + + self.share_group_snapshots_list = [self.share_group_snapshot] + self.group_snapshot_mocks.list.return_value = ( + self.share_group_snapshots_list) + + self.values = ( + oscutils.get_dict_properties(s._info, self.columns) + for s in self.share_group_snapshots_list + ) + + self.cmd = osc_share_group_snapshots.ListShareGroupSnapshot( + self.app, None) + + def test_share_group_snapshot_list_no_options(self): + arglist = [] + verifylist = [] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.list.assert_called_once_with( + search_opts={ + 'all_tenants': False, + 'name': None, + 'status': None, + 'share_group_id': None, + 'limit': None, + 'offset': None, + }) + + self.assertEqual(self.columns, columns) + self.assertEqual(list(self.values), list(data)) + + def test_share_group_snapshot_list_detail_all_projects(self): + columns_detail = [ + 'ID', + 'Name', + 'Status', + 'Description', + 'Created At', + 'Share Group ID', + 'Project ID' + ] + + values = ( + oscutils.get_dict_properties(s._info, columns_detail) + for s in self.share_group_snapshots_list) + + arglist = [ + '--detailed', + '--all-projects', + ] + + verifylist = [ + ('detailed', True), + ('all_projects', True), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.list.assert_called_once_with( + search_opts={ + 'all_tenants': True, + 'name': None, + 'status': None, + 'share_group_id': None, + 'limit': None, + 'offset': None, + }) + + self.assertEqual(columns_detail, columns) + self.assertEqual(list(values), list(data)) + + def test_share_group_snapshot_list_search_options(self): + arglist = [ + '--name', self.share_group_snapshot.name, + '--status', self.share_group_snapshot.status, + '--share-group', self.share_group.id, + ] + verifylist = [ + ('name', self.share_group_snapshot.name), + ('status', self.share_group_snapshot.status), + ('share_group', self.share_group.id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.groups_mock.get.assert_called_with(self.share_group.id) + self.group_snapshot_mocks.list.assert_called_once_with( + search_opts={ + 'all_tenants': False, + 'name': self.share_group_snapshot.name, + 'status': self.share_group_snapshot.status, + 'share_group_id': self.share_group.id, + 'limit': None, + 'offset': None, + }) + + self.assertEqual(self.columns, columns) + self.assertEqual(list(self.values), list(data)) + + +class TestListShareGroupSnapshotMembers(TestShareGroupSnapshot): + + columns = [ + 'Share ID', + 'Size', + ] + + def setUp(self): + super(TestListShareGroupSnapshotMembers, self).setUp() + + self.share = manila_fakes.FakeShare.create_one_share() + + self.share_group_snapshot = ( + manila_fakes.FakeShareGroupSnapshot + .create_one_share_group_snapshot({ + 'members': [{ + 'share_id': self.share.id, + 'size': self.share.size + }] + })) + + self.group_snapshot_mocks.get.return_value = ( + self.share_group_snapshot) + + self.values = ( + oscutils.get_dict_properties(s, self.columns) + for s in self.share_group_snapshot.members + ) + + self.cmd = osc_share_group_snapshots.ListShareGroupSnapshotMembers( + self.app, None) + + def test_share_group_snapshot_list_members(self): + arglist = [ + self.share_group_snapshot.id + ] + verifylist = [ + ('share_group_snapshot', self.share_group_snapshot.id) + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.group_snapshot_mocks.get.assert_called_with( + self.share_group_snapshot.id) + + self.assertEqual(self.columns, columns) + self.assertEqual(list(self.values), list(data)) diff --git a/setup.cfg b/setup.cfg index b731c8f9a..eef4acac4 100644 --- a/setup.cfg +++ b/setup.cfg @@ -134,6 +134,13 @@ openstack.share.v2 = share_group_type_access_create = manilaclient.osc.v2.share_group_type_access:ShareGroupTypeAccessAllow share_group_type_access_list = manilaclient.osc.v2.share_group_type_access:ListShareGroupTypeAccess share_group_type_access_delete = manilaclient.osc.v2.share_group_type_access:ShareGroupTypeAccessDeny + share_group_snapshot_create = manilaclient.osc.v2.share_group_snapshots:CreateShareGroupSnapshot + share_group_snapshot_delete = manilaclient.osc.v2.share_group_snapshots:DeleteShareGroupSnapshot + share_group_snapshot_show= manilaclient.osc.v2.share_group_snapshots:ShowShareGroupSnapshot + share_group_snapshot_list = manilaclient.osc.v2.share_group_snapshots:ListShareGroupSnapshot + share_group_snapshot_set = manilaclient.osc.v2.share_group_snapshots:SetShareGroupSnapshot + share_group_snapshot_unset = manilaclient.osc.v2.share_group_snapshots:UnsetShareGroupSnapshot + share_group_snapshot_members_list = manilaclient.osc.v2.share_group_snapshots:ListShareGroupSnapshotMembers [coverage:run] omit = manilaclient/tests/*