Add export-location filter in share and share instance list API

Share and share instance list API will accept new query string parameter
'export_location'. It can pass path and id of export_location to
retrieve shares filtered.

APIImpact

Partly-implement: BP support-filter-share-by-export-location
Change-Id: I5fdf6d89d0b6c7fa182ddfaac60979bc6c0fc2a6
This commit is contained in:
zhongjun 2017-05-02 18:10:47 +08:00 committed by zhongjun
parent a5817bb907
commit f1fbc5952d
22 changed files with 394 additions and 34 deletions

View File

@ -206,6 +206,22 @@ consistency_group_id_5:
in: query
required: false
type: string
export_location_id_query:
description: |
The export location UUID that can be used to filter shares or
share instances.
in: query
required: false
type: string
min_version: 2.35
export_location_path_query:
description: |
The export location path that can be used to filter shares or
share instances.
in: query
required: false
type: string
min_version: 2.35
extra_specs_1:
description: |
The extra specifications as a set of one or more

View File

@ -25,6 +25,8 @@ Request
.. rest_parameters:: parameters.yaml
- tenant_id: tenant_id_1
- export_location_id: export_location_id_query
- export_location_path: export_location_path_query
Response parameters
-------------------

View File

@ -113,6 +113,8 @@ Request
- project_id: project_id_6
- is_public: is_public
- consistency_group_id: consistency_group_id_6
- export_location_id: export_location_id_query
- export_location_path: export_location_path_query
Response parameters
-------------------
@ -164,6 +166,8 @@ Request
- project_id: project_id_6
- is_public: is_public
- consistency_group_id: consistency_group_id_6
- export_location_id: export_location_id_query
- export_location_path: export_location_path_query
Response parameters
-------------------

View File

@ -102,13 +102,16 @@ REST_API_VERSION_HISTORY = """
access_list API.
* 2.34 - Added 'availability_zone_id' and 'consistent_snapshot_support'
fields to 'share_group' object.
* 2.35 - Added support to retrieve shares filtered by export_location_id
and export_location_path.
"""
# 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 = "2.0"
_MAX_API_VERSION = "2.34"
_MAX_API_VERSION = "2.35"
DEFAULT_API_VERSION = _MIN_API_VERSION

View File

@ -200,3 +200,8 @@ user documentation.
----
Added 'availability_zone_id' and 'consistent_snapshot_support' fields to
'share_group' object.
2.35
----
Added support to retrieve shares filtered by export_location_id and
export_location_path.

View File

@ -100,10 +100,14 @@ class ShareMixin(object):
def index(self, req):
"""Returns a summary list of shares."""
req.GET.pop('export_location_id', None)
req.GET.pop('export_location_path', None)
return self._get_shares(req, is_detail=False)
def detail(self, req):
"""Returns a detailed list of shares."""
req.GET.pop('export_location_id', None)
req.GET.pop('export_location_path', None)
return self._get_shares(req, is_detail=True)
def _get_shares(self, req, is_detail):
@ -159,7 +163,8 @@ class ShareMixin(object):
'display_name', 'status', 'share_server_id', 'volume_type_id',
'share_type_id', 'snapshot_id', 'host', 'share_network_id',
'is_public', 'metadata', 'extra_specs', 'sort_key', 'sort_dir',
'share_group_id', 'share_group_snapshot_id'
'share_group_id', 'share_group_snapshot_id',
'export_location_id', 'export_location_path'
)
def update(self, req, id, body):

View File

@ -15,6 +15,7 @@
from webob import exc
from manila.api import common
from manila.api.openstack import wsgi
from manila.api.views import share_instance as instance_view
from manila import db
@ -61,14 +62,28 @@ class ShareInstancesController(wsgi.Controller, wsgi.AdminActionsMixin):
def instance_force_delete(self, req, id, body):
return self._force_delete(req, id, body)
@wsgi.Controller.api_version("2.3")
@wsgi.Controller.api_version("2.3", "2.34") # noqa
@wsgi.Controller.authorize
def index(self, req):
def index(self, req): # pylint: disable=E0102
context = req.environ['manila.context']
req.GET.pop('export_location_id', None)
req.GET.pop('export_location_path', None)
instances = db.share_instances_get_all(context)
return self._view_builder.detail_list(req, instances)
@wsgi.Controller.api_version("2.35") # noqa
@wsgi.Controller.authorize
def index(self, req): # pylint: disable=E0102
context = req.environ['manila.context']
filters = {}
filters.update(req.GET)
common.remove_invalid_options(
context, filters, ('export_location_id', 'export_location_path'))
instances = db.share_instances_get_all(context, filters)
return self._view_builder.detail_list(req, instances)
@wsgi.Controller.api_version("2.3")
@wsgi.Controller.authorize
def show(self, req, id):

