Filter migrations by user_id/project_id

In microversion 2.80, the ``GET /os-migrations`` API will have
optional ``user_id`` and ``project_id`` query parameters for
filtering migrations by user and/or project:

* GET /os-migrations?user_id=ef9d34b4-45d0-4530-871b-3fb535988394
* GET /os-migrations?project_id=011ee9f4-8f16-4c38-8633-a254d420fd54
* GET /os-migrations?user_id=ef9d34b4-45d0-4530-871b-3fb535988394&project_id=011ee9f4-8f16-4c38-8633-a254d420fd54

And expose the ``user_id`` and ``project_id`` fields in the following APIs:

* GET /os-migrations
* GET /servers/{server_id}/migrations
* GET /servers/{server_id}/migrations/{migration_id}

Co-Authored-By: Qiu Fossen <qiujunting>
Part of blueprint add-user-id-field-to-the-migrations-table
Change-Id: I7313d6cde1a5e1dc7dd6f3c0dff9f30bbf4bee2c
This commit is contained in:
zhangbailin 2019-08-02 17:27:37 +08:00 committed by Dan Smith
parent d14ae3a126
commit ac165112b7
35 changed files with 1115 additions and 25 deletions

View File

@ -39,6 +39,8 @@ Request
- marker: migration_marker
- changes-since: changes_since_migration
- changes-before: changes_before_migration
- user_id: user_id_query_migrations
- project_id: project_id_query_migrations
Response
--------
@ -62,19 +64,20 @@ Response
- links: migration_links_2_23
- uuid: migration_uuid
- migrations_links: migration_next_links_2_59
- user_id: user_id_migration_2_80
- project_id: project_id_migration_2_80
**Example List Migrations: JSON response**
.. literalinclude:: ../../doc/api_samples/os-migrations/migrations-get.json
:language: javascript
**Example List Migrations (v2.59):**
**Example List Migrations (v2.80):**
.. literalinclude:: ../../doc/api_samples/os-migrations/v2.59/migrations-get.json
.. literalinclude:: ../../doc/api_samples/os-migrations/v2.80/migrations-get.json
:language: javascript
**Example List Migrations With Paging (v2.59):**
**Example List Migrations With Paging (v2.80):**
.. literalinclude:: ../../doc/api_samples/os-migrations/v2.59/migrations-get-with-limit.json
.. literalinclude:: ../../doc/api_samples/os-migrations/v2.80/migrations-get-with-limit.json
:language: javascript

View File

@ -1133,6 +1133,13 @@ progress_query_server:
in: query
required: false
type: integer
project_id_query_migrations:
description: |
Filter the migrations by the given project ID.
in: query
required: false
type: string
min_version: 2.80
project_id_query_server:
description: |
Filter the list of servers by the given project ID.
@ -1409,6 +1416,13 @@ usage_marker:
required: false
type: string
min_version: 2.40
user_id_query_migrations:
description: |
Filter the migrations by the given user ID.
in: query
required: false
type: string
min_version: 2.80
user_id_query_quota:
description: |
ID of user to list the quotas for.
@ -5697,6 +5711,14 @@ project_id:
in: body
required: false
type: string
project_id_migration_2_80:
description: |
The ID of the project which initiated the server migration. The value
may be ``null`` for older migration records.
in: body
required: true
type: string
min_version: 2.80
project_id_server:
description: |
The ID of the project that this server belongs to.
@ -7113,6 +7135,14 @@ user_id:
in: body
required: true
type: string
user_id_migration_2_80:
description: |
The ID of the user which initiated the server migration. The value
may be ``null`` for older migration records.
in: body
required: true
type: string
min_version: 2.80
user_id_server_action:
description: |
The ID of the user which initiated the server action.

View File

