Skip to content

Commit 46ead4a

Browse files
Zuulopenstack-gerrit
authored andcommitted
Merge "image: Add 'image task list' command"
2 parents 97af1b6 + c9d445f commit 46ead4a

6 files changed

Lines changed: 233 additions & 3 deletions

File tree

doc/source/cli/data/glance.csv

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ member-list,image member list,Describe sharing permissions by image.
5353
member-update,image set --accept --reject --status,Update the status of a member for a given image.
5454
stores-delete,,Delete image from specific store.
5555
stores-info,,Print available backends from Glance.
56-
task-create,,Create a new task.
57-
task-list,,List tasks you can access.
56+
task-create,WONTFIX,Create a new task.
57+
task-list,image task list,List tasks you can access.
5858
task-show,image task show,Describe a specific task.
5959
bash-completion,complete,Prints arguments for bash_completion.
6060
help,help,Display help about this program or one of its subcommands.

openstackclient/image/v2/task.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,14 @@
1212

1313
from osc_lib.cli import format_columns
1414
from osc_lib.command import command
15+
from osc_lib import utils
1516

1617
from openstackclient.i18n import _
1718

19+
_formatters = {
20+
'tags': format_columns.ListColumn,
21+
}
22+
1823

1924
def _format_task(task):
2025
"""Format an task to make it more consistent with OSC operations."""
@@ -76,3 +81,99 @@ def take_action(self, parsed_args):
7681
info = _format_task(task)
7782

7883
return zip(*sorted(info.items()))
84+
85+
86+
class ListTask(command.Lister):
87+
_description = _('List tasks')
88+
89+
def get_parser(self, prog_name):
90+
parser = super().get_parser(prog_name)
91+
92+
parser.add_argument(
93+
'--sort-key',
94+
metavar='<key>[:<field>]',
95+
help=_(
96+
'Sorts the response by one of the following attributes: '
97+
'created_at, expires_at, id, status, type, updated_at. '
98+
'(default is created_at) '
99+
'(multiple keys and directions can be specified separated '
100+
'by comma)'
101+
),
102+
)
103+
parser.add_argument(
104+
'--sort-dir',
105+
metavar='<key>[:<direction>]',
106+
help=_(
107+
'Sort output by selected keys and directions (asc or desc) '
108+
'(default: name:desc) '
109+
'(multiple keys and directions can be specified separated '
110+
'by comma)'
111+
),
112+
)
113+
parser.add_argument(
114+
'--limit',
115+
metavar='<num-tasks>',
116+
type=int,
117+
help=_('Maximum number of tasks to display.'),
118+
)
119+
parser.add_argument(
120+
'--marker',
121+
metavar='<task>',
122+
help=_(
123+
'The last task of the previous page. '
124+
'Display list of tasks after marker. '
125+
'Display all tasks if not specified. '
126+
'(name or ID)'
127+
),
128+
)
129+
parser.add_argument(
130+
'--type',
131+
metavar='<type>',
132+
choices=['import'],
133+
help=_('Filters the response by a task type.'),
134+
)
135+
parser.add_argument(
136+
'--status',
137+
metavar='<status>',
138+
choices=[
139+
'pending',
140+
'processing',
141+
'success',
142+
'failure',
143+
],
144+
help=_('Filter tasks based on status.'),
145+
)
146+
147+
return parser
148+
149+
def take_action(self, parsed_args):
150+
image_client = self.app.client_manager.image
151+
152+
columns = ('id', 'type', 'status', 'owner_id')
153+
column_headers = ('ID', 'Type', 'Status', 'Owner')
154+
155+
kwargs = {}
156+
copy_attrs = {
157+
'sort_key',
158+
'sort_dir',
159+
'limit',
160+
'marker',
161+
'type',
162+
'status',
163+
}
164+
for attr in copy_attrs:
165+
val = getattr(parsed_args, attr, None)
166+
if val is not None:
167+
# Only include a value in kwargs for attributes that are
168+
# actually present on the command line
169+
kwargs[attr] = val
170+
171+
data = image_client.tasks(**kwargs)
172+
173+
return (
174+
column_headers,
175+
(
176+
utils.get_item_properties(s, columns, formatters=_formatters)
177+
for s in data
178+
),
179+
)

openstackclient/tests/unit/image/v2/fakes.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ def __init__(self, **kwargs):
5252
self.management_url = kwargs['endpoint']
5353
self.version = 2.0
5454

55+
self.tasks = mock.Mock()
56+
self.tasks.resource_class = fakes.FakeResource(None, {})
57+
5558

5659
class TestImagev2(utils.TestCommand):
5760

@@ -176,10 +179,26 @@ def create_one_task(attrs=None):
176179
# https://github.com/openstack/glance/blob/24.0.0/glance/api/v2/tasks.py#L186-L190
177180
'type': 'import',
178181
'updated_at': '2016-06-29T16:13:07Z',
179-
180182
}
181183