View File

@ -415,6 +415,30 @@ class ShareController(shares.ShareMixin,
def revert(self, req, id, body=None):
return self._revert(req, id, body)
@wsgi.Controller.api_version("2.0", "2.34") # noqa
def index(self, req): # pylint: disable=E0102
"""Returns a summary list of shares."""
req.GET.pop('export_location_id', None)
req.GET.pop('export_location_path', None)
return self._get_shares(req, is_detail=False)
@wsgi.Controller.api_version("2.35") # noqa
def index(self, req): # pylint: disable=E0102
"""Returns a summary list of shares."""
return self._get_shares(req, is_detail=False)
@wsgi.Controller.api_version("2.0", "2.34") # noqa
def detail(self, req): # pylint: disable=E0102
"""Returns a detailed list of shares."""
req.GET.pop('export_location_id', None)
req.GET.pop('export_location_path', None)
return self._get_shares(req, is_detail=True)
@wsgi.Controller.api_version("2.35") # noqa
def detail(self, req): # pylint: disable=E0102
"""Returns a detailed list of shares."""
return self._get_shares(req, is_detail=True)
def create_resource():
return wsgi.Resource(ShareController())

View File

@ -294,9 +294,9 @@ def share_instance_update(context, instance_id, values, with_share_data=False):
with_share_data=with_share_data)
def share_instances_get_all(context):
def share_instances_get_all(context, filters=None):
"""Returns all share instances."""
return IMPL.share_instances_get_all(context)
return IMPL.share_instances_get_all(context, filters=filters)
def share_instances_get_all_by_share_server(context, share_server_id):

View File

