Skip to content

Commit 3e1d542

Browse files
Jenkinsopenstack-gerrit
authored andcommitted
Merge "Show project access for volume type"
2 parents ba34c59 + 5e8957e commit 3e1d542

5 files changed

Lines changed: 132 additions & 2 deletions

File tree

doc/source/command-objects/volume-type.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,6 @@ volume type show
145145

146146
Display volume type details
147147

148-
149148
.. program:: volume type show
150149
.. code:: bash
151150

openstackclient/tests/volume/v2/fakes.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,38 @@ def create_one_transfer(attrs=None):
7676
return transfer
7777

7878

79+
class FakeTypeAccess(object):
80+
"""Fake one or more volume type access."""
81+
82+
@staticmethod
83+
def create_one_type_access(attrs=None):
84+
"""Create a fake volume type access for project.
85+
86+
:param Dictionary attrs:
87+
A dictionary with all attributes
88+
:return:
89+
A FakeResource object, with Volume_type_ID and Project_ID.
90+
"""
91+
if attrs is None:
92+
attrs = {}
93+
94+
# Set default attributes.
95+
type_access_attrs = {
96+
'volume_type_id': 'volume-type-id-' + uuid.uuid4().hex,
97+
'project_id': 'project-id-' + uuid.uuid4().hex,
98+
}
99+
100+
# Overwrite default attributes.
101+
type_access_attrs.update(attrs)
102+
103+
type_access = fakes.FakeResource(
104+
None,
105+
type_access_attrs,
106+
loaded=True)
107+
108+
return type_access
109+
110+
79111
class FakeServiceClient(object):
80112

81113
def __init__(self, **kwargs):
@@ -666,6 +698,7 @@ def create_one_type(attrs=None, methods=None):
666698
"name": 'type-name-' + uuid.uuid4().hex,
667699
"description": 'type-description-' + uuid.uuid4().hex,
668700
"extra_specs": {"foo": "bar"},
701+
"is_public": True,
669702
}
670703

671704
# Overwrite default attributes.

openstackclient/tests/volume/v2/test_type.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#
1414

1515
import copy
16+
import mock
1617

1718
from osc_lib import exceptions
1819
from osc_lib import utils
@@ -46,6 +47,7 @@ class TestTypeCreate(TestType):
4647
columns = (
4748
'description',
4849
'id',
50+
'is_public',
4951
'name',
5052
)
5153

@@ -56,6 +58,7 @@ def setUp(self):
5658
self.data = (
5759
self.new_volume_type.description,
5860
self.new_volume_type.id,
61+
True,
5962
self.new_volume_type.name,
6063
)
6164

@@ -357,8 +360,10 @@ def test_type_set_project_access(self):
357360
class TestTypeShow(TestType):
358361

359362
columns = (
363+
'access_project_ids',
360364
'description',
361365
'id',
366+
'is_public',
362367
'name',
363368
'properties',
364369
)
@@ -368,8 +373,10 @@ def setUp(self):
368373

369374
self.volume_type = volume_fakes.FakeType.create_one_type()
370375
self.data = (
376+
None,
371377
self.volume_type.description,
372378
self.volume_type.id,
379+
True,
373380
self.volume_type.name,
374381
utils.format_dict(self.volume_type.extra_specs)
375382
)
@@ -394,6 +401,71 @@ def test_type_show(self):
394401
self.assertEqual(self.columns, columns)
395402
self.assertEqual(self.data, data)
396403

404+
def test_type_show_with_access(self):
405+
arglist = [
406+
self.volume_type.id
407+
]
408+
verifylist = [
409+
("volume_type", self.volume_type.id)
410+
]
411+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
412+
413+
private_type = volume_fakes.FakeType.create_one_type(
414+
attrs={'is_public': False})
415+
type_access_list = volume_fakes.FakeTypeAccess.create_one_type_access()
416+
with mock.patch.object(self.types_mock, 'get',
417+
return_value=private_type):
418+
with mock.patch.object(self.types_access_mock, 'list',
419+
return_value=[type_access_list]):
420+
columns, data = self.cmd.take_action(parsed_args)
421+
self.types_mock.get.assert_called_once_with(
422+
self.volume_type.id)
423+
self.types_access_mock.list.assert_called_once_with(
424+
private_type.id)
425+
426+
self.assertEqual(self.columns, columns)
427+
private_type_data = (
428+
utils.format_list([type_access_list.project_id]),
429+
private_type.description,
430+
private_type.id,
431+
private_type.is_public,
432+
private_type.name,
433+
utils.format_dict(private_type.extra_specs)
434+
)
435+
self.assertEqual(private_type_data, data)
436+
437+
def test_type_show_with_list_access_exec(self):
438+
arglist = [
439+
self.volume_type.id
440+
]
441+
verifylist = [
442+
("volume_type", self.volume_type.id)
443+
]
444+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
445+
446+
private_type = volume_fakes.FakeType.create_one_type(
447+
attrs={'is_public': False})
448+
with mock.patch.object(self.types_mock, 'get',
449+
return_value=private_type):
450+
with mock.patch.object(self.types_access_mock, 'list',
451+
side_effect=Exception()):
452+
columns, data = self.cmd.take_action(parsed_args)
453+
self.types_mock.get.assert_called_once_with(
454+
self.volume_type.id)
455+
self.types_access_mock.list.assert_called_once_with(
456+
private_type.id)
457+
458+
self.assertEqual(self.columns, columns)
459+
private_type_data = (
460+
None,
461+
private_type.description,
462+
private_type.id,
463+
private_type.is_public,
464+
private_type.name,
465+
utils.format_dict(private_type.extra_specs)
466+
)
467+
self.assertEqual(private_type_data, data)
468+
397469

398470
class TestTypeUnset(TestType):
399471

openstackclient/volume/v2/volume_type.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -282,8 +282,24 @@ def take_action(self, parsed_args):
282282
volume_client = self.app.client_manager.volume
283283
volume_type = utils.find_resource(
284284
volume_client.volume_types, parsed_args.volume_type)
285-
properties = utils.format_dict(volume_type._info.pop('extra_specs'))
285+
properties = utils.format_dict(
286+
volume_type._info.pop('extra_specs', {}))
286287
volume_type._info.update({'properties': properties})
288+
access_project_ids = None
289+
if not volume_type.is_public:
290+
try:
291+
volume_type_access = volume_client.volume_type_access.list(
292+
volume_type.id)
293+
project_ids = [utils.get_field(item, 'project_id')
294+
for item in volume_type_access]
295+
# TODO(Rui Chen): This format list case can be removed after
296+
# patch https://review.openstack.org/#/c/330223/ merged.
297+
access_project_ids = utils.format_list(project_ids)
298+
except Exception as e:
299+
msg = _('Failed to get access project list for volume type '
300+
'%(type)s: %(e)s')
301+
LOG.error(msg % {'type': volume_type.id, 'e': e})
302+
volume_type._info.update({'access_project_ids': access_project_ids})
287303
return zip(*sorted(six.iteritems(volume_type._info)))
288304

289305

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
features:
3+
- |
4+
Show project access details for private volume type.
5+
6+
An user can list projects which have access to
7+
a specific private volume type by using
8+
``volume type show <volume-type>``
9+
10+
[Bug `1554891 <https://bugs.launchpad.net/python-openstackclient/+bug/1554891>`_]

0 commit comments

Comments
 (0)