summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZuul <zuul@review.opendev.org>2022-09-30 11:59:21 +0000
committerGerrit Code Review <review@openstack.org>2022-09-30 11:59:21 +0000
commit46ead4abea4296a86e862fc035811eba2c7efac4 (patch)
treed214f5a92c829b78ec7ab8bc8eaf62b79282c067
parent97af1b661e96f2d6359898f7959a7bfd78657953 (diff)
parentc9d445fc4baf036793103b15c9eb2632da3610e0 (diff)
downloadpython-openstackclient-46ead4abea4296a86e862fc035811eba2c7efac4.tar.gz
Merge "image: Add 'image task list' command"
-rw-r--r--doc/source/cli/data/glance.csv4
-rw-r--r--openstackclient/image/v2/task.py101
-rw-r--r--openstackclient/tests/unit/image/v2/fakes.py21
-rw-r--r--openstackclient/tests/unit/image/v2/test_task.py107
-rw-r--r--releasenotes/notes/add-image-task-commands-50c3643ebfd0421f.yaml2
-rw-r--r--setup.cfg1
6 files changed, 233 insertions, 3 deletions
diff --git a/doc/source/cli/data/glance.csv b/doc/source/cli/data/glance.csv
index 90625a6f..12b6851d 100644
--- a/doc/source/cli/data/glance.csv
+++ b/doc/source/cli/data/glance.csv
@@ -53,8 +53,8 @@ member-list,image member list,Describe sharing permissions by image.
member-update,image set --accept --reject --status,Update the status of a member for a given image.
stores-delete,,Delete image from specific store.
stores-info,,Print available backends from Glance.
-task-create,,Create a new task.
-task-list,,List tasks you can access.
+task-create,WONTFIX,Create a new task.
+task-list,image task list,List tasks you can access.
task-show,image task show,Describe a specific task.
bash-completion,complete,Prints arguments for bash_completion.
help,help,Display help about this program or one of its subcommands.
diff --git a/openstackclient/image/v2/task.py b/openstackclient/image/v2/task.py
index 5f0c4ed5..924eaaf1 100644
--- a/openstackclient/image/v2/task.py
+++ b/openstackclient/image/v2/task.py
@@ -12,9 +12,14 @@
from osc_lib.cli import format_columns
from osc_lib.command import command
+from osc_lib import utils
from openstackclient.i18n import _
+_formatters = {
+ 'tags': format_columns.ListColumn,
+}
+
def _format_task(task):
"""Format an task to make it more consistent with OSC operations."""
@@ -76,3 +81,99 @@ class ShowTask(command.ShowOne):
info = _format_task(task)
return zip(*sorted(info.items()))
+
+
+class ListTask(command.Lister):
+ _description = _('List tasks')
+
+ def get_parser(self, prog_name):
+ parser = super().get_parser(prog_name)
+
+ parser.add_argument(
+ '--sort-key',
+ metavar='<key>[:<field>]',
+ help=_(
+ 'Sorts the response by one of the following attributes: '
+ 'created_at, expires_at, id, status, type, updated_at. '
+ '(default is created_at) '
+ '(multiple keys and directions can be specified separated '
+ 'by comma)'
+ ),
+ )
+ parser.add_argument(
+ '--sort-dir',
+ metavar='<key>[:<direction>]',
+ help=_(
+ 'Sort output by selected keys and directions (asc or desc) '
+ '(default: name:desc) '
+ '(multiple keys and directions can be specified separated '
+ 'by comma)'
+ ),
+ )
+ parser.add_argument(
+ '--limit',
+ metavar='<num-tasks>',
+ type=int,
+ help=_('Maximum number of tasks to display.'),
+ )
+ parser.add_argument(
+ '--marker',
+ metavar='<task>',
+ help=_(
+ 'The last task of the previous page. '
+ 'Display list of tasks after marker. '
+ 'Display all tasks if not specified. '
+ '(name or ID)'
+ ),
+ )
+ parser.add_argument(
+ '--type',
+ metavar='<type>',
+ choices=['import'],
+ help=_('Filters the response by a task type.'),
+ )
+ parser.add_argument(
+ '--status',
+ metavar='<status>',
+ choices=[
+ 'pending',
+ 'processing',
+ 'success',
+ 'failure',
+ ],
+ help=_('Filter tasks based on status.'),
+ )
+
+ return parser
+
+ def take_action(self, parsed_args):
+ image_client = self.app.client_manager.image
+
+ columns = ('id', 'type', 'status', 'owner_id')
+ column_headers = ('ID', 'Type', 'Status', 'Owner')
+
+ kwargs = {}
+ copy_attrs = {
+ 'sort_key',
+ 'sort_dir',
+ 'limit',
+ 'marker',
+ 'type',
+ 'status',
+ }
+ for attr in copy_attrs:
+ val = getattr(parsed_args, attr, None)
+ if val is not None:
+ # Only include a value in kwargs for attributes that are
+ # actually present on the command line
+ kwargs[attr] = val
+
+ data = image_client.tasks(**kwargs)
+
+ return (
+ column_headers,
+ (
+ utils.get_item_properties(s, columns, formatters=_formatters)
+ for s in data
+ ),
+ )
diff --git a/openstackclient/tests/unit/image/v2/fakes.py b/openstackclient/tests/unit/image/v2/fakes.py
index 2decd122..f2015450 100644
--- a/openstackclient/tests/unit/image/v2/fakes.py
+++ b/openstackclient/tests/unit/image/v2/fakes.py
@@ -52,6 +52,9 @@ class FakeImagev2Client:
self.management_url = kwargs['endpoint']
self.version = 2.0
+ self.tasks = mock.Mock()
+ self.tasks.resource_class = fakes.FakeResource(None, {})
+
class TestImagev2(utils.TestCommand):
@@ -176,10 +179,26 @@ def create_one_task(attrs=None):
# https://github.com/openstack/glance/blob/24.0.0/glance/api/v2/tasks.py#L186-L190
'type': 'import',
'updated_at': '2016-06-29T16:13:07Z',
-
}
# Overwrite default attributes if there are some attributes set
task_info.update(attrs)
return task.Task(**task_info)
+
+
+def create_tasks(attrs=None, count=2):
+ """Create multiple fake tasks.
+
+ :param attrs: A dictionary with all attributes of Task
+ :type attrs: dict
+ :param count: The number of tasks to be faked
+ :type count: int
+ :return: A list of fake Task objects
+ :rtype: list
+ """
+ tasks = []
+ for n in range(0, count):
+ tasks.append(create_one_task(attrs))
+
+ return tasks
diff --git a/openstackclient/tests/unit/image/v2/test_task.py b/openstackclient/tests/unit/image/v2/test_task.py
index 90fa11d8..e077e2b1 100644
--- a/openstackclient/tests/unit/image/v2/test_task.py
+++ b/openstackclient/tests/unit/image/v2/test_task.py
@@ -78,3 +78,110 @@ class TestTaskShow(TestTask):
self.assertEqual(self.columns, columns)
self.assertCountEqual(self.data, data)
+
+
+class TestTaskList(TestTask):
+
+ tasks = image_fakes.create_tasks()
+
+ columns = (
+ 'ID',
+ 'Type',
+ 'Status',
+ 'Owner',
+ )
+ datalist = [
+ (
+ task.id,
+ task.type,
+ task.status,
+ task.owner_id,
+ )
+ for task in tasks
+ ]
+
+ def setUp(self):
+ super().setUp()
+
+ self.client.tasks.side_effect = [self.tasks, []]
+
+ # Get the command object to test
+ self.cmd = task.ListTask(self.app, None)
+
+ def test_task_list_no_options(self):
+ arglist = []
+ verifylist = [
+ ('sort_key', None),
+ ('sort_dir', None),
+ ('limit', None),
+ ('marker', None),
+ ('type', None),
+ ('status', None),
+ ]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.client.tasks.assert_called_with()
+
+ self.assertEqual(self.columns, columns)
+ self.assertCountEqual(self.datalist, data)
+
+ def test_task_list_sort_key_option(self):
+ arglist = ['--sort-key', 'created_at']
+ verifylist = [('sort_key', 'created_at')]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ columns, data = self.cmd.take_action(parsed_args)
+
+ self.client.tasks.assert_called_with(
+ sort_key=parsed_args.sort_key,
+ )
+
+ self.assertEqual(self.columns, columns)
+ self.assertCountEqual(self.datalist, data)
+
+ def test_task_list_sort_dir_option(self):
+ arglist = ['--sort-dir', 'desc']
+ verifylist = [('sort_dir', 'desc')]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.client.tasks.assert_called_with(
+ sort_dir=parsed_args.sort_dir,
+ )
+
+ def test_task_list_pagination_options(self):
+ arglist = ['--limit', '1', '--marker', self.tasks[0].id]
+ verifylist = [('limit', 1), ('marker', self.tasks[0].id)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.client.tasks.assert_called_with(
+ limit=parsed_args.limit,
+ marker=parsed_args.marker,
+ )
+
+ def test_task_list_type_option(self):
+ arglist = ['--type', self.tasks[0].type]
+ verifylist = [('type', self.tasks[0].type)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.client.tasks.assert_called_with(
+ type=self.tasks[0].type,
+ )
+
+ def test_task_list_status_option(self):
+ arglist = ['--status', self.tasks[0].status]
+ verifylist = [('status', self.tasks[0].status)]
+ parsed_args = self.check_parser(self.cmd, arglist, verifylist)
+
+ self.cmd.take_action(parsed_args)
+
+ self.client.tasks.assert_called_with(
+ status=self.tasks[0].status,
+ )
diff --git a/releasenotes/notes/add-image-task-commands-50c3643ebfd0421f.yaml b/releasenotes/notes/add-image-task-commands-50c3643ebfd0421f.yaml
index 927f6a80..1e441979 100644
--- a/releasenotes/notes/add-image-task-commands-50c3643ebfd0421f.yaml
+++ b/releasenotes/notes/add-image-task-commands-50c3643ebfd0421f.yaml
@@ -2,3 +2,5 @@
features:
- |
Add ``image task show`` command to show a task for the image service.
+ - |
+ Add ``image task list`` command to list tasks for the image service.
diff --git a/setup.cfg b/setup.cfg
index 1d00ec33..fd43d1ab 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -383,6 +383,7 @@ openstack.image.v2 =
image_set = openstackclient.image.v2.image:SetImage
image_unset = openstackclient.image.v2.image:UnsetImage
image_task_show = openstackclient.image.v2.task:ShowTask
+ image_task_list = openstackclient.image.v2.task:ListTask
openstack.network.v2 =
address_group_create = openstackclient.network.v2.address_group:CreateAddressGroup