@ -1202,13 +1202,35 @@ def share_instance_get(context, share_instance_id, session=None,
@require_admin_context
def share_instances_get_all(context):
def share_instances_get_all(context, filters=None):
session = get_session()
return model_query(
query = model_query(
context, models.ShareInstance, session=session, read_deleted="no",
).options(
joinedload('export_locations'),
).all()
)
filters = filters or {}
export_location_id = filters.get('export_location_id')
export_location_path = filters.get('export_location_path')
if export_location_id or export_location_path:
query = query.join(
models.ShareInstanceExportLocations,
models.ShareInstanceExportLocations.share_instance_id ==
models.ShareInstance.id)
if export_location_path:
query = query.filter(
models.ShareInstanceExportLocations.path ==
export_location_path)
if export_location_id:
query = query.filter(
models.ShareInstanceExportLocations.uuid ==
export_location_id)
# Returns list of share instances that satisfy filters.
query = query.all()
return query
@require_context
@ -1594,6 +1616,23 @@ def _share_get_all_with_filters(context, project_id=None, share_server_id=None,
# Apply filters
if not filters:
filters = {}
export_location_id = filters.get('export_location_id')
export_location_path = filters.get('export_location_path')
if export_location_id or export_location_path:
query = query.join(
models.ShareInstanceExportLocations,
models.ShareInstanceExportLocations.share_instance_id ==
models.ShareInstance.id)
if export_location_path:
query = query.filter(
models.ShareInstanceExportLocations.path ==
export_location_path)
if export_location_id:
query = query.filter(
models.ShareInstanceExportLocations.uuid ==
export_location_id)
if 'metadata' in filters:
for k, v in filters['metadata'].items():
query = query.filter(

View File

@ -1490,6 +1490,12 @@ class API(base.Base):
# Prepare filters
filters = {}
if 'export_location_id' in search_opts:
filters['export_location_id'] = search_opts.pop(
'export_location_id')
if 'export_location_path' in search_opts:
filters['export_location_path'] = search_opts.pop(
'export_location_path')
if 'metadata' in search_opts:
filters['metadata'] = search_opts.pop('metadata')
if not isinstance(filters['metadata'], dict):

View File

@ -68,8 +68,13 @@ class ShareInstancesAPITest(test.TestCase):
self.assertEqual([i['id'] for i in expected],
[i['id'] for i in actual])
def test_index(self):
req = self._get_request('/share_instances')
@ddt.data("2.3", "2.34", "2.35")
def test_index(self, version):
url = '/share_instances'
if (api_version_request.APIVersionRequest(version) >=
api_version_request.APIVersionRequest('2.35')):
url += "?export_location_path=/admin/export/location"
req = self._get_request(url, version=version)
req_context = req.environ['manila.context']
share_instances_count = 3
test_instances = [
@ -77,8 +82,15 @@ class ShareInstancesAPITest(test.TestCase):
for s in range(0, share_instances_count)
]
db.share_export_locations_update(
self.admin_context, test_instances[0]['id'],
'/admin/export/location', False)
actual_result = self.controller.index(req)
if (api_version_request.APIVersionRequest(version) >=
api_version_request.APIVersionRequest('2.35')):
test_instances = test_instances[:1]
self._validate_ids_in_share_instances_list(
test_instances, actual_result['share_instances'])
self.mock_policy_check.assert_called_once_with(

View File

@ -1497,7 +1497,11 @@ class ShareAPITest(test.TestCase):
req,
1)
def _share_list_summary_with_search_opts(self, use_admin_context):
@ddt.data({'use_admin_context': False, 'version': '2.4'},
{'use_admin_context': True, 'version': '2.4'},
{'use_admin_context': True, 'version': '2.35'},
{'use_admin_context': False, 'version': '2.35'})
def share_list_summary_with_search_opts(self, use_admin_context, version):
search_opts = {
'name': 'fake_name',
'status': constants.STATUS_AVAILABLE,
@ -1512,6 +1516,8 @@ class ShareAPITest(test.TestCase):
'limit': '1',
'offset': '1',
'is_public': 'False',
'export_location_id': 'fake_export_location_id',
'export_location_path': 'fake_export_location_path',
}
if use_admin_context:
search_opts['host'] = 'fake_host'
@ -1519,7 +1525,8 @@ class ShareAPITest(test.TestCase):
url = '/shares?fake_key=fake_value'
for k, v in search_opts.items():
url = url + '&' + k + '=' + v
req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context)
req = fakes.HTTPRequest.blank(url, version=version,
use_admin_context=use_admin_context)
shares = [
{'id': 'id1', 'display_name': 'n1'},
@ -1537,12 +1544,18 @@ class ShareAPITest(test.TestCase):
'share_server_id': search_opts['share_server_id'],
'share_type_id': search_opts['share_type_id'],
'snapshot_id': search_opts['snapshot_id'],
'share_network_id': search_opts['share_network_id'],
'metadata': {'k1': 'v1'},
'extra_specs': {'k2': 'v2'},
'is_public': 'False',
}
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.35')):
search_opts_expected['export_location_id'] = (
search_opts['export_location_id'])
search_opts_expected['export_location_path'] = (
search_opts['export_location_path'])
if use_admin_context:
search_opts_expected.update({'fake_key': 'fake_value'})
search_opts_expected['host'] = search_opts['host']
@ -1557,12 +1570,6 @@ class ShareAPITest(test.TestCase):
self.assertEqual(
shares[1]['display_name'], result['shares'][0]['name'])
def test_share_list_summary_with_search_opts_by_non_admin(self):
self._share_list_summary_with_search_opts(use_admin_context=False)
def test_share_list_summary_with_search_opts_by_admin(self):
self._share_list_summary_with_search_opts(use_admin_context=True)
def test_share_list_summary(self):
self.mock_object(share_api.API, 'get_all',
stubs.stub_share_get_all_by_project)
@ -1588,7 +1595,11 @@ class ShareAPITest(test.TestCase):
}
self.assertEqual(expected, res_dict)
def _share_list_detail_with_search_opts(self, use_admin_context):
@ddt.data({'use_admin_context': False, 'version': '2.4'},
{'use_admin_context': True, 'version': '2.4'},
{'use_admin_context': True, 'version': '2.35'},
{'use_admin_context': False, 'version': '2.35'})
def _share_list_detail_with_search_opts(self, use_admin_context, version):
search_opts = {
'name': 'fake_name',
'status': constants.STATUS_AVAILABLE,
@ -1603,6 +1614,8 @@ class ShareAPITest(test.TestCase):
'limit': '1',
'offset': '1',
'is_public': 'False',
'export_location_id': 'fake_export_location_id',
'export_location_path': 'fake_export_location_path',
}
if use_admin_context:
search_opts['host'] = 'fake_host'
@ -1610,7 +1623,8 @@ class ShareAPITest(test.TestCase):
url = '/shares/detail?fake_key=fake_value'
for k, v in search_opts.items():
url = url + '&' + k + '=' + v
req = fakes.HTTPRequest.blank(url, use_admin_context=use_admin_context)
req = fakes.HTTPRequest.blank(url, version=version,
use_admin_context=use_admin_context)
shares = [
{'id': 'id1', 'display_name': 'n1'},
@ -1627,6 +1641,7 @@ class ShareAPITest(test.TestCase):
},
{'id': 'id3', 'display_name': 'n3'},
]
self.mock_object(share_api.API, 'get_all',
mock.Mock(return_value=shares))
@ -1643,6 +1658,13 @@ class ShareAPITest(test.TestCase):
'extra_specs': {'k2': 'v2'},
'is_public': 'False',
}
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.35')):
search_opts_expected['export_location_id'] = (
search_opts['export_location_id'])
search_opts_expected['export_location_path'] = (
search_opts['export_location_path'])
if use_admin_context:
search_opts_expected.update({'fake_key': 'fake_value'})
search_opts_expected['host'] = search_opts['host']
@ -1671,12 +1693,10 @@ class ShareAPITest(test.TestCase):
self.assertEqual(
shares[1]['instance']['share_network_id'],
result['shares'][0]['share_network_id'])
def test_share_list_detail_with_search_opts_by_non_admin(self):
self._share_list_detail_with_search_opts(use_admin_context=False)
def test_share_list_detail_with_search_opts_by_admin(self):
self._share_list_detail_with_search_opts(use_admin_context=True)
if (api_version.APIVersionRequest(version) >=
api_version.APIVersionRequest('2.35')):
self.assertEqual(shares[1]['export_location'],
result['shares'][0]['export_location'])
def _list_detail_common_expected(self, admin=False):
share_dict = {

View File

@ -335,6 +335,29 @@ class ShareDatabaseAPITestCase(test.TestCase):
self.assertEqual('share-%s' % instance['id'], instance['name'])
@ddt.data('id', 'path')
def test_share_instance_get_all_by_export_location(self, type):
share = db_utils.create_share()
initial_location = ['fake_export_location']
db_api.share_export_locations_update(self.ctxt, share.instance['id'],
initial_location, False)
if type == 'id':
export_location = (
db_api.share_export_locations_get_by_share_id(self.ctxt,
share['id']))
value = export_location[0]['uuid']
else:
value = 'fake_export_location'
instances = db_api.share_instances_get_all(
self.ctxt, filters={'export_location_' + type: value})
self.assertEqual(1, len(instances))
instance = instances[0]
self.assertEqual('share-%s' % instance['id'], instance['name'])
@ddt.data('host', 'share_group_id')
def test_share_get_all_sort_by_share_instance_fields(self, sort_key):
shares = [db_utils.create_share(**{sort_key: n, 'size': 1})
@ -346,6 +369,36 @@ class ShareDatabaseAPITestCase(test.TestCase):
self.assertEqual(2, len(actual_result))
self.assertEqual(shares[0]['id'], actual_result[1]['id'])
@ddt.data('id', 'path')
def test_share_get_all_by_export_location(self, type):
share = db_utils.create_share()
initial_location = ['fake_export_location']
db_api.share_export_locations_update(self.ctxt, share.instance['id'],
initial_location, False)
if type == 'id':
export_location = db_api.share_export_locations_get_by_share_id(
self.ctxt, share['id'])
value = export_location[0]['uuid']
else:
value = 'fake_export_location'
actual_result = db_api.share_get_all(
self.ctxt, filters={'export_location_' + type: value})
self.assertEqual(1, len(actual_result))
self.assertEqual(share['id'], actual_result[0]['id'])
@ddt.data('id', 'path')
def test_share_get_all_by_export_location_not_exist(self, type):
share = db_utils.create_share()
initial_location = ['fake_export_location']
db_api.share_export_locations_update(self.ctxt, share.instance['id'],
initial_location, False)
filter = {'export_location_' + type: 'export_location_not_exist'}
actual_result = db_api.share_get_all(self.ctxt, filters=filter)
self.assertEqual(0, len(actual_result))
@ddt.data(None, 'writable')
def test_share_get_has_replicas_field(self, replication_type):
share = db_utils.create_share(replication_type=replication_type)

View File

@ -310,6 +310,22 @@ class ShareAPITestCase(test.TestCase):
)
self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[1::2], shares)
@ddt.data('id', 'path')
def test_get_all_admin_filter_by_export_location(self, type):
ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=True)
self.mock_object(db_api, 'share_get_all_by_project',
mock.Mock(return_value=_FAKE_LIST_OF_ALL_SHARES[1:]))
shares = self.api.get_all(ctx, {'export_location_' + type: 'test'})
share_api.policy.check_policy.assert_has_calls([
mock.call(ctx, 'share', 'get_all'),
])
db_api.share_get_all_by_project.assert_called_once_with(
ctx, sort_dir='desc', sort_key='created_at',
project_id='fake_pid_2',
filters={'export_location_' + type: 'test'}, is_public=False
)
self.assertEqual(_FAKE_LIST_OF_ALL_SHARES[1:], shares)
def test_get_all_admin_filter_by_name_and_all_tenants(self):
ctx = context.RequestContext('fake_uid', 'fake_pid_2', is_admin=True)
self.mock_object(db_api, 'share_get_all',

View File

@ -30,7 +30,7 @@ ShareGroup = [
help="The minimum api microversion is configured to be the "
"value of the minimum microversion supported by Manila."),
cfg.StrOpt("max_api_microversion",
default="2.34",
default="2.35",
help="The maximum api microversion is configured to be the "
"value of the latest microversion supported by Manila."),
cfg.StrOpt("region",

View File

@ -294,8 +294,11 @@ class SharesV2Client(shares_client.SharesClient):
self.expected_success(200, resp.status)
return self._parse_resp(body)
def list_share_instances(self, version=LATEST_MICROVERSION):
resp, body = self.get("share_instances", version=version)
def list_share_instances(self, version=LATEST_MICROVERSION,
params=None):
uri = 'share_instances'
uri += '?%s' % urlparse.urlencode(params) if params else ''
resp, body = self.get(uri, version=version)
self.expected_success(200, resp.status)
return self._parse_resp(body)

View File

@ -14,14 +14,11 @@
# under the License.
import ddt
from tempest import config
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
from manila_tempest_tests import utils
CONF = config.CONF
@ddt.ddt
class ShareInstancesTest(base.BaseSharesAdminTest):
@ -92,3 +89,26 @@ class ShareInstancesTest(base.BaseSharesAdminTest):
'Share instance %s returned incorrect keys; '
'expected %s, got %s.' % (
si['id'], expected_keys, actual_keys))
@ddt.data('path', 'id')
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.35")
def test_list_share_instances_with_export_location_path_and_id(
self, export_location_type):
share_instances_except = (
self.shares_v2_client.get_instances_of_share(
self.share['id']))
export_locations = (
self.shares_v2_client.list_share_instance_export_locations(
share_instances_except[0]['id']))
filters = {
'export_location_' + export_location_type:
export_locations[0][export_location_type],
}
share_instances = self.shares_v2_client.list_share_instances(
params=filters)
self.assertEqual(1, len(share_instances))
self.assertEqual(share_instances_except[0]['id'],
share_instances[0]['id'])

View File

@ -0,0 +1,54 @@
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import ddt
from testtools import testcase as tc
from manila_tempest_tests.tests.api import base
@ddt.ddt
class ShareInstancesNegativeTest(base.BaseSharesAdminTest):
@classmethod
def resource_setup(cls):
super(ShareInstancesNegativeTest, cls).resource_setup()
cls.share = cls.create_share()
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_not_supported("2.34")
@ddt.data('path', 'id')
def test_list_share_instances_with_export_location_and_invalid_version(
self, export_location_type):
# In API versions <v2.35, querying the share instance API by export
# location path or ID should have no effect. Those filters were
# supported from v2.35
filters = {
'export_location_' + export_location_type: 'fake',
}
share_instances = self.shares_v2_client.list_share_instances(
params=filters, version="2.34")
self.assertGreater(len(share_instances), 0)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.35")
@ddt.data('path', 'id')
def test_list_share_instances_with_export_location_not_exist(
self, export_location_type):
filters = {
'export_location_' + export_location_type: 'fake_not_exist',
}
share_instances = self.shares_v2_client.list_share_instances(
params=filters)
self.assertEqual(0, len(share_instances))

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
from tempest import config
from tempest.lib.common.utils import data_utils
import testtools
@ -23,6 +24,7 @@ from manila_tempest_tests.tests.api import base
CONF = config.CONF
@ddt.ddt
class SharesActionsAdminTest(base.BaseSharesAdminTest):
"""Covers share functionality, that doesn't related to share type."""
@ -236,6 +238,32 @@ class SharesActionsAdminTest(base.BaseSharesAdminTest):
for share in shares:
self.assertEqual(filters['host'], share['host'])
@base.skip_if_microversion_lt("2.35")
@ddt.data(('path', True), ('id', True), ('path', False), ('id', False))
@ddt.unpack
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
def test_list_shares_or_with_detail_filter_by_export_location(
self, export_location_type, enable_detail):
export_locations = self.shares_v2_client.list_share_export_locations(
self.shares[0]['id'])
if not isinstance(export_locations, (list, tuple, set)):
export_locations = (export_locations, )
filters = {
'export_location_' + export_location_type:
export_locations[0][export_location_type],
}
# list shares
if enable_detail:
shares = self.shares_v2_client.list_shares_with_detail(
params=filters)
else:
shares = self.shares_v2_client.list_shares(params=filters)
# verify response
self.assertEqual(1, len(shares))
self.assertEqual(self.shares[0]['id'], shares[0]['id'])
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
@testtools.skipIf(
not CONF.share.multitenancy_enabled, "Only for multitenancy.")

View File

@ -13,6 +13,7 @@
# License for the specific language governing permissions and limitations
# under the License.
import ddt
from tempest import config
from tempest.lib import exceptions as lib_exc
import testtools
@ -23,6 +24,7 @@ from manila_tempest_tests.tests.api import base
CONF = config.CONF
@ddt.ddt
class SharesActionsNegativeTest(base.BaseSharesMixedTest):
@classmethod
def resource_setup(cls):
@ -134,3 +136,32 @@ class SharesActionsNegativeTest(base.BaseSharesMixedTest):
self.shares_client.shrink_share,
share['id'],
new_size)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_not_supported("2.34")
@ddt.data('path', 'id')
def test_list_shares_with_export_location_and_invalid_version(
self, export_location_type):
# In API versions <v2.35, querying the share API by export
# location path or ID should have no effect. Those filters were
# supported from v2.35
filters = {
'export_location_' + export_location_type: 'fake',
}
shares = self.shares_v2_client.list_shares(
params=filters, version="2.34")
self.assertGreater(len(shares), 0)
@tc.attr(base.TAG_NEGATIVE, base.TAG_API_WITH_BACKEND)
@base.skip_if_microversion_lt("2.35")
@ddt.data('path', 'id')
def test_list_shares_with_export_location_not_exist(
self, export_location_type):
filters = {
'export_location_' + export_location_type: 'fake_not_exist',
}
shares = self.shares_v2_client.list_shares(
params=filters)
self.assertEqual(0, len(shares))

View File

@ -0,0 +1,4 @@
---
features:
- It is now possible to filter shares and share instances with
export location ID or path.