Resource retrieving: add changes-before filter

This adds the changes-before filter to the servers,
os-instance-actions and os-migrations APIs for
filtering resources which were last updated before
or equal to the given time. The changes-before filter,
like the changes-since filter, will return deleted
server resources.

Part of bp support-to-query-nova-resources-filter-by-changes-before
Change-Id: If91c179e3823c8b0da744a9363906b0f7b05c326
This commit is contained in:
zhangbailin 2018-09-03 10:55:05 +08:00 committed by Matt Riedemann
parent 82270cc261
commit 28c1075b59
61 changed files with 2426 additions and 54 deletions

View File

@ -1,32 +1,81 @@
==================================================
Efficient polling with the changes-since parameter
==================================================
=================
Efficient polling
=================
The REST API allows you to poll for the status of certain operations by
performing a **GET** on various elements. Rather than re-downloading and
re-parsing the full status at each polling interval, your REST client
may use the ``changes-since`` parameter to check for changes since a
previous request.
re-parsing the full status at each polling interval, your REST client may
use the ``changes-since`` and/or ``changes-before`` parameters to check
for changes within a specified time.
The ``changes-since`` time is specified as an `ISO
8601 <https://en.wikipedia.org/wiki/ISO_8601>`__ dateTime
The ``changes-since`` time or ``changes-before`` time is specified as
an `ISO 8601 <https://en.wikipedia.org/wiki/ISO_8601>`__ dateTime
(2011-01-24T17:08Z). The form for the timestamp is **CCYY-MM-DDThh:mm:ss**.
An optional time zone may be written in by appending the form ±hh:mm
which describes the timezone as an offset from UTC. When the timezone is
not specified (2011-01-24T17:08), the UTC timezone is assumed.
If nothing has changed since the ``changes-since`` time, an empty list is
returned. If data has changed, only the items changed since the
specified time are returned in the response. For example, performing a
**GET** against::
The following situations need to be considered:
https://api.servers.openstack.org/v2.1/servers?changes-since=2015-01-24T17:08Z
* If nothing has changed since the ``changes-since`` time, an empty list is
returned. If data has changed, only the items changed since the specified
time are returned in the response. For example, performing a
**GET** against::
would list all servers that have changed since Mon, 24 Jan 2015 17:08:00 UTC.
https://api.servers.openstack.org/v2.1/servers?changes-since=2015-01-24T17:08Z
would list all servers that have changed since Mon, 24 Jan 2015 17:08:00
UTC.
* If nothing has changed earlier than or equal to the ``changes-before``
time, an empty list is returned. If data has changed, only the items
changed earlier than or equal to the specified time are returned in the
response. For example, performing a **GET** against::
https://api.servers.openstack.org/v2.1/servers?changes-before=2015-01-24T17:08Z
would list all servers that have changed earlier than or equal to
Mon, 24 Jan 2015 17:08:00 UTC.
* If nothing has changed later than or equal to ``changes-since``, or
earlier than or equal to ``changes-before``, an empty list is returned.
If data has changed, only the items changed between ``changes-since``
time and ``changes-before`` time are returned in the response.
For example, performing a **GET** against::
https://api.servers.openstack.org/v2.1/servers?changes-since=2015-01-24T17:08Z&changes-before=2015-01-25T17:08Z
would list all servers that have changed later than or equal to Mon,
24 Jan 2015 17:08:00 UTC, and earlier than or equal to Mon, 25 Jan 2015
17:08:00 UTC.
Microversion change history for servers, instance actions and migrations
regarding ``changes-since`` and ``changes-before``:
* The `2.21 microversion`_ allows reading instance actions for a deleted
server resource.
* The `2.58 microversion`_ allows filtering on ``changes-since`` when listing
instance actions for a server.
* The `2.59 microversion`_ allows filtering on ``changes-since`` when listing
migration records.
* The `2.66 microversion`_ adds the ``changes-before`` filter when listing
servers, instance actions and migrations.
The ``changes-since`` filter nor the ``changes-before`` filter
change any read-deleted behavior in the os-instance-actions or
os-migrations APIs. The os-instance-actions API with the 2.21 microversion
allows retrieving instance actions for a deleted server resource.
The os-migrations API takes an optional ``instance_uuid`` filter parameter
but does not support returning deleted migration records.
To allow clients to keep track of changes, the ``changes-since`` filter
displays items that have been *recently* deleted. Both images and
servers contain a ``DELETED`` status that indicates that the resource
has been removed. Implementations are not required to keep track of
deleted resources indefinitely, so sending a ``changes-since`` time in the
distant past may miss deletions.
and ``changes-before`` filter displays items that have been *recently*
deleted. Servers contain a ``DELETED`` status that indicates that the
resource has been removed. Implementations are not required to keep track
of deleted resources indefinitely, so sending a ``changes-since`` time or
a ``changes-before`` time in the distant past may miss deletions.
.. _2.21 microversion: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id19
.. _2.58 microversion: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id53
.. _2.59 microversion: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id54
.. _2.66 microversion: https://docs.openstack.org/nova/latest/reference/api-microversion-history.html#id59

View File

