Support az filter for snapshot

Sometimes if users want to create volumes from snapshots
with a specified availability_zone, users may want to know
what snapshots are available. In this case, users always
want to filter the snapshots with "availability_zone" first.

This patch added the availability_zone filter for snapshot list.

Change-Id: I8953eca5f535c1399dc882c4a232fbeef9bb2959
This commit is contained in:
wangxiyuan 2017-08-01 14:39:38 +08:00 committed by TommyLike
parent bd1e2fd60f
commit 0f5a7f3ac3
6 changed files with 32 additions and 15 deletions

View File

@ -2983,9 +2983,9 @@ def snapshot_get_all(context, filters=None, marker=None, limit=None,
paired with corresponding item in sort_keys paired with corresponding item in sort_keys
:returns: list of matching snapshots :returns: list of matching snapshots
""" """
if filters and not is_valid_model_filters(models.Snapshot, filters, if filters and not is_valid_model_filters(
exclude_list=('host', models.Snapshot, filters,
'cluster_name')): exclude_list=('host', 'cluster_name', 'availability_zone')):
return [] return []
session = get_session() session = get_session()
@ -3011,7 +3011,7 @@ def _process_snaps_filters(query, filters):
if filters: if filters:
filters = filters.copy() filters = filters.copy()
exclude_list = ('host', 'cluster_name') exclude_list = ('host', 'cluster_name', 'availability_zone')
# Ensure that filters' keys exist on the model or is metadata # Ensure that filters' keys exist on the model or is metadata
for key in filters.keys(): for key in filters.keys():
@ -3043,13 +3043,16 @@ def _process_snaps_filters(query, filters):
# filter handling for host and cluster name # filter handling for host and cluster name
host = filters.pop('host', None) host = filters.pop('host', None)
cluster = filters.pop('cluster_name', None) cluster = filters.pop('cluster_name', None)
if host or cluster: az = filters.pop('availability_zone', None)
if host or cluster or az:
query = query.join(models.Snapshot.volume) query = query.join(models.Snapshot.volume)
vol_field = models.Volume vol_field = models.Volume
if host: if host:
query = query.filter(_filter_host(vol_field.host, host)) query = query.filter(_filter_host(vol_field.host, host))
if cluster: if cluster:
query = query.filter(_filter_host(vol_field.cluster_name, cluster)) query = query.filter(_filter_host(vol_field.cluster_name, cluster))
if az:
query = query.filter_by(availability_zone=az)
filters_dict = {} filters_dict = {}
LOG.debug("Building query based on filter") LOG.debug("Building query based on filter")
@ -3162,7 +3165,8 @@ def snapshot_get_all_by_project(context, project_id, filters=None, marker=None,
:returns: list of matching snapshots :returns: list of matching snapshots
""" """
if filters and not is_valid_model_filters( if filters and not is_valid_model_filters(
models.Snapshot, filters, exclude_list=('host', 'cluster_name')): models.Snapshot, filters,
exclude_list=('host', 'cluster_name', 'availability_zone')):
return [] return []
authorize_project_context(context, project_id) authorize_project_context(context, project_id)

View File

@ -466,7 +466,8 @@ class GeneralFiltersTest(test.TestCase):
{'resource': 'backup', {'resource': 'backup',
'expected': ["name", "status", "volume_id"]}, 'expected': ["name", "status", "volume_id"]},
{'resource': 'snapshot', {'resource': 'snapshot',
'expected': ["name", "status", "volume_id", "metadata"]}, 'expected': ["name", "status", "volume_id", "metadata",
"availability_zone"]},
{'resource': 'group_snapshot', {'resource': 'group_snapshot',
'expected': ["status", "group_id"]}, 'expected': ["status", "group_id"]},
{'resource': 'attachment', {'resource': 'attachment',

View File

@ -126,18 +126,25 @@ class SnapshotApiTest(test.TestCase):
body = {"snapshot": snap} body = {"snapshot": snap}
self.controller.create(req, body) self.controller.create(req, body)
@ddt.data(('host', 'test_host1'), ('cluster_name', 'cluster1')) @ddt.data(('host', 'test_host1', True), ('cluster_name', 'cluster1', True),
('availability_zone', 'nova1', False))
@ddt.unpack @ddt.unpack
def test_snapshot_list_with_filter(self, filter_name, filter_value): def test_snapshot_list_with_filter(self, filter_name, filter_value,
is_admin_user):
volume1 = test_utils.create_volume(self.ctx, host='test_host1', volume1 = test_utils.create_volume(self.ctx, host='test_host1',
cluster_name='cluster1') cluster_name='cluster1',
availability_zone='nova1')
volume2 = test_utils.create_volume(self.ctx, host='test_host2', volume2 = test_utils.create_volume(self.ctx, host='test_host2',
cluster_name='cluster2') cluster_name='cluster2',
availability_zone='nova2')
snapshot1 = test_utils.create_snapshot(self.ctx, volume1.id) snapshot1 = test_utils.create_snapshot(self.ctx, volume1.id)
snapshot2 = test_utils.create_snapshot(self.ctx, volume2.id) # noqa test_utils.create_snapshot(self.ctx, volume2.id)
url = '/v3/snapshots?%s=%s' % (filter_name, filter_value) url = '/v3/snapshots?%s=%s' % (filter_name, filter_value)
req = fakes.HTTPRequest.blank(url, use_admin_context=True) # 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='3.31')
res_dict = self.controller.detail(req) res_dict = self.controller.detail(req)
self.assertEqual(1, len(res_dict['snapshots'])) self.assertEqual(1, len(res_dict['snapshots']))

View File

@ -58,7 +58,8 @@ valid for first. The supported APIs are marked with "*" below in the table.
| | size, description, replication_status, multiattach | | | size, description, replication_status, multiattach |
+-----------------+-------------------------------------------------------------------------+ +-----------------+-------------------------------------------------------------------------+
| | id, volume_id, user_id, project_id, status, volume_size, name, | | | id, volume_id, user_id, project_id, status, volume_size, name, |
| list snapshot* | description, volume_type_id, group_snapshot_id, metadata | | list snapshot* | description, volume_type_id, group_snapshot_id, metadata, |
| | availability_zone |
+-----------------+-------------------------------------------------------------------------+ +-----------------+-------------------------------------------------------------------------+
| | id, name, status, container, availability_zone, description, | | | id, name, status, container, availability_zone, description, |
| list backup* | volume_id, is_incremental, size, host, parent_id | | list backup* | volume_id, is_incremental, size, host, parent_id |

View File

@ -3,7 +3,8 @@
"bootable", "migration_status", "availability_zone", "bootable", "migration_status", "availability_zone",
"group_id"], "group_id"],
"backup": ["name", "status", "volume_id"], "backup": ["name", "status", "volume_id"],
"snapshot": ["name", "status", "volume_id", "metadata"], "snapshot": ["name", "status", "volume_id", "metadata",
"availability_zone"],
"group": [], "group": [],
"group_snapshot": ["status", "group_id"], "group_snapshot": ["status", "group_id"],
"attachment": ["volume_id", "status", "instance_id", "attach_status"], "attachment": ["volume_id", "status", "instance_id", "attach_status"],

View File

@ -0,0 +1,3 @@
---
features:
- Added availability_zone filter for snapshots list.