Add pagination and Changes-since filter support for os-migrations.
This patch adds pagination support and changes-since filter for os-migrations API. Users can now use 'limit' and 'marker' to perform paginate query of running migrations list. Users can also filter the results according to the migrations' updated time. The ``GET /os-migrations`` and server migrations APIs will now return a uuid value in addition to the migrations id in the response, and the query parameter schema of the ``GET /os-migrations`` API no longer allows additional properties. Co-Authored-By: Yikun Jiang <yikunkero@gmail.com> Implement: blueprint add-pagination-and-change-since-for-migration-list Change-Id: I7e01f95d7173d9217f76e838b3ea71555151ef56
This commit is contained in:
parent
55f59172ee
commit
92a0fc0b9f
@ -1,14 +1,11 @@
|
||||
.. -*- rst -*-
|
||||
|
||||
=========================================
|
||||
Migrations (os-migrations) (frozen)
|
||||
Migrations (os-migrations)
|
||||
=========================================
|
||||
|
||||
Shows data on migrations.
|
||||
|
||||
.. warning:: The old top-level resource `/os-migrations` is frozen,
|
||||
it won't be extended anymore. Use /servers/{uuid}/migrations instead.
|
||||
|
||||
List Migrations
|
||||
===============
|
||||
|
||||
@ -22,7 +19,7 @@ this operation. Cloud providers can change these permissions through the
|
||||
|
||||
Normal response codes: 200
|
||||
|
||||
Error response codes: unauthorized(401), forbidden(403)
|
||||
Error response codes: badRequest(400), unauthorized(401), forbidden(403)
|
||||
|
||||
Request
|
||||
-------
|
||||
@ -35,6 +32,9 @@ Request
|
||||
- migration_type: migration_type
|
||||
- source_compute: migration_source_compute
|
||||
- status: migration_status
|
||||
- limit: migration_limit
|
||||
- marker: migration_marker
|
||||
- changes-since: changes_since_migration
|
||||
|
||||
Response
|
||||
--------
|
||||
@ -55,9 +55,21 @@ Response
|
||||
- updated_at: updated
|
||||
- migration_type: migration_type_2_23
|
||||
- links: migration_links_2_23
|
||||
- uuid: migration_uuid
|
||||
- migrations_links: migration_next_links_2_59
|
||||
|
||||
**Example List Migrations: JSON response**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/os-migrations/migrations-get.json
|
||||
:language: javascript
|
||||
|
||||
**Example List Migrations (v2.59):**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/os-migrations/v2.59/migrations-get.json
|
||||
:language: javascript
|
||||
|
||||
**Example List Migrations With Links (v2.59):**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/os-migrations/v2.59/migrations-get-with-limit.json
|
||||
:language: javascript
|
||||
|
||||
|
@ -446,6 +446,23 @@ changes_since_instance_action:
|
||||
required: false
|
||||
type: string
|
||||
min_version: 2.58
|
||||
changes_since_migration:
|
||||
description: |
|
||||
Filters the response by a date and time stamp when the migration last
|
||||
changed. Those changed after the specified date and time stamp are returned.
|
||||
|
||||
The date and time stamp format is `ISO 8601 <https://en.wikipedia.org/wiki/ISO_8601>`_:
|
||||
::
|
||||
|
||||
CCYY-MM-DDThh:mm:ss±hh:mm
|
||||
|
||||
The ``±hh:mm`` value, if included, returns the time zone as an offset from UTC.
|
||||
For example, ``2015-08-27T09:49:58-05:00``.
|
||||
If you omit the time zone, the UTC time zone is assumed.
|
||||
in: query
|
||||
required: false
|
||||
type: string
|
||||
min_version: 2.59
|
||||
changes_since_server:
|
||||
description: |
|
||||
Filters the response by a date and time stamp when the server last
|
||||
@ -845,6 +862,25 @@ migration_instance_uuid:
|
||||
in: query
|
||||
required: false
|
||||
type: string
|
||||
migration_limit:
|
||||
description: |
|
||||
Requests a page size of items. Returns a number of items up to a limit value.
|
||||
Use the ``limit`` parameter to make an initial limited request and use the
|
||||
last-seen item from the response as the ``marker`` parameter value in a
|
||||
subsequent limited request.
|
||||
in: query
|
||||
required: false
|
||||
type: integer
|
||||
min_version: 2.59
|
||||
migration_marker:
|
||||
description: |
|
||||
The UUID of the last-seen migration. Use the ``limit`` parameter to make an
|
||||
initial limited request and use the last-seen item from the response as
|
||||
the ``marker`` parameter value in a subsequent limited request.
|
||||
in: query
|
||||
required: false
|
||||
type: string
|
||||
min_version: 2.59
|
||||
migration_source_compute:
|
||||
description: |
|
||||
The source compute node of migration to filter.
|
||||
@ -4084,6 +4120,17 @@ migration_new_flavor_id:
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
migration_next_links_2_59:
|
||||
description: |
|
||||
Links pertaining to the migration.
|
||||
This parameter is returned when paging and more data is available.
|
||||
See `API Guide / Links and References
|
||||
<http://developer.openstack.org/api-guide/compute/links_and_references.html>`_
|
||||
for more info.
|
||||
in: body
|
||||
required: false
|
||||
type: array
|
||||
min_version: 2.59
|
||||
migration_old_flavor_id:
|
||||
description: |
|
||||
The flavor ID of the server when the migration was started.
|
||||
@ -4098,6 +4145,13 @@ migration_type_2_23:
|
||||
required: true
|
||||
type: string
|
||||
min_version: 2.23
|
||||
migration_uuid:
|
||||
description: |
|
||||
The UUID of the migration.
|
||||
in: body
|
||||
required: true
|
||||
type: string
|
||||
min_version: 2.59
|
||||
migrations:
|
||||
description: |
|
||||
The list of server migration objects.
|
||||
|
@ -52,10 +52,11 @@ Response
|
||||
- source_node: migrate_source_node
|
||||
- status: migrate_status
|
||||
- updated_at: updated
|
||||
- uuid: migration_uuid
|
||||
|
||||
**Example List Migrations**
|
||||
**Example List Migrations (2.59)**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/server-migrations/v2.23/migrations-index.json
|
||||
.. literalinclude:: ../../doc/api_samples/server-migrations/v2.59/migrations-index.json
|
||||
:language: javascript
|
||||
|
||||
Show Migration Details
|
||||
@ -105,10 +106,11 @@ Response
|
||||
- source_node: migrate_source_node
|
||||
- status: migrate_status
|
||||
- updated_at: updated
|
||||
- uuid: migration_uuid
|
||||
|
||||
**Example Show Migration Details**
|
||||
**Example Show Migration Details (2.59)**
|
||||
|
||||
.. literalinclude:: ../../doc/api_samples/server-migrations/v2.23/migrations-get.json
|
||||
.. literalinclude:: ../../doc/api_samples/server-migrations/v2.59/migrations-get.json
|
||||
:language: javascript
|
||||
|
||||
Force Migration Complete Action (force_complete Action)
|
||||
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
"migrations": [
|
||||
{
|
||||
"created_at": "2016-06-23T14:42:02.000000",
|
||||
"dest_compute": "compute20",
|
||||
"dest_host": "5.6.7.8",
|
||||
"dest_node": "node20",
|
||||
"id": 4,
|
||||
"instance_uuid": "9128d044-7b61-403e-b766-7547076ff6c1",
|
||||
"new_instance_type_id": 6,
|
||||
"old_instance_type_id": 5,
|
||||
"source_compute": "compute10",
|
||||
"source_node": "node10",
|
||||
"status": "migrating",
|
||||
"migration_type": "resize",
|
||||
"updated_at": "2016-06-23T14:42:02.000000",
|
||||
"uuid": "42341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
],
|
||||
"migrations_links": [{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/os-migrations?limit=1&marker=42341d4b-346a-40d0-83c6-5f4f6892b650",
|
||||
"rel": "next"
|
||||
}]
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
{
|
||||
"migrations": [
|
||||
{
|
||||
"created_at": "2016-01-29T11:42:02.000000",
|
||||
"dest_compute": "compute2",
|
||||
"dest_host": "1.2.3.4",
|
||||
"dest_node": "node2",
|
||||
"id": 1,
|
||||
"instance_uuid": "8600d31b-d1a1-4632-b2ff-45c2be1a70ff",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/8600d31b-d1a1-4632-b2ff-45c2be1a70ff/migrations/1",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/8600d31b-d1a1-4632-b2ff-45c2be1a70ff/migrations/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"new_instance_type_id": 1,
|
||||
"old_instance_type_id": 1,
|
||||
"source_compute": "compute1",
|
||||
"source_node": "node1",
|
||||
"status": "running",
|
||||
"migration_type": "live-migration",
|
||||
"updated_at": "2016-01-29T11:42:02.000000",
|
||||
"uuid": "12341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
{
|
||||
"migrations": [
|
||||
{
|
||||
"created_at": "2016-06-23T14:42:02.000000",
|
||||
"dest_compute": "compute20",
|
||||
"dest_host": "5.6.7.8",
|
||||
"dest_node": "node20",
|
||||
"id": 4,
|
||||
"instance_uuid": "9128d044-7b61-403e-b766-7547076ff6c1",
|
||||
"new_instance_type_id": 6,
|
||||
"old_instance_type_id": 5,
|
||||
"source_compute": "compute10",
|
||||
"source_node": "node10",
|
||||
"status": "migrating",
|
||||
"migration_type": "resize",
|
||||
"updated_at": "2016-06-23T14:42:02.000000",
|
||||
"uuid": "42341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
},
|
||||
{
|
||||
"created_at": "2016-06-23T13:42:02.000000",
|
||||
"dest_compute": "compute20",
|
||||
"dest_host": "5.6.7.8",
|
||||
"dest_node": "node20",
|
||||
"id": 3,
|
||||
"instance_uuid": "9128d044-7b61-403e-b766-7547076ff6c1",
|
||||
"new_instance_type_id": 6,
|
||||
"old_instance_type_id": 5,
|
||||
"source_compute": "compute10",
|
||||
"source_node": "node10",
|
||||
"status": "error",
|
||||
"migration_type": "resize",
|
||||
"updated_at": "2016-06-23T13:42:02.000000",
|
||||
"uuid": "32341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
]
|
||||
}
|
78
doc/api_samples/os-migrations/v2.59/migrations-get.json
Normal file
78
doc/api_samples/os-migrations/v2.59/migrations-get.json
Normal file
@ -0,0 +1,78 @@
|
||||
{
|
||||
"migrations": [
|
||||
{
|
||||
"created_at": "2016-06-23T14:42:02.000000",
|
||||
"dest_compute": "compute20",
|
||||
"dest_host": "5.6.7.8",
|
||||
"dest_node": "node20",
|
||||
"id": 4,
|
||||
"instance_uuid": "9128d044-7b61-403e-b766-7547076ff6c1",
|
||||
"new_instance_type_id": 6,
|
||||
"old_instance_type_id": 5,
|
||||
"source_compute": "compute10",
|
||||
"source_node": "node10",
|
||||
"status": "migrating",
|
||||
"migration_type": "resize",
|
||||
"updated_at": "2016-06-23T14:42:02.000000",
|
||||
"uuid": "42341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
},
|
||||
{
|
||||
"created_at": "2016-06-23T13:42:02.000000",
|
||||
"dest_compute": "compute20",
|
||||
"dest_host": "5.6.7.8",
|
||||
"dest_node": "node20",
|
||||
"id": 3,
|
||||
"instance_uuid": "9128d044-7b61-403e-b766-7547076ff6c1",
|
||||
"new_instance_type_id": 6,
|
||||
"old_instance_type_id": 5,
|
||||
"source_compute": "compute10",
|
||||
"source_node": "node10",
|
||||
"status": "error",
|
||||
"migration_type": "resize",
|
||||
"updated_at": "2016-06-23T13:42:02.000000",
|
||||
"uuid": "32341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
},
|
||||
{
|
||||
"created_at": "2016-01-29T12:42:02.000000",
|
||||
"dest_compute": "compute2",
|
||||
"dest_host": "1.2.3.4",
|
||||
"dest_node": "node2",
|
||||
"id": 2,
|
||||
"instance_uuid": "8600d31b-d1a1-4632-b2ff-45c2be1a70ff",
|
||||
"new_instance_type_id": 1,
|
||||
"old_instance_type_id": 1,
|
||||
"source_compute": "compute1",
|
||||
"source_node": "node1",
|
||||
"status": "error",
|
||||
"migration_type": "live-migration",
|
||||
"updated_at": "2016-01-29T12:42:02.000000",
|
||||
"uuid": "22341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
},
|
||||
{
|
||||
"created_at": "2016-01-29T11:42:02.000000",
|
||||
"dest_compute": "compute2",
|
||||
"dest_host": "1.2.3.4",
|
||||
"dest_node": "node2",
|
||||
"id": 1,
|
||||
"instance_uuid": "8600d31b-d1a1-4632-b2ff-45c2be1a70ff",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/8600d31b-d1a1-4632-b2ff-45c2be1a70ff/migrations/1",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/8600d31b-d1a1-4632-b2ff-45c2be1a70ff/migrations/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"new_instance_type_id": 1,
|
||||
"old_instance_type_id": 1,
|
||||
"source_compute": "compute1",
|
||||
"source_node": "node1",
|
||||
"status": "running",
|
||||
"migration_type": "live-migration",
|
||||
"updated_at": "2016-01-29T11:42:02.000000",
|
||||
"uuid": "12341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
]
|
||||
}
|
21
doc/api_samples/server-migrations/v2.59/migrations-get.json
Normal file
21
doc/api_samples/server-migrations/v2.59/migrations-get.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"migration": {
|
||||
"created_at": "2016-01-29T13:42:02.000000",
|
||||
"dest_compute": "compute2",
|
||||
"dest_host": "1.2.3.4",
|
||||
"dest_node": "node2",
|
||||
"id": 1,
|
||||
"server_uuid": "4cfba335-03d8-49b2-8c52-e69043d1e8fe",
|
||||
"source_compute": "compute1",
|
||||
"source_node": "node1",
|
||||
"status": "running",
|
||||
"memory_total_bytes": 123456,
|
||||
"memory_processed_bytes": 12345,
|
||||
"memory_remaining_bytes": 111111,
|
||||
"disk_total_bytes": 234567,
|
||||
"disk_processed_bytes": 23456,
|
||||
"disk_remaining_bytes": 211111,
|
||||
"updated_at": "2016-01-29T13:42:02.000000",
|
||||
"uuid": "12341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
{
|
||||
"migrations": [
|
||||
{
|
||||
"created_at": "2016-01-29T13:42:02.000000",
|
||||
"dest_compute": "compute2",
|
||||
"dest_host": "1.2.3.4",
|
||||
"dest_node": "node2",
|
||||
"id": 1,
|
||||
"server_uuid": "4cfba335-03d8-49b2-8c52-e69043d1e8fe",
|
||||
"source_compute": "compute1",
|
||||
"source_node": "node1",
|
||||
"status": "running",
|
||||
"memory_total_bytes": 123456,
|
||||
"memory_processed_bytes": 12345,
|
||||
"memory_remaining_bytes": 111111,
|
||||
"disk_total_bytes": 234567,
|
||||
"disk_processed_bytes": 23456,
|
||||
"disk_remaining_bytes": 211111,
|
||||
"updated_at": "2016-01-29T13:42:02.000000",
|
||||
"uuid": "12341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
]
|
||||
}
|
@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.58",
|
||||
"version": "2.59",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
}
|
||||
],
|
||||
"status": "CURRENT",
|
||||
"version": "2.58",
|
||||
"version": "2.59",
|
||||
"min_version": "2.1",
|
||||
"updated": "2013-07-23T11:33:21Z"
|
||||
}
|
||||
|
@ -139,6 +139,9 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
related limits and quota resources are also removed.
|
||||
* 2.58 - Add pagination support and changes-since filter for
|
||||
os-instance-actions API.
|
||||
* 2.59 - Add pagination support and changes-since filter for os-migrations
|
||||
API. And the os-migrations API now returns both the id and the
|
||||
uuid in response.
|
||||
"""
|
||||
|
||||
# The minimum and maximum versions of the API supported
|
||||
@ -147,7 +150,7 @@ REST_API_VERSION_HISTORY = """REST API Version History:
|
||||
# Note(cyeoh): This only applies for the v2.1 API once microversions
|
||||
# support is fully merged. It does not affect the V2 API.
|
||||
_MIN_API_VERSION = "2.1"
|
||||
_MAX_API_VERSION = "2.58"
|
||||
_MAX_API_VERSION = "2.59"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
# Almost all proxy APIs which are related to network, images and baremetal
|
||||
|
@ -10,12 +10,16 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from nova.api.openstack import api_version_request
|
||||
from oslo_utils import timeutils
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack.compute.schemas import migrations as schema_migrations
|
||||
from nova.api.openstack.compute.views import migrations as migrations_view
|
||||
from nova.api.openstack import wsgi
|
||||
from nova.api import validation
|
||||
from nova import compute
|
||||
from nova import exception
|
||||
from nova.objects import base as obj_base
|
||||
from nova.policies import migrations as migrations_policies
|
||||
|
||||
@ -23,14 +27,14 @@ from nova.policies import migrations as migrations_policies
|
||||
class MigrationsController(wsgi.Controller):
|
||||
"""Controller for accessing migrations in OpenStack API."""
|
||||
|
||||
_view_builder_class = common.ViewBuilder
|
||||
_view_builder_class = migrations_view.ViewBuilder
|
||||
_collection_name = "servers/%s/migrations"
|
||||
|
||||
def __init__(self):
|
||||
super(MigrationsController, self).__init__()
|
||||
self.compute_api = compute.API()
|
||||
|
||||
def _output(self, req, migrations_obj, add_link=False):
|
||||
def _output(self, req, migrations_obj, add_link=False, add_uuid=False):
|
||||
"""Returns the desired output of the API from an object.
|
||||
|
||||
From a MigrationsList's object this method returns a list of
|
||||
@ -51,7 +55,8 @@ class MigrationsController(wsgi.Controller):
|
||||
del obj['deleted']
|
||||
del obj['deleted_at']
|
||||
del obj['hidden']
|
||||
del obj['uuid']
|
||||
if not add_uuid:
|
||||
del obj['uuid']
|
||||
if 'memory_total' in obj:
|
||||
for key in detail_keys:
|
||||
del obj[key]
|
||||
@ -68,15 +73,71 @@ class MigrationsController(wsgi.Controller):
|
||||
|
||||
return objects
|
||||
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(schema_migrations.list_query_schema_v20)
|
||||
def index(self, req):
|
||||
"""Return all migrations using the query parameters as filters."""
|
||||
def _index(self, req, add_link=False, next_link=False, add_uuid=False,
|
||||
sort_dirs=None, sort_keys=None, limit=None, marker=None,
|
||||
allow_changes_since=False):
|
||||
context = req.environ['nova.context']
|
||||
context.can(migrations_policies.POLICY_ROOT % 'index')
|
||||
migrations = self.compute_api.get_migrations(context, req.GET)
|
||||
search_opts = {}
|
||||
search_opts.update(req.GET)
|
||||
if 'changes-since' in search_opts:
|
||||
if allow_changes_since:
|
||||
search_opts['changes-since'] = timeutils.parse_isotime(
|
||||
search_opts['changes-since'])
|
||||
else:
|
||||
# Before microversion 2.59, the changes-since filter was not
|
||||
# supported in the DB API. However, the schema allowed
|
||||
# additionalProperties=True, so a user could pass it before
|
||||
# 2.59 and filter by the updated_at field if we don't remove
|
||||
# it from search_opts.
|
||||
del search_opts['changes-since']
|
||||
|
||||
if api_version_request.is_supported(req, min_version='2.23'):
|
||||
return {'migrations': self._output(req, migrations, True)}
|
||||
if sort_keys:
|
||||
try:
|
||||
migrations = self.compute_api.get_migrations_sorted(
|
||||
context, search_opts,
|
||||
sort_dirs=sort_dirs, sort_keys=sort_keys,
|
||||
limit=limit, marker=marker)
|
||||
except exception.MarkerNotFound as e:
|
||||
raise exc.HTTPBadRequest(explanation=e.format_message())
|
||||
else:
|
||||
migrations = self.compute_api.get_migrations(
|
||||
context, search_opts)
|
||||
|
||||
return {'migrations': self._output(req, migrations)}
|
||||
migrations = self._output(req, migrations, add_link, add_uuid)
|
||||
migrations_dict = {'migrations': migrations}
|
||||
|
||||
if next_link:
|
||||
migrations_links = self._view_builder.get_links(req, migrations)
|
||||
if migrations_links:
|
||||
migrations_dict['migrations_links'] = migrations_links
|
||||
return migrations_dict
|
||||
|
||||
@wsgi.Controller.api_version("2.1", "2.22") # noqa
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(schema_migrations.list_query_schema_v20,
|
||||
"2.1", "2.22")
|
||||
def index(self, req):
|
||||
"""Return all migrations using the query parameters as filters."""
|
||||
return self._index(req)
|
||||
|
||||
@wsgi.Controller.api_version("2.23", "2.58") # noqa
|
||||
@wsgi.expected_errors(())
|
||||
@validation.query_schema(schema_migrations.list_query_schema_v20,
|
||||
"2.23", "2.58")
|
||||
def index(self, req):
|
||||
"""Return all migrations using the query parameters as filters."""
|
||||
return self._index(req, add_link=True)
|
||||
|
||||
@wsgi.Controller.api_version("2.59") # noqa
|
||||
@wsgi.expected_errors(400)
|
||||
@validation.query_schema(schema_migrations.list_query_params_v259,
|
||||
"2.59")
|
||||
def index(self, req):
|
||||
"""Return all migrations using the query parameters as filters."""
|
||||
limit, marker = common.get_limit_and_marker(req)
|
||||
return self._index(req, add_link=True, next_link=True, add_uuid=True,
|
||||
sort_keys=['created_at', 'id'],
|
||||
sort_dirs=['desc', 'desc'],
|
||||
limit=limit, marker=marker,
|
||||
allow_changes_since=True)
|
||||
|
@ -740,3 +740,20 @@ API. Users can now use ``limit`` and ``marker`` to perform paginated query
|
||||
when listing instance actions. Users can also use ``changes-since`` filter
|
||||
to filter the results based on the last time the instance action was
|
||||
updated.
|
||||
|
||||
2.59
|
||||
----
|
||||
|
||||
Added pagination support for migrations, there are four changes:
|
||||
|
||||
* Add pagination support and ``changes-since`` filter for os-migrations
|
||||
API. Users can now use ``limit`` and ``marker`` to perform paginate query
|
||||
when listing migrations.
|
||||
* Users can also use ``changes-since`` filter to filter the results based
|
||||
on the last time the migration record was updated.
|
||||
* ``GET /os-migrations``,
|
||||
``GET /servers/{server_id}/migrations/{migration_id}`` and
|
||||
``GET /servers/{server_id}/migrations`` will now return a uuid value in
|
||||
addition to the migrations id in the response.
|
||||
* The query parameter schema of the ``GET /os-migrations`` API no longer
|
||||
allows additional properties.
|
||||
|
@ -12,6 +12,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
|
||||
from nova.api.validation import parameter_types
|
||||
|
||||
list_query_schema_v20 = {
|
||||
@ -25,9 +27,17 @@ list_query_schema_v20 = {
|
||||
'migration_type': parameter_types.common_query_param,
|
||||
},
|
||||
# For backward compatible changes
|
||||
# TODO(mriedem): In a future microversion, consider changing
|
||||
# additionalProperties to False, remove the 'hidden' filter since
|
||||
# it's vestigial, and enforce type and enum checks for the filters
|
||||
# where that makes sense, e.g. instance_uuid, status and migration_type.
|
||||
'additionalProperties': True
|
||||
}
|
||||
|
||||
list_query_params_v259 = copy.deepcopy(list_query_schema_v20)
|
||||
list_query_params_v259['properties'].update({
|
||||
# The 2.59 microversion added support for paging by limit and marker
|
||||
# and filtering by changes-since.
|
||||
'limit': parameter_types.single_param(
|
||||
parameter_types.non_negative_integer),
|
||||
'marker': parameter_types.single_param({'type': 'string'}),
|
||||
'changes-since': parameter_types.single_param(
|
||||
{'type': 'string', 'format': 'date-time'}),
|
||||
})
|
||||
list_query_params_v259['additionalProperties'] = False
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack import api_version_request
|
||||
from nova.api.openstack import common
|
||||
from nova.api.openstack.compute.schemas import server_migrations
|
||||
from nova.api.openstack import wsgi
|
||||
@ -25,13 +26,13 @@ from nova.i18n import _
|
||||
from nova.policies import servers_migrations as sm_policies
|
||||
|
||||
|
||||
def output(migration):
|
||||
def output(migration, include_uuid=False):
|
||||
"""Returns the desired output of the API from an object.
|
||||
|
||||
From a Migrations's object this method returns the primitive
|
||||
object with the only necessary and expected fields.
|
||||
"""
|
||||
return {
|
||||
result = {
|
||||
"created_at": migration.created_at,
|
||||
"dest_compute": migration.dest_compute,
|
||||
"dest_host": migration.dest_host,
|
||||
@ -49,6 +50,9 @@ def output(migration):
|
||||
"status": migration.status,
|
||||
"updated_at": migration.updated_at
|
||||
}
|
||||
if include_uuid:
|
||||
result['uuid'] = migration.uuid
|
||||
return result
|
||||
|
||||
|
||||
class ServerMigrationsController(wsgi.Controller):
|
||||
@ -96,7 +100,9 @@ class ServerMigrationsController(wsgi.Controller):
|
||||
migrations = self.compute_api.get_migrations_in_progress_by_instance(
|
||||
context, server_id, 'live-migration')
|
||||
|
||||
return {'migrations': [output(migration) for migration in migrations]}
|
||||
include_uuid = api_version_request.is_supported(req, '2.59')
|
||||
return {'migrations': [output(
|
||||
migration, include_uuid) for migration in migrations]}
|
||||
|
||||
@wsgi.Controller.api_version("2.23")
|
||||
@wsgi.expected_errors(404)
|
||||
@ -129,7 +135,8 @@ class ServerMigrationsController(wsgi.Controller):
|
||||
" progress.") % {"id": id, "uuid": server_id}
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
|
||||
return {'migration': output(migration)}
|
||||
include_uuid = api_version_request.is_supported(req, '2.59')
|
||||
return {'migration': output(migration, include_uuid)}
|
||||
|
||||
@wsgi.Controller.api_version("2.24")
|
||||
@wsgi.response(202)
|
||||
|
24
nova/api/openstack/compute/views/migrations.py
Normal file
24
nova/api/openstack/compute/views/migrations.py
Normal file
@ -0,0 +1,24 @@
|
||||
# Copyright 2017 Huawei Technologies Co.,LTD.
|
||||
#
|
||||
# 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 nova.api.openstack import common
|
||||
|
||||
|
||||
class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
_collection_name = "os-migrations"
|
||||
|
||||
def get_links(self, request, migrations):
|
||||
return self._get_collection_links(request, migrations,
|
||||
self._collection_name, 'uuid')
|
@ -0,0 +1,24 @@
|
||||
{
|
||||
"migrations": [
|
||||
{
|
||||
"created_at": "2016-06-23T14:42:02.000000",
|
||||
"dest_compute": "compute20",
|
||||
"dest_host": "5.6.7.8",
|
||||
"dest_node": "node20",
|
||||
"id": 4,
|
||||
"instance_uuid": "%(instance_2)s",
|
||||
"new_instance_type_id": 6,
|
||||
"old_instance_type_id": 5,
|
||||
"source_compute": "compute10",
|
||||
"source_node": "node10",
|
||||
"status": "migrating",
|
||||
"migration_type": "resize",
|
||||
"updated_at": "2016-06-23T14:42:02.000000",
|
||||
"uuid": "42341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
],
|
||||
"migrations_links": [{
|
||||
"href": "%(host)s/v2.1/6f70656e737461636b20342065766572/os-migrations?limit=1&marker=42341d4b-346a-40d0-83c6-5f4f6892b650",
|
||||
"rel": "next"
|
||||
}]
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
{
|
||||
"migrations": [
|
||||
{
|
||||
"created_at": "2016-01-29T11:42:02.000000",
|
||||
"dest_compute": "compute2",
|
||||
"dest_host": "1.2.3.4",
|
||||
"dest_node": "node2",
|
||||
"id": 1,
|
||||
"instance_uuid": "%(instance_1)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v2.1/6f70656e737461636b20342065766572/servers/%(instance_1)s/migrations/1",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/6f70656e737461636b20342065766572/servers/%(instance_1)s/migrations/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"new_instance_type_id": 1,
|
||||
"old_instance_type_id": 1,
|
||||
"source_compute": "compute1",
|
||||
"source_node": "node1",
|
||||
"migration_type": "live-migration",
|
||||
"status": "running",
|
||||
"updated_at": "2016-01-29T11:42:02.000000",
|
||||
"uuid": "12341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
{
|
||||
"migrations": [
|
||||
{
|
||||
"created_at": "2016-06-23T14:42:02.000000",
|
||||
"dest_compute": "compute20",
|
||||
"dest_host": "5.6.7.8",
|
||||
"dest_node": "node20",
|
||||
"id": 4,
|
||||
"instance_uuid": "%(instance_2)s",
|
||||
"new_instance_type_id": 6,
|
||||
"old_instance_type_id": 5,
|
||||
"source_compute": "compute10",
|
||||
"source_node": "node10",
|
||||
"migration_type": "resize",
|
||||
"status": "migrating",
|
||||
"updated_at": "2016-06-23T14:42:02.000000",
|
||||
"uuid": "42341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
},
|
||||
{
|
||||
"created_at": "2016-06-23T13:42:02.000000",
|
||||
"dest_compute": "compute20",
|
||||
"dest_host": "5.6.7.8",
|
||||
"dest_node": "node20",
|
||||
"id": 3,
|
||||
"instance_uuid": "%(instance_2)s",
|
||||
"new_instance_type_id": 6,
|
||||
"old_instance_type_id": 5,
|
||||
"source_compute": "compute10",
|
||||
"source_node": "node10",
|
||||
"migration_type": "resize",
|
||||
"status": "error",
|
||||
"updated_at": "2016-06-23T13:42:02.000000",
|
||||
"uuid": "32341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
{
|
||||
"migrations": [
|
||||
{
|
||||
"created_at": "2016-06-23T14:42:02.000000",
|
||||
"dest_compute": "compute20",
|
||||
"dest_host": "5.6.7.8",
|
||||
"dest_node": "node20",
|
||||
"id": 4,
|
||||
"instance_uuid": "%(instance_2)s",
|
||||
"new_instance_type_id": 6,
|
||||
"old_instance_type_id": 5,
|
||||
"source_compute": "compute10",
|
||||
"source_node": "node10",
|
||||
"migration_type": "resize",
|
||||
"status": "migrating",
|
||||
"updated_at": "2016-06-23T14:42:02.000000",
|
||||
"uuid": "42341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
},
|
||||
{
|
||||
"created_at": "2016-06-23T13:42:02.000000",
|
||||
"dest_compute": "compute20",
|
||||
"dest_host": "5.6.7.8",
|
||||
"dest_node": "node20",
|
||||
"id": 3,
|
||||
"instance_uuid": "%(instance_2)s",
|
||||
"new_instance_type_id": 6,
|
||||
"old_instance_type_id": 5,
|
||||
"source_compute": "compute10",
|
||||
"source_node": "node10",
|
||||
"migration_type": "resize",
|
||||
"status": "error",
|
||||
"updated_at": "2016-06-23T13:42:02.000000",
|
||||
"uuid": "32341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
},
|
||||
{
|
||||
"created_at": "2016-01-29T12:42:02.000000",
|
||||
"dest_compute": "compute2",
|
||||
"dest_host": "1.2.3.4",
|
||||
"dest_node": "node2",
|
||||
"id": 2,
|
||||
"instance_uuid": "%(instance_1)s",
|
||||
"new_instance_type_id": 1,
|
||||
"old_instance_type_id": 1,
|
||||
"source_compute": "compute1",
|
||||
"source_node": "node1",
|
||||
"migration_type": "live-migration",
|
||||
"status": "error",
|
||||
"updated_at": "2016-01-29T12:42:02.000000",
|
||||
"uuid": "22341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
},
|
||||
{
|
||||
"created_at": "2016-01-29T11:42:02.000000",
|
||||
"dest_compute": "compute2",
|
||||
"dest_host": "1.2.3.4",
|
||||
"dest_node": "node2",
|
||||
"id": 1,
|
||||
"instance_uuid": "%(instance_1)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v2.1/6f70656e737461636b20342065766572/servers/%(instance_1)s/migrations/1",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/6f70656e737461636b20342065766572/servers/%(instance_1)s/migrations/1",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"new_instance_type_id": 1,
|
||||
"old_instance_type_id": 1,
|
||||
"source_compute": "compute1",
|
||||
"source_node": "node1",
|
||||
"migration_type": "live-migration",
|
||||
"status": "running",
|
||||
"updated_at": "2016-01-29T11:42:02.000000",
|
||||
"uuid": "12341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"migration": {
|
||||
"created_at": "2016-01-29T13:42:02.000000",
|
||||
"dest_compute": "compute2",
|
||||
"dest_host": "1.2.3.4",
|
||||
"dest_node": "node2",
|
||||
"id": 1,
|
||||
"server_uuid": "%(server_uuid)s",
|
||||
"source_compute": "compute1",
|
||||
"source_node": "node1",
|
||||
"status": "running",
|
||||
"memory_total_bytes": 123456,
|
||||
"memory_processed_bytes": 12345,
|
||||
"memory_remaining_bytes": 111111,
|
||||
"disk_total_bytes": 234567,
|
||||
"disk_processed_bytes": 23456,
|
||||
"disk_remaining_bytes": 211111,
|
||||
"updated_at": "2016-01-29T13:42:02.000000",
|
||||
"uuid": "12341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
{
|
||||
"migrations": [
|
||||
{
|
||||
"created_at": "2016-01-29T13:42:02.000000",
|
||||
"dest_compute": "compute2",
|
||||
"dest_host": "1.2.3.4",
|
||||
"dest_node": "node2",
|
||||
"id": 1,
|
||||
"server_uuid": "%(server_uuid_1)s",
|
||||
"source_compute": "compute1",
|
||||
"source_node": "node1",
|
||||
"status": "running",
|
||||
"memory_total_bytes": 123456,
|
||||
"memory_processed_bytes": 12345,
|
||||
"memory_remaining_bytes": 111111,
|
||||
"disk_total_bytes": 234567,
|
||||
"disk_processed_bytes": 23456,
|
||||
"disk_remaining_bytes": 211111,
|
||||
"updated_at": "2016-01-29T13:42:02.000000",
|
||||
"uuid": "12341d4b-346a-40d0-83c6-5f4f6892b650"
|
||||
}
|
||||
]
|
||||
}
|
@ -184,3 +184,110 @@ class MigrationsSamplesJsonTestV2_23(api_sample_base.ApiSampleTestBaseV21):
|
||||
'migrations-get',
|
||||
{"instance_1": INSTANCE_UUID_1, "instance_2": INSTANCE_UUID_2},
|
||||
response, 200)
|
||||
|
||||
|
||||
class MigrationsSamplesJsonTestV2_59(MigrationsSamplesJsonTestV2_23):
|
||||
microversion = '2.59'
|
||||
scenarios = [('v2_59', {'api_major_version': 'v2.1'})]
|
||||
fake_migrations = [
|
||||
# in-progress live-migration.
|
||||
{
|
||||
'source_node': 'node1',
|
||||
'dest_node': 'node2',
|
||||
'source_compute': 'compute1',
|
||||
'dest_compute': 'compute2',
|
||||
'dest_host': '1.2.3.4',
|
||||
'status': 'running',
|
||||
'instance_uuid': INSTANCE_UUID_1,
|
||||
'old_instance_type_id': 1,
|
||||
'new_instance_type_id': 1,
|
||||
'migration_type': 'live-migration',
|
||||
'hidden': False,
|
||||
'created_at': datetime.datetime(2016, 0o1, 29, 11, 42, 2),
|
||||
'updated_at': datetime.datetime(2016, 0o1, 29, 11, 42, 2),
|
||||
'deleted_at': None,
|
||||
'deleted': False,
|
||||
'uuid': '12341d4b-346a-40d0-83c6-5f4f6892b650'
|
||||
},
|
||||
# non in-progress live-migration.
|
||||
{
|
||||
'source_node': 'node1',
|
||||
'dest_node': 'node2',
|
||||
'source_compute': 'compute1',
|
||||
'dest_compute': 'compute2',
|
||||
'dest_host': '1.2.3.4',
|
||||
'status': 'error',
|
||||
'instance_uuid': INSTANCE_UUID_1,
|
||||
'old_instance_type_id': 1,
|
||||
'new_instance_type_id': 1,
|
||||
'migration_type': 'live-migration',
|
||||
'hidden': False,
|
||||
'created_at': datetime.datetime(2016, 0o1, 29, 12, 42, 2),
|
||||
'updated_at': datetime.datetime(2016, 0o1, 29, 12, 42, 2),
|
||||
'deleted_at': None,
|
||||
'deleted': False,
|
||||
'uuid': '22341d4b-346a-40d0-83c6-5f4f6892b650'
|
||||
},
|
||||
# non in-progress resize.
|
||||
{
|
||||
'source_node': 'node10',
|
||||
'dest_node': 'node20',
|
||||
'source_compute': 'compute10',
|
||||
'dest_compute': 'compute20',
|
||||
'dest_host': '5.6.7.8',
|
||||
'status': 'error',
|
||||
'instance_uuid': INSTANCE_UUID_2,
|
||||
'old_instance_type_id': 5,
|
||||
'new_instance_type_id': 6,
|
||||
'migration_type': 'resize',
|
||||
'hidden': False,
|
||||
'created_at': datetime.datetime(2016, 0o6, 23, 13, 42, 2),
|
||||
'updated_at': datetime.datetime(2016, 0o6, 23, 13, 42, 2),
|
||||
'deleted_at': None,
|
||||
'deleted': False,
|
||||
'uuid': '32341d4b-346a-40d0-83c6-5f4f6892b650'
|
||||
},
|
||||
# in-progress resize.
|
||||
{
|
||||
'source_node': 'node10',
|
||||
'dest_node': 'node20',
|
||||
'source_compute': 'compute10',
|
||||
'dest_compute': 'compute20',
|
||||
'dest_host': '5.6.7.8',
|
||||
'status': 'migrating',
|
||||
'instance_uuid': INSTANCE_UUID_2,
|
||||
'old_instance_type_id': 5,
|
||||
'new_instance_type_id': 6,
|
||||
'migration_type': 'resize',
|
||||
'hidden': False,
|
||||
'created_at': datetime.datetime(2016, 0o6, 23, 14, 42, 2),
|
||||
'updated_at': datetime.datetime(2016, 0o6, 23, 14, 42, 2),
|
||||
'deleted_at': None,
|
||||
'deleted': False,
|
||||
'uuid': '42341d4b-346a-40d0-83c6-5f4f6892b650'
|
||||
}
|
||||
]
|
||||
|
||||
def test_get_migrations_with_limit(self):
|
||||
response = self._do_get('os-migrations?limit=1')
|
||||
self.assertEqual(200, response.status_code)
|
||||
self._verify_response(
|
||||
'migrations-get-with-limit',
|
||||
{"instance_2": INSTANCE_UUID_2}, response, 200)
|
||||
|
||||
def test_get_migrations_with_marker(self):
|
||||
response = self._do_get(
|
||||
'os-migrations?marker=22341d4b-346a-40d0-83c6-5f4f6892b650')
|
||||
self.assertEqual(200, response.status_code)
|
||||
self._verify_response(
|
||||
'migrations-get-with-marker',
|
||||
{"instance_1": INSTANCE_UUID_1, "instance_2": INSTANCE_UUID_2},
|
||||
response, 200)
|
||||
|
||||
def test_get_migrations_with_timestamp_filter(self):
|
||||
response = self._do_get(
|
||||
'os-migrations?changes-since=2016-06-23T13:42:01.000000')
|
||||
self.assertEqual(200, response.status_code)
|
||||
self._verify_response(
|
||||
'migrations-get-with-timestamp-filter',
|
||||
{"instance_2": INSTANCE_UUID_2}, response, 200)
|
||||
|
@ -210,3 +210,19 @@ class ServerMigrationsSampleJsonTestV2_24(test_servers.ServersSampleBase):
|
||||
uri = 'servers/%s/migrations/%s' % (self.uuid, self.migration.id)
|
||||
response = self._do_delete(uri)
|
||||
self.assertEqual(400, response.status_code)
|
||||
|
||||
|
||||
class ServerMigrationsSamplesJsonTestV2_59(
|
||||
ServerMigrationsSamplesJsonTestV2_23
|
||||
):
|
||||
ADMIN_API = True
|
||||
microversion = '2.59'
|
||||
scenarios = [('v2_59', {'api_major_version': 'v2.1'})]
|
||||
|
||||
def setUp(self):
|
||||
# Add UUIDs to the fake migrations used in the tests.
|
||||
self.fake_migrations[0][
|
||||
'uuid'] = '12341d4b-346a-40d0-83c6-5f4f6892b650'
|
||||
self.fake_migrations[1][
|
||||
'uuid'] = '22341d4b-346a-40d0-83c6-5f4f6892b650'
|
||||
super(ServerMigrationsSamplesJsonTestV2_59, self).setUp()
|
||||
|
@ -15,6 +15,8 @@
|
||||
import datetime
|
||||
|
||||
import mock
|
||||
import six
|
||||
from webob import exc
|
||||
|
||||
from nova.api.openstack.compute import migrations as migrations_v21
|
||||
from nova import context
|
||||
@ -258,6 +260,98 @@ class MigrationsTestCaseV223(MigrationsTestCaseV21):
|
||||
self.assertIn('migration_type', response['migrations'][0])
|
||||
|
||||
|
||||
class MigrationsTestCaseV259(MigrationsTestCaseV223):
|
||||
wsgi_api_version = '2.59'
|
||||
|
||||
def test_index(self):
|
||||
migrations = {'migrations': self.controller._output(
|
||||
self.req, migrations_obj, True, True)}
|
||||
|
||||
for i, mig in enumerate(migrations['migrations']):
|
||||
# first item is in-progress live migration
|
||||
if i == 0:
|
||||
self.assertIn('links', mig)
|
||||
else:
|
||||
self.assertNotIn('links', mig)
|
||||
|
||||
self.assertIn('migration_type', mig)
|
||||
self.assertIn('id', mig)
|
||||
self.assertIn('uuid', mig)
|
||||
self.assertNotIn('deleted', mig)
|
||||
self.assertNotIn('deleted_at', mig)
|
||||
|
||||
with mock.patch.object(self.controller.compute_api,
|
||||
'get_migrations_sorted') as m_get:
|
||||
m_get.return_value = migrations_obj
|
||||
response = self.controller.index(self.req)
|
||||
self.assertEqual(migrations, response)
|
||||
self.assertIn('links', response['migrations'][0])
|
||||
self.assertIn('migration_type', response['migrations'][0])
|
||||
|
||||
@mock.patch('nova.compute.api.API.get_migrations_sorted')
|
||||
def test_index_with_invalid_marker(self, mock_migrations_get):
|
||||
"""Tests detail paging with an invalid marker (not found)."""
|
||||
mock_migrations_get.side_effect = exception.MarkerNotFound(
|
||||
marker=uuids.invalid_marker)
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/os-migrations?marker=%s' % uuids.invalid_marker,
|
||||
version=self.wsgi_api_version, use_admin_context=True)
|
||||
e = self.assertRaises(exc.HTTPBadRequest,
|
||||
self.controller.index, req)
|
||||
self.assertEqual(
|
||||
"Marker %s could not be found." % uuids.invalid_marker,
|
||||
six.text_type(e))
|
||||
|
||||
def test_index_with_invalid_limit(self):
|
||||
"""Tests detail paging with an invalid limit."""
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/os-migrations?limit=x', version=self.wsgi_api_version,
|
||||
use_admin_context=True)
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.controller.index, req)
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/os-migrations?limit=-1', version=self.wsgi_api_version,
|
||||
use_admin_context=True)
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.controller.index, req)
|
||||
|
||||
def test_index_with_invalid_changes_since(self):
|
||||
"""Tests detail paging with an invalid changes-since value."""
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/os-migrations?changes-since=wrong_time',
|
||||
version=self.wsgi_api_version, use_admin_context=True)
|
||||
self.assertRaises(exception.ValidationError,
|
||||
self.controller.index, req)
|
||||
|
||||
def test_index_with_unknown_query_param(self):
|
||||
"""Tests detail paging with an unknown query parameter."""
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/os-migrations?foo=bar',
|
||||
version=self.wsgi_api_version, use_admin_context=True)
|
||||
ex = self.assertRaises(exception.ValidationError,
|
||||
self.controller.index, req)
|
||||
self.assertIn('Additional properties are not allowed',
|
||||
six.text_type(ex))
|
||||
|
||||
@mock.patch('nova.compute.api.API.get_migrations',
|
||||
return_value=objects.MigrationList())
|
||||
def test_index_with_changes_since_old_microversion(self, get_migrations):
|
||||
"""Tests that the changes-since query parameteris ignored before
|
||||
microversion 2.59.
|
||||
"""
|
||||
# Also use a valid filter (instance_uuid) to make sure only
|
||||
# changes-since is removed.
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/os-migrations?changes-since=2018-01-10T16:59:24.138939&'
|
||||
'instance_uuid=%s' % uuids.instance_uuid,
|
||||
version='2.58', use_admin_context=True)
|
||||
result = self.controller.index(req)
|
||||
self.assertEqual({'migrations': []}, result)
|
||||
get_migrations.assert_called_once_with(
|
||||
req.environ['nova.context'],
|
||||
{'instance_uuid': uuids.instance_uuid})
|
||||
|
||||
|
||||
class MigrationsPolicyEnforcement(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
super(MigrationsPolicyEnforcement, self).setUp()
|
||||
@ -281,3 +375,7 @@ class MigrationsPolicyEnforcementV223(MigrationsPolicyEnforcement):
|
||||
def setUp(self):
|
||||
super(MigrationsPolicyEnforcementV223, self).setUp()
|
||||
self.req = fakes.HTTPRequest.blank('', version=self.wsgi_api_version)
|
||||
|
||||
|
||||
class MigrationsPolicyEnforcementV259(MigrationsPolicyEnforcementV223):
|
||||
wsgi_api_version = '2.59'
|
||||
|
@ -0,0 +1,16 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Added pagination support for migrations, there are four changes:
|
||||
|
||||
- Add pagination support and ``changes-since`` filter for os-migrations
|
||||
API. Users can now use ``limit`` and ``marker`` to perform paginate query
|
||||
when listing migrations.
|
||||
- Users can also use ``changes-since`` filter to filter the results based
|
||||
on the last time the migration record was updated.
|
||||
- ``GET /os-migrations``,
|
||||
``GET /servers/{server_id}/migrations/{migration_id}`` and
|
||||
``GET /servers/{server_id}/migrations`` will now return a uuid value in
|
||||
addition to the migrations id in the response.
|
||||
- The query parameter schema of the ``GET /os-migrations`` API no longer
|
||||
allows additional properties.
|
Loading…
Reference in New Issue
Block a user