@ -53,10 +53,12 @@ Response
- status: migrate_status
- updated_at: updated
- uuid: migration_uuid
- user_id: user_id_migration_2_80
- project_id: project_id_migration_2_80
**Example List Migrations (2.59)**
**Example List Migrations (2.80)**
.. literalinclude:: ../../doc/api_samples/server-migrations/v2.59/migrations-index.json
.. literalinclude:: ../../doc/api_samples/server-migrations/v2.80/migrations-index.json
:language: javascript
Show Migration Details
@ -107,10 +109,12 @@ Response
- status: migrate_status
- updated_at: updated
- uuid: migration_uuid
- user_id: user_id_migration_2_80
- project_id: project_id_migration_2_80
**Example Show Migration Details (2.59)**
**Example Show Migration Details (2.80)**
.. literalinclude:: ../../doc/api_samples/server-migrations/v2.59/migrations-get.json
.. literalinclude:: ../../doc/api_samples/server-migrations/v2.80/migrations-get.json
:language: javascript
Force Migration Complete Action (force_complete Action)

View File

@ -0,0 +1,32 @@
{
"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",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
}
]
}

View File

@ -0,0 +1,40 @@
{
"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",
"user_id": "78348f0e-97ee-4d70-ad34-189692673ea2",
"project_id": "9842f0f7-1229-4355-afe7-15ebdbb8c3d8"
},
{
"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",
"user_id": "78348f0e-97ee-4d70-ad34-189692673ea2",
"project_id": "9842f0f7-1229-4355-afe7-15ebdbb8c3d8"
}
]
}

View File

@ -0,0 +1,28 @@
{
"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",
"user_id": "78348f0e-97ee-4d70-ad34-189692673ea2",
"project_id": "9842f0f7-1229-4355-afe7-15ebdbb8c3d8"
}
],
"migrations_links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/os-migrations?limit=1&marker=42341d4b-346a-40d0-83c6-5f4f6892b650",
"rel": "next"
}
]
}

View File

@ -0,0 +1,32 @@
{
"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",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
}
]
}

View File

@ -0,0 +1,50 @@
{
"migrations": [
{
"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",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
},
{
"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",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
}
]
}

View File

@ -0,0 +1,86 @@
{
"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",
"user_id": "78348f0e-97ee-4d70-ad34-189692673ea2",
"project_id": "9842f0f7-1229-4355-afe7-15ebdbb8c3d8"
},
{
"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",
"user_id": "78348f0e-97ee-4d70-ad34-189692673ea2",
"project_id": "9842f0f7-1229-4355-afe7-15ebdbb8c3d8"
},
{
"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",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
},
{
"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",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
}
]
}

View File

@ -0,0 +1,6 @@
{
"os-migrateLive": {
"host": null,
"block_migration": "auto"
}
}

View File

@ -0,0 +1,23 @@
{
"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",
"user_id": "8dbaa0f0-ab95-4ffe-8cb4-9c89d2ac9d24",
"project_id": "5f705771-3aa9-4f4c-8660-0d9522ffdbea"
}
}

View File

@ -0,0 +1,25 @@
{
"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",
"user_id": "8dbaa0f0-ab95-4ffe-8cb4-9c89d2ac9d24",
"project_id": "5f705771-3aa9-4f4c-8660-0d9522ffdbea"
}
]
}

View File

@ -19,7 +19,7 @@
}
],
"status": "CURRENT",
"version": "2.79",
"version": "2.80",
"min_version": "2.1",
"updated": "2013-07-23T11:33:21Z"
}

View File

@ -22,7 +22,7 @@
}
],
"status": "CURRENT",
"version": "2.79",
"version": "2.80",
"min_version": "2.1",
"updated": "2013-07-23T11:33:21Z"
}

View File

@ -211,6 +211,12 @@ REST_API_VERSION_HISTORY = """REST API Version History:
this via the response from
``GET /servers/{server_id}/os-volume_attachments`` and
``GET /servers/{server_id}/os-volume_attachments/{volume_id}``.
* 2.80 - Adds support for optional query parameters ``user_id`` and
``project_id`` to the ``GET /os-migrations`` API and exposes
``user_id`` and ``project_id`` via the response from
``GET /os-migrations``,
``GET /servers/{server_id}/migrations``, and
``GET /servers/{server_id}/migrations/{migration_id}``.
"""
# The minimum and maximum versions of the API supported
@ -219,7 +225,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.79"
_MAX_API_VERSION = "2.80"
DEFAULT_API_VERSION = _MIN_API_VERSION
# Almost all proxy APIs which are related to network, images and baremetal