@ -132,9 +132,9 @@ For different user roles, the user has different query options set:
- For general user, there is limited set of attributes of the servers can be
used as query option. ``reservation_id``, ``name``, ``status``, ``image``,
``flavor``, ``ip``, ``changes-since``, ``ip6``, ``tags``, ``tags-any``,
``not-tags``, ``not-tags-any`` are supported options to be used. Other
options will be ignored by nova silently.
``flavor``, ``ip``, ``changes-since``, ``changes-before``, ``ip6``,
``tags``, ``tags-any``, ``not-tags``, ``not-tags-any`` are supported options
to be used. Other options will be ignored by nova silently.
- For administrator, most of the server attributes can be used as query
options. Before the Ocata release, the fields in the database schema of
@ -197,11 +197,14 @@ For different user roles, the user has different query options set:
]
}
There are also some speical query options:
There are also some special query options:
- ``changes-since`` returns the servers updated after the given time.
Please see: :doc:`polling_changes-since_parameter`
- ``changes-before`` returns the servers updated before the given time.
Please see: :doc:`polling_changes-since_parameter`
- ``deleted`` returns (or excludes) deleted servers
- ``soft_deleted`` modifies behavior of 'deleted' to either include or exclude
@ -212,7 +215,7 @@ There are also some speical query options:
.. code::
**Example: User query server with special keys changes-since**
**Example: User query server with special keys changes-since or changes-before**
Precondition:
GET /servers/detail
@ -221,13 +224,13 @@ There are also some speical query options:
{
"servers": [
{
"name": "t1"
"updated": "2015-12-15T15:55:52Z"
"name": "t1",
"updated": "2015-12-15T15:55:52Z",
...
},
{
"name": "t2",
"updated": "2015-12-17T15:55:52Z"
"updated": "2015-12-17T15:55:52Z",
...
}
]
@ -239,11 +242,40 @@ There are also some speical query options:
{
{
"name": "t2",
"updated": "2015-12-17T15:55:52Z"
"updated": "2015-12-17T15:55:52Z",
...
}
}
GET /servers/detail?changes-before='2015-12-16T15:55:52Z'
Response:
{
{
"name": "t1",
"updated": "2015-12-15T15:55:52Z",
...
}
}
GET /servers/detail?changes-since='2015-12-10T15:55:52Z'&changes-before='2015-12-28T15:55:52Z'
Response:
{
"servers": [
{
"name": "t1",
"updated": "2015-12-15T15:55:52Z",
...
},
{
"name": "t2",
"updated": "2015-12-17T15:55:52Z",
...
}
]
}
There are two kinds of matching in query options: Exact matching and
regex matching.

View File

@ -34,6 +34,7 @@ Request
- limit: instance_action_limit
- marker: instance_action_marker
- changes-since: changes_since_instance_action
- changes-before: changes_before_instance_action
Response
--------

View File

@ -35,6 +35,7 @@ Request
- limit: migration_limit
- marker: migration_marker
- changes-since: changes_since_migration
- changes-before: changes_before_migration
Response
--------

View File

@ -453,6 +453,61 @@ changes-since:
in: query
required: false
type: string
changes_before_instance_action:
description: |
Filters the response by a date and time stamp when the instance actions last changed.
Those instances that changed before or equal to 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.66
changes_before_migration:
description: |
Filters the response by a date and time stamp when the migration last
changed. Those migrations that changed before or equal to 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.66
changes_before_server:
description: |
Filters the response by a date and time stamp when the server last changed.
Those servers that changed before or equal to the specified date and time stamp
are returned. To help keep track of changes this may also return recently deleted
servers.
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.66
changes_since_instance_action:
description: |
Filters the response by a date and time stamp when the instance action last

View File

@ -169,6 +169,7 @@ whitelist will be silently ignored.
- ``status``
- ``tags`` (New in version 2.26)
- ``tags-any`` (New in version 2.26)
- ``changes-before`` (New in version 2.66)
- For admin user, whitelist includes all filter keys mentioned in
@ -230,6 +231,7 @@ Request
- not-tags-any: not_tags_any_query
- tags: tags_query
- tags-any: tags_any_query
- changes-before: changes_before_server
Response
--------
@ -552,6 +554,7 @@ Request
- not-tags-any: not_tags_any_query
- tags: tags_query
- tags-any: tags_any_query
- changes-before: changes_before_server
Response
--------

View File

@ -0,0 +1,21 @@
{
"instanceAction": {
"action": "stop",
"events": [
{
"event": "compute_stop_instance",
"finish_time": "2018-04-25T01:26:34.784165",
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
"result": "Success",
"start_time": "2018-04-25T01:26:34.612020"
}
],
"instance_uuid": "79edaa44-ad4f-4af7-b994-154518c2b927",
"message": null,
"project_id": "6f70656e737461636b20342065766572",
"request_id": "req-8eb28d4a-db6c-4337-bab8-ce154e9c620e",
"start_time": "2018-04-25T01:26:34.388280",
"updated_at": "2018-04-25T01:26:34.784165",
"user_id": "fake"
}
}

View File

@ -0,0 +1,23 @@
{
"instanceAction": {
"action": "stop",
"events": [
{
"event": "compute_stop_instance",
"finish_time": "2018-04-25T01:26:36.790544",
"host": "compute",
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
"result": "Success",
"start_time": "2018-04-25T01:26:36.539271",
"traceback": null
}
],
"instance_uuid": "4bf3473b-d550-4b65-9409-292d44ab14a2",
"message": null,
"project_id": "6f70656e737461636b20342065766572",
"request_id": "req-0d819d5c-1527-4669-bdf0-ffad31b5105b",
"start_time": "2018-04-25T01:26:36.341290",
"updated_at": "2018-04-25T01:26:36.790544",
"user_id": "admin"
}
}

View File

@ -0,0 +1,24 @@
{
"instanceActions": [
{
"action": "stop",
"instance_uuid": "15835b6f-1e14-4cfa-9f66-1abea1a1c0d5",
"message": null,
"project_id": "6f70656e737461636b20342065766572",
"request_id": "req-f04d4b92-6241-42da-b82d-2cedb225c58d",
"start_time": "2018-04-25T01:26:36.036697",
"updated_at": "2018-04-25T01:26:36.525308",
"user_id": "admin"
},
{
"action": "create",
"instance_uuid": "15835b6f-1e14-4cfa-9f66-1abea1a1c0d5",
"message": null,
"project_id": "6f70656e737461636b20342065766572",
"request_id": "req-d8790618-9bbf-4df0-8af8-fc9e24de29c0",
"start_time": "2018-04-25T01:26:33.692125",
"updated_at": "2018-04-25T01:26:35.993821",
"user_id": "admin"
}
]
}

View File

@ -0,0 +1,24 @@
{
"instanceActions": [
{
"action": "stop",
"instance_uuid": "2150964c-30fe-4214-9547-8822375aa7d0",
"message": null,
"project_id": "6f70656e737461636b20342065766572",
"request_id": "req-0c3b2079-0a44-474d-a5b2-7466d4b4c642",
"start_time": "2018-04-25T01:26:29.594237",
"updated_at": "2018-04-25T01:26:30.065061",
"user_id": "admin"
},
{
"action": "create",
"instance_uuid": "15835b6f-1e14-4cfa-9f66-1abea1a1c0d5",
"message": null,
"project_id": "6f70656e737461636b20342065766572",
"request_id": "req-d8790618-9bbf-4df0-8af8-fc9e24de29c0",
"start_time": "2018-04-25T01:26:33.692125",
"updated_at": "2018-04-25T01:26:35.993821",
"user_id": "admin"
}
]
}

View File

@ -0,0 +1,14 @@
{
"instanceActions": [
{
"action": "stop",
"instance_uuid": "2150964c-30fe-4214-9547-8822375aa7d0",
"message": null,
"project_id": "6f70656e737461636b20342065766572",
"request_id": "req-0c3b2079-0a44-474d-a5b2-7466d4b4c642",
"start_time": "2018-04-25T01:26:29.594237",
"updated_at": "2018-04-25T01:26:30.065061",
"user_id": "admin"
}
]
}

View File

@ -0,0 +1,20 @@
{
"instanceActions": [
{
"action": "stop",
"instance_uuid": "ca3d3be5-1a40-427f-9515-f5e181f479d0",
"message": null,
"project_id": "6f70656e737461636b20342065766572",
"request_id": "req-4dbefbb7-d743-4d42-b0a1-a79cbe256138",
"start_time": "2018-04-25T01:26:28.909887",
"updated_at": "2018-04-25T01:26:29.400606",
"user_id": "admin"
}
],
"links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/ca3d3be5-1a40-427f-9515-f5e181f479d0/os-instance-actions?limit=1&marker=req-4dbefbb7-d743-4d42-b0a1-a79cbe256138",
"rel": "next"
}
]
}

View File

@ -0,0 +1,14 @@
{
"instanceActions": [
{
"action": "create",
"instance_uuid": "9bde1fd5-8435-45c5-afc1-bedd0605275b",
"message": null,
"project_id": "6f70656e737461636b20342065766572",
"request_id": "req-4510fb10-447f-4572-a64d-c2324547d86c",
"start_time": "2018-04-25T01:26:33.710291",
"updated_at": "2018-04-25T01:26:35.374936",
"user_id": "fake"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

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": "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"
}
]
}

View File

@ -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"
}
]
}

View 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"
}
]
}

View File

@ -0,0 +1,28 @@
{
"server" : {
"accessIPv4": "1.2.3.4",
"accessIPv6": "80fe::",
"name" : "new-server-test",
"imageRef" : "70a599e0-31e7-49b7-b260-868f441e862b",
"flavorRef" : "6",
"availability_zone": "nova",
"OS-DCF:diskConfig": "AUTO",
"metadata" : {
"My Server Name" : "Apache1"
},
"security_groups": [
{
"name": "default"
}
],
"user_data" : "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==",
"networks": "auto",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
]
},
"OS-SCH-HNT:scheduler_hints": {
"same_host": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"
}
}

View File

@ -0,0 +1,22 @@
{
"server": {
"OS-DCF:diskConfig": "AUTO",
"adminPass": "wKLKinb9u7GM",
"id": "aab35fd0-b459-4b59-9308-5a23147f3165",
"links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/aab35fd0-b459-4b59-9308-5a23147f3165",
"rel": "self"
},
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/aab35fd0-b459-4b59-9308-5a23147f3165",
"rel": "bookmark"
}
],
"security_groups": [
{
"name": "default"
}
]
}
}

View File

@ -0,0 +1,184 @@
{
"server": [
{
"OS-DCF:diskConfig": "AUTO",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "compute",
"OS-EXT-SRV-ATTR:hostname": "new-server-test",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini",
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
"OS-EXT-SRV-ATTR:kernel_id": "",
"OS-EXT-SRV-ATTR:launch_index": 0,
"OS-EXT-SRV-ATTR:ramdisk_id": "",
"OS-EXT-SRV-ATTR:reservation_id": "r-ov3q80zj",
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
"OS-EXT-SRV-ATTR:user_data": "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==",
"OS-EXT-STS:power_state": 1,
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"OS-SRV-USG:launched_at": "2018-02-14T19:23:59.895661",
"OS-SRV-USG:terminated_at": null,
"accessIPv4": "1.2.3.4",
"accessIPv6": "80fe::",
"addresses": {
"private": [
{
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
"OS-EXT-IPS:type": "fixed",
"addr": "192.168.0.3",
"version": 4
}
]
},
"config_drive": "",
"created": "2018-02-14T15:23:58Z",
"description": null,
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {
"hw:cpu_policy": "dedicated",
"hw:mem_page_size": "2048"
},
"original_name": "m1.tiny.specs",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
"host_status": "UP",
"id": "9168b536-cd40-4630-b43f-b259807c6e87",
"image": {
"id": "70a599e0-31e7-49b7-b260-868f441e862b",
"links": [
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b",
"rel": "bookmark"
}
]
},
"key_name": null,
"links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/9168b536-cd40-4630-b43f-b259807c6e87",
"rel": "self"
},
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/9168b536-cd40-4630-b43f-b259807c6e87",
"rel": "bookmark"
}
],
"locked": false,
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"os-extended-volumes:volumes_attached": [],
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"status": "ACTIVE",
"tags": [],
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
],
"updated": "2018-02-14T15:24:00Z",
"user_id": "fake"
},
{
"OS-DCF:diskConfig": "AUTO",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "compute",
"OS-EXT-SRV-ATTR:hostname": "new-server-test",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini",
"OS-EXT-SRV-ATTR:instance_name": "instance-00000002",
"OS-EXT-SRV-ATTR:kernel_id": "",
"OS-EXT-SRV-ATTR:launch_index": 0,
"OS-EXT-SRV-ATTR:ramdisk_id": "",
"OS-EXT-SRV-ATTR:reservation_id": "r-ov3q80zj",
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
"OS-EXT-SRV-ATTR:user_data": "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==",
"OS-EXT-STS:power_state": 1,
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"OS-SRV-USG:launched_at": "2018-02-14T19:23:59.895661",
"OS-SRV-USG:terminated_at": null,
"accessIPv4": "1.2.3.4",
"accessIPv6": "80fe::",
"addresses": {
"private": [
{
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
"OS-EXT-IPS:type": "fixed",
"addr": "192.168.0.2",
"version": 4
}
]
},
"config_drive": "",
"created": "2018-02-14T17:23:58Z",
"description": null,
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {
"hw:cpu_policy": "dedicated",
"hw:mem_page_size": "2048"
},
"original_name": "m1.tiny.specs",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
"host_status": "UP",
"id": "9168b536-cd40-4630-b43f-b259807c6e83",
"image": {
"id": "70a599e0-31e7-49b7-b260-868f441e862b",
"links": [
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b",
"rel": "bookmark"
}
]
},
"key_name": null,
"links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/9168b536-cd40-4630-b43f-b259807c6e87",
"rel": "self"
},
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/9168b536-cd40-4630-b43f-b259807c6e87",
"rel": "bookmark"
}
],
"locked": false,
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"os-extended-volumes:volumes_attached": [],
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"status": "ACTIVE",
"tags": [],
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
],
"updated": "2018-02-14T17:24:00Z",
"user_id": "fake"
}
]
}

