From be2d2a1b8da02d6b8ab05240e4ab61b26f65e442 Mon Sep 17 00:00:00 2001 From: Sheel Rana <ranasheel2000@gmail.com> Date: Wed, 30 Mar 2016 08:37:22 +0530 Subject: [PATCH] Add support for setting volume-type-access OSC does not support to set volume type access to project. This patch will provide support for adding volume type access to existing project. Closes-Bug:#1554889 Implements: bp cinder-command-support Change-Id: Ie36e202bdde7de36eb263a476eb66699d82f7565 --- doc/source/command-objects/volume-type.rst | 13 ++++ openstackclient/tests/volume/v2/fakes.py | 2 + openstackclient/tests/volume/v2/test_type.py | 66 +++++++++++++++++++ openstackclient/volume/v2/volume_type.py | 54 +++++++++++++-- ...d_volume_type_access-32ba8d4bfb0f5f3d.yaml | 18 +++++ 5 files changed, 147 insertions(+), 6 deletions(-) create mode 100644 releasenotes/notes/add_volume_type_access-32ba8d4bfb0f5f3d.yaml diff --git a/doc/source/command-objects/volume-type.rst b/doc/source/command-objects/volume-type.rst index 69944fb954..64b1bd52d9 100644 --- a/doc/source/command-objects/volume-type.rst +++ b/doc/source/command-objects/volume-type.rst @@ -88,6 +88,8 @@ Set volume type properties [--name <name>] [--description <description>] [--property <key=value> [...] ] + [--project <project>] + [--project-domain <project-domain>] <volume-type> .. option:: --name <name> @@ -102,6 +104,17 @@ Set volume type properties .. versionadded:: 2 +.. option:: --project <project> + + Set volume type access to project (name or ID) (admin only) + + *Volume version 2 only* + +.. option:: --project-domain <project-domain> + + Domain the project belongs to (name or ID). + This can be used in case collisions between project names exist. + .. option:: --property <key=value> Set a property on this volume type (repeat option to set multiple properties) diff --git a/openstackclient/tests/volume/v2/fakes.py b/openstackclient/tests/volume/v2/fakes.py index 97bbc59bce..3c238d1006 100644 --- a/openstackclient/tests/volume/v2/fakes.py +++ b/openstackclient/tests/volume/v2/fakes.py @@ -243,6 +243,8 @@ class FakeVolumeClient(object): self.backups.resource_class = fakes.FakeResource(None, {}) self.volume_types = mock.Mock() self.volume_types.resource_class = fakes.FakeResource(None, {}) + self.volume_type_access = mock.Mock() + self.volume_type_access.resource_class = fakes.FakeResource(None, {}) self.restores = mock.Mock() self.restores.resource_class = fakes.FakeResource(None, {}) self.qos_specs = mock.Mock() diff --git a/openstackclient/tests/volume/v2/test_type.py b/openstackclient/tests/volume/v2/test_type.py index b014706b69..448da4320e 100644 --- a/openstackclient/tests/volume/v2/test_type.py +++ b/openstackclient/tests/volume/v2/test_type.py @@ -15,6 +15,8 @@ import copy from openstackclient.tests import fakes +from openstackclient.tests.identity.v3 import fakes as identity_fakes +from openstackclient.tests import utils as tests_utils from openstackclient.tests.volume.v2 import fakes as volume_fakes from openstackclient.volume.v2 import volume_type @@ -41,6 +43,13 @@ class TestType(volume_fakes.TestVolume): self.types_mock = self.app.client_manager.volume.volume_types self.types_mock.reset_mock() + self.types_access_mock = ( + self.app.client_manager.volume.volume_type_access) + self.types_access_mock.reset_mock() + + self.projects_mock = self.app.client_manager.identity.projects + self.projects_mock.reset_mock() + class TestTypeCreate(TestType): @@ -211,6 +220,13 @@ class TestTypeSet(TestType): loaded=True, ) + # Return a project + self.projects_mock.get.return_value = fakes.FakeResource( + None, + copy.deepcopy(identity_fakes.PROJECT), + loaded=True, + ) + # Get the command object to test self.cmd = volume_type.SetVolumeType(self.app, None) @@ -286,6 +302,56 @@ class TestTypeSet(TestType): self.assertIn('myprop', result) self.assertEqual('myvalue', result['myprop']) + def test_type_set_not_called_without_project_argument(self): + arglist = [ + '--project', '', + volume_fakes.type_id, + ] + verifylist = [ + ('project', ''), + ('volume_type', volume_fakes.type_id), + ] + + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.assertIsNone(result) + + self.assertFalse(self.types_access_mock.add_project_access.called) + + def test_type_set_failed_with_missing_volume_type_argument(self): + arglist = [ + '--project', 'identity_fakes.project_id', + ] + verifylist = [ + ('project', 'identity_fakes.project_id'), + ] + + self.assertRaises(tests_utils.ParserException, + self.check_parser, + self.cmd, + arglist, + verifylist) + + def test_type_set_project_access(self): + arglist = [ + '--project', identity_fakes.project_id, + volume_fakes.type_id, + ] + verifylist = [ + ('project', identity_fakes.project_id), + ('volume_type', volume_fakes.type_id), + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + result = self.cmd.take_action(parsed_args) + self.assertIsNone(result) + + self.types_access_mock.add_project_access.assert_called_with( + volume_fakes.type_id, + identity_fakes.project_id, + ) + class TestTypeShow(TestType): diff --git a/openstackclient/volume/v2/volume_type.py b/openstackclient/volume/v2/volume_type.py index 5509ac5261..12828de2c4 100644 --- a/openstackclient/volume/v2/volume_type.py +++ b/openstackclient/volume/v2/volume_type.py @@ -17,8 +17,10 @@ import six from openstackclient.common import command +from openstackclient.common import exceptions from openstackclient.common import parseractions from openstackclient.common import utils +from openstackclient.identity import common as identity_common class CreateVolumeType(command.ShowOne): @@ -156,19 +158,30 @@ class SetVolumeType(command.Command): help='Set a property on this volume type ' '(repeat option to set multiple properties)', ) + parser.add_argument( + '--project', + metavar='<project>', + help='Set volume type access to project (name or ID) (admin only)', + ) + identity_common.add_project_domain_option_to_parser(parser) + return parser def take_action(self, parsed_args): volume_client = self.app.client_manager.volume + identity_client = self.app.client_manager.identity + volume_type = utils.find_resource( volume_client.volume_types, parsed_args.volume_type) if (not parsed_args.name and not parsed_args.description - and not parsed_args.property): + and not parsed_args.property + and not parsed_args.project): self.app.log.error("No changes requested\n") return + result = 0 kwargs = {} if parsed_args.name: kwargs['name'] = parsed_args.name @@ -176,13 +189,42 @@ class SetVolumeType(command.Command): kwargs['description'] = parsed_args.description if kwargs: - volume_client.volume_types.update( - volume_type.id, - **kwargs - ) + try: + volume_client.volume_types.update( + volume_type.id, + **kwargs + ) + except Exception as e: + self.app.log.error("Failed to update volume type name or" + " description: " + str(e)) + result += 1 if parsed_args.property: - volume_type.set_keys(parsed_args.property) + try: + volume_type.set_keys(parsed_args.property) + except Exception as e: + self.app.log.error("Failed to set volume type property: " + + str(e)) + result += 1 + + if parsed_args.project: + project_info = None + try: + project_info = identity_common.find_project( + identity_client, + parsed_args.project, + parsed_args.project_domain) + + volume_client.volume_type_access.add_project_access( + volume_type.id, project_info.id) + except Exception as e: + self.app.log.error("Failed to set volume type access to" + " project: " + str(e)) + result += 1 + + if result > 0: + raise exceptions.CommandError("Command Failed: One or more of the" + " operations failed") class ShowVolumeType(command.ShowOne): diff --git a/releasenotes/notes/add_volume_type_access-32ba8d4bfb0f5f3d.yaml b/releasenotes/notes/add_volume_type_access-32ba8d4bfb0f5f3d.yaml new file mode 100644 index 0000000000..69ae6e76f0 --- /dev/null +++ b/releasenotes/notes/add_volume_type_access-32ba8d4bfb0f5f3d.yaml @@ -0,0 +1,18 @@ +--- +features: + - | + Added support for setting volume type access to project. + + By default, volumes types are public. + To create a private volume type, user needs to set is_public boolean + field to false at volume type creation time. + To control access to a private volume type, user needs to add access + of a private volume type to project. + + So, this feature enables user to add private volume type access to a + project using below command + + ``volume type set --project <project> <volume_type>``. + + [Bug 1554889 'https://bugs.launchpad.net/python-openstackclient/+bug/1554889'_] +