View File

@ -13,6 +13,7 @@
from oslo_utils import timeutils
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 migrations as schema_migrations
from nova.api.openstack.compute.views import migrations as migrations_view
@ -35,7 +36,8 @@ class MigrationsController(wsgi.Controller):
super(MigrationsController, self).__init__()
self.compute_api = compute.API()
def _output(self, req, migrations_obj, add_link=False, add_uuid=False):
def _output(self, req, migrations_obj, add_link=False,
add_uuid=False, add_user_project=False):
"""Returns the desired output of the API from an object.
From a MigrationsList's object this method returns a list of
@ -62,10 +64,11 @@ class MigrationsController(wsgi.Controller):
if 'memory_total' in obj:
for key in detail_keys:
del obj[key]
if 'user_id' in obj:
del obj['user_id']
if 'project_id' in obj:
del obj['project_id']
if not add_user_project:
if 'user_id' in obj:
del obj['user_id']
if 'project_id' in obj:
del obj['project_id']
# NOTE(Shaohe Feng) above version 2.23, add migration_type for all
# kinds of migration, but we only add links just for in-progress
# live-migration.
@ -127,7 +130,9 @@ class MigrationsController(wsgi.Controller):
migrations = self.compute_api.get_migrations(
context, search_opts)
migrations = self._output(req, migrations, add_link, add_uuid)
add_user_project = api_version_request.is_supported(req, '2.80')
migrations = self._output(req, migrations, add_link,
add_uuid, add_user_project)
migrations_dict = {'migrations': migrations}
if next_link:
@ -168,7 +173,9 @@ class MigrationsController(wsgi.Controller):
@wsgi.Controller.api_version("2.66") # noqa
@wsgi.expected_errors(400)
@validation.query_schema(schema_migrations.list_query_params_v266,
"2.66")
"2.66", "2.79")
@validation.query_schema(schema_migrations.list_query_params_v280,
"2.80")
def index(self, req):
"""Return all migrations using the query parameters as filters."""
limit, marker = common.get_limit_and_marker(req)

View File

@ -1029,3 +1029,22 @@ The affected APIs are as follows:
* ``POST /servers/{server_id}/os-volume_attachments``
* ``GET /servers/{server_id}/os-volume_attachments``
* ``GET /servers/{server_id}/os-volume_attachments/{volume_id}``
2.80
----
Microversion 2.80 changes the list migrations APIs and the os-migrations API.
Expose the ``user_id`` and ``project_id`` fields in the following APIs:
* ``GET /os-migrations``
* ``GET /servers/{server_id}/migrations``
* ``GET /servers/{server_id}/migrations/{migration_id}``
The ``GET /os-migrations`` API will also have optional ``user_id`` and
``project_id`` query parameters for filtering migrations by user and/or
project, for example:
* ``GET /os-migrations?user_id=ef9d34b4-45d0-4530-871b-3fb535988394``
* ``GET /os-migrations?project_id=011ee9f4-8f16-4c38-8633-a254d420fd54``
* ``GET /os-migrations?user_id=ef9d34b4-45d0-4530-871b-3fb535988394&project_id=011ee9f4-8f16-4c38-8633-a254d420fd54``

View File

@ -47,3 +47,11 @@ list_query_params_v266['properties'].update({
'changes-before': parameter_types.single_param(
{'type': 'string', 'format': 'date-time'}),
})
list_query_params_v280 = copy.deepcopy(list_query_params_v266)
list_query_params_v280['properties'].update({
# The 2.80 microversion added support for filtering migrations
# by user_id and/or project_id
'user_id': parameter_types.single_param({'type': 'string'}),
'project_id': parameter_types.single_param({'type': 'string'}),
})

View File

@ -26,7 +26,7 @@ from nova.i18n import _
from nova.policies import servers_migrations as sm_policies
def output(migration, include_uuid=False):
def output(migration, include_uuid=False, include_user_project=False):
"""Returns the desired output of the API from an object.
From a Migrations's object this method returns the primitive
@ -52,6 +52,9 @@ def output(migration, include_uuid=False):
}
if include_uuid:
result['uuid'] = migration.uuid
if include_user_project:
result['user_id'] = migration.user_id
result['project_id'] = migration.project_id
return result
@ -101,8 +104,11 @@ class ServerMigrationsController(wsgi.Controller):
context, server_id, 'live-migration')
include_uuid = api_version_request.is_supported(req, '2.59')
return {'migrations': [output(
migration, include_uuid) for migration in migrations]}
include_user_project = api_version_request.is_supported(req, '2.80')
return {'migrations': [
output(migration, include_uuid, include_user_project)
for migration in migrations]}
@wsgi.Controller.api_version("2.23")
@wsgi.expected_errors(404)
@ -136,7 +142,10 @@ class ServerMigrationsController(wsgi.Controller):
raise exc.HTTPNotFound(explanation=msg)
include_uuid = api_version_request.is_supported(req, '2.59')
return {'migration': output(migration, include_uuid)}
include_user_project = api_version_request.is_supported(req, '2.80')
return {'migration': output(migration, include_uuid,
include_user_project)}
@wsgi.Controller.api_version("2.24")
@wsgi.response(202)