View File

@ -0,0 +1,190 @@
{
"servers": [
{
"OS-DCF:diskConfig": "AUTO",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "compute",
"OS-EXT-SRV-ATTR:hostname": "new-server-test",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini",
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
"OS-EXT-SRV-ATTR:kernel_id": "",
"OS-EXT-SRV-ATTR:launch_index": 0,
"OS-EXT-SRV-ATTR:ramdisk_id": "",
"OS-EXT-SRV-ATTR:reservation_id": "r-y0w4v32k",
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
"OS-EXT-SRV-ATTR:user_data": "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==",
"OS-EXT-STS:power_state": 1,
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"OS-SRV-USG:launched_at": "2018-10-10T15:49:09.516729",
"OS-SRV-USG:terminated_at": null,
"accessIPv4": "1.2.3.4",
"accessIPv6": "80fe::",
"addresses": {
"private": [
{
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
"OS-EXT-IPS:type": "fixed",
"addr": "192.168.0.1",
"version": 4
}
]
},
"config_drive": "",
"created": "2018-10-10T15:49:08Z",
"description": null,
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {
"hw:cpu_policy": "dedicated",
"hw:mem_page_size": "2048"
},
"original_name": "m1.tiny.specs",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
"host_status": "UP",
"id": "569f39f9-7c76-42a1-9c2d-8394e2638a6e",
"image": {
"id": "70a599e0-31e7-49b7-b260-868f441e862b",
"links": [
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b",
"rel": "bookmark"
}
]
},
"key_name": null,
"links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/569f39f9-7c76-42a1-9c2d-8394e2638a6d",
"rel": "self"
},
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/569f39f9-7c76-42a1-9c2d-8394e2638a6d",
"rel": "bookmark"
}
],
"locked": false,
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"os-extended-volumes:volumes_attached": [],
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"status": "ACTIVE",
"tags": [],
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
],
"updated": "2018-10-10T15:49:09Z",
"user_id": "fake"
},
{
"OS-DCF:diskConfig": "AUTO",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "compute",
"OS-EXT-SRV-ATTR:hostname": "new-server-test",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini",
"OS-EXT-SRV-ATTR:instance_name": "instance-00000002",
"OS-EXT-SRV-ATTR:kernel_id": "",
"OS-EXT-SRV-ATTR:launch_index": 0,
"OS-EXT-SRV-ATTR:ramdisk_id": "",
"OS-EXT-SRV-ATTR:reservation_id": "r-y0w4v32k",
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
"OS-EXT-SRV-ATTR:user_data": "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==",
"OS-EXT-STS:power_state": 1,
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"OS-SRV-USG:launched_at": "2018-10-10T17:49:09.516729",
"OS-SRV-USG:terminated_at": null,
"accessIPv4": "1.2.3.4",
"accessIPv6": "80fe::",
"addresses": {
"private": [
{
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
"OS-EXT-IPS:type": "fixed",
"addr": "192.168.0.2",
"version": 4
}
]
},
"config_drive": "",
"created": "2018-10-10T17:49:08Z",
"description": null,
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {
"hw:cpu_policy": "dedicated",
"hw:mem_page_size": "2048"
},
"original_name": "m1.tiny.specs",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
"host_status": "UP",
"id": "569f39f9-7c76-42a1-9c2d-8394e2638a6f",
"image": {
"id": "70a599e0-31e7-49b7-b260-868f441e862b",
"links": [
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b",
"rel": "bookmark"
}
]
},
"key_name": null,
"links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/569f39f9-7c76-42a1-9c2d-8394e2638a6d",
"rel": "self"
},
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/569f39f9-7c76-42a1-9c2d-8394e2638a6d",
"rel": "bookmark"
}
],
"locked": false,
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"os-extended-volumes:volumes_attached": [],
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"status": "ACTIVE",
"tags": [],
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
],
"updated": "2018-10-10T17:49:09Z",
"user_id": "fake"
}
],
"servers_links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/detail?limit=1&marker=569f39f9-7c76-42a1-9c2d-8394e2638a6d",
"rel": "next"
}
]
}

View File

@ -0,0 +1,94 @@
{
"servers": [
{
"OS-DCF:diskConfig": "AUTO",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "compute",
"OS-EXT-SRV-ATTR:hostname": "new-server-test",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "fake-mini",
"OS-EXT-SRV-ATTR:instance_name": "instance-00000001",
"OS-EXT-SRV-ATTR:kernel_id": "",
"OS-EXT-SRV-ATTR:launch_index": 0,
"OS-EXT-SRV-ATTR:ramdisk_id": "",
"OS-EXT-SRV-ATTR:reservation_id": "r-y0w4v32k",
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
"OS-EXT-SRV-ATTR:user_data": "IyEvYmluL2Jhc2gKL2Jpbi9zdQplY2hvICJJIGFtIGluIHlvdSEiCg==",
"OS-EXT-STS:power_state": 1,
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"OS-SRV-USG:launched_at": "2018-10-10T15:49:09.516729",
"OS-SRV-USG:terminated_at": null,
"accessIPv4": "1.2.3.4",
"accessIPv6": "80fe::",
"addresses": {
"private": [
{
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
"OS-EXT-IPS:type": "fixed",
"addr": "192.168.0.1",
"version": 4
}
]
},
"config_drive": "",
"created": "2018-10-10T15:49:08Z",
"description": null,
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {
"hw:cpu_policy": "dedicated",
"hw:mem_page_size": "2048"
},
"original_name": "m1.tiny.specs",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "2091634baaccdc4c5a1d57069c833e402921df696b7f970791b12ec6",
"host_status": "UP",
"id": "569f39f9-7c76-42a1-9c2d-8394e2638a6e",
"image": {
"id": "70a599e0-31e7-49b7-b260-868f441e862b",
"links": [
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/images/70a599e0-31e7-49b7-b260-868f441e862b",
"rel": "bookmark"
}
]
},
"key_name": null,
"links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/569f39f9-7c76-42a1-9c2d-8394e2638a6d",
"rel": "self"
},
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/569f39f9-7c76-42a1-9c2d-8394e2638a6d",
"rel": "bookmark"
}
],
"locked": false,
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"os-extended-volumes:volumes_attached": [],
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"status": "ACTIVE",
"tags": [],
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
],
"updated": "2018-10-10T15:49:09Z",
"user_id": "fake"
}
]
}

View File

@ -0,0 +1,18 @@
{
"servers": [
{
"id": "6e3a87e6-a133-452e-86e1-a31291c1b1c8",
"links": [
{
"href": "http://openstack.example.com/v2.1/6f70656e737461636b20342065766572/servers/6e3a87e6-a133-452e-86e1-a31291c1b1c8",
"rel": "self"
},
{
"href": "http://openstack.example.com/6f70656e737461636b20342065766572/servers/6e3a87e6-a133-452e-86e1-a31291c1b1c8",
"rel": "bookmark"
}
],
"name": "new-server-test"
}
]
}

View File

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

View File

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

View File

