Add Support for showing flavor access list

Add a attribute "access_project_id" for flavor object to
display the access project id list by using "flavor show"
command.

Change-Id: I7f0c152b816e0ca2e32e47f9b5c1aa7663d33b6d
Closes-Bug:#1575461
This commit is contained in:
Huanxuan Ao 2016-07-07 21:27:22 +08:00
parent 55c1c575d6
commit b0c317ebdd
4 changed files with 98 additions and 1 deletions

View File

@ -380,7 +380,27 @@ class ShowFlavor(command.ShowOne):
def take_action(self, parsed_args): def take_action(self, parsed_args):
compute_client = self.app.client_manager.compute compute_client = self.app.client_manager.compute
resource_flavor = _find_flavor(compute_client, parsed_args.flavor) resource_flavor = _find_flavor(compute_client, parsed_args.flavor)
access_projects = None
# get access projects list of this flavor
if not resource_flavor.is_public:
try:
flavor_access = compute_client.flavor_access.list(
flavor=resource_flavor.id)
projects = [utils.get_field(access, 'tenant_id')
for access in flavor_access]
# TODO(Huanxuan Ao): This format case can be removed after
# patch https://review.openstack.org/#/c/330223/ merged.
access_projects = utils.format_list(projects)
except Exception as e:
msg = _("Failed to get access projects list "
"for flavor '%(flavor)s': %(e)s")
LOG.error(msg % {'flavor': parsed_args.flavor, 'e': e})
flavor = resource_flavor._info.copy() flavor = resource_flavor._info.copy()
flavor.update({
'access_project_ids': access_projects
})
flavor.pop("links", None) flavor.pop("links", None)
flavor['properties'] = utils.format_dict(resource_flavor.get_keys()) flavor['properties'] = utils.format_dict(resource_flavor.get_keys())

View File

@ -787,6 +787,35 @@ class FakeFlavor(object):
return mock.MagicMock(side_effect=flavors) return mock.MagicMock(side_effect=flavors)
class FakeFlavorAccess(object):
"""Fake one or more flavor accesses."""
@staticmethod
def create_one_flavor_access(attrs=None):
"""Create a fake flavor access.
:param Dictionary attrs:
A dictionary with all attributes
:return:
A FakeResource object, with flavor_id, tenat_id
"""
attrs = attrs or {}
# Set default attributes.
flavor_access_info = {
'flavor_id': 'flavor-id-' + uuid.uuid4().hex,
'tenant_id': 'tenant-id-' + uuid.uuid4().hex,
}
# Overwrite default attributes.
flavor_access_info.update(attrs)
flavor_access = fakes.FakeResource(
info=copy.deepcopy(flavor_access_info), loaded=True)
return flavor_access
class FakeKeypair(object): class FakeKeypair(object):
"""Fake one or more keypairs.""" """Fake one or more keypairs."""

View File

@ -619,11 +619,13 @@ class TestFlavorSet(TestFlavor):
class TestFlavorShow(TestFlavor): class TestFlavorShow(TestFlavor):
# Return value of self.flavors_mock.find(). # Return value of self.flavors_mock.find().
flavor_access = compute_fakes.FakeFlavorAccess.create_one_flavor_access()
flavor = compute_fakes.FakeFlavor.create_one_flavor() flavor = compute_fakes.FakeFlavor.create_one_flavor()
columns = ( columns = (
'OS-FLV-DISABLED:disabled', 'OS-FLV-DISABLED:disabled',
'OS-FLV-EXT-DATA:ephemeral', 'OS-FLV-EXT-DATA:ephemeral',
'access_project_ids',
'disk', 'disk',
'id', 'id',
'name', 'name',
@ -638,6 +640,7 @@ class TestFlavorShow(TestFlavor):
data = ( data = (
flavor.disabled, flavor.disabled,
flavor.ephemeral, flavor.ephemeral,
None,
flavor.disk, flavor.disk,
flavor.id, flavor.id,
flavor.name, flavor.name,
@ -655,6 +658,7 @@ class TestFlavorShow(TestFlavor):
# Return value of _find_resource() # Return value of _find_resource()
self.flavors_mock.find.return_value = self.flavor self.flavors_mock.find.return_value = self.flavor
self.flavors_mock.get.side_effect = exceptions.NotFound(None) self.flavors_mock.get.side_effect = exceptions.NotFound(None)
self.flavor_access_mock.list.return_value = [self.flavor_access]
self.cmd = flavor.ShowFlavor(self.app, None) self.cmd = flavor.ShowFlavor(self.app, None)
def test_show_no_options(self): def test_show_no_options(self):
@ -665,7 +669,7 @@ class TestFlavorShow(TestFlavor):
self.assertRaises(tests_utils.ParserException, self.check_parser, self.assertRaises(tests_utils.ParserException, self.check_parser,
self.cmd, arglist, verifylist) self.cmd, arglist, verifylist)
def test_flavor_show(self): def test_public_flavor_show(self):
arglist = [ arglist = [
self.flavor.name, self.flavor.name,
] ]
@ -680,6 +684,45 @@ class TestFlavorShow(TestFlavor):
self.assertEqual(self.columns, columns) self.assertEqual(self.columns, columns)
self.assertEqual(self.data, data) self.assertEqual(self.data, data)
def test_private_flavor_show(self):
private_flavor = compute_fakes.FakeFlavor.create_one_flavor(
attrs={
'os-flavor-access:is_public': False,
}
)
self.flavors_mock.find.return_value = private_flavor
arglist = [
private_flavor.name,
]
verifylist = [
('flavor', private_flavor.name),
]
data_with_project = (
private_flavor.disabled,
private_flavor.ephemeral,
self.flavor_access.tenant_id,
private_flavor.disk,
private_flavor.id,
private_flavor.name,
private_flavor.is_public,
utils.format_dict(private_flavor.get_keys()),
private_flavor.ram,
private_flavor.rxtx_factor,
private_flavor.swap,
private_flavor.vcpus,
)
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
columns, data = self.cmd.take_action(parsed_args)
self.flavor_access_mock.list.assert_called_with(
flavor=private_flavor.id)
self.assertEqual(self.columns, columns)
self.assertEqual(data_with_project, data)
class TestFlavorUnset(TestFlavor): class TestFlavorUnset(TestFlavor):

View File

@ -0,0 +1,5 @@
---
features:
- |
Add support for showing flavor access list by using ``flavor show`` command.
[Bug `1575461 <https://bugs.launchpad.net/bugs/1575461>`_]