View File

@ -499,8 +499,13 @@ class TestOpenStackClient(object):
return self.api_get('/servers/%s/migrations' %
server_id).body['migrations']
def get_migrations(self):
return self.api_get('os-migrations').body['migrations']
def get_migrations(self, user_id=None, project_id=None):
url = '/os-migrations?'
if user_id:
url += 'user_id=%s&' % user_id
if project_id:
url += 'project_id=%s&' % project_id
return self.api_get(url).body['migrations']
def force_complete_migration(self, server_id, migration_id):
return self.api_post(

View File

@ -0,0 +1,32 @@
{
"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",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
}
]
}

View File

@ -0,0 +1,40 @@
{
"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",
"user_id": "78348f0e-97ee-4d70-ad34-189692673ea2",
"project_id": "9842f0f7-1229-4355-afe7-15ebdbb8c3d8"
},
{
"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",
"user_id": "78348f0e-97ee-4d70-ad34-189692673ea2",
"project_id": "9842f0f7-1229-4355-afe7-15ebdbb8c3d8"
}
]
}

View File

@ -0,0 +1,26 @@
{
"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",
"user_id": "78348f0e-97ee-4d70-ad34-189692673ea2",
"project_id": "9842f0f7-1229-4355-afe7-15ebdbb8c3d8"
}
],
"migrations_links": [{
"href": "%(host)s/v2.1/6f70656e737461636b20342065766572/os-migrations?limit=1&marker=42341d4b-346a-40d0-83c6-5f4f6892b650",
"rel": "next"
}]
}

View File

@ -0,0 +1,32 @@
{
"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"
}
],
"migration_type": "live-migration",
"new_instance_type_id": 1,
"old_instance_type_id": 1,
"source_compute": "compute1",
"source_node": "node1",
"status": "running",
"updated_at": "2016-01-29T11:42:02.000000",
"uuid": "12341d4b-346a-40d0-83c6-5f4f6892b650",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
}
]
}

View File

@ -0,0 +1,50 @@
{
"migrations": [
{
"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",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
},
{
"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",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
}
]
}

View File

@ -0,0 +1,86 @@
{
"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",
"user_id": "78348f0e-97ee-4d70-ad34-189692673ea2",
"project_id": "9842f0f7-1229-4355-afe7-15ebdbb8c3d8"
},
{
"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",
"user_id": "78348f0e-97ee-4d70-ad34-189692673ea2",
"project_id": "9842f0f7-1229-4355-afe7-15ebdbb8c3d8"
},
{
"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",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
},
{
"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",
"user_id": "5c48ebaa-193f-4c5d-948a-f559cc92cd5e",
"project_id": "ef92ccff-00f3-46e4-b015-811110e36ee4"
}
]
}