@ -158,6 +158,10 @@ REST_API_VERSION_HISTORY = """REST API Version History:
/os-server-groups/{group_id} API.
* 2.65 - Add support for abort live migrations in ``queued`` and
``preparing`` status.
* 2.66 - Add ``changes-before`` to support users to specify the
``updated_at`` time to filter nova resources, the resources
include the servers API, os-instance-action API and
os-migrations API.
"""
# The minimum and maximum versions of the API supported
@ -166,7 +170,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.65"
_MAX_API_VERSION = "2.66"
DEFAULT_API_VERSION = _MIN_API_VERSION
# Almost all proxy APIs which are related to network, images and baremetal

View File

@ -92,8 +92,10 @@ class InstanceActionsController(wsgi.Controller):
@wsgi.Controller.api_version("2.58") # noqa
@wsgi.expected_errors((400, 404))
@validation.query_schema(schema_instance_actions.list_query_params_v266,
"2.66")
@validation.query_schema(schema_instance_actions.list_query_params_v258,
"2.58")
"2.58", "2.65")
def index(self, req, server_id):
"""Returns the list of actions recorded for a given instance."""
context = req.environ["nova.context"]
@ -105,6 +107,10 @@ class InstanceActionsController(wsgi.Controller):
search_opts['changes-since'] = timeutils.parse_isotime(
search_opts['changes-since'])
if 'changes-before' in search_opts:
search_opts['changes-before'] = timeutils.parse_isotime(
search_opts['changes-before'])
limit, marker = common.get_limit_and_marker(req)
try:
actions_raw = self.action_api.actions_get(context, instance,

View File

@ -75,7 +75,7 @@ class MigrationsController(wsgi.Controller):
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):
allow_changes_since=False, allow_changes_before=False):
context = req.environ['nova.context']
context.can(migrations_policies.POLICY_ROOT % 'index')
search_opts = {}
@ -92,6 +92,17 @@ class MigrationsController(wsgi.Controller):
# it from search_opts.
del search_opts['changes-since']
if 'changes-before' in search_opts:
if allow_changes_before:
search_opts['changes-before'] = timeutils.parse_isotime(
search_opts['changes-before'])
else:
# Before microversion 2.59 the schema allowed
# additionalProperties=True, so a user could pass
# changes-before before 2.59 and filter by the updated_at
# field if we don't remove it from search_opts.
del search_opts['changes-before']
if sort_keys:
try:
migrations = self.compute_api.get_migrations_sorted(
@ -129,10 +140,10 @@ class MigrationsController(wsgi.Controller):
"""Return all migrations using the query parameters as filters."""
return self._index(req, add_link=True)
@wsgi.Controller.api_version("2.59") # noqa
@wsgi.Controller.api_version("2.59", "2.65") # noqa
@wsgi.expected_errors(400)
@validation.query_schema(schema_migrations.list_query_params_v259,
"2.59")
"2.59", "2.65")
def index(self, req):
"""Return all migrations using the query parameters as filters."""
limit, marker = common.get_limit_and_marker(req)
@ -141,3 +152,17 @@ class MigrationsController(wsgi.Controller):
sort_dirs=['desc', 'desc'],
limit=limit, marker=marker,
allow_changes_since=True)
@wsgi.Controller.api_version("2.66") # noqa
@wsgi.expected_errors(400)
@validation.query_schema(schema_migrations.list_query_params_v266,
"2.66")
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,
allow_changes_before=True)

View File

@ -842,3 +842,15 @@ in server group APIs:
Add support for abort live migrations in ``queued`` and ``preparing`` status
for API ``DELETE /servers/{server_id}/migrations/{migration_id}``.
2.66
----
The ``changes-before`` filter can be included as a request parameter of the
following APIs to filter by changes before or equal to the resource
``updated_at`` time:
* ``GET /servers``
* ``GET /servers/detail``
* ``GET /servers/{server_id}/os-instance-actions``
* ``GET /os-migrations``

View File

@ -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_params_v258 = {
@ -27,3 +29,9 @@ list_query_params_v258 = {
},
'additionalProperties': False
}
list_query_params_v266 = copy.deepcopy(list_query_params_v258)
list_query_params_v266['properties'].update({
'changes-before': parameter_types.single_param(
{'type': 'string', 'format': 'date-time'}),
})

View File

@ -41,3 +41,9 @@ list_query_params_v259['properties'].update({
{'type': 'string', 'format': 'date-time'}),
})
list_query_params_v259['additionalProperties'] = False
list_query_params_v266 = copy.deepcopy(list_query_params_v259)
list_query_params_v266['properties'].update({
'changes-before': parameter_types.single_param(
{'type': 'string', 'format': 'date-time'}),
})

View File

@ -621,3 +621,9 @@ query_params_v226['properties'].update({
'not-tags': parameter_types.common_query_regex_param,
'not-tags-any': parameter_types.common_query_regex_param,
})
query_params_v266 = copy.deepcopy(query_params_v226)
query_params_v266['properties'].update({
'changes-before': multi_params({'type': 'string',
'format': 'date-time'}),
})

View File

@ -78,7 +78,8 @@ class ServersController(wsgi.Controller):
self.compute_api = compute.API()
@wsgi.expected_errors((400, 403))
@validation.query_schema(schema_servers.query_params_v226, '2.26')
@validation.query_schema(schema_servers.query_params_v266, '2.66')
@validation.query_schema(schema_servers.query_params_v226, '2.26', '2.65')
@validation.query_schema(schema_servers.query_params_v21, '2.1', '2.25')
def index(self, req):
"""Returns a list of server names and ids for a given user."""
@ -91,7 +92,8 @@ class ServersController(wsgi.Controller):
return servers
@wsgi.expected_errors((400, 403))
@validation.query_schema(schema_servers.query_params_v226, '2.26')
@validation.query_schema(schema_servers.query_params_v266, '2.66')
@validation.query_schema(schema_servers.query_params_v226, '2.26', '2.65')
@validation.query_schema(schema_servers.query_params_v21, '2.1', '2.25')
def detail(self, req):
"""Returns a list of server details for a given user."""
@ -154,15 +156,32 @@ class ServersController(wsgi.Controller):
msg = _("Invalid filter field: changes-since.")
raise exc.HTTPBadRequest(explanation=msg)
if 'changes-before' in search_opts:
try:
search_opts['changes-before'] = timeutils.parse_isotime(
search_opts['changes-before'])
changes_since = search_opts.get('changes-since')
if changes_since and search_opts['changes-before'] < \
search_opts['changes-since']:
msg = _('The value of changes-since must be'
' less than or equal to changes-before.')
raise exc.HTTPBadRequest(explanation=msg)
except ValueError:
msg = _("Invalid filter field: changes-before.")
raise exc.HTTPBadRequest(explanation=msg)
# By default, compute's get_all() will return deleted instances.
# If an admin hasn't specified a 'deleted' search option, we need
# to filter out deleted instances by setting the filter ourselves.
# ... Unless 'changes-since' is specified, because 'changes-since'
# should return recently deleted instances according to the API spec.
# ... Unless 'changes-since' or 'changes-before' is specified,
# because those will return recently deleted instances according to
# the API spec.
if 'deleted' not in search_opts:
if 'changes-since' not in search_opts:
# No 'changes-since', so we only want non-deleted servers
if 'changes-since' not in search_opts and \
'changes-before' not in search_opts:
# No 'changes-since' or 'changes-before', so we only
# want non-deleted servers
search_opts['deleted'] = False
else:
# Convert deleted filter value to a valid boolean.
@ -1090,6 +1109,8 @@ class ServersController(wsgi.Controller):
opt_list += ('ip6',)
if api_version_request.is_supported(req, min_version='2.26'):
opt_list += TAG_SEARCH_FILTERS
if api_version_request.is_supported(req, min_version='2.66'):
opt_list += ('changes-before',)
return opt_list
def _get_instance(self, context, instance_uuid):

View File

