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:
parent
a5817bb907
commit
f1fbc5952d
@ -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
|
||||
|
@ -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
|
||||
-------------------
|
||||
|
@ -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
|
||||
-------------------
|
||||
|
@ -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
|
||||
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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):
|
||||
|
@ -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):
|
||||
|
@ -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())
|
||||
|
@ -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):
|
||||
|
@ -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(
|
||||
|
@ -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):
|
||||
|
@ -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(
|
||||
|
@ -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 = {
|
||||
|
@ -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)
|
||||
|
@ -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',
|
||||
|
@ -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",
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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'])
|
||||
|
@ -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))
|
@ -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.")
|
||||
|
@ -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))
|
||||
|
@ -0,0 +1,4 @@
|
||||
---
|
||||
features:
|
||||
- It is now possible to filter shares and share instances with
|
||||
export location ID or path.
|
Loading…
Reference in New Issue
Block a user