View File

@ -0,0 +1,6 @@
{
"os-migrateLive": {
"host": null,
"block_migration": "auto"
}
}

View File

@ -0,0 +1,23 @@
{
"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",
"user_id": "8dbaa0f0-ab95-4ffe-8cb4-9c89d2ac9d24",
"project_id": "5f705771-3aa9-4f4c-8660-0d9522ffdbea"
}
}

View File

@ -0,0 +1,25 @@
{
"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",
"user_id": "8dbaa0f0-ab95-4ffe-8cb4-9c89d2ac9d24",
"project_id": "5f705771-3aa9-4f4c-8660-0d9522ffdbea"
}
]
}

View File

@ -315,3 +315,125 @@ class MigrationsSamplesJsonTestV2_66(MigrationsSamplesJsonTestV2_59):
self._verify_response(
'migrations-get-with-changes-before',
{"instance_1": INSTANCE_UUID_1}, response, 200)
class MigrationsSamplesJsonTestV2_80(MigrationsSamplesJsonTestV2_66):
microversion = '2.80'
scenarios = [('v2_80', {'api_major_version': 'v2.1'})]
USER_ID1 = "5c48ebaa-193f-4c5d-948a-f559cc92cd5e"
PROJECT_ID1 = "ef92ccff-00f3-46e4-b015-811110e36ee4"
USER_ID2 = "78348f0e-97ee-4d70-ad34-189692673ea2"
PROJECT_ID2 = "9842f0f7-1229-4355-afe7-15ebdbb8c3d8"
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',
'cross_cell_move': False,
'user_id': USER_ID1,
'project_id': PROJECT_ID1
},
# 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',
'cross_cell_move': False,
'user_id': USER_ID1,
'project_id': PROJECT_ID1
},
# 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',
'cross_cell_move': False,
'user_id': USER_ID2,
'project_id': PROJECT_ID2
},
# 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',
'cross_cell_move': False,
'user_id': USER_ID2,
'project_id': PROJECT_ID2
}
]
def test_get_migrations_with_user_id(self):
response = self._do_get('os-migrations?user_id=%s' % self.USER_ID1)
self.assertEqual(200, response.status_code)
self._verify_response('migrations-get-with-user-or-project-id',
{"instance_1": INSTANCE_UUID_1}, response, 200)
def test_get_migrations_with_project_id(self):
response = self._do_get('os-migrations?project_id=%s'
% self.PROJECT_ID1)
self.assertEqual(200, response.status_code)
self._verify_response('migrations-get-with-user-or-project-id',
{"instance_1": INSTANCE_UUID_1}, response, 200)
def test_get_migrations_with_user_and_project_id(self):
response = self._do_get('os-migrations?user_id=%s&project_id=%s'
% (self.USER_ID1, self.PROJECT_ID1))
self.assertEqual(200, response.status_code)
self._verify_response(
'migrations-get-with-user-or-project-id',
{"instance_1": INSTANCE_UUID_1}, response, 200)

View File