@ -2003,6 +2003,32 @@ def instance_get_all_by_filters(context, filters, sort_key, sort_dir,
sort_dirs=[sort_dir])
def _get_query_nova_resource_by_changes_time(query, filters, model_object):
"""Filter resources by changes-since or changes-before.
Special keys are used to tweek the query further::
| 'changes-since' - only return resources updated after
| 'changes-before' - only return resources updated before
Return query results.
:param query: query to apply filters to.
:param filters: dictionary of filters with regex values.
:param model_object: object of the operation target.
"""
for change_filter in ['changes-since', 'changes-before']:
if filters and filters.get(change_filter):
changes_filter_time = timeutils.normalize_time(
filters.get(change_filter))
updated_at = getattr(model_object, 'updated_at')
if change_filter == 'changes-since':
query = query.filter(updated_at >= changes_filter_time)
else:
query = query.filter(updated_at <= changes_filter_time)
return query
@require_context
@pick_context_manager_reader_allow_async
def instance_get_all_by_filters_sort(context, filters, limit=None, marker=None,
@ -2036,6 +2062,7 @@ def instance_get_all_by_filters_sort(context, filters, limit=None, marker=None,
Special keys are used to tweek the query further::
| 'changes-since' - only return instances updated after
| 'changes-before' - only return instances updated before
| 'deleted' - only return (or exclude) deleted instances
| 'soft_deleted' - modify behavior of 'deleted' to either
| include or exclude instances whose
@ -2097,10 +2124,10 @@ def instance_get_all_by_filters_sort(context, filters, limit=None, marker=None,
# be modifying it and we shouldn't affect the caller's use of it.
filters = copy.deepcopy(filters)
if 'changes-since' in filters:
changes_since = timeutils.normalize_time(filters['changes-since'])
query_prefix = query_prefix.\
filter(models.Instance.updated_at >= changes_since)
model_object = models.Instance
query_prefix = _get_query_nova_resource_by_changes_time(query_prefix,
filters,
model_object)
if 'deleted' in filters:
# Instances can be soft or hard deleted and the query needs to
@ -4371,10 +4398,12 @@ def migration_get_all_by_filters(context, filters,
uuid = filters["uuid"]
uuid = [uuid] if isinstance(uuid, six.string_types) else uuid
query = query.filter(models.Migration.uuid.in_(uuid))
if 'changes-since' in filters:
changes_since = timeutils.normalize_time(filters['changes-since'])
query = query. \
filter(models.Migration.updated_at >= changes_since)
model_object = models.Migration
query = _get_query_nova_resource_by_changes_time(query,
filters,
model_object)
if "status" in filters:
status = filters["status"]
status = [status] if isinstance(status, six.string_types) else status
@ -5117,10 +5146,11 @@ def actions_get(context, instance_uuid, limit=None, marker=None,
query_prefix = model_query(context, models.InstanceAction).\
filter_by(instance_uuid=instance_uuid)
if filters and 'changes-since' in filters:
changes_since = timeutils.normalize_time(filters['changes-since'])
query_prefix = query_prefix. \
filter(models.InstanceAction.updated_at >= changes_since)
model_object = models.InstanceAction
query_prefix = _get_query_nova_resource_by_changes_time(query_prefix,
filters,
model_object)
if marker is not None:
marker = action_get_by_request_id(context, instance_uuid, marker)

View File

@ -0,0 +1,21 @@
{
"instanceAction": {
"action": "stop",
"instance_uuid": "%(uuid)s",
"request_id": "%(request_id)s",
"user_id": "%(user_id)s",
"project_id": "%(project_id)s",
"start_time": "%(strtime)s",
"updated_at": "%(strtime)s",
"message": null,
"events": [
{
"event": "compute_stop_instance",
"start_time": "%(strtime)s",
"finish_time": "%(strtime)s",
"result": "Success",
"hostId": "%(event_hostId)s"
}
]
}
}

View File

@ -0,0 +1,23 @@
{
"instanceAction": {
"action": "stop",
"instance_uuid": "%(uuid)s",
"request_id": "%(request_id)s",
"user_id": "%(user_id)s",
"project_id": "%(project_id)s",
"start_time": "%(strtime)s",
"updated_at": "%(strtime)s",
"message": null,
"events": [
{
"event": "compute_stop_instance",
"start_time": "%(strtime)s",
"finish_time": "%(strtime)s",
"result": "Success",
"traceback": null,
"host": "%(event_host)s",
"hostId": "%(event_hostId)s"
}
]
}
}

View File

@ -0,0 +1,24 @@
{
"instanceActions": [
{
"action": "stop",
"instance_uuid": "%(uuid)s",
"request_id": "%(request_id)s",
"user_id": "%(user_id)s",
"project_id": "%(project_id)s",
"start_time": "%(strtime)s",
"updated_at": "%(strtime)s",
"message": null
},
{
"action": "create",
"instance_uuid": "%(uuid)s",
"request_id": "%(request_id)s",
"user_id": "%(user_id)s",
"project_id": "%(project_id)s",
"start_time": "%(strtime)s",
"updated_at": "%(strtime)s",
"message": null
}
]
}

View File

@ -0,0 +1,24 @@
{
"instanceActions": [
{
"action": "stop",
"instance_uuid": "%(uuid)s",
"request_id": "%(request_id)s",
"user_id": "%(user_id)s",
"project_id": "%(project_id)s",
"start_time": "%(strtime)s",
"updated_at": "%(strtime)s",
"message": null
},
{
"action": "create",
"instance_uuid": "%(uuid)s",
"request_id": "%(request_id)s",
"user_id": "%(user_id)s",
"project_id": "%(project_id)s",
"start_time": "%(strtime)s",
"updated_at": "%(strtime)s",
"message": null
}
]
}

View File

@ -0,0 +1,14 @@
{
"instanceActions": [
{
"action": "stop",
"instance_uuid": "%(uuid)s",
"request_id": "%(request_id)s",
"user_id": "%(user_id)s",
"project_id": "%(project_id)s",
"start_time": "%(strtime)s",
"updated_at": "%(strtime)s",
"message": null
}
]
}

View File

@ -0,0 +1,20 @@
{
"instanceActions": [
{
"action": "stop",
"instance_uuid": "%(uuid)s",
"request_id": "%(request_id)s",
"user_id": "%(user_id)s",
"project_id": "%(project_id)s",
"start_time": "%(strtime)s",
"updated_at": "%(strtime)s",
"message": null
}
],
"links": [
{
"href": "%(versioned_compute_endpoint)s/servers/%(uuid)s/os-instance-actions?limit=1&marker=%(request_id)s",
"rel": "next"
}
]
}

View File

@ -0,0 +1,14 @@
{
"instanceActions": [
{
"action": "create",
"instance_uuid": "%(uuid)s",
"request_id": "%(request_id)s",
"user_id": "%(user_id)s",
"project_id": "%(project_id)s",
"start_time": "%(strtime)s",
"updated_at": "%(strtime)s",
"message": null
}
]
}

View File

@ -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"
}
]
}

View File

@ -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"
}
]
}

View File

@ -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"
}]
}

View File

@ -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"
}
]
}

View 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": "%(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"
}
]
}

View File

@ -0,0 +1,28 @@
{
"server" : {
"accessIPv4": "%(access_ip_v4)s",
"accessIPv6": "%(access_ip_v6)s",
"name" : "%(name)s",
"imageRef" : "%(image_id)s",
"flavorRef" : "6",
"availability_zone": "nova",
"OS-DCF:diskConfig": "AUTO",
"metadata" : {
"My Server Name" : "Apache1"
},
"security_groups": [
{
"name": "default"
}
],
"user_data" : "%(user_data)s",
"networks": "auto",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
]
},
"OS-SCH-HNT:scheduler_hints": {
"same_host": "%(uuid)s"
}
}

View File

@ -0,0 +1,22 @@
{
"server": {
"OS-DCF:diskConfig": "AUTO",
"adminPass": "%(password)s",
"id": "%(id)s",
"links": [
{
"href": "%(versioned_compute_endpoint)s/servers/%(uuid)s",
"rel": "self"
},
{
"href": "%(compute_endpoint)s/servers/%(uuid)s",
"rel": "bookmark"
}
],
"security_groups": [
{
"name": "default"
}
]
}
}

View File

