Microversion 2.58 - Instance actions list pagination
Add optional parameters 'limit', 'marker' and 'changes-since' to the os-instance-actions endpoints for pagination. Implement: blueprint pagination-add-changes-since-for-instance-action-list Change-Id: Ie66d9b00c90236fdcc01aed7649dc7f163aa323e
This commit is contained in:
parent
038cfdd5b3
commit
8d80a5e099
@ -25,4 +25,4 @@ API_MIN_VERSION = api_versions.APIVersion("2.1")
|
|||||||
# when client supported the max version, and bumped sequentially, otherwise
|
# when client supported the max version, and bumped sequentially, otherwise
|
||||||
# the client may break due to server side new version may include some
|
# the client may break due to server side new version may include some
|
||||||
# backward incompatible change.
|
# backward incompatible change.
|
||||||
API_MAX_VERSION = api_versions.APIVersion("2.57")
|
API_MAX_VERSION = api_versions.APIVersion("2.58")
|
||||||
|
@ -10,6 +10,9 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
import time
|
||||||
|
|
||||||
|
from oslo_utils import timeutils
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
import six
|
import six
|
||||||
from tempest.lib import exceptions
|
from tempest.lib import exceptions
|
||||||
@ -57,3 +60,56 @@ class TestInstanceActionCLI(base.ClientTestBase):
|
|||||||
# ensure that obtained action is "create".
|
# ensure that obtained action is "create".
|
||||||
self.assertEqual("create",
|
self.assertEqual("create",
|
||||||
self._get_value_from_the_table(output, "action"))
|
self._get_value_from_the_table(output, "action"))
|
||||||
|
|
||||||
|
|
||||||
|
class TestInstanceActionCLIV258(TestInstanceActionCLI):
|
||||||
|
"""Instance action functional tests for v2.58 nova-api microversion."""
|
||||||
|
|
||||||
|
COMPUTE_API_VERSION = "2.58"
|
||||||
|
|
||||||
|
def test_list_instance_action_with_marker_and_limit(self):
|
||||||
|
server = self._create_server()
|
||||||
|
server.stop()
|
||||||
|
# The actions are sorted by created_at in descending order,
|
||||||
|
# and now we have two actions: create and stop.
|
||||||
|
output = self.nova("instance-action-list %s --limit 1" % server.id)
|
||||||
|
marker_req = self._get_column_value_from_single_row_table(
|
||||||
|
output, "Request_ID")
|
||||||
|
action = self._get_list_of_values_from_single_column_table(
|
||||||
|
output, "Action")
|
||||||
|
# The stop action was most recently created so it's what
|
||||||
|
# we get back when limit=1.
|
||||||
|
self.assertEqual(action, ['stop'])
|
||||||
|
|
||||||
|
output = self.nova("instance-action-list %s --limit 1 "
|
||||||
|
"--marker %s" % (server.id, marker_req))
|
||||||
|
action = self._get_list_of_values_from_single_column_table(
|
||||||
|
output, "Action")
|
||||||
|
self.assertEqual(action, ['create'])
|
||||||
|
|
||||||
|
def test_list_instance_action_with_changes_since(self):
|
||||||
|
# Ignore microseconds to make this a deterministic test.
|
||||||
|
before_create = timeutils.utcnow().replace(microsecond=0).isoformat()
|
||||||
|
server = self._create_server()
|
||||||
|
time.sleep(2)
|
||||||
|
before_stop = timeutils.utcnow().replace(microsecond=0).isoformat()
|
||||||
|
server.stop()
|
||||||
|
|
||||||
|
create_output = self.nova(
|
||||||
|
"instance-action-list %s --changes-since %s" %
|
||||||
|
(server.id, before_create))
|
||||||
|
action = self._get_list_of_values_from_single_column_table(
|
||||||
|
create_output, "Action")
|
||||||
|
# The actions are sorted by created_at in descending order.
|
||||||
|
self.assertEqual(action, ['create', 'stop'])
|
||||||
|
|
||||||
|
stop_output = self.nova("instance-action-list %s --changes-since %s" %
|
||||||
|
(server.id, before_stop))
|
||||||
|
action = self._get_list_of_values_from_single_column_table(
|
||||||
|
stop_output, "Action")
|
||||||
|
# Provide detailed debug information if this fails.
|
||||||
|
self.assertEqual(action, ['stop'],
|
||||||
|
'Expected to find the stop action with '
|
||||||
|
'--changes-since=%s but got: %s\n\n'
|
||||||
|
'First instance-action-list output: %s' %
|
||||||
|
(before_stop, stop_output, create_output))
|
||||||
|
@ -1948,26 +1948,31 @@ class FakeSessionClient(base_client.SessionClient):
|
|||||||
return (200, FAKE_RESPONSE_HEADERS, {})
|
return (200, FAKE_RESPONSE_HEADERS, {})
|
||||||
|
|
||||||
def get_servers_1234_os_instance_actions(self, **kw):
|
def get_servers_1234_os_instance_actions(self, **kw):
|
||||||
return (200, FAKE_RESPONSE_HEADERS, {
|
action = {"instance_uuid": "1234",
|
||||||
"instanceActions":
|
|
||||||
[{"instance_uuid": "1234",
|
|
||||||
"user_id": "b968c25e04ab405f9fe4e6ca54cce9a5",
|
"user_id": "b968c25e04ab405f9fe4e6ca54cce9a5",
|
||||||
"start_time": "2013-03-25T13:45:09.000000",
|
"start_time": "2013-03-25T13:45:09.000000",
|
||||||
"request_id": "req-abcde12345",
|
"request_id": "req-abcde12345",
|
||||||
"action": "create",
|
"action": "create",
|
||||||
"message": None,
|
"message": None,
|
||||||
"project_id": "04019601fe3648c0abd4f4abfb9e6106"}]})
|
"project_id": "04019601fe3648c0abd4f4abfb9e6106"}
|
||||||
|
if self.api_version >= api_versions.APIVersion('2.58'):
|
||||||
|
# This is intentionally different from the start_time.
|
||||||
|
action['updated_at'] = '2013-03-25T13:50:09.000000'
|
||||||
|
return (200, FAKE_RESPONSE_HEADERS, {
|
||||||
|
"instanceActions": [action]})
|
||||||
|
|
||||||
def get_servers_1234_os_instance_actions_req_abcde12345(self, **kw):
|
def get_servers_1234_os_instance_actions_req_abcde12345(self, **kw):
|
||||||
|
action = {"instance_uuid": "1234",
|
||||||
|
"user_id": "b968c25e04ab405f9fe4e6ca54cce9a5",
|
||||||
|
"start_time": "2013-03-25T13:45:09.000000",
|
||||||
|
"request_id": "req-abcde12345",
|
||||||
|
"action": "create",
|
||||||
|
"message": None,
|
||||||
|
"project_id": "04019601fe3648c0abd4f4abfb9e6106"}
|
||||||
|
if self.api_version >= api_versions.APIVersion('2.58'):
|
||||||
|
action['updated_at'] = '2013-03-25T13:45:09.000000'
|
||||||
return (200, FAKE_RESPONSE_HEADERS, {
|
return (200, FAKE_RESPONSE_HEADERS, {
|
||||||
"instanceAction":
|
"instanceAction": action})
|
||||||
{"instance_uuid": "1234",
|
|
||||||
"user_id": "b968c25e04ab405f9fe4e6ca54cce9a5",
|
|
||||||
"start_time": "2013-03-25T13:45:09.000000",
|
|
||||||
"request_id": "req-abcde12345",
|
|
||||||
"action": "create",
|
|
||||||
"message": None,
|
|
||||||
"project_id": "04019601fe3648c0abd4f4abfb9e6106"}})
|
|
||||||
|
|
||||||
def post_servers_uuid1_action(self, **kw):
|
def post_servers_uuid1_action(self, **kw):
|
||||||
return 202, {}, {}
|
return 202, {}, {}
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
from novaclient import api_versions
|
from novaclient import api_versions
|
||||||
from novaclient.tests.unit import utils
|
from novaclient.tests.unit import utils
|
||||||
from novaclient.tests.unit.v2 import fakes
|
from novaclient.tests.unit.v2 import fakes
|
||||||
|
from novaclient.v2 import instance_action
|
||||||
|
|
||||||
|
|
||||||
class InstanceActionExtensionTests(utils.TestCase):
|
class InstanceActionExtensionTests(utils.TestCase):
|
||||||
@ -39,3 +40,24 @@ class InstanceActionExtensionTests(utils.TestCase):
|
|||||||
self.cs.assert_called(
|
self.cs.assert_called(
|
||||||
'GET', '/servers/%s/os-instance-actions/%s'
|
'GET', '/servers/%s/os-instance-actions/%s'
|
||||||
% (server_uuid, request_id))
|
% (server_uuid, request_id))
|
||||||
|
|
||||||
|
|
||||||
|
class InstanceActionExtensionV258Tests(InstanceActionExtensionTests):
|
||||||
|
def setUp(self):
|
||||||
|
super(InstanceActionExtensionV258Tests, self).setUp()
|
||||||
|
self.cs.api_version = api_versions.APIVersion("2.58")
|
||||||
|
|
||||||
|
def test_list_instance_actions_with_limit_marker_params(self):
|
||||||
|
server_uuid = '1234'
|
||||||
|
marker = '12140183-c814-4ddf-8453-6df43028aa67'
|
||||||
|
|
||||||
|
ias = self.cs.instance_action.list(
|
||||||
|
server_uuid, marker=marker, limit=10,
|
||||||
|
changes_since='2016-02-29T06:23:22')
|
||||||
|
self.assert_request_id(ias, fakes.FAKE_REQUEST_ID_LIST)
|
||||||
|
self.cs.assert_called(
|
||||||
|
'GET',
|
||||||
|
'/servers/%s/os-instance-actions?changes-since=%s&limit=10&'
|
||||||
|
'marker=%s' % (server_uuid, '2016-02-29T06%3A23%3A22', marker))
|
||||||
|
for ia in ias:
|
||||||
|
self.assertIsInstance(ia, instance_action.InstanceAction)
|
||||||
|
@ -2976,6 +2976,49 @@ class ShellTest(utils.TestCase):
|
|||||||
'GET',
|
'GET',
|
||||||
'/servers/1234/os-instance-actions/req-abcde12345')
|
'/servers/1234/os-instance-actions/req-abcde12345')
|
||||||
|
|
||||||
|
def test_instance_action_list_marker_pre_v258_not_allowed(self):
|
||||||
|
cmd = 'instance-action-list sample-server --marker %s'
|
||||||
|
self.assertRaises(SystemExit, self.run_command,
|
||||||
|
cmd % FAKE_UUID_1, api_version='2.57')
|
||||||
|
|
||||||
|
def test_instance_action_list_limit_pre_v258_not_allowed(self):
|
||||||
|
cmd = 'instance-action-list sample-server --limit 10'
|
||||||
|
self.assertRaises(SystemExit, self.run_command,
|
||||||
|
cmd, api_version='2.57')
|
||||||
|
|
||||||
|
def test_instance_action_list_changes_since_pre_v258_not_allowed(self):
|
||||||
|
cmd = 'instance-action-list sample-server --changes-since ' \
|
||||||
|
'2016-02-29T06:23:22'
|
||||||
|
self.assertRaises(SystemExit, self.run_command,
|
||||||
|
cmd, api_version='2.57')
|
||||||
|
|
||||||
|
def test_instance_action_list_limit_marker_v258(self):
|
||||||
|
out = self.run_command('instance-action-list sample-server --limit 10 '
|
||||||
|
'--marker %s' % FAKE_UUID_1,
|
||||||
|
api_version='2.58')[0]
|
||||||
|
# Assert that the updated_at value is in the output.
|
||||||
|
self.assertIn('2013-03-25T13:50:09.000000', out)
|
||||||
|
self.assert_called(
|
||||||
|
'GET',
|
||||||
|
'/servers/1234/os-instance-actions?'
|
||||||
|
'limit=10&marker=%s' % FAKE_UUID_1)
|
||||||
|
|
||||||
|
def test_instance_action_list_with_changes_since_v258(self):
|
||||||
|
self.run_command('instance-action-list sample-server '
|
||||||
|
'--changes-since 2016-02-29T06:23:22',
|
||||||
|
api_version='2.58')
|
||||||
|
self.assert_called(
|
||||||
|
'GET',
|
||||||
|
'/servers/1234/os-instance-actions?'
|
||||||
|
'changes-since=2016-02-29T06%3A23%3A22')
|
||||||
|
|
||||||
|
def test_instance_action_list_with_changes_since_invalid_value_v258(self):
|
||||||
|
ex = self.assertRaises(
|
||||||
|
exceptions.CommandError, self.run_command,
|
||||||
|
'instance-action-list sample-server --changes-since 0123456789',
|
||||||
|
api_version='2.58')
|
||||||
|
self.assertIn('Invalid changes-since value', six.text_type(ex))
|
||||||
|
|
||||||
def test_cell_show(self):
|
def test_cell_show(self):
|
||||||
self.run_command('cell-show child_cell')
|
self.run_command('cell-show child_cell')
|
||||||
self.assert_called('GET', '/os-cells/child_cell')
|
self.assert_called('GET', '/os-cells/child_cell')
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
from novaclient import api_versions
|
||||||
from novaclient import base
|
from novaclient import base
|
||||||
|
|
||||||
|
|
||||||
@ -32,9 +33,37 @@ class InstanceActionManager(base.ManagerWithFind):
|
|||||||
return self._get("/servers/%s/os-instance-actions/%s" %
|
return self._get("/servers/%s/os-instance-actions/%s" %
|
||||||
(base.getid(server), request_id), 'instanceAction')
|
(base.getid(server), request_id), 'instanceAction')
|
||||||
|
|
||||||
|
@api_versions.wraps("2.0", "2.57")
|
||||||
def list(self, server):
|
def list(self, server):
|
||||||
"""
|
"""
|
||||||
Get a list of actions performed on a server.
|
Get a list of actions performed on a server.
|
||||||
|
|
||||||
|
:param server: The :class:`Server` (or its ID)
|
||||||
"""
|
"""
|
||||||
return self._list('/servers/%s/os-instance-actions' %
|
return self._list('/servers/%s/os-instance-actions' %
|
||||||
base.getid(server), 'instanceActions')
|
base.getid(server), 'instanceActions')
|
||||||
|
|
||||||
|
@api_versions.wraps("2.58")
|
||||||
|
def list(self, server, marker=None, limit=None, changes_since=None):
|
||||||
|
"""
|
||||||
|
Get a list of actions performed on a server.
|
||||||
|
|
||||||
|
:param server: The :class:`Server` (or its ID)
|
||||||
|
:param marker: Begin returning actions that appear later in the action
|
||||||
|
list than that represented by this action request id
|
||||||
|
(optional).
|
||||||
|
:param limit: Maximum number of actions to return. (optional).
|
||||||
|
:param changes_since: List only instance actions changed after a
|
||||||
|
certain point of time. The provided time should
|
||||||
|
be an ISO 8061 formatted time. ex
|
||||||
|
2016-03-04T06:27:59Z . (optional).
|
||||||
|
"""
|
||||||
|
opts = {}
|
||||||
|
if marker:
|
||||||
|
opts['marker'] = marker
|
||||||
|
if limit:
|
||||||
|
opts['limit'] = limit
|
||||||
|
if changes_since:
|
||||||
|
opts['changes-since'] = changes_since
|
||||||
|
return self._list('/servers/%s/os-instance-actions' %
|
||||||
|
base.getid(server), 'instanceActions', filters=opts)
|
||||||
|
@ -4864,6 +4864,7 @@ def do_instance_action(cs, args):
|
|||||||
utils.print_dict(action)
|
utils.print_dict(action)
|
||||||
|
|
||||||
|
|
||||||
|
@api_versions.wraps("2.0", "2.57")
|
||||||
@utils.arg(
|
@utils.arg(
|
||||||
'server',
|
'server',
|
||||||
metavar='<server>',
|
metavar='<server>',
|
||||||
@ -4887,6 +4888,56 @@ def do_instance_action_list(cs, args):
|
|||||||
sortby_index=3)
|
sortby_index=3)
|
||||||
|
|
||||||
|
|
||||||
|
@api_versions.wraps("2.58")
|
||||||
|
@utils.arg(
|
||||||
|
'server',
|
||||||
|
metavar='<server>',
|
||||||
|
help=_('Name or UUID of the server to list actions for. Only UUID can be '
|
||||||
|
'used to list actions on a deleted server.'))
|
||||||
|
@utils.arg(
|
||||||
|
'--marker',
|
||||||
|
dest='marker',
|
||||||
|
metavar='<marker>',
|
||||||
|
default=None,
|
||||||
|
help=_('The last instance action of the previous page; displays list of '
|
||||||
|
'actions after "marker".'))
|
||||||
|
@utils.arg(
|
||||||
|
'--limit',
|
||||||
|
dest='limit',
|
||||||
|
metavar='<limit>',
|
||||||
|
type=int,
|
||||||
|
default=None,
|
||||||
|
help=_('Maximum number of instance actions to display. Note that there '
|
||||||
|
'is a configurable max limit on the server, and the limit that is '
|
||||||
|
'used will be the minimum between what is requested here and what '
|
||||||
|
'is configured in the server.'))
|
||||||
|
@utils.arg(
|
||||||
|
'--changes-since',
|
||||||
|
dest='changes_since',
|
||||||
|
metavar='<changes_since>',
|
||||||
|
default=None,
|
||||||
|
help=_('List only instance actions changed after a certain point of '
|
||||||
|
'time. The provided time should be an ISO 8061 formatted time. '
|
||||||
|
'ex 2016-03-04T06:27:59Z.'))
|
||||||
|
def do_instance_action_list(cs, args):
|
||||||
|
"""List actions on a server."""
|
||||||
|
server = _find_server(cs, args.server, raise_if_notfound=False)
|
||||||
|
if args.changes_since:
|
||||||
|
try:
|
||||||
|
timeutils.parse_isotime(args.changes_since)
|
||||||
|
except ValueError:
|
||||||
|
raise exceptions.CommandError(_('Invalid changes-since value: %s')
|
||||||
|
% args.changes_since)
|
||||||
|
actions = cs.instance_action.list(server, marker=args.marker,
|
||||||
|
limit=args.limit,
|
||||||
|
changes_since=args.changes_since)
|
||||||
|
# TODO(yikun): Output a "Marker" column if there is a next link?
|
||||||
|
utils.print_list(actions,
|
||||||
|
['Action', 'Request_ID', 'Message', 'Start_Time',
|
||||||
|
'Updated_At'],
|
||||||
|
sortby_index=3)
|
||||||
|
|
||||||
|
|
||||||
def do_list_extensions(cs, _args):
|
def do_list_extensions(cs, _args):
|
||||||
"""
|
"""
|
||||||
List all the os-api extensions that are available.
|
List all the os-api extensions that are available.
|
||||||
|
@ -0,0 +1,8 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- |
|
||||||
|
Added support for microversion v2.58 which introduces pagination support
|
||||||
|
for instance actions with the help of new optional parameters ``limit``,
|
||||||
|
``marker``, and also adds the new filter ``changes-since``. Users can use
|
||||||
|
``changes-since`` filter to filter the results based on the last time the
|
||||||
|
instance action was updated.
|
Loading…
x
Reference in New Issue
Block a user