@ -245,3 +245,64 @@ class ServerMigrationsSampleJsonTestV2_65(ServerMigrationsSampleJsonTestV2_24):
uri = 'servers/%s/migrations/%s' % (self.uuid, self.migration.id)
response = self._do_delete(uri)
self.assertEqual(202, response.status_code)
class ServerMigrationsSampleJsonTestV2_80(
ServerMigrationsSampleJsonTestV2_65):
microversion = '2.80'
scenarios = [('v2_80', {'api_major_version': 'v2.1'})]
UUID_1 = '4cfba335-03d8-49b2-8c52-e69043d1e8fe'
UUID_2 = '058fc419-a8a8-4e08-b62c-a9841ef9cd3f'
USER_ID = '8dbaa0f0-ab95-4ffe-8cb4-9c89d2ac9d24'
PROJECT_ID = '5f705771-3aa9-4f4c-8660-0d9522ffdbea'
fake_migrations = [
{
'source_node': 'node1',
'dest_node': 'node2',
'source_compute': 'compute1',
'dest_compute': 'compute2',
'dest_host': '1.2.3.4',
'status': 'running',
'instance_uuid': UUID_1,
'migration_type': 'live-migration',
'hidden': False,
'memory_total': 123456,
'memory_processed': 12345,
'memory_remaining': 111111,
'disk_total': 234567,
'disk_processed': 23456,
'disk_remaining': 211111,
'created_at': datetime.datetime(2016, 0o1, 29, 13, 42, 2),
'updated_at': datetime.datetime(2016, 0o1, 29, 13, 42, 2),
'deleted_at': None,
'deleted': False,
'user_id': USER_ID,
'project_id': PROJECT_ID
},
{
'source_node': 'node10',
'dest_node': 'node20',
'source_compute': 'compute10',
'dest_compute': 'compute20',
'dest_host': '5.6.7.8',
'status': 'migrating',
'instance_uuid': UUID_2,
'migration_type': 'resize',
'hidden': False,
'memory_total': 456789,
'memory_processed': 56789,
'memory_remaining': 400000,
'disk_total': 96789,
'disk_processed': 6789,
'disk_remaining': 90000,
'created_at': datetime.datetime(2016, 0o1, 22, 13, 42, 2),
'updated_at': datetime.datetime(2016, 0o1, 22, 13, 42, 2),
'deleted_at': None,
'deleted': False,
'user_id': USER_ID,
'project_id': PROJECT_ID
}
]

View File

