diff --git a/doc/source/cli/command-objects/image.rst b/doc/source/cli/command-objects/image.rst index e2257bbbba..f0b5bfaade 100644 --- a/doc/source/cli/command-objects/image.rst +++ b/doc/source/cli/command-objects/image.rst @@ -266,6 +266,22 @@ List available images *Image version 2 only* +image member list +----------------- + +List projects associated with image + +.. program:: image member list +.. code:: bash + + openstack image member list + + +.. _image_member_list-image: +.. describe:: + + Image(s) to view members for (name or ID) + image remove project -------------------- diff --git a/doc/source/cli/commands.rst b/doc/source/cli/commands.rst index d840549c3f..76126a7475 100644 --- a/doc/source/cli/commands.rst +++ b/doc/source/cli/commands.rst @@ -104,6 +104,7 @@ referring to both Compute and Volume quotas. * ``hypervisor stats``: (**Compute**) hypervisor statistics over all compute nodes * ``identity provider``: (**Identity**) a source of users and authentication * ``image``: (**Image**) a disk image +* ``image member``: (**Image**) a project that is a member of an Image * ``ip availability``: (**Network**) - details of IP usage of a network * ``ip fixed``: (**Compute**, **Network**) - an internal IP address assigned to a server * ``ip floating``: (**Compute**, **Network**) - a public IP address that can be mapped to a server diff --git a/openstackclient/image/v2/image.py b/openstackclient/image/v2/image.py index 7e6a7aa178..9407e665d2 100644 --- a/openstackclient/image/v2/image.py +++ b/openstackclient/image/v2/image.py @@ -592,6 +592,39 @@ class ListImage(command.Lister): ) +class ListImageProjects(command.Lister): + _description = _("List projects associated with image") + + def get_parser(self, prog_name): + parser = super(ListImageProjects, self).get_parser(prog_name) + parser.add_argument( + "image", + metavar="", + help=_("Image (name or ID)"), + ) + common.add_project_domain_option_to_parser(parser) + return parser + + def take_action(self, parsed_args): + image_client = self.app.client_manager.image + columns = ( + "Image ID", + "Member ID", + "Status" + ) + + image_id = utils.find_resource( + image_client.images, + parsed_args.image).id + + data = image_client.image_members.list(image_id) + + return (columns, + (utils.get_item_properties( + s, columns, + ) for s in data)) + + class RemoveProjectImage(command.Command): _description = _("Disassociate project with image") diff --git a/openstackclient/tests/unit/image/v2/test_image.py b/openstackclient/tests/unit/image/v2/test_image.py index e1a79d13ce..301cd0377e 100644 --- a/openstackclient/tests/unit/image/v2/test_image.py +++ b/openstackclient/tests/unit/image/v2/test_image.py @@ -780,6 +780,52 @@ class TestImageList(TestImage): ) +class TestListImageProjects(TestImage): + + project = identity_fakes.FakeProject.create_one_project() + _image = image_fakes.FakeImage.create_one_image() + member = image_fakes.FakeImage.create_one_image_member( + attrs={'image_id': _image.id, + 'member_id': project.id} + ) + + columns = ( + "Image ID", + "Member ID", + "Status" + ) + + datalist = (( + _image.id, + member.member_id, + member.status, + )) + + def setUp(self): + super(TestListImageProjects, self).setUp() + + self.images_mock.get.return_value = self._image + self.image_members_mock.list.return_value = self.datalist + + self.cmd = image.ListImageProjects(self.app, None) + + def test_image_member_list(self): + arglist = [ + self._image.id + ] + verifylist = [ + ('image', self._image.id) + ] + parsed_args = self.check_parser(self.cmd, arglist, verifylist) + + columns, data = self.cmd.take_action(parsed_args) + + self.image_members_mock.list.assert_called_with(self._image.id) + + self.assertEqual(self.columns, columns) + self.assertEqual(len(self.datalist), len(tuple(data))) + + class TestRemoveProjectImage(TestImage): project = identity_fakes.FakeProject.create_one_project() diff --git a/releasenotes/notes/add-image-member-list-1630ead5988348c2.yaml b/releasenotes/notes/add-image-member-list-1630ead5988348c2.yaml new file mode 100644 index 0000000000..f939a2fd86 --- /dev/null +++ b/releasenotes/notes/add-image-member-list-1630ead5988348c2.yaml @@ -0,0 +1,4 @@ +--- +features: + - The OpenStack client now has the ability to list all members of an image + in order to faciliate management of member projects for images. diff --git a/setup.cfg b/setup.cfg index b031cc5f6c..a78dc31b71 100644 --- a/setup.cfg +++ b/setup.cfg @@ -353,6 +353,7 @@ openstack.image.v2 = image_create = openstackclient.image.v2.image:CreateImage image_delete = openstackclient.image.v2.image:DeleteImage image_list = openstackclient.image.v2.image:ListImage + image_member_list = openstackclient.image.v2.image:ListImageProjects image_remove_project = openstackclient.image.v2.image:RemoveProjectImage image_save = openstackclient.image.v2.image:SaveImage image_show = openstackclient.image.v2.image:ShowImage