Merge "Show project access for volume type"

This commit is contained in:
Jenkins 2016-07-21 22:07:50 +00:00 committed by Gerrit Code Review
commit 3e1d54299f
5 changed files with 132 additions and 2 deletions

View File

@ -145,7 +145,6 @@ volume type show
Display volume type details
.. program:: volume type show
.. code:: bash

View File

@ -76,6 +76,38 @@ class FakeTransfer(object):
return transfer
class FakeTypeAccess(object):
"""Fake one or more volume type access."""
@staticmethod
def create_one_type_access(attrs=None):
"""Create a fake volume type access for project.
:param Dictionary attrs:
A dictionary with all attributes
:return:
A FakeResource object, with Volume_type_ID and Project_ID.
"""
if attrs is None:
attrs = {}
# Set default attributes.
type_access_attrs = {
'volume_type_id': 'volume-type-id-' + uuid.uuid4().hex,
'project_id': 'project-id-' + uuid.uuid4().hex,
}
# Overwrite default attributes.
type_access_attrs.update(attrs)
type_access = fakes.FakeResource(
None,
type_access_attrs,
loaded=True)
return type_access
class FakeServiceClient(object):
def __init__(self, **kwargs):
@ -666,6 +698,7 @@ class FakeType(object):
"name": 'type-name-' + uuid.uuid4().hex,
"description": 'type-description-' + uuid.uuid4().hex,
"extra_specs": {"foo": "bar"},
"is_public": True,
}
# Overwrite default attributes.

View File

@ -13,6 +13,7 @@
#
import copy
import mock
from osc_lib import exceptions
from osc_lib import utils
@ -46,6 +47,7 @@ class TestTypeCreate(TestType):
columns = (
'description',
'id',
'is_public',
'name',
)
@ -56,6 +58,7 @@ class TestTypeCreate(TestType):
self.data = (
self.new_volume_type.description,
self.new_volume_type.id,
True,
self.new_volume_type.name,
)
@ -357,8 +360,10 @@ class TestTypeSet(TestType):
class TestTypeShow(TestType):
columns = (
'access_project_ids',
'description',
'id',
'is_public',
'name',
'properties',
)
@ -368,8 +373,10 @@ class TestTypeShow(TestType):
self.volume_type = volume_fakes.FakeType.create_one_type()
self.data = (
None,
self.volume_type.description,
self.volume_type.id,
True,
self.volume_type.name,
utils.format_dict(self.volume_type.extra_specs)
)
@ -394,6 +401,71 @@ class TestTypeShow(TestType):
self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data)
def test_type_show_with_access(self):
arglist = [
self.volume_type.id
]
verifylist = [
("volume_type", self.volume_type.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
private_type = volume_fakes.FakeType.create_one_type(
attrs={'is_public': False})
type_access_list = volume_fakes.FakeTypeAccess.create_one_type_access()
with mock.patch.object(self.types_mock, 'get',
return_value=private_type):
with mock.patch.object(self.types_access_mock, 'list',
return_value=[type_access_list]):
columns, data = self.cmd.take_action(parsed_args)
self.types_mock.get.assert_called_once_with(
self.volume_type.id)
self.types_access_mock.list.assert_called_once_with(
private_type.id)
self.assertEqual(self.columns, columns)
private_type_data = (
utils.format_list([type_access_list.project_id]),
private_type.description,
private_type.id,
private_type.is_public,
private_type.name,
utils.format_dict(private_type.extra_specs)
)
self.assertEqual(private_type_data, data)
def test_type_show_with_list_access_exec(self):
arglist = [
self.volume_type.id
]
verifylist = [
("volume_type", self.volume_type.id)
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
private_type = volume_fakes.FakeType.create_one_type(
attrs={'is_public': False})
with mock.patch.object(self.types_mock, 'get',
return_value=private_type):
with mock.patch.object(self.types_access_mock, 'list',
side_effect=Exception()):
columns, data = self.cmd.take_action(parsed_args)
self.types_mock.get.assert_called_once_with(
self.volume_type.id)
self.types_access_mock.list.assert_called_once_with(
private_type.id)
self.assertEqual(self.columns, columns)
private_type_data = (
None,
private_type.description,
private_type.id,
private_type.is_public,
private_type.name,
utils.format_dict(private_type.extra_specs)
)
self.assertEqual(private_type_data, data)
class TestTypeUnset(TestType):

View File

@ -282,8 +282,24 @@ class ShowVolumeType(command.ShowOne):
volume_client = self.app.client_manager.volume
volume_type = utils.find_resource(
volume_client.volume_types, parsed_args.volume_type)
properties = utils.format_dict(volume_type._info.pop('extra_specs'))
properties = utils.format_dict(
volume_type._info.pop('extra_specs', {}))
volume_type._info.update({'properties': properties})
access_project_ids = None
if not volume_type.is_public:
try:
volume_type_access = volume_client.volume_type_access.list(
volume_type.id)
project_ids = [utils.get_field(item, 'project_id')
for item in volume_type_access]
# TODO(Rui Chen): This format list case can be removed after
# patch https://review.openstack.org/#/c/330223/ merged.
access_project_ids = utils.format_list(project_ids)
except Exception as e:
msg = _('Failed to get access project list for volume type '
'%(type)s: %(e)s')
LOG.error(msg % {'type': volume_type.id, 'e': e})
volume_type._info.update({'access_project_ids': access_project_ids})
return zip(*sorted(six.iteritems(volume_type._info)))

View File

@ -0,0 +1,10 @@
---
features:
- |
Show project access details for private volume type.
An user can list projects which have access to
a specific private volume type by using
``volume type show <volume-type>``
[Bug `1554891 <https://bugs.launchpad.net/python-openstackclient/+bug/1554891>`_]