@ -1613,6 +1613,95 @@ class ServerRebuildTestCase(integrated_helpers._IntegratedTestBase,
'volume-backed server', six.text_type(resp))
class ServersTestV280(ServersTestBase):
api_major_version = 'v2.1'
def setUp(self):
super(ServersTestV280, self).setUp()
api_fixture = self.useFixture(nova_fixtures.OSAPIFixture(
api_version='v2.1'))
self.api = api_fixture.api
self.admin_api = api_fixture.admin_api
self.api.microversion = '2.80'
self.admin_api.microversion = '2.80'
def test_get_migrations_after_cold_migrate_server_in_same_project(
self):
# Create a server by non-admin
server = self.api.post_server({
'server': {
'flavorRef': 1,
'imageRef': '155d900f-4e14-4e4c-a73d-069cbf4541e6',
'name': 'migrate-server-test',
'networks': 'none'
}})
server_id = server['id']
# Check it's there
found_server = self.api.get_server(server_id)
self.assertEqual(server_id, found_server['id'])
self.start_service('compute', host='host2')
post = {'migrate': {}}
self.admin_api.post_server_action(server_id, post)
# Get the migration records by admin
migrations = self.admin_api.get_migrations(
user_id=self.admin_api.auth_user)
self.assertEqual(1, len(migrations))
self.assertEqual(server_id, migrations[0]['instance_uuid'])
# Get the migration records by non-admin
migrations = self.admin_api.get_migrations(
user_id=self.api.auth_user)
self.assertEqual([], migrations)
def test_get_migrations_after_live_migrate_server_in_different_project(
self):
# Create a server by non-admin
server = self.api.post_server({
'server': {
'flavorRef': 1,
'imageRef': '155d900f-4e14-4e4c-a73d-069cbf4541e6',
'name': 'migrate-server-test',
'networks': 'none'
}})
server_id = server['id']
# Check it's there
found_server = self.api.get_server(server_id)
self.assertEqual(server_id, found_server['id'])
server = self._wait_for_state_change(found_server, 'BUILD')
self.start_service('compute', host='host2')
project_id_1 = '4906260553374bf0a5d566543b320516'
project_id_2 = 'c850298c1b6b4796a8f197ac310b2469'
new_api_fixture = self.useFixture(nova_fixtures.OSAPIFixture(
api_version=self.api_major_version, project_id=project_id_1))
new_admin_api = new_api_fixture.admin_api
new_admin_api.microversion = '2.80'
post = {
'os-migrateLive': {
'host': 'host2',
'block_migration': True
}
}
new_admin_api.post_server_action(server_id, post)
# Get the migration records
migrations = new_admin_api.get_migrations(project_id=project_id_1)
self.assertEqual(1, len(migrations))
self.assertEqual(server_id, migrations[0]['instance_uuid'])
# Get the migration records by not exist project_id
migrations = new_admin_api.get_migrations(project_id=project_id_2)
self.assertEqual([], migrations)
class ServerMovingTests(integrated_helpers.ProviderUsageBaseTestCase):
"""Tests moving servers while checking the resource allocations and usages

View File

@ -449,6 +449,63 @@ class MigrationTestCaseV266(MigrationsTestCaseV259):
{'instance_uuid': uuids.instance_uuid})
class MigrationsTestCaseV280(MigrationTestCaseV266):
wsgi_api_version = '2.80'
def test_index(self):
migrations = {'migrations': self.controller._output(
self.req, migrations_obj,
add_link=True, add_uuid=True,
add_user_project=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.assertIn('user_id', mig)
self.assertIn('project_id', 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])
def test_index_filter_by_user_id_pre_v280(self):
"""Tests that the migrations by user_id query parameter
is not allowed before microversion 2.80.
"""
req = fakes.HTTPRequest.blank(
'/os-migrations?user_id=%s' % uuids.user_id,
version='2.79', use_admin_context=True)
ex = self.assertRaises(exception.ValidationError,
self.controller.index, req)
self.assertIn('Additional properties are not allowed',
six.text_type(ex))
def test_index_filter_by_project_id_pre_v280(self):
"""Tests that the migrations by project_id query parameter
is not allowed before microversion 2.80.
"""
req = fakes.HTTPRequest.blank(
'/os-migrations?project_id=%s' % uuids.project_id,
version='2.79', use_admin_context=True)
ex = self.assertRaises(exception.ValidationError,
self.controller.index, req)
self.assertIn('Additional properties are not allowed',
six.text_type(ex))
class MigrationsPolicyEnforcement(test.NoDBTestCase):
def setUp(self):
super(MigrationsPolicyEnforcement, self).setUp()
@ -476,3 +533,7 @@ class MigrationsPolicyEnforcementV223(MigrationsPolicyEnforcement):
class MigrationsPolicyEnforcementV259(MigrationsPolicyEnforcementV223):
wsgi_api_version = '2.59'
class MigrationsPolicyEnforcementV280(MigrationsPolicyEnforcementV259):
wsgi_api_version = '2.80'

View File

@ -368,6 +368,10 @@ class ServerMigrationsTestsV265(ServerMigrationsTestsV224):
_do_test()
class ServerMigrationsTestsV280(ServerMigrationsTestsV265):
wsgi_api_version = '2.80'
class ServerMigrationsPolicyEnforcementV21(test.NoDBTestCase):
wsgi_api_version = '2.22'

View File

@ -0,0 +1,20 @@
---
features:
- |
Microversion 2.80 changes the list migrations APIs and the
os-migrations API.
In this microversion, expose the ``user_id`` and ``project_id``
fields in the following APIs:
* ``GET /os-migrations``
* ``GET /servers/{server_id}/migrations``
* ``GET /servers/{server_id}/migrations/{migration_id}``
The ``GET /os-migrations`` API will also have optional ``user_id`` and
``project_id`` query parameters for filtering migrations by user and/or
project, for example:
* ``GET /os-migrations?user_id=ef9d34b4-45d0-4530-871b-3fb535988394``
* ``GET /os-migrations?project_id=011ee9f4-8f16-4c38-8633-a254d420fd54``
* ``GET /os-migrations?user_id=ef9d34b4-45d0-4530-871b-3fb535988394&project_id=011ee9f4-8f16-4c38-8633-a254d420fd54``