@ -0,0 +1,184 @@
{
"server": [
{
"accessIPv4": "%(access_ip_v4)s",
"accessIPv6": "%(access_ip_v6)s",
"addresses": {
"private": [
{
"addr": "%(ip)s",
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
"OS-EXT-IPS:type": "fixed",
"version": 4
}
]
},
"created": "%(isotime)s",
"description": null,
"host_status": "UP",
"locked": false,
"tags": [],
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {
"hw:cpu_policy": "dedicated",
"hw:mem_page_size": "2048"
},
"original_name": "m1.tiny.specs",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "%(hostid)s",
"id": "%(id)s",
"image": {
"id": "%(uuid)s",
"links": [
{
"href": "%(compute_endpoint)s/images/%(uuid)s",
"rel": "bookmark"
}
]
},
"key_name": null,
"links": [
{
"href": "%(versioned_compute_endpoint)s/servers/%(uuid)s",
"rel": "self"
},
{
"href": "%(compute_endpoint)s/servers/%(uuid)s",
"rel": "bookmark"
}
],
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"config_drive": "%(cdrive)s",
"OS-DCF:diskConfig": "AUTO",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "%(compute_host)s",
"OS-EXT-SRV-ATTR:hostname": "%(hostname)s",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s",
"OS-EXT-SRV-ATTR:instance_name": "%(instance_name)s",
"OS-EXT-SRV-ATTR:kernel_id": "",
"OS-EXT-SRV-ATTR:launch_index": 0,
"OS-EXT-SRV-ATTR:ramdisk_id": "",
"OS-EXT-SRV-ATTR:reservation_id": "%(reservation_id)s",
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
"OS-EXT-SRV-ATTR:user_data": "%(user_data)s",
"OS-EXT-STS:power_state": 1,
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"os-extended-volumes:volumes_attached": [],
"OS-SRV-USG:launched_at": "%(strtime)s",
"OS-SRV-USG:terminated_at": null,
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"status": "ACTIVE",
"tenant_id": "6f70656e737461636b20342065766572",
"updated": "%(isotime)s",
"user_id": "fake",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
]
},
{
"accessIPv4": "%(access_ip_v4)s",
"accessIPv6": "%(access_ip_v6)s",
"addresses": {
"private": [
{
"addr": "%(ip)s",
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
"OS-EXT-IPS:type": "fixed",
"version": 4
}
]
},
"created": "%(isotime)s",
"description": null,
"host_status": "UP",
"locked": false,
"tags": [],
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {
"hw:cpu_policy": "dedicated",
"hw:mem_page_size": "2048"
},
"original_name": "m1.tiny.specs",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "%(hostid)s",
"id": "%(id)s",
"image": {
"id": "%(uuid)s",
"links": [
{
"href": "%(compute_endpoint)s/images/%(uuid)s",
"rel": "bookmark"
}
]
},
"key_name": null,
"links": [
{
"href": "%(versioned_compute_endpoint)s/servers/%(uuid)s",
"rel": "self"
},
{
"href": "%(compute_endpoint)s/servers/%(uuid)s",
"rel": "bookmark"
}
],
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"config_drive": "%(cdrive)s",
"OS-DCF:diskConfig": "AUTO",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "%(compute_host)s",
"OS-EXT-SRV-ATTR:hostname": "%(hostname)s",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s",
"OS-EXT-SRV-ATTR:instance_name": "%(instance_name)s",
"OS-EXT-SRV-ATTR:kernel_id": "",
"OS-EXT-SRV-ATTR:launch_index": 0,
"OS-EXT-SRV-ATTR:ramdisk_id": "",
"OS-EXT-SRV-ATTR:reservation_id": "%(reservation_id)s",
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
"OS-EXT-SRV-ATTR:user_data": "%(user_data)s",
"OS-EXT-STS:power_state": 1,
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"os-extended-volumes:volumes_attached": [],
"OS-SRV-USG:launched_at": "%(strtime)s",
"OS-SRV-USG:terminated_at": null,
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"status": "ACTIVE",
"tenant_id": "6f70656e737461636b20342065766572",
"updated": "%(isotime)s",
"user_id": "fake",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
]
}
]
}

View File

@ -0,0 +1,190 @@
{
"servers": [
{
"accessIPv4": "%(access_ip_v4)s",
"accessIPv6": "%(access_ip_v6)s",
"addresses": {
"private": [
{
"addr": "%(ip)s",
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
"OS-EXT-IPS:type": "fixed",
"version": 4
}
]
},
"created": "%(isotime)s",
"description": null,
"host_status": "UP",
"locked": false,
"tags": [],
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {
"hw:mem_page_size": "2048",
"hw:cpu_policy": "dedicated"
},
"original_name": "m1.tiny.specs",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "%(hostid)s",
"id": "%(id)s",
"image": {
"id": "%(uuid)s",
"links": [
{
"href": "%(compute_endpoint)s/images/%(uuid)s",
"rel": "bookmark"
}
]
},
"key_name": null,
"links": [
{
"href": "%(versioned_compute_endpoint)s/servers/%(uuid)s",
"rel": "self"
},
{
"href": "%(compute_endpoint)s/servers/%(id)s",
"rel": "bookmark"
}
],
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"config_drive": "%(cdrive)s",
"OS-DCF:diskConfig": "AUTO",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "%(compute_host)s",
"OS-EXT-SRV-ATTR:hostname": "%(hostname)s",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s",
"OS-EXT-SRV-ATTR:instance_name": "%(instance_name)s",
"OS-EXT-SRV-ATTR:kernel_id": "",
"OS-EXT-SRV-ATTR:launch_index": 0,
"OS-EXT-SRV-ATTR:ramdisk_id": "",
"OS-EXT-SRV-ATTR:reservation_id": "%(reservation_id)s",
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
"OS-EXT-SRV-ATTR:user_data": "%(user_data)s",
"OS-EXT-STS:power_state": 1,
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"os-extended-volumes:volumes_attached": [],
"OS-SRV-USG:launched_at": "%(strtime)s",
"OS-SRV-USG:terminated_at": null,
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"status": "ACTIVE",
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
],
"updated": "%(isotime)s",
"user_id": "fake"
},
{
"accessIPv4": "%(access_ip_v4)s",
"accessIPv6": "%(access_ip_v6)s",
"addresses": {
"private": [
{
"addr": "%(ip)s",
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
"OS-EXT-IPS:type": "fixed",
"version": 4
}
]
},
"created": "%(isotime)s",
"description": null,
"host_status": "UP",
"locked": false,
"tags": [],
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {
"hw:mem_page_size": "2048",
"hw:cpu_policy": "dedicated"
},
"original_name": "m1.tiny.specs",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "%(hostid)s",
"id": "%(id)s",
"image": {
"id": "%(uuid)s",
"links": [
{
"href": "%(compute_endpoint)s/images/%(uuid)s",
"rel": "bookmark"
}
]
},
"key_name": null,
"links": [
{
"href": "%(versioned_compute_endpoint)s/servers/%(uuid)s",
"rel": "self"
},
{
"href": "%(compute_endpoint)s/servers/%(id)s",
"rel": "bookmark"
}
],
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"config_drive": "%(cdrive)s",
"OS-DCF:diskConfig": "AUTO",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "%(compute_host)s",
"OS-EXT-SRV-ATTR:hostname": "%(hostname)s",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s",
"OS-EXT-SRV-ATTR:instance_name": "%(instance_name)s",
"OS-EXT-SRV-ATTR:kernel_id": "",
"OS-EXT-SRV-ATTR:launch_index": 0,
"OS-EXT-SRV-ATTR:ramdisk_id": "",
"OS-EXT-SRV-ATTR:reservation_id": "%(reservation_id)s",
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
"OS-EXT-SRV-ATTR:user_data": "%(user_data)s",
"OS-EXT-STS:power_state": 1,
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"os-extended-volumes:volumes_attached": [],
"OS-SRV-USG:launched_at": "%(strtime)s",
"OS-SRV-USG:terminated_at": null,
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"status": "ACTIVE",
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
],
"updated": "%(isotime)s",
"user_id": "fake"
}
],
"servers_links": [
{
"href": "%(versioned_compute_endpoint)s/servers/detail?limit=1&marker=%(id)s",
"rel": "next"
}
]
}

View File

@ -0,0 +1,94 @@
{
"servers": [
{
"accessIPv4": "%(access_ip_v4)s",
"accessIPv6": "%(access_ip_v6)s",
"addresses": {
"private": [
{
"addr": "%(ip)s",
"OS-EXT-IPS-MAC:mac_addr": "aa:bb:cc:dd:ee:ff",
"OS-EXT-IPS:type": "fixed",
"version": 4
}
]
},
"created": "%(isotime)s",
"description": null,
"host_status": "UP",
"locked": false,
"tags": [],
"flavor": {
"disk": 1,
"ephemeral": 0,
"extra_specs": {
"hw:mem_page_size": "2048",
"hw:cpu_policy": "dedicated"
},
"original_name": "m1.tiny.specs",
"ram": 512,
"swap": 0,
"vcpus": 1
},
"hostId": "%(hostid)s",
"id": "%(id)s",
"image": {
"id": "%(uuid)s",
"links": [
{
"href": "%(compute_endpoint)s/images/%(uuid)s",
"rel": "bookmark"
}
]
},
"key_name": null,
"links": [
{
"href": "%(versioned_compute_endpoint)s/servers/%(uuid)s",
"rel": "self"
},
{
"href": "%(compute_endpoint)s/servers/%(id)s",
"rel": "bookmark"
}
],
"metadata": {
"My Server Name": "Apache1"
},
"name": "new-server-test",
"config_drive": "%(cdrive)s",
"OS-DCF:diskConfig": "AUTO",
"OS-EXT-AZ:availability_zone": "nova",
"OS-EXT-SRV-ATTR:host": "%(compute_host)s",
"OS-EXT-SRV-ATTR:hostname": "%(hostname)s",
"OS-EXT-SRV-ATTR:hypervisor_hostname": "%(hypervisor_hostname)s",
"OS-EXT-SRV-ATTR:instance_name": "%(instance_name)s",
"OS-EXT-SRV-ATTR:kernel_id": "",
"OS-EXT-SRV-ATTR:launch_index": 0,
"OS-EXT-SRV-ATTR:ramdisk_id": "",
"OS-EXT-SRV-ATTR:reservation_id": "%(reservation_id)s",
"OS-EXT-SRV-ATTR:root_device_name": "/dev/sda",
"OS-EXT-SRV-ATTR:user_data": "%(user_data)s",
"OS-EXT-STS:power_state": 1,
"OS-EXT-STS:task_state": null,
"OS-EXT-STS:vm_state": "active",
"os-extended-volumes:volumes_attached": [],
"OS-SRV-USG:launched_at": "%(strtime)s",
"OS-SRV-USG:terminated_at": null,
"progress": 0,
"security_groups": [
{
"name": "default"
}
],
"status": "ACTIVE",
"tenant_id": "6f70656e737461636b20342065766572",
"trusted_image_certificates": [
"0b5d2c72-12cc-4ba6-a8d7-3ff5cc1d8cb8",
"674736e3-f25c-405c-8362-bbf991e0ce0a"
],
"updated": "%(isotime)s",
"user_id": "fake"
}
]
}

