Merge "Add support for setting volume-type-access"

This commit is contained in:
Jenkins 2016-04-12 22:27:07 +00:00 committed by Gerrit Code Review
commit 85c47b76fb
5 changed files with 147 additions and 6 deletions
doc/source/command-objects
openstackclient
tests/volume/v2
volume/v2
releasenotes/notes

@ -88,6 +88,8 @@ Set volume type properties
[--name <name>] [--name <name>]
[--description <description>] [--description <description>]
[--property <key=value> [...] ] [--property <key=value> [...] ]
[--project <project>]
[--project-domain <project-domain>]
<volume-type> <volume-type>
.. option:: --name <name> .. option:: --name <name>
@ -102,6 +104,17 @@ Set volume type properties
.. versionadded:: 2 .. 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> .. option:: --property <key=value>
Set a property on this volume type (repeat option to set multiple properties) Set a property on this volume type (repeat option to set multiple properties)

@ -243,6 +243,8 @@ class FakeVolumeClient(object):
self.backups.resource_class = fakes.FakeResource(None, {}) self.backups.resource_class = fakes.FakeResource(None, {})
self.volume_types = mock.Mock() self.volume_types = mock.Mock()
self.volume_types.resource_class = fakes.FakeResource(None, {}) 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 = mock.Mock()
self.restores.resource_class = fakes.FakeResource(None, {}) self.restores.resource_class = fakes.FakeResource(None, {})
self.qos_specs = mock.Mock() self.qos_specs = mock.Mock()

@ -15,6 +15,8 @@
import copy import copy
from openstackclient.tests import fakes 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.tests.volume.v2 import fakes as volume_fakes
from openstackclient.volume.v2 import volume_type 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 = self.app.client_manager.volume.volume_types
self.types_mock.reset_mock() 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): class TestTypeCreate(TestType):
@ -211,6 +220,13 @@ class TestTypeSet(TestType):
loaded=True, 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 # Get the command object to test
self.cmd = volume_type.SetVolumeType(self.app, None) self.cmd = volume_type.SetVolumeType(self.app, None)
@ -286,6 +302,56 @@ class TestTypeSet(TestType):
self.assertIn('myprop', result) self.assertIn('myprop', result)
self.assertEqual('myvalue', result['myprop']) 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): class TestTypeShow(TestType):

@ -17,8 +17,10 @@
import six import six
from openstackclient.common import command from openstackclient.common import command
from openstackclient.common import exceptions
from openstackclient.common import parseractions from openstackclient.common import parseractions
from openstackclient.common import utils from openstackclient.common import utils
from openstackclient.identity import common as identity_common
class CreateVolumeType(command.ShowOne): class CreateVolumeType(command.ShowOne):
@ -156,19 +158,30 @@ class SetVolumeType(command.Command):
help='Set a property on this volume type ' help='Set a property on this volume type '
'(repeat option to set multiple properties)', '(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 return parser
def take_action(self, parsed_args): def take_action(self, parsed_args):
volume_client = self.app.client_manager.volume volume_client = self.app.client_manager.volume
identity_client = self.app.client_manager.identity
volume_type = utils.find_resource( volume_type = utils.find_resource(
volume_client.volume_types, parsed_args.volume_type) volume_client.volume_types, parsed_args.volume_type)
if (not parsed_args.name if (not parsed_args.name
and not parsed_args.description 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") self.app.log.error("No changes requested\n")
return return
result = 0
kwargs = {} kwargs = {}
if parsed_args.name: if parsed_args.name:
kwargs['name'] = parsed_args.name kwargs['name'] = parsed_args.name
@ -176,13 +189,42 @@ class SetVolumeType(command.Command):
kwargs['description'] = parsed_args.description kwargs['description'] = parsed_args.description
if kwargs: if kwargs:
volume_client.volume_types.update( try:
volume_type.id, volume_client.volume_types.update(
**kwargs 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: 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): class ShowVolumeType(command.ShowOne):

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