182184
# Overwrite default attributes if there are some attributes set
183185
task_info.update(attrs)
184186

185187
return task.Task(**task_info)
188+
189+
190+
def create_tasks(attrs=None, count=2):
191+
"""Create multiple fake tasks.
192+
193+
:param attrs: A dictionary with all attributes of Task
194+
:type attrs: dict
195+
:param count: The number of tasks to be faked
196+
:type count: int
197+
:return: A list of fake Task objects
198+
:rtype: list
199+
"""
200+
tasks = []
201+
for n in range(0, count):
202+
tasks.append(create_one_task(attrs))
203+
204+
return tasks

openstackclient/tests/unit/image/v2/test_task.py

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,110 @@ def test_task_show(self):
7878

7979
self.assertEqual(self.columns, columns)
8080
self.assertCountEqual(self.data, data)
81+
82+
83+
class TestTaskList(TestTask):
84+
85+
tasks = image_fakes.create_tasks()
86+
87+
columns = (
88+
'ID',
89+
'Type',
90+
'Status',
91+
'Owner',
92+
)
93+
datalist = [
94+
(
95+
task.id,
96+
task.type,
97+
task.status,
98+
task.owner_id,
99+
)
100+
for task in tasks
101+
]
102+
103+
def setUp(self):
104+
super().setUp()
105+
106+
self.client.tasks.side_effect = [self.tasks, []]
107+
108+
# Get the command object to test
109+
self.cmd = task.ListTask(self.app, None)
110+
111+
def test_task_list_no_options(self):
112+
arglist = []
113+
verifylist = [
114+
('sort_key', None),
115+
('sort_dir', None),
116+
('limit', None),
117+
('marker', None),
118+
('type', None),
119+
('status', None),
120+
]
121+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
122+
123+
columns, data = self.cmd.take_action(parsed_args)
124+
125+
self.client.tasks.assert_called_with()
126+
127+
self.assertEqual(self.columns, columns)
128+
self.assertCountEqual(self.datalist, data)
129+
130+
def test_task_list_sort_key_option(self):
131+
arglist = ['--sort-key', 'created_at']
132+
verifylist = [('sort_key', 'created_at')]
133+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
134+
135+
columns, data = self.cmd.take_action(parsed_args)
136+
137+
self.client.tasks.assert_called_with(
138+
sort_key=parsed_args.sort_key,
139+
)
140+
141+
self.assertEqual(self.columns, columns)
142+
self.assertCountEqual(self.datalist, data)
143+
144+
def test_task_list_sort_dir_option(self):
145+
arglist = ['--sort-dir', 'desc']
146+
verifylist = [('sort_dir', 'desc')]
147+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
148+
149+
self.cmd.take_action(parsed_args)
150+
151+
self.client.tasks.assert_called_with(
152+
sort_dir=parsed_args.sort_dir,
153+
)
154+
155+
def test_task_list_pagination_options(self):
156+
arglist = ['--limit', '1', '--marker', self.tasks[0].id]
157+
verifylist = [('limit', 1), ('marker', self.tasks[0].id)]
158+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
159+
160+
self.cmd.take_action(parsed_args)
161+
162+
self.client.tasks.assert_called_with(
163+
limit=parsed_args.limit,
164+
marker=parsed_args.marker,
165+
)
166+
167+
def test_task_list_type_option(self):
168+
arglist = ['--type', self.tasks[0].type]
169+
verifylist = [('type', self.tasks[0].type)]
170+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
171+
172+
self.cmd.take_action(parsed_args)
173+
174+
self.client.tasks.assert_called_with(
175+
type=self.tasks[0].type,
176+
)
177+
178+
def test_task_list_status_option(self):
179+
arglist = ['--status', self.tasks[0].status]
180+
verifylist = [('status', self.tasks[0].status)]
181+
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
182+
183+
self.cmd.take_action(parsed_args)
184+
185+
self.client.tasks.assert_called_with(
186+
status=self.tasks[0].status,
187+
)

releasenotes/notes/add-image-task-commands-50c3643ebfd0421f.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,5 @@
22
features:
33
- |
44
Add ``image task show`` command to show a task for the image service.
5+
- |
6+
Add ``image task list`` command to list tasks for the image service.

setup.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,7 @@ openstack.image.v2 =
383383
image_set = openstackclient.image.v2.image:SetImage
384384
image_unset = openstackclient.image.v2.image:UnsetImage
385385
image_task_show = openstackclient.image.v2.task:ShowTask
386+
image_task_list = openstackclient.image.v2.task:ListTask
386387

387388
openstack.network.v2 =
388389
address_group_create = openstackclient.network.v2.address_group:CreateAddressGroup

0 commit comments

Comments
 (0)