View File

@ -0,0 +1,18 @@
{
"servers": [
{
"id": "%(id)s",
"links": [
{
"href": "%(versioned_compute_endpoint)s/servers/%(id)s",
"rel": "self"
},
{
"href": "%(compute_endpoint)s/servers/%(id)s",
"rel": "bookmark"
}
],
"name": "new-server-test"
}
]
}

View File

@ -139,3 +139,17 @@ class ServerActionsV262SampleJsonTest(ServerActionsV258SampleJsonTest):
class ServerActionsV262NonAdminSampleJsonTest(ServerActionsV262SampleJsonTest):
ADMIN_API = False
class ServerActionsV266SampleJsonTest(ServerActionsV262SampleJsonTest):
microversion = '2.66'
scenarios = [('v2_66', {'api_major_version': 'v2.1'})]
def test_instance_actions_with_changes_before(self):
stop_action_time = self.action_stop['updated_at']
response = self._do_get(
'servers/%s/os-instance-actions'
'?changes-before=%s' % (self.uuid, stop_action_time))
self._verify_response(
'instance-actions-list-with-changes-before',
self._get_subs(), response, 200)

View File

@ -292,3 +292,16 @@ class MigrationsSamplesJsonTestV2_59(MigrationsSamplesJsonTestV2_23):
self._verify_response(
'migrations-get-with-changes-since',
{"instance_2": INSTANCE_UUID_2}, response, 200)
class MigrationsSamplesJsonTestV2_66(MigrationsSamplesJsonTestV2_59):
microversion = '2.66'
scenarios = [('v2_66', {'api_major_version': 'v2.1'})]
def test_get_migrations_with_changes_before(self):
response = self._do_get(
'os-migrations?changes-before=2016-01-29T11:42:02.000000')
self.assertEqual(200, response.status_code)
self._verify_response(
'migrations-get-with-changes-before',
{"instance_1": INSTANCE_UUID_1}, response, 200)

View File

@ -16,6 +16,7 @@
import base64
import time
from oslo_utils import timeutils
import six
from nova.api.openstack import api_version_request as avr
@ -311,6 +312,47 @@ class ServersSampleJson263Test(ServersSampleBase):
self._verify_response('server-update-resp', subs, response, 200)
class ServersSampleJson266Test(ServersSampleBase):
microversion = '2.66'
scenarios = [('v2_66', {'api_major_version': 'v2.1'})]
def setUp(self):
super(ServersSampleJson266Test, self).setUp()
self.common_subs = {
'hostid': '[a-f0-9]+',
'instance_name': 'instance-\d{8}',
'hypervisor_hostname': r'[\w\.\-]+',
'hostname': r'[\w\.\-]+',
'access_ip_v4': '1.2.3.4',
'access_ip_v6': '80fe::',
'user_data': (self.user_data if six.PY2
else self.user_data.decode('utf-8')),
'cdrive': '.*',
}
def test_get_servers_list_with_changes_before(self):
uuid = self._post_server(use_common_server_api_samples=False)
current_time = timeutils.parse_isotime(timeutils.utcnow().isoformat())
response = self._do_get(
'servers?changes-before=%s' % timeutils.normalize_time(
current_time))
subs = self.common_subs.copy()
subs['id'] = uuid
self._verify_response(
'servers-list-with-changes-before', subs, response, 200)
def test_get_servers_detail_with_changes_before(self):
uuid = self._post_server(use_common_server_api_samples=False)
current_time = timeutils.parse_isotime(timeutils.utcnow().isoformat())
response = self._do_get(
'servers/detail?changes-before=%s' % timeutils.normalize_time(
current_time))
subs = self.common_subs.copy()
subs['id'] = uuid
self._verify_response(
'servers-details-with-changes-before', subs, response, 200)
class ServersUpdateSampleJsonTest(ServersSampleBase):
def test_update_server(self):

View File

