summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/source/cli/command-objects/image.rst16
-rw-r--r--doc/source/cli/commands.rst1
-rw-r--r--openstackclient/image/v2/image.py33
-rw-r--r--openstackclient/tests/unit/image/v2/test_image.py46
-rw-r--r--releasenotes/notes/add-image-member-list-1630ead5988348c2.yaml4
-rw-r--r--setup.cfg1
6 files changed, 101 insertions, 0 deletions
diff --git a/doc/source/cli/command-objects/image.rst b/doc/source/cli/command-objects/image.rst
index e2257bbb..f0b5bfaa 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>
+
+.. _image_member_list-image:
+.. describe:: <image>
+
+ 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 d840549c..76126a74 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 ddcee4ad..4a51062f 100644
--- a/openstackclient/image/v2/image.py
+++ b/openstackclient/image/v2/image.py
@@ -591,6 +591,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="<image>",
+ 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 e1a79d13..301cd037 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 00000000..f939a2fd
--- /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 b031cc5f..a78dc31b 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