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
This commit is contained in:
Sheel Rana 2016-03-30 08:37:22 +05:30
parent 9e7f0cf1a5
commit be2d2a1b8d
5 changed files with 147 additions and 6 deletions

View File

@ -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)

View File

@ -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()

View File

@ -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):

View File

@ -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):

View File

@ -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'_]