Expose volume & snapshot use_quota field
This patch adds a new REST API microversion to expose the new use_quota DB field present in volumes and snapshots. The field will be reported when listing and showing resources and can be used when filtering as well. The field is exposed in the REST API as `consumes_quota` to prevent confusion for users and admins, since exposing it as `use_quota` may give them the wrong impression that they can set it up for their own purposes. For users we say what is happening with the quota for that resource -it consumes or doesn't consume quota-, whereas internally we express instruction to the core code -whether to use quota or not-, hence the difference in the naming. APIImpact DocImpact Implements: blueprint temp-resources Change-Id: I655a47fc75ddc11caf1defe984d9a66a9ad5a2e7
This commit is contained in:
parent
94dfad99c2
commit
ec44fc8999
@ -214,6 +214,18 @@ detail:
|
||||
in: query
|
||||
required: false
|
||||
type: boolean
|
||||
filter_consumes_quota:
|
||||
description: |
|
||||
Filters results by ``consumes_quota`` field. Resources that don't use
|
||||
quotas are usually temporary internal resources created to perform an
|
||||
operation. Default is to not filter by it. Filtering by this option may
|
||||
not be always possible in a cloud, see
|
||||
:ref:`List Resource Filters <resource-filters>` to determine whether this
|
||||
filter is available in your cloud.
|
||||
in: query
|
||||
required: false
|
||||
type: boolean
|
||||
min_version: 3.65
|
||||
filter_created_at:
|
||||
description: |
|
||||
Filters reuslts by a time that resources are created at with time
|
||||
@ -841,6 +853,15 @@ consumer:
|
||||
in: body
|
||||
required: false
|
||||
type: string
|
||||
consumes_quota:
|
||||
description: |
|
||||
Whether this resource consumes quota or not. Resources that not counted
|
||||
for quota usage are usually temporary internal resources created to perform
|
||||
an operation.
|
||||
in: body
|
||||
required: false
|
||||
type: boolean
|
||||
min_version: 3.65
|
||||
container:
|
||||
description: |
|
||||
The container name or null.
|
||||
|
@ -1,5 +1,7 @@
|
||||
.. -*- rst -*-
|
||||
|
||||
.. _resource-filters:
|
||||
|
||||
Resource Filters (resource_filters)
|
||||
===================================
|
||||
|
||||
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"snapshot": {
|
||||
"created_at": "2019-03-11T16:24:34.469003",
|
||||
"description": "Daily backup",
|
||||
"id": "b36476e5-d18b-47f9-ac69-4818cb43ee21",
|
||||
"metadata": {
|
||||
"key": "v3"
|
||||
},
|
||||
"name": "snap-001",
|
||||
"size": 10,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"volume_id": "d291b81c-6e40-4525-8231-90aa1588121e",
|
||||
"group_snapshot_id": null,
|
||||
"user_id": "c853ca26-e8ea-4797-8a52-ee124a013d0e",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"snapshot": {
|
||||
"created_at": "2019-03-12T04:42:00.809352",
|
||||
"description": "Daily backup",
|
||||
"id": "4a584cae-e4ce-429b-9154-d4c9eb8fda4c",
|
||||
"metadata": {
|
||||
"key": "v3"
|
||||
},
|
||||
"name": "snap-001",
|
||||
"os-extended-snapshot-attributes:progress": "0%",
|
||||
"os-extended-snapshot-attributes:project_id": "89afd400-b646-4bbc-b12b-c0a4d63e5bd3",
|
||||
"size": 10,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"volume_id": "b72c48f1-64b7-4cd8-9745-b12e0be82d37",
|
||||
"group_snapshot_id": null,
|
||||
"user_id": "c853ca26-e8ea-4797-8a52-ee124a013d0e",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"snapshot": {
|
||||
"created_at": "2019-03-12T04:53:53.426591",
|
||||
"description": "This is yet, another snapshot.",
|
||||
"id": "43666194-8e72-451a-b7bb-54fef763b2b8",
|
||||
"metadata": {
|
||||
"key": "v3"
|
||||
},
|
||||
"name": "snap-002",
|
||||
"size": 10,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"volume_id": "070c942d-9909-42e9-a467-7a781f150c58",
|
||||
"group_snapshot_id": null,
|
||||
"user_id": "c853ca26-e8ea-4797-8a52-ee124a013d0e",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
"snapshots": [
|
||||
{
|
||||
"created_at": "2019-03-11T16:24:36.464445",
|
||||
"description": "Daily backup",
|
||||
"id": "d0083dc5-8795-4c1a-bc9c-74f70006c205",
|
||||
"metadata": {
|
||||
"key": "v3"
|
||||
},
|
||||
"name": "snap-001",
|
||||
"os-extended-snapshot-attributes:progress": "0%",
|
||||
"os-extended-snapshot-attributes:project_id": "89afd400-b646-4bbc-b12b-c0a4d63e5bd3",
|
||||
"size": 10,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"volume_id": "7acd675e-4e06-4653-af9f-2ecd546342d6",
|
||||
"group_snapshot_id": null,
|
||||
"user_id": "c853ca26-e8ea-4797-8a52-ee124a013d0e",
|
||||
"consumes_quota": true
|
||||
}
|
||||
]
|
||||
}
|
@ -21,8 +21,8 @@
|
||||
],
|
||||
"min_version": "3.0",
|
||||
"status": "CURRENT",
|
||||
"updated": "2021-05-30T00:00:00Z",
|
||||
"version": "3.64"
|
||||
"updated": "2021-08-25T00:00:00Z",
|
||||
"version": "3.65"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -21,8 +21,8 @@
|
||||
],
|
||||
"min_version": "3.0",
|
||||
"status": "CURRENT",
|
||||
"updated": "2021-05-30T00:00:00Z",
|
||||
"version": "3.64"
|
||||
"updated": "2021-08-25T00:00:00Z",
|
||||
"version": "3.65"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -0,0 +1,41 @@
|
||||
{
|
||||
"volume": {
|
||||
"attachments": [],
|
||||
"availability_zone": "nova",
|
||||
"bootable": "false",
|
||||
"consistencygroup_id": null,
|
||||
"created_at": "2018-11-28T06:21:12.715987",
|
||||
"description": null,
|
||||
"encrypted": false,
|
||||
"id": "2b955850-f177-45f7-9f49-ecb2c256d161",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://127.0.0.1:33951/v3/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/2b955850-f177-45f7-9f49-ecb2c256d161",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://127.0.0.1:33951/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/2b955850-f177-45f7-9f49-ecb2c256d161",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"migration_status": null,
|
||||
"multiattach": false,
|
||||
"name": null,
|
||||
"replication_status": null,
|
||||
"size": 10,
|
||||
"snapshot_id": null,
|
||||
"source_volid": null,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"user_id": "c853ca26-e8ea-4797-8a52-ee124a013d0e",
|
||||
"volume_type": "__DEFAULT__",
|
||||
"group_id": null,
|
||||
"provider_id": null,
|
||||
"service_uuid": null,
|
||||
"shared_targets": true,
|
||||
"cluster_name": null,
|
||||
"volume_type_id": "5fed9d7c-401d-46e2-8e80-f30c70cb7e1d",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
{
|
||||
"volume": {
|
||||
"attachments": [],
|
||||
"availability_zone": "nova",
|
||||
"bootable": "false",
|
||||
"consistencygroup_id": null,
|
||||
"created_at": "2018-11-29T06:50:07.770785",
|
||||
"description": null,
|
||||
"encrypted": false,
|
||||
"id": "f7223234-1afc-4d19-bfa3-d19deb6235ef",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://127.0.0.1:45839/v3/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/f7223234-1afc-4d19-bfa3-d19deb6235ef",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://127.0.0.1:45839/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/f7223234-1afc-4d19-bfa3-d19deb6235ef",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"migration_status": null,
|
||||
"multiattach": false,
|
||||
"name": null,
|
||||
"os-vol-host-attr:host": null,
|
||||
"os-vol-mig-status-attr:migstat": null,
|
||||
"os-vol-mig-status-attr:name_id": null,
|
||||
"os-vol-tenant-attr:tenant_id": "89afd400-b646-4bbc-b12b-c0a4d63e5bd3",
|
||||
"replication_status": null,
|
||||
"size": 10,
|
||||
"snapshot_id": null,
|
||||
"source_volid": null,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"user_id": "c853ca26-e8ea-4797-8a52-ee124a013d0e",
|
||||
"volume_type": "__DEFAULT__",
|
||||
"provider_id": null,
|
||||
"group_id": null,
|
||||
"service_uuid": null,
|
||||
"shared_targets": true,
|
||||
"cluster_name": null,
|
||||
"volume_type_id": "5fed9d7c-401d-46e2-8e80-f30c70cb7e1d",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
{
|
||||
"volume": {
|
||||
"attachments": [],
|
||||
"availability_zone": "nova",
|
||||
"bootable": "false",
|
||||
"consistencygroup_id": null,
|
||||
"created_at": "2018-11-29T06:59:23.679903",
|
||||
"description": "This is yet, another volume.",
|
||||
"encrypted": false,
|
||||
"id": "8b2459d1-0059-4e14-a89f-dfa73a452af6",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://127.0.0.1:41467/v3/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/8b2459d1-0059-4e14-a89f-dfa73a452af6",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://127.0.0.1:41467/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/8b2459d1-0059-4e14-a89f-dfa73a452af6",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"name": "metadata0"
|
||||
},
|
||||
"migration_status": null,
|
||||
"multiattach": false,
|
||||
"name": "vol-003",
|
||||
"replication_status": null,
|
||||
"size": 10,
|
||||
"snapshot_id": null,
|
||||
"source_volid": null,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"user_id": "c853ca26-e8ea-4797-8a52-ee124a013d0e",
|
||||
"volume_type": "__DEFAULT__",
|
||||
"group_id": null,
|
||||
"provider_id": null,
|
||||
"service_uuid": null,
|
||||
"shared_targets": true,
|
||||
"cluster_name": null,
|
||||
"volume_type_id": "5fed9d7c-401d-46e2-8e80-f30c70cb7e1d",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
{
|
||||
"volumes": [
|
||||
{
|
||||
"attachments": [],
|
||||
"availability_zone": "nova",
|
||||
"bootable": "false",
|
||||
"consistencygroup_id": null,
|
||||
"created_at": "2018-11-28T06:25:15.288987",
|
||||
"description": null,
|
||||
"encrypted": false,
|
||||
"id": "cb49b381-9012-40cb-b8ee-80c19a4801b5",
|
||||
"links": [
|
||||
{
|
||||
"href": "http://127.0.0.1:43543/v3/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/cb49b381-9012-40cb-b8ee-80c19a4801b5",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "http://127.0.0.1:43543/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/cb49b381-9012-40cb-b8ee-80c19a4801b5",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"migration_status": null,
|
||||
"multiattach": false,
|
||||
"name": null,
|
||||
"os-vol-host-attr:host": null,
|
||||
"os-vol-mig-status-attr:migstat": null,
|
||||
"os-vol-mig-status-attr:name_id": null,
|
||||
"os-vol-tenant-attr:tenant_id": "89afd400-b646-4bbc-b12b-c0a4d63e5bd3",
|
||||
"replication_status": null,
|
||||
"size": 10,
|
||||
"snapshot_id": null,
|
||||
"source_volid": null,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"user_id": "c853ca26-e8ea-4797-8a52-ee124a013d0e",
|
||||
"volume_type": "__DEFAULT__",
|
||||
"volume_type_id": "5fed9d7c-401d-46e2-8e80-f30c70cb7e1d",
|
||||
"provider_id": null,
|
||||
"group_id": null,
|
||||
"service_uuid": null,
|
||||
"shared_targets": true,
|
||||
"cluster_name": null,
|
||||
"consumes_quota": true
|
||||
}
|
||||
]
|
||||
}
|
@ -67,6 +67,7 @@ Request
|
||||
- offset: offset
|
||||
- marker: marker
|
||||
- with_count: with_count
|
||||
- consumes_quota: filter_consumes_quota
|
||||
|
||||
|
||||
Response Parameters
|
||||
@ -89,11 +90,12 @@ Response Parameters
|
||||
- updated_at: updated_at
|
||||
- snapshots_links: links_snap
|
||||
- group_snapshot_id: group_snapshot_id_3_14
|
||||
- consumes_quota: consumes_quota
|
||||
|
||||
Response Example (v3.41)
|
||||
Response Example (v3.65)
|
||||
------------------------
|
||||
|
||||
.. literalinclude:: ./samples/snapshots/v3.41/snapshots-list-detailed-response.json
|
||||
.. literalinclude:: ./samples/snapshots/v3.65/snapshots-list-detailed-response.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
@ -149,11 +151,12 @@ Response Parameters
|
||||
- size: size
|
||||
- updated_at: updated_at
|
||||
- group_snapshot_id: group_snapshot_id_3_14
|
||||
- consumes_quota: consumes_quota
|
||||
|
||||
Response Example (v3.41)
|
||||
Response Example (v3.65)
|
||||
------------------------
|
||||
|
||||
.. literalinclude:: ./samples/snapshots/v3.41/snapshot-create-response.json
|
||||
.. literalinclude:: ./samples/snapshots/v3.65/snapshot-create-response.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
@ -189,6 +192,7 @@ Request
|
||||
- limit: limit
|
||||
- offset: offset
|
||||
- marker: marker
|
||||
- consumes_quota: filter_consumes_quota
|
||||
- with_count: with_count
|
||||
|
||||
|
||||
@ -388,11 +392,12 @@ Response Parameters
|
||||
- metadata: metadata
|
||||
- updated_at: updated_at
|
||||
- group_snapshot_id: group_snapshot_id_3_14
|
||||
- consumes_quota: consumes_quota
|
||||
|
||||
Response Example (v3.41)
|
||||
Response Example (v3.65)
|
||||
------------------------
|
||||
|
||||
.. literalinclude:: ./samples/snapshots/v3.41/snapshot-show-response.json
|
||||
.. literalinclude:: ./samples/snapshots/v3.65/snapshot-show-response.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
@ -446,11 +451,12 @@ Response Parameters
|
||||
- user_id: user_id_min
|
||||
- metadata: metadata
|
||||
- group_snapshot_id: group_snapshot_id_3_14
|
||||
- consumes_quota: consumes_quota
|
||||
|
||||
Response Example (v3.41)
|
||||
Response Example (v3.65)
|
||||
------------------------
|
||||
|
||||
.. literalinclude:: ./samples/snapshots/v3.41/snapshot-update-response.json
|
||||
.. literalinclude:: ./samples/snapshots/v3.65/snapshot-update-response.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
|
@ -98,6 +98,7 @@ Request
|
||||
- with_count: with_count
|
||||
- created_at: filter_created_at
|
||||
- updated_at: filter_updated_at
|
||||
- consumes_quota: filter_consumes_quota
|
||||
|
||||
|
||||
Response Parameters
|
||||
@ -140,13 +141,14 @@ Response Parameters
|
||||
- service_uuid: service_uuid
|
||||
- shared_targets: shared_targets
|
||||
- cluster_name: cluster_name
|
||||
- consumes_quota: consumes_quota
|
||||
- count: count
|
||||
|
||||
|
||||
Response Example (v3.63)
|
||||
Response Example (v3.65)
|
||||
------------------------
|
||||
|
||||
.. literalinclude:: ./samples/volumes/v3.63/volumes-list-detailed-response.json
|
||||
.. literalinclude:: ./samples/volumes/v3.65/volumes-list-detailed-response.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
@ -258,11 +260,12 @@ Response Parameters
|
||||
- service_uuid: service_uuid
|
||||
- shared_targets: shared_targets
|
||||
- cluster_name: cluster_name
|
||||
- consumes_quota: consumes_quota
|
||||
|
||||
Response Example (v3.63)
|
||||
Response Example (v3.65)
|
||||
------------------------
|
||||
|
||||
.. literalinclude:: ./samples/volumes/v3.63/volume-create-response.json
|
||||
.. literalinclude:: ./samples/volumes/v3.65/volume-create-response.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
@ -301,6 +304,7 @@ Request
|
||||
- marker: marker
|
||||
- with_count: with_count
|
||||
- created_at: filter_created_at
|
||||
- consumes_quota: filter_consumes_quota
|
||||
- updated_at: filter_updated_at
|
||||
|
||||
|
||||
@ -394,12 +398,13 @@ Response Parameters
|
||||
- cluster_name: cluster_name
|
||||
- provider_id: provider_id
|
||||
- group_id: group_id_optional
|
||||
- consumes_quota: consumes_quota
|
||||
|
||||
|
||||
Response Example (v3.63)
|
||||
Response Example (v3.65)
|
||||
------------------------
|
||||
|
||||
.. literalinclude:: ./samples/volumes/v3.63/volume-show-response.json
|
||||
.. literalinclude:: ./samples/volumes/v3.65/volume-show-response.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
@ -473,12 +478,13 @@ Response Parameters
|
||||
- service_uuid: service_uuid
|
||||
- shared_targets: shared_targets
|
||||
- cluster_name: cluster_name
|
||||
- consumes_quota: consumes_quota
|
||||
|
||||
|
||||
Response Example (v3.63)
|
||||
Response Example (v3.65)
|
||||
------------------------
|
||||
|
||||
.. literalinclude:: ./samples/volumes/v3.63/volume-update-response.json
|
||||
.. literalinclude:: ./samples/volumes/v3.65/volume-update-response.json
|
||||
:language: javascript
|
||||
|
||||
|
||||
|
@ -49,7 +49,8 @@ LOG = logging.getLogger(__name__)
|
||||
_FILTERS_COLLECTION = None
|
||||
|
||||
ATTRIBUTE_CONVERTERS = {'name~': 'display_name~',
|
||||
'description~': 'display_description~'}
|
||||
'description~': 'display_description~',
|
||||
'consumes_quota': 'use_quota'}
|
||||
|
||||
|
||||
METADATA_TYPES = enum.Enum('METADATA_TYPES', 'user image')
|
||||
|
@ -167,6 +167,8 @@ VOLUME_TYPE_ID_IN_VOLUME_DETAIL = '3.63'
|
||||
|
||||
ENCRYPTION_KEY_ID_IN_DETAILS = '3.64'
|
||||
|
||||
USE_QUOTA = '3.65'
|
||||
|
||||
|
||||
def get_mv_header(version):
|
||||
"""Gets a formatted HTTP microversion header.
|
||||
|
@ -148,14 +148,17 @@ REST_API_VERSION_HISTORY = """
|
||||
("GET /v3/{project_id}/volumes/detail") and volume-show
|
||||
("GET /v3/{project_id}/volumes/{volume_id}") calls.
|
||||
* 3.64 - Include 'encryption_key_id' in volume and backup details
|
||||
* 3.65 - Include 'consumes_quota' in volume and snapshot details
|
||||
- Accept 'consumes_quota' filter in volume and snapshot list
|
||||
operation.
|
||||
"""
|
||||
|
||||
# The minimum and maximum versions of the API supported
|
||||
# The default api version request is defined to be the
|
||||
# minimum version of the API supported.
|
||||
_MIN_API_VERSION = "3.0"
|
||||
_MAX_API_VERSION = "3.64"
|
||||
UPDATED = "2021-05-30T00:00:00Z"
|
||||
_MAX_API_VERSION = "3.65"
|
||||
UPDATED = "2021-08-25T00:00:00Z"
|
||||
|
||||
|
||||
# NOTE(cyeoh): min and max versions declared as functions so we can
|
||||
|
@ -53,16 +53,24 @@ class SnapshotsController(snapshots_v2.SnapshotsController):
|
||||
LOG.debug('Could not evaluate value %s, assuming string',
|
||||
search_opts['metadata'])
|
||||
|
||||
if 'use_quota' in search_opts:
|
||||
search_opts['use_quota'] = utils.get_bool_param('use_quota',
|
||||
search_opts)
|
||||
|
||||
MV_ADDED_FILTERS = (
|
||||
(mv.get_prior_version(mv.SNAPSHOT_LIST_METADATA_FILTER), 'metadata'),
|
||||
# REST API receives consumes_quota, but process_general_filtering
|
||||
# transforms it into use_quota
|
||||
(mv.get_prior_version(mv.USE_QUOTA), 'use_quota'),
|
||||
)
|
||||
|
||||
@common.process_general_filtering('snapshot')
|
||||
def _process_snapshot_filtering(self, context=None, filters=None,
|
||||
req_version=None):
|
||||
"""Formats allowed filters"""
|
||||
|
||||
# if the max version is less than SNAPSHOT_LIST_METADATA_FILTER
|
||||
# metadata based filtering is not supported
|
||||
if req_version.matches(
|
||||
None, mv.get_prior_version(mv.SNAPSHOT_LIST_METADATA_FILTER)):
|
||||
filters.pop('metadata', None)
|
||||
for version, field in self.MV_ADDED_FILTERS:
|
||||
if req_version.matches(None, version):
|
||||
filters.pop(field, None)
|
||||
|
||||
# Filter out invalid options
|
||||
allowed_search_options = self._get_snapshot_filter_options()
|
||||
|
@ -27,9 +27,11 @@ class ViewBuilder(views_v2.ViewBuilder):
|
||||
req_version = request.api_version_request
|
||||
# Add group_snapshot_id if min version is greater than or equal
|
||||
# to GROUP_SNAPSHOTS.
|
||||
snap = snapshot_ref['snapshot']
|
||||
if req_version.matches(mv.GROUP_SNAPSHOTS, None):
|
||||
snapshot_ref['snapshot']['group_snapshot_id'] = (
|
||||
snapshot.get('group_snapshot_id'))
|
||||
snap['group_snapshot_id'] = snapshot.get('group_snapshot_id')
|
||||
if req_version.matches(mv.SNAPSHOT_LIST_USER_ID, None):
|
||||
snapshot_ref['snapshot']['user_id'] = snapshot.get('user_id')
|
||||
snap['user_id'] = snapshot.get('user_id')
|
||||
if req_version.matches(mv.USE_QUOTA):
|
||||
snap['consumes_quota'] = snapshot.get('use_quota')
|
||||
return snapshot_ref
|
||||
|
@ -77,6 +77,9 @@ class ViewBuilder(views_v2.ViewBuilder):
|
||||
encryption_key_id != cinder_constants.FIXED_KEY_ID):
|
||||
volume_ref['volume']['encryption_key_id'] = encryption_key_id
|
||||
|
||||
if req_version.matches(mv.USE_QUOTA):
|
||||
volume_ref['volume']['consumes_quota'] = volume.get('use_quota')
|
||||
|
||||
return volume_ref
|
||||
|
||||
def _list_view(self, func, request, volumes, volume_count,
|
||||
|
@ -80,18 +80,23 @@ class VolumeController(volumes_v2.VolumeController):
|
||||
|
||||
return webob.Response(status_int=HTTPStatus.ACCEPTED)
|
||||
|
||||
MV_ADDED_FILTERS = (
|
||||
(mv.get_prior_version(mv.VOLUME_LIST_GLANCE_METADATA),
|
||||
'glance_metadata'),
|
||||
(mv.get_prior_version(mv.VOLUME_LIST_GROUP), 'group_id'),
|
||||
(mv.get_prior_version(mv.VOLUME_TIME_COMPARISON_FILTER), 'created_at'),
|
||||
(mv.get_prior_version(mv.VOLUME_TIME_COMPARISON_FILTER), 'updated_at'),
|
||||
# REST API receives consumes_quota, but process_general_filtering
|
||||
# transforms it into use_quota
|
||||
(mv.get_prior_version(mv.USE_QUOTA), 'use_quota'),
|
||||
)
|
||||
|
||||
@common.process_general_filtering('volume')
|
||||
def _process_volume_filtering(self, context=None, filters=None,
|
||||
req_version=None):
|
||||
if req_version.matches(None, mv.MESSAGES):
|
||||
filters.pop('glance_metadata', None)
|
||||
|
||||
if req_version.matches(None, mv.BACKUP_UPDATE):
|
||||
filters.pop('group_id', None)
|
||||
|
||||
if req_version.matches(None, mv.SUPPORT_TRANSFER_PAGINATION):
|
||||
filters.pop('created_at', None)
|
||||
filters.pop('updated_at', None)
|
||||
for version, field in self.MV_ADDED_FILTERS:
|
||||
if req_version.matches(None, version):
|
||||
filters.pop(field, None)
|
||||
|
||||
api_utils.remove_invalid_filter_options(
|
||||
context, filters,
|
||||
@ -155,6 +160,9 @@ class VolumeController(volumes_v2.VolumeController):
|
||||
if 'name' in filters:
|
||||
filters['display_name'] = filters.pop('name')
|
||||
|
||||
if 'use_quota' in filters:
|
||||
filters['use_quota'] = utils.get_bool_param('use_quota', filters)
|
||||
|
||||
self._handle_time_comparison_filters(filters)
|
||||
|
||||
strict = req.api_version_request.matches(
|
||||
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"snapshot": {
|
||||
"created_at": "%(strtime)s",
|
||||
"description": "Daily backup",
|
||||
"id": "%(uuid)s",
|
||||
"metadata": {
|
||||
"key": "v3"
|
||||
},
|
||||
"name": "snap-001",
|
||||
"size": 10,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"volume_id": "%(uuid)s",
|
||||
"group_snapshot_id": null,
|
||||
"user_id": "%(uuid)s",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
{
|
||||
"snapshot": {
|
||||
"created_at": "%(strtime)s",
|
||||
"description": "Daily backup",
|
||||
"id": "%(uuid)s",
|
||||
"metadata": {
|
||||
"key": "v3"
|
||||
},
|
||||
"name": "snap-001",
|
||||
"os-extended-snapshot-attributes:progress": "0%",
|
||||
"os-extended-snapshot-attributes:project_id": "%(uuid)s",
|
||||
"size": 10,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"volume_id": "%(uuid)s",
|
||||
"group_snapshot_id": null,
|
||||
"user_id": "%(uuid)s",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
{
|
||||
"snapshot": {
|
||||
"created_at": "%(strtime)s",
|
||||
"description": "This is yet, another snapshot.",
|
||||
"id": "%(uuid)s",
|
||||
"metadata": {
|
||||
"key": "v3"
|
||||
},
|
||||
"name": "snap-002",
|
||||
"size": 10,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"volume_id": "%(uuid)s",
|
||||
"group_snapshot_id": null,
|
||||
"user_id": "%(uuid)s",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
{
|
||||
"snapshots": [
|
||||
{
|
||||
"created_at": "%(strtime)s",
|
||||
"description": "Daily backup",
|
||||
"id": "%(uuid)s",
|
||||
"metadata": {
|
||||
"key": "v3"
|
||||
},
|
||||
"name": "snap-001",
|
||||
"os-extended-snapshot-attributes:progress": "0%",
|
||||
"os-extended-snapshot-attributes:project_id": "%(uuid)s",
|
||||
"size": 10,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"volume_id": "%(uuid)s",
|
||||
"group_snapshot_id": null,
|
||||
"user_id": "%(uuid)s",
|
||||
"consumes_quota": true
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
{
|
||||
"volume": {
|
||||
"attachments": [],
|
||||
"availability_zone": "nova",
|
||||
"bootable": "false",
|
||||
"consistencygroup_id": null,
|
||||
"created_at": "%(strtime)s",
|
||||
"description": null,
|
||||
"encrypted": false,
|
||||
"id": "%(uuid)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v3/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"migration_status": null,
|
||||
"multiattach": false,
|
||||
"name": null,
|
||||
"replication_status": null,
|
||||
"size": 10,
|
||||
"snapshot_id": null,
|
||||
"source_volid": null,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"user_id": "%(uuid)s",
|
||||
"volume_type": "__DEFAULT__",
|
||||
"group_id": null,
|
||||
"provider_id": null,
|
||||
"service_uuid": null,
|
||||
"shared_targets": true,
|
||||
"cluster_name": null,
|
||||
"volume_type_id": "%(uuid)s",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
{
|
||||
"volume": {
|
||||
"attachments": [],
|
||||
"availability_zone": "nova",
|
||||
"bootable": "false",
|
||||
"consistencygroup_id": null,
|
||||
"created_at": "%(strtime)s",
|
||||
"description": null,
|
||||
"encrypted": false,
|
||||
"id": "%(uuid)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v3/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"migration_status": null,
|
||||
"multiattach": false,
|
||||
"name": null,
|
||||
"os-vol-host-attr:host": null,
|
||||
"os-vol-mig-status-attr:migstat": null,
|
||||
"os-vol-mig-status-attr:name_id": null,
|
||||
"os-vol-tenant-attr:tenant_id": "%(uuid)s",
|
||||
"replication_status": null,
|
||||
"size": 10,
|
||||
"snapshot_id": null,
|
||||
"source_volid": null,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"user_id": "%(uuid)s",
|
||||
"volume_type": "__DEFAULT__",
|
||||
"provider_id": null,
|
||||
"group_id": null,
|
||||
"service_uuid": null,
|
||||
"shared_targets": true,
|
||||
"cluster_name": null,
|
||||
"volume_type_id": "%(uuid)s",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
{
|
||||
"volume": {
|
||||
"attachments": [],
|
||||
"availability_zone": "nova",
|
||||
"bootable": "false",
|
||||
"consistencygroup_id": null,
|
||||
"created_at": "%(strtime)s",
|
||||
"description": "This is yet, another volume.",
|
||||
"encrypted": false,
|
||||
"id": "%(uuid)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v3/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"name": "metadata0"
|
||||
},
|
||||
"migration_status": null,
|
||||
"multiattach": false,
|
||||
"name": "vol-003",
|
||||
"replication_status": null,
|
||||
"size": 10,
|
||||
"snapshot_id": null,
|
||||
"source_volid": null,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"user_id": "%(uuid)s",
|
||||
"volume_type": "__DEFAULT__",
|
||||
"group_id": null,
|
||||
"provider_id": null,
|
||||
"service_uuid": null,
|
||||
"shared_targets": true,
|
||||
"cluster_name": null,
|
||||
"volume_type_id": "%(uuid)s",
|
||||
"consumes_quota": true
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
{
|
||||
"volumes": [
|
||||
{
|
||||
"attachments": [],
|
||||
"availability_zone": "nova",
|
||||
"bootable": "false",
|
||||
"consistencygroup_id": null,
|
||||
"created_at": "%(strtime)s",
|
||||
"description": null,
|
||||
"encrypted": false,
|
||||
"id": "%(uuid)s",
|
||||
"links": [
|
||||
{
|
||||
"href": "%(host)s/v3/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/%(uuid)s",
|
||||
"rel": "self"
|
||||
},
|
||||
{
|
||||
"href": "%(host)s/89afd400-b646-4bbc-b12b-c0a4d63e5bd3/volumes/%(uuid)s",
|
||||
"rel": "bookmark"
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"migration_status": null,
|
||||
"multiattach": false,
|
||||
"name": null,
|
||||
"os-vol-host-attr:host": null,
|
||||
"os-vol-mig-status-attr:migstat": null,
|
||||
"os-vol-mig-status-attr:name_id": null,
|
||||
"os-vol-tenant-attr:tenant_id": "%(uuid)s",
|
||||
"replication_status": null,
|
||||
"size": 10,
|
||||
"snapshot_id": null,
|
||||
"source_volid": null,
|
||||
"status": "creating",
|
||||
"updated_at": null,
|
||||
"user_id": "%(uuid)s",
|
||||
"volume_type": "%(name)s",
|
||||
"volume_type_id": "%(uuid)s",
|
||||
"service_uuid": null,
|
||||
"provider_id": null,
|
||||
"group_id": null,
|
||||
"shared_targets": true,
|
||||
"cluster_name": null,
|
||||
"consumes_quota": true
|
||||
}
|
||||
]
|
||||
}
|
@ -39,7 +39,8 @@ class SnapshotBaseTest(test_base.VolumesSampleBase):
|
||||
@test_base.VolumesSampleBase.use_versions(
|
||||
mv.BASE_VERSION, # 3.0
|
||||
mv.GROUP_SNAPSHOTS, # 3.14
|
||||
mv.SNAPSHOT_LIST_USER_ID) # 3.41
|
||||
mv.SNAPSHOT_LIST_USER_ID, # 3.41
|
||||
mv.USE_QUOTA) # 3.65
|
||||
class SnapshotDetailTests(SnapshotBaseTest):
|
||||
"""Test snapshot details returned for operations with different MVs.
|
||||
|
||||
|
@ -22,7 +22,8 @@ from cinder.tests.functional import api_samples_test_base as test_base
|
||||
mv.VOLUME_DETAIL_PROVIDER_ID, # 3.21
|
||||
mv.VOLUME_SHARED_TARGETS_AND_SERVICE_FIELDS, # 3.48
|
||||
mv.VOLUME_CLUSTER_NAME, # 3.61
|
||||
mv.VOLUME_TYPE_ID_IN_VOLUME_DETAIL) # 3.63
|
||||
mv.VOLUME_TYPE_ID_IN_VOLUME_DETAIL, # 3.63
|
||||
mv.USE_QUOTA) # 3.65
|
||||
class VolumeDetailTests(test_base.VolumesSampleBase):
|
||||
"""Test volume details returned for operations with different MVs.
|
||||
|
||||
|
@ -487,12 +487,13 @@ class GeneralFiltersTest(test.TestCase):
|
||||
'expected': ["name", "status", "metadata",
|
||||
"bootable", "migration_status",
|
||||
"availability_zone", "group_id",
|
||||
"size", "created_at", "updated_at"]},
|
||||
"size", "created_at", "updated_at",
|
||||
"consumes_quota"]},
|
||||
{'resource': 'backup',
|
||||
'expected': ["name", "status", "volume_id"]},
|
||||
{'resource': 'snapshot',
|
||||
'expected': ["name", "status", "volume_id", "metadata",
|
||||
"availability_zone"]},
|
||||
"availability_zone", "consumes_quota"]},
|
||||
{'resource': 'group_snapshot',
|
||||
'expected': ["name", "status", "group_id"]},
|
||||
{'resource': 'attachment',
|
||||
|
@ -115,6 +115,28 @@ class SnapshotApiTest(test.TestCase):
|
||||
self.assertNotIn('group_snapshot_id', resp_dict['snapshot'])
|
||||
self.assertNotIn('user_id', resp_dict['snapshot'])
|
||||
|
||||
@ddt.data(
|
||||
(True, True, mv.USE_QUOTA),
|
||||
(True, False, mv.USE_QUOTA),
|
||||
(False, True, mv.get_prior_version(mv.USE_QUOTA)),
|
||||
(False, False, mv.get_prior_version(mv.USE_QUOTA)),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_snapshot_show_with_use_quota(self, present, value, microversion):
|
||||
volume = test_utils.create_volume(self.ctx, host='test_host1',
|
||||
cluster_name='cluster1',
|
||||
availability_zone='nova1')
|
||||
snapshot = test_utils.create_snapshot(self.ctx, volume.id,
|
||||
use_quota=value)
|
||||
|
||||
url = '/v3/snapshots?%s' % snapshot.id
|
||||
req = fakes.HTTPRequest.blank(url, version=microversion)
|
||||
res_dict = self.controller.show(req, snapshot.id)['snapshot']
|
||||
if present:
|
||||
self.assertIs(value, res_dict['consumes_quota'])
|
||||
else:
|
||||
self.assertNotIn('consumes_quota', res_dict)
|
||||
|
||||
def test_snapshot_show_invalid_id(self):
|
||||
snapshot_id = INVALID_UUID
|
||||
req = fakes.HTTPRequest.blank('/v3/snapshots/%s' % snapshot_id)
|
||||
@ -133,25 +155,28 @@ class SnapshotApiTest(test.TestCase):
|
||||
body = {"snapshot": snap}
|
||||
self.controller.create(req, body=body)
|
||||
|
||||
@ddt.data(('host', 'test_host1', True), ('cluster_name', 'cluster1', True),
|
||||
('availability_zone', 'nova1', False))
|
||||
@ddt.data(('host', 'test_host1', True, mv.RESOURCE_FILTER),
|
||||
('cluster_name', 'cluster1', True, mv.RESOURCE_FILTER),
|
||||
('availability_zone', 'nova1', False, mv.RESOURCE_FILTER),
|
||||
('consumes_quota', 'true', False, mv.USE_QUOTA))
|
||||
@ddt.unpack
|
||||
def test_snapshot_list_with_filter(self, filter_name, filter_value,
|
||||
is_admin_user):
|
||||
is_admin_user, microversion):
|
||||
volume1 = test_utils.create_volume(self.ctx, host='test_host1',
|
||||
cluster_name='cluster1',
|
||||
availability_zone='nova1')
|
||||
volume2 = test_utils.create_volume(self.ctx, host='test_host2',
|
||||
cluster_name='cluster2',
|
||||
availability_zone='nova2')
|
||||
snapshot1 = test_utils.create_snapshot(self.ctx, volume1.id)
|
||||
test_utils.create_snapshot(self.ctx, volume2.id)
|
||||
snapshot1 = test_utils.create_snapshot(self.ctx, volume1.id,
|
||||
use_quota=True)
|
||||
test_utils.create_snapshot(self.ctx, volume2.id, use_quota=False)
|
||||
|
||||
url = '/v3/snapshots?%s=%s' % (filter_name, filter_value)
|
||||
# Generic filtering is introduced since '3,31' and we add
|
||||
# 'availability_zone' support by using generic filtering.
|
||||
req = fakes.HTTPRequest.blank(url, use_admin_context=is_admin_user,
|
||||
version=mv.RESOURCE_FILTER)
|
||||
version=microversion)
|
||||
res_dict = self.controller.detail(req)
|
||||
|
||||
self.assertEqual(1, len(res_dict['snapshots']))
|
||||
|
@ -343,6 +343,45 @@ class VolumeApiTest(test.TestCase):
|
||||
volumes = res_dict['volumes']
|
||||
self.assertEqual(2, len(volumes))
|
||||
|
||||
@ddt.data(('true', 0), ('false', 1))
|
||||
@ddt.unpack
|
||||
def test_volume_list_with_quota_filter(self, use_quota, expected_index):
|
||||
volumes = (test_utils.create_volume(self.ctxt, host='test_host1',
|
||||
cluster_name='cluster1',
|
||||
volume_type_id=None,
|
||||
use_quota=True,
|
||||
availability_zone='nova1'),
|
||||
test_utils.create_volume(self.ctxt, host='test_host2',
|
||||
cluster_name='cluster2',
|
||||
volume_type_id=None,
|
||||
use_quota=False,
|
||||
availability_zone='nova2'))
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/v3/volumes?consumes_quota=%s' % use_quota, version=mv.USE_QUOTA)
|
||||
res_dict = self.controller.detail(req)
|
||||
self.assertEqual(1, len(res_dict['volumes']))
|
||||
self.assertEqual(volumes[expected_index].id,
|
||||
res_dict['volumes'][0]['id'])
|
||||
|
||||
def test_volume_list_without_quota_filter(self):
|
||||
num_vols = 4
|
||||
vol_ids = set()
|
||||
# Half of the volumes will use quota, the other half won't
|
||||
for i in range(num_vols):
|
||||
vol = test_utils.create_volume(self.ctxt,
|
||||
use_quota=bool(i % 2),
|
||||
host='test_host',
|
||||
cluster_name='cluster',
|
||||
volume_type_id=None,
|
||||
availability_zone='nova1')
|
||||
vol_ids.add(vol.id)
|
||||
req = fakes.HTTPRequest.blank('/v3/volumes', version=mv.USE_QUOTA)
|
||||
res_dict = self.controller.detail(req)
|
||||
|
||||
res_vol_ids = {v['id'] for v in res_dict['volumes']}
|
||||
self.assertEqual(num_vols, len(res_vol_ids))
|
||||
self.assertEqual(vol_ids, res_vol_ids)
|
||||
|
||||
def _fake_volumes_summary_request(self,
|
||||
version=mv.VOLUME_SUMMARY,
|
||||
all_tenant=False,
|
||||
@ -900,6 +939,27 @@ class VolumeApiTest(test.TestCase):
|
||||
else:
|
||||
self.assertNotIn('encryption_key_id', volume_details)
|
||||
|
||||
@ddt.data(
|
||||
(True, True, mv.USE_QUOTA),
|
||||
(True, False, mv.USE_QUOTA),
|
||||
(False, True, mv.get_prior_version(mv.USE_QUOTA)),
|
||||
(False, False, mv.get_prior_version(mv.USE_QUOTA)),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_volume_show_with_use_quota(self, present, value, microversion):
|
||||
volume = test_utils.create_volume(self.ctxt,
|
||||
volume_type_id=None,
|
||||
use_quota=value)
|
||||
|
||||
req = fakes.HTTPRequest.blank('/v3/volumes/%s' % volume.id,
|
||||
version=microversion)
|
||||
volume_details = self.controller.show(req, volume.id)['volume']
|
||||
|
||||
if present:
|
||||
self.assertIs(value, volume_details['consumes_quota'])
|
||||
else:
|
||||
self.assertNotIn('consumes_quota', volume_details)
|
||||
|
||||
def _fake_create_volume(self, size=1):
|
||||
vol = {
|
||||
'display_name': 'fake_volume1',
|
||||
|
@ -1,10 +1,11 @@
|
||||
{
|
||||
"volume": ["name", "status", "metadata",
|
||||
"bootable", "migration_status", "availability_zone",
|
||||
"group_id", "size", "created_at", "updated_at"],
|
||||
"group_id", "size", "created_at", "updated_at",
|
||||
"consumes_quota"],
|
||||
"backup": ["name", "status", "volume_id"],
|
||||
"snapshot": ["name", "status", "volume_id", "metadata",
|
||||
"availability_zone"],
|
||||
"availability_zone", "consumes_quota"],
|
||||
"group": ["name"],
|
||||
"group_snapshot": ["name", "status", "group_id"],
|
||||
"attachment": ["volume_id", "status", "instance_id", "attach_status"],
|
||||
|
14
releasenotes/notes/mv-use_quota-b8e010f8f68a1eaa.yaml
Normal file
14
releasenotes/notes/mv-use_quota-b8e010f8f68a1eaa.yaml
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Starting with API microversion 3.65, a ``consumes_quota`` field
|
||||
is included in the response body of volumes and snapshots to indicate
|
||||
whether the volume is using quota or not.
|
||||
|
||||
Additionally, ``consumes_quota`` can be used as a listing filter for
|
||||
volumes and snapshots. Its availability is controlled by its inclusion in
|
||||
``etc/cinder/resource_filters.json``, where it is included by default. The
|
||||
default listing behavior is not to use this filter.
|
||||
|
||||
Only temporary resources created internally by cinder will have the value
|
||||
set to ``false``.
|
Loading…
Reference in New Issue
Block a user