@ -145,6 +145,13 @@ class InstanceActionsTestV21(test.NoDBTestCase):
use_admin_context=use_admin_context,
version=self.wsgi_api_version)
def _get_http_req_with_version(self, action, use_admin_context=False,
version="2.21"):
fake_url = '/123/servers/12/%s' % action
return fakes.HTTPRequest.blank(fake_url,
use_admin_context=use_admin_context,
version=version)
def _set_policy_rules(self):
rules = {'compute:get': '',
'os_compute_api:os-instance-actions': '',
@ -319,3 +326,29 @@ class InstanceActionsTestV262(InstanceActionsTestV251):
wsgi_api_version = "2.62"
expect_event_hostId = True
expect_event_host = True
class InstanceActionsTestV266(InstanceActionsTestV258):
wsgi_api_version = "2.66"
def test_get_action_with_invalid_changes_before(self):
"""Tests get paging with a invalid changes-before."""
req = self._get_http_req('os-instance-actions?'
'changes-before=wrong_time')
ex = self.assertRaises(exception.ValidationError,
self.controller.index, req)
self.assertIn('Invalid input for query parameters changes-before',
six.text_type(ex))
def test_get_action_with_changes_before_old_microversion(self):
"""Tests that the changes-before query parameter is an error before
microversion 2.66.
"""
param = 'changes-before=2018-09-13T15:13:03Z'
req = self._get_http_req_with_version('os-instance-actions?%s' %
param, use_admin_context=True,
version="2.65")
ex = self.assertRaises(exception.ValidationError,
self.controller.index, req)
detail = 'Additional properties are not allowed'
self.assertIn(detail, six.text_type(ex))

View File

@ -336,7 +336,7 @@ class MigrationsTestCaseV259(MigrationsTestCaseV223):
@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
"""Tests that the changes-since query parameter is ignored before
microversion 2.59.
"""
# Also use a valid filter (instance_uuid) to make sure only
@ -352,6 +352,51 @@ class MigrationsTestCaseV259(MigrationsTestCaseV223):
{'instance_uuid': uuids.instance_uuid})
class MigrationTestCaseV266(MigrationsTestCaseV259):
wsgi_api_version = '2.66'
def test_index_with_invalid_changes_before(self):
"""Tests detail paging with an invalid changes-before value."""
req = fakes.HTTPRequest.blank(
'/os-migrations?changes-before=wrong_time',
version=self.wsgi_api_version, use_admin_context=True)
self.assertRaises(exception.ValidationError,
self.controller.index, req)
def test_index_with_changes_before_old_microversion_failed(self):
"""Tests that the changes-before query parameter is an error before
microversion 2.66.
"""
# Also use a valid filter (instance_uuid) to make sure
# changes-before is an additional property.
req = fakes.HTTPRequest.blank(
'/os-migrations?changes-before=2018-01-10T16:59:24.138939&'
'instance_uuid=%s' % uuids.instance_uuid,
version='2.65', 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_before_old_microversion(self, get_migrations):
"""Tests that the changes-before query parameter is ignored before
microversion 2.59.
"""
# Also use a valid filter (instance_uuid) to make sure only
# changes-before is removed.
req = fakes.HTTPRequest.blank(
'/os-migrations?changes-before=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()

View File

@ -2054,6 +2054,97 @@ class ServerControllerTestV247(ControllerTest):
self.assertEqual(s['flavor'], expected_flavor)
class ServerControllerTestV266(ControllerTest):
"""Server controller test for microversion 2.66
Add changes-before parameter to get servers or servers details of
2.66 microversion.
Filters the response by a date and time stamp when the server last
changed. Those changed before the specified date and time stamp are
returned.
"""
wsgi_api_version = '2.66'
def req(self, url, use_admin_context=False):
return fakes.HTTPRequest.blank(url,
use_admin_context=use_admin_context,
version=self.wsgi_api_version)
def test_get_servers_allows_changes_before(self):
def fake_get_all(context, search_opts=None,
limit=None, marker=None,
expected_attrs=None, sort_keys=None, sort_dirs=None):
self.assertIsNotNone(search_opts)
self.assertIn('changes-before', search_opts)
changes_before = datetime.datetime(2011, 1, 24, 17, 8, 1,
tzinfo=iso8601.iso8601.UTC)
self.assertEqual(search_opts['changes-before'], changes_before)
self.assertNotIn('deleted', search_opts)
return objects.InstanceList(
objects=[fakes.stub_instance_obj(100, uuid=uuids.fake)])
self.mock_get_all.side_effect = fake_get_all
params = 'changes-before=2011-01-24T17:08:01Z'
req = self.req('/fake/servers?%s' % params)
req.api_version_request = api_version_request.APIVersionRequest('2.66')
servers = self.controller.index(req)['servers']
self.assertEqual(1, len(servers))
self.assertEqual(uuids.fake, servers[0]['id'])
def test_get_servers_allows_changes_before_bad_value(self):
params = 'changes-before=asdf'
req = self.req('/fake/servers?%s' % params)
req.api_version_request = api_version_request.APIVersionRequest('2.66')
self.assertRaises(exception.ValidationError, self.controller.index,
req)
def test_get_servers_allows_changes_before_bad_value_on_compat_mode(self):
params = 'changes-before=asdf'
req = self.req('/fake/servers?%s' % params)
req.api_version_request = api_version_request.APIVersionRequest('2.66')
req.set_legacy_v2()
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.index, req)
def test_get_servers_allows_changes_since_and_changes_before(self):
def fake_get_all(context, search_opts=None,
limit=None, marker=None,
expected_attrs=None, sort_keys=None, sort_dirs=None):
self.assertIsNotNone(search_opts)
self.assertIn('changes-since', search_opts)
changes_since = datetime.datetime(2011, 1, 23, 17, 8, 1,
tzinfo=iso8601.iso8601.UTC)
self.assertIn('changes-before', search_opts)
changes_before = datetime.datetime(2011, 1, 24, 17, 8, 1,
tzinfo=iso8601.iso8601.UTC)
self.assertEqual(search_opts['changes-since'], changes_since)
self.assertEqual(search_opts['changes-before'], changes_before)
self.assertNotIn('deleted', search_opts)
return objects.InstanceList(
objects=[fakes.stub_instance_obj(100, uuid=uuids.fake)])
self.mock_get_all.side_effect = fake_get_all
params = 'changes-since=2011-01-23T17:08:01Z&' \
'changes-before=2011-01-24T17:08:01Z'
req = self.req('/fake/servers?%s' % params)
req.api_version_request = api_version_request.APIVersionRequest('2.66')
servers = self.controller.index(req)['servers']
self.assertEqual(1, len(servers))
self.assertEqual(uuids.fake, servers[0]['id'])
def test_get_servers_filters_with_distinct_changes_time_bad_request(self):
changes_since = '2018-09-04T05:45:27Z'
changes_before = '2018-09-03T05:45:27Z'
req = self.req('/fake/servers?changes-since=%s&changes-before=%s' %
(changes_since, changes_before))
req.api_version_request = api_version_request.APIVersionRequest('2.66')
self.assertRaises(webob.exc.HTTPBadRequest, self.controller.index, req)
class ServersControllerDeleteTest(ControllerTest):
def setUp(self):

View File

@ -1375,6 +1375,19 @@ class MigrationTestCase(test.TestCase):
self.assertEqual(migrations[0]['uuid'], uuidsentinel.uuid_time2)
self.assertEqual(migrations[1]['uuid'], uuidsentinel.uuid_time3)
def test_get_migrations_by_filters_with_changes_before(self):
changes_time = timeutils.utcnow(with_timezone=True)
self._create_3_migration_after_time(changes_time)
after_3day_2hours = datetime.timedelta(days=3, hours=2)
filters = {"changes-before": changes_time + after_3day_2hours}
migrations = db.migration_get_all_by_filters(
self.ctxt, filters,
sort_keys=['updated_at'], sort_dirs=['asc'])
self.assertEqual(3, len(migrations))
self.assertEqual(migrations[0]['uuid'], uuidsentinel.uuid_time1)
self.assertEqual(migrations[1]['uuid'], uuidsentinel.uuid_time2)
self.assertEqual(migrations[2]['uuid'], uuidsentinel.uuid_time3)
class ModelsObjectComparatorMixin(object):
def _dict_from_object(self, obj, ignored_keys):
@ -2144,6 +2157,65 @@ class InstanceTestCase(test.TestCase, ModelsObjectComparatorMixin):
filters)
self._assertEqualListsOfInstances([i2], result)
def test_instance_get_all_by_filters_changes_before(self):
i1 = self.create_instance_with_args(updated_at=
'2013-12-05T15:03:25.000000')
i2 = self.create_instance_with_args(updated_at=
'2013-12-05T15:03:26.000000')
changes_before = iso8601.parse_date('2013-12-05T15:03:26.000000')
result = db.instance_get_all_by_filters(self.ctxt,
{'changes-before':
changes_before})
self._assertEqualListsOfInstances([i1, i2], result)
changes_before = iso8601.parse_date('2013-12-05T15:03:25.000000')
result = db.instance_get_all_by_filters(self.ctxt,
{'changes-before':
changes_before})
self._assertEqualListsOfInstances([i1], result)
db.instance_destroy(self.ctxt, i2['uuid'])
filters = {}
filters['changes-before'] = changes_before
filters['marker'] = i2['uuid']
result = db.instance_get_all_by_filters(self.ctxt,
filters)
self._assertEqualListsOfInstances([i1], result)
def test_instance_get_all_by_filters_changes_time_period(self):
i1 = self.create_instance_with_args(updated_at=
'2013-12-05T15:03:25.000000')
i2 = self.create_instance_with_args(updated_at=
'2013-12-05T15:03:26.000000')
i3 = self.create_instance_with_args(updated_at=
'2013-12-05T15:03:27.000000')
changes_since = iso8601.parse_date('2013-12-05T15:03:25.000000')
changes_before = iso8601.parse_date('2013-12-05T15:03:27.000000')
result = db.instance_get_all_by_filters(self.ctxt,
{'changes-since':
changes_since,
'changes-before':
changes_before})
self._assertEqualListsOfInstances([i1, i2, i3], result)
changes_since = iso8601.parse_date('2013-12-05T15:03:26.000000')
changes_before = iso8601.parse_date('2013-12-05T15:03:27.000000')
result = db.instance_get_all_by_filters(self.ctxt,
{'changes-since':
changes_since,
'changes-before':
changes_before})
self._assertEqualListsOfInstances([i2, i3], result)
db.instance_destroy(self.ctxt, i1['uuid'])
filters = {}
filters['changes-since'] = changes_since
filters['changes-before'] = changes_before
filters['marker'] = i1['uuid']
result = db.instance_get_all_by_filters(self.ctxt,
filters)
self._assertEqualListsOfInstances([i2, i3], result)
def test_instance_get_all_by_filters_exact_match(self):
instance = self.create_instance_with_args(host='host1')
self.create_instance_with_args(host='host12')
@ -3590,6 +3662,35 @@ class InstanceActionTestCase(test.TestCase, ModelsObjectComparatorMixin):
self.assertEqual(1, len(actions))
self._assertEqualListsOfObjects([action2], actions)
def test_instance_actions_get_with_changes_before(self):
"""Test list instance actions can support timestamp filter."""
uuid1 = uuidsentinel.uuid1
expected = []
extra = {
'created_at': timeutils.utcnow()
}
action_values = self._create_action_values(uuid1, extra=extra)
action = db.action_start(self.ctxt, action_values)
expected.append(action)
timestamp = timeutils.utcnow()
action_values['start_time'] = timestamp
action_values['updated_at'] = timestamp
action_values['action'] = 'delete'
action = db.action_start(self.ctxt, action_values)
expected.append(action)
actions = db.actions_get(self.ctxt, uuid1)
self.assertEqual(2, len(actions))
self.assertNotEqual(actions[0]['updated_at'],
actions[1]['updated_at'])
actions = db.actions_get(
self.ctxt, uuid1, filters={'changes-before': timestamp})
self.assertEqual(2, len(actions))
self._assertEqualListsOfObjects(expected, actions)
def test_instance_actions_get_with_not_found_marker(self):
self.assertRaises(exception.MarkerNotFound,
db.actions_get, self.ctxt, uuidsentinel.uuid1,

View File

@ -0,0 +1,24 @@
---
features:
- |
Microversion 2.66 adds the optional filter parameter ``changes-before``
which can be used to get resources changed before or equal to the
specified date and time.
Like the ``changes-since`` filter, the ``changes-before`` filter will
also return deleted servers.
This parameter (``changes-before``) does not change any read-deleted
behavior in the os-instance-actions or os-migrations APIs.
The os-instance-actions API with the 2.21 microversion allows retrieving
instance actions for a deleted server resource. The os-migrations API
takes an optional ``instance_uuid`` filter parameter but does not support
returning deleted migration records.
The ``changes-before`` request parameter can be passed to the servers,
os-instance-action and os-migrations APIs:
* ``GET /servers``
* ``GET /servers/detail``
* ``GET /servers/{server_id}/os-instance-actions``
* ``GET /os-migrations``