image: Add 'image task list' command
This replaces the 'glance task-list' command. $ openstack image task list We also indicate that the 'image task create' command will never be implemented. This is an admin-only API that isn't really intended to be used by humans thus it does not need an OSC command implementation. Change-Id: Id8a943a5443782fc70c0fbf3639f5aa17b9d30af
This commit is contained in:
parent
d163a20904
commit
c9d445fc4b
@ -53,8 +53,8 @@ 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.
|
||||
|
|
@ -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
|
||||
),
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user