Merge "image: Add 'image task show' commands"

This commit is contained in:
Zuul 2022-09-30 11:59:18 +00:00 committed by Gerrit Code Review
commit 97af1b661e
6 changed files with 218 additions and 1 deletions
doc/source/cli/data
openstackclient
image/v2
tests/unit/image/v2
releasenotes/notes
setup.cfg

@ -55,6 +55,6 @@ stores-delete,,Delete image from specific store.
stores-info,,Print available backends from Glance. stores-info,,Print available backends from Glance.
task-create,,Create a new task. task-create,,Create a new task.
task-list,,List tasks you can access. task-list,,List tasks you can access.
task-show,,Describe a specific task. task-show,image task show,Describe a specific task.
bash-completion,complete,Prints arguments for bash_completion. bash-completion,complete,Prints arguments for bash_completion.
help,help,Display help about this program or one of its subcommands. help,help,Display help about this program or one of its subcommands.

1 explain WONTFIX Describe a specific model.
55 stores-info Print available backends from Glance.
56 task-create Create a new task.
57 task-list List tasks you can access.
58 task-show image task show Describe a specific task.
59 bash-completion complete Prints arguments for bash_completion.
60 help help Display help about this program or one of its subcommands.

@ -0,0 +1,78 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from osc_lib.cli import format_columns
from osc_lib.command import command
from openstackclient.i18n import _
def _format_task(task):
"""Format an task to make it more consistent with OSC operations."""
info = {}
properties = {}
# the only fields we're not including is "links", "tags" and the properties
fields_to_show = [
'created_at',
'expires_at',
'id',
'input',
'message',
'owner_id',
'result',
'status',
'type',
'updated_at',
]
# split out the usual key and the properties which are top-level
for field in fields_to_show:
info[field] = task.get(field)
for key in task:
if key in fields_to_show:
continue
if key in {'location', 'name', 'schema'}:
continue
properties[key] = task.get(key)
# add properties back into the dictionary as a top-level key
info['properties'] = format_columns.DictColumn(properties)
return info
class ShowTask(command.ShowOne):
_description = _('Display task details')
def get_parser(self, prog_name):
parser = super(ShowTask, self).get_parser(prog_name)
parser.add_argument(
'task',
metavar='<Task ID>',
help=_('Task to display (ID)'),
)
return parser
def take_action(self, parsed_args):
image_client = self.app.client_manager.image
task = image_client.get_task(parsed_args.task)
info = _format_task(task)
return zip(*sorted(info.items()))

@ -18,6 +18,7 @@ import uuid
from openstack.image.v2 import image from openstack.image.v2 import image
from openstack.image.v2 import member from openstack.image.v2 import member
from openstack.image.v2 import task
from openstackclient.tests.unit import fakes from openstackclient.tests.unit import fakes
from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes from openstackclient.tests.unit.identity.v3 import fakes as identity_fakes
@ -44,6 +45,9 @@ class FakeImagev2Client:
self.remove_tag = mock.Mock() self.remove_tag = mock.Mock()
self.tasks = mock.Mock()
self.get_task = mock.Mock()
self.auth_token = kwargs['token'] self.auth_token = kwargs['token']
self.management_url = kwargs['endpoint'] self.management_url = kwargs['endpoint']
self.version = 2.0 self.version = 2.0
@ -129,3 +133,53 @@ def create_one_image_member(attrs=None):
image_member_info.update(attrs) image_member_info.update(attrs)
return member.Member(**image_member_info) return member.Member(**image_member_info)
def create_one_task(attrs=None):
"""Create a fake task.
:param attrs: A dictionary with all attributes of task
:type attrs: dict
:return: A fake Task object.
:rtype: `openstack.image.v2.task.Task`
"""
attrs = attrs or {}
# Set default attribute
task_info = {
'created_at': '2016-06-29T16:13:07Z',
'expires_at': '2016-07-01T16:13:07Z',
'id': str(uuid.uuid4()),
'input': {
'image_properties': {
'container_format': 'ovf',
'disk_format': 'vhd'
},
'import_from': 'https://apps.openstack.org/excellent-image',
'import_from_format': 'qcow2'
},
'message': '',
'owner': str(uuid.uuid4()),
'result': {
'image_id': str(uuid.uuid4()),
},
'schema': '/v2/schemas/task',
'status': random.choice(
[
'pending',
'processing',
'success',
'failure',
]
),
# though not documented, the API only allows 'import'
# 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)

@ -0,0 +1,80 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from osc_lib.cli import format_columns
from openstackclient.image.v2 import task
from openstackclient.tests.unit.image.v2 import fakes as image_fakes
class TestTask(image_fakes.TestImagev2):
def setUp(self):
super().setUp()
# Get shortcuts to mocked image client
self.client = self.app.client_manager.image
class TestTaskShow(TestTask):
task = image_fakes.create_one_task()
columns = (
'created_at',
'expires_at',
'id',
'input',
'message',
'owner_id',
'properties',
'result',
'status',
'type',
'updated_at',
)
data = (
task.created_at,
task.expires_at,
task.id,
task.input,
task.message,
task.owner_id,
format_columns.DictColumn({}),
task.result,
task.status,
task.type,
task.updated_at,
)
def setUp(self):
super().setUp()
self.client.get_task.return_value = self.task
# Get the command object to test
self.cmd = task.ShowTask(self.app, None)
def test_task_show(self):
arglist = [self.task.id]
verifylist = [
('task', self.task.id),
]
parsed_args = self.check_parser(self.cmd, arglist, verifylist)
# In base command class ShowOne in cliff, abstract method take_action()
# returns a two-part tuple with a tuple of column names and a tuple of
# data to be shown.
columns, data = self.cmd.take_action(parsed_args)
self.client.get_task.assert_called_with(self.task.id)
self.assertEqual(self.columns, columns)
self.assertCountEqual(self.data, data)

@ -0,0 +1,4 @@
---
features:
- |
Add ``image task show`` command to show a task for the image service.

@ -382,6 +382,7 @@ openstack.image.v2 =
image_show = openstackclient.image.v2.image:ShowImage image_show = openstackclient.image.v2.image:ShowImage
image_set = openstackclient.image.v2.image:SetImage image_set = openstackclient.image.v2.image:SetImage
image_unset = openstackclient.image.v2.image:UnsetImage image_unset = openstackclient.image.v2.image:UnsetImage
image_task_show = openstackclient.image.v2.task:ShowTask
openstack.network.v2 = openstack.network.v2 =
address_group_create = openstackclient.network.v2.address_group:CreateAddressGroup address_group_create = openstackclient.network.v2.address_group:CreateAddressGroup