Merge "Support group specs search for share group type API"
This commit is contained in:
commit
37c41e57cf
@ -298,6 +298,19 @@ group_snapshot_status_query:
|
|||||||
in: query
|
in: query
|
||||||
required: false
|
required: false
|
||||||
type: string
|
type: string
|
||||||
|
group_specs_query:
|
||||||
|
description: |
|
||||||
|
The group specifications as a set of one or more
|
||||||
|
key-value pairs. In each pair, the key is the name of the group
|
||||||
|
specification and the value is the share group type that was used to
|
||||||
|
filter search share group type list. The query must be a “percent-encoded” string,
|
||||||
|
for example, the following query parameters: {'group-specs':
|
||||||
|
{'consistent_snapshot_support': 'true'}} is encoded as
|
||||||
|
'group_specs=%7B%27consistent_snapshot_support%27%3A+%27True%27%7D'
|
||||||
|
in: query
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
min_version: 2.66
|
||||||
host_query:
|
host_query:
|
||||||
description: |
|
description: |
|
||||||
The host name of the resource to query with. Querying by hostname is a
|
The host name of the resource to query with. Querying by hostname is a
|
||||||
|
@ -58,6 +58,8 @@ Request
|
|||||||
.. rest_parameters:: parameters.yaml
|
.. rest_parameters:: parameters.yaml
|
||||||
|
|
||||||
- project_id: project_id_path
|
- project_id: project_id_path
|
||||||
|
- is_public: is_public_query
|
||||||
|
- group_specs: group_specs_query
|
||||||
|
|
||||||
Response parameters
|
Response parameters
|
||||||
-------------------
|
-------------------
|
||||||
|
@ -266,6 +266,27 @@ def check_share_network_is_active(share_network):
|
|||||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_is_public(is_public):
|
||||||
|
"""Parse is_public into something usable.
|
||||||
|
|
||||||
|
:returns:
|
||||||
|
- True: API should list public share group types only
|
||||||
|
- False: API should list private share group types only
|
||||||
|
- None: API should list both public and private share group types
|
||||||
|
"""
|
||||||
|
if is_public is None:
|
||||||
|
# preserve default value of showing only public types
|
||||||
|
return True
|
||||||
|
elif six.text_type(is_public).lower() == "all":
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
return strutils.bool_from_string(is_public, strict=True)
|
||||||
|
except ValueError:
|
||||||
|
msg = _('Invalid is_public filter [%s]') % is_public
|
||||||
|
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||||
|
|
||||||
|
|
||||||
class ViewBuilder(object):
|
class ViewBuilder(object):
|
||||||
"""Model API responses as dictionaries."""
|
"""Model API responses as dictionaries."""
|
||||||
|
|
||||||
|
@ -172,13 +172,14 @@ REST_API_VERSION_HISTORY = """
|
|||||||
'update_security_service', 'update_security_service_check' and
|
'update_security_service', 'update_security_service_check' and
|
||||||
'add_security_service_check'.
|
'add_security_service_check'.
|
||||||
* 2.65 - Added ability to set scheduler hints via the share create API.
|
* 2.65 - Added ability to set scheduler hints via the share create API.
|
||||||
|
* 2.66 - Added filter search by group spec for share group type list.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# The minimum and maximum versions of the API supported
|
# The minimum and maximum versions of the API supported
|
||||||
# The default api version request is defined to be the
|
# The default api version request is defined to be the
|
||||||
# minimum version of the API supported.
|
# minimum version of the API supported.
|
||||||
_MIN_API_VERSION = "2.0"
|
_MIN_API_VERSION = "2.0"
|
||||||
_MAX_API_VERSION = "2.65"
|
_MAX_API_VERSION = "2.66"
|
||||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||||
|
|
||||||
|
|
||||||
|
@ -363,3 +363,7 @@ user documentation.
|
|||||||
Added ability to specify "scheduler_hints" in the request body of the POST
|
Added ability to specify "scheduler_hints" in the request body of the POST
|
||||||
/shares request. These hints will invoke Affinity/Anti-Affinity scheduler
|
/shares request. These hints will invoke Affinity/Anti-Affinity scheduler
|
||||||
filters during share creation and share migration.
|
filters during share creation and share migration.
|
||||||
|
|
||||||
|
2.66
|
||||||
|
----
|
||||||
|
Added filter search by group spec for share group type list.
|
||||||
|
@ -11,14 +11,16 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
"""The group type API controller module."""
|
"""The group type API controller module."""
|
||||||
|
import ast
|
||||||
|
|
||||||
from oslo_utils import strutils
|
|
||||||
from oslo_utils import uuidutils
|
from oslo_utils import uuidutils
|
||||||
import six
|
import six
|
||||||
from six.moves import http_client
|
from six.moves import http_client
|
||||||
import webob
|
import webob
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
|
from manila.api import common
|
||||||
|
from manila.api.openstack import api_version_request as api_version
|
||||||
from manila.api.openstack import wsgi
|
from manila.api.openstack import wsgi
|
||||||
from manila.api.views import share_group_types as views
|
from manila.api.views import share_group_types as views
|
||||||
from manila import exception
|
from manila import exception
|
||||||
@ -104,35 +106,27 @@ class ShareGroupTypesController(wsgi.Controller):
|
|||||||
context = req.environ['manila.context']
|
context = req.environ['manila.context']
|
||||||
if context.is_admin:
|
if context.is_admin:
|
||||||
# Only admin has query access to all group types
|
# Only admin has query access to all group types
|
||||||
filters['is_public'] = self._parse_is_public(
|
filters['is_public'] = common.parse_is_public(
|
||||||
req.params.get('is_public'))
|
req.params.get('is_public'))
|
||||||
else:
|
else:
|
||||||
filters['is_public'] = True
|
filters['is_public'] = True
|
||||||
|
|
||||||
|
group_specs = req.params.get('group_specs', {})
|
||||||
|
group_specs_disallowed = (req.api_version_request <
|
||||||
|
api_version.APIVersionRequest("2.66"))
|
||||||
|
|
||||||
|
if group_specs and group_specs_disallowed:
|
||||||
|
msg = _("Filter by 'group_specs' is not supported by this "
|
||||||
|
"microversion. Use 2.66 or greater microversion to "
|
||||||
|
"be able to use filter search by 'group_specs.")
|
||||||
|
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||||
|
elif group_specs:
|
||||||
|
filters['group_specs'] = ast.literal_eval(group_specs)
|
||||||
|
|
||||||
limited_types = share_group_types.get_all(
|
limited_types = share_group_types.get_all(
|
||||||
context, search_opts=filters).values()
|
context, search_opts=filters).values()
|
||||||
return list(limited_types)
|
return list(limited_types)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parse_is_public(is_public):
|
|
||||||
"""Parse is_public into something usable.
|
|
||||||
|
|
||||||
:returns:
|
|
||||||
- True: API should list public share group types only
|
|
||||||
- False: API should list private share group types only
|
|
||||||
- None: API should list both public and private share group types
|
|
||||||
"""
|
|
||||||
if is_public is None:
|
|
||||||
# preserve default value of showing only public types
|
|
||||||
return True
|
|
||||||
elif six.text_type(is_public).lower() == "all":
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
return strutils.bool_from_string(is_public, strict=True)
|
|
||||||
except ValueError:
|
|
||||||
msg = _('Invalid is_public filter [%s]') % is_public
|
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
|
||||||
|
|
||||||
@wsgi.Controller.authorize('create')
|
@wsgi.Controller.authorize('create')
|
||||||
def _create(self, req, body):
|
def _create(self, req, body):
|
||||||
"""Creates a new share group type."""
|
"""Creates a new share group type."""
|
||||||
|
@ -25,6 +25,7 @@ from six.moves import http_client
|
|||||||
import webob
|
import webob
|
||||||
from webob import exc
|
from webob import exc
|
||||||
|
|
||||||
|
from manila.api import common
|
||||||
from manila.api.openstack import api_version_request as api_version
|
from manila.api.openstack import api_version_request as api_version
|
||||||
from manila.api.openstack import wsgi
|
from manila.api.openstack import wsgi
|
||||||
from manila.api.views import types as views_types
|
from manila.api.views import types as views_types
|
||||||
@ -125,7 +126,7 @@ class ShareTypesController(wsgi.Controller):
|
|||||||
context = req.environ['manila.context']
|
context = req.environ['manila.context']
|
||||||
if context.is_admin:
|
if context.is_admin:
|
||||||
# Only admin has query access to all share types
|
# Only admin has query access to all share types
|
||||||
filters['is_public'] = self._parse_is_public(
|
filters['is_public'] = common.parse_is_public(
|
||||||
req.params.get('is_public'))
|
req.params.get('is_public'))
|
||||||
else:
|
else:
|
||||||
filters['is_public'] = True
|
filters['is_public'] = True
|
||||||
@ -148,26 +149,6 @@ class ShareTypesController(wsgi.Controller):
|
|||||||
context, search_opts=filters).values()
|
context, search_opts=filters).values()
|
||||||
return list(limited_types)
|
return list(limited_types)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def _parse_is_public(is_public):
|
|
||||||
"""Parse is_public into something usable.
|
|
||||||
|
|
||||||
* True: API should list public share types only
|
|
||||||
* False: API should list private share types only
|
|
||||||
* None: API should list both public and private share types
|
|
||||||
"""
|
|
||||||
if is_public is None:
|
|
||||||
# preserve default value of showing only public types
|
|
||||||
return True
|
|
||||||
elif six.text_type(is_public).lower() == "all":
|
|
||||||
return None
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
return strutils.bool_from_string(is_public, strict=True)
|
|
||||||
except ValueError:
|
|
||||||
msg = _('Invalid is_public filter [%s]') % is_public
|
|
||||||
raise exc.HTTPBadRequest(explanation=msg)
|
|
||||||
|
|
||||||
@wsgi.Controller.api_version("1.0", "2.23")
|
@wsgi.Controller.api_version("1.0", "2.23")
|
||||||
@wsgi.action("create")
|
@wsgi.action("create")
|
||||||
def create(self, req, body):
|
def create(self, req, body):
|
||||||
|
@ -344,6 +344,16 @@ class MiscFunctionsTest(test.TestCase):
|
|||||||
result = common.check_net_id_and_subnet_id(body)
|
result = common.check_net_id_and_subnet_id(body)
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
@ddt.data(None, True, 'true', 'false', 'all')
|
||||||
|
def test_parse_is_public_valid(self, value):
|
||||||
|
result = common.parse_is_public(value)
|
||||||
|
self.assertIn(result, (True, False, None))
|
||||||
|
|
||||||
|
def test_parse_is_public_invalid(self):
|
||||||
|
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||||
|
common.parse_is_public,
|
||||||
|
'fakefakefake')
|
||||||
|
|
||||||
|
|
||||||
@ddt.ddt
|
@ddt.ddt
|
||||||
class ViewBuilderTest(test.TestCase):
|
class ViewBuilderTest(test.TestCase):
|
||||||
|
@ -430,16 +430,6 @@ class ShareTypesAPITest(test.TestCase):
|
|||||||
self.assertDictEqual(expected_share_type,
|
self.assertDictEqual(expected_share_type,
|
||||||
output['share_types'][i])
|
output['share_types'][i])
|
||||||
|
|
||||||
@ddt.data(None, True, 'true', 'false', 'all')
|
|
||||||
def test_parse_is_public_valid(self, value):
|
|
||||||
result = self.controller._parse_is_public(value)
|
|
||||||
self.assertIn(result, (True, False, None))
|
|
||||||
|
|
||||||
def test_parse_is_public_invalid(self):
|
|
||||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
|
||||||
self.controller._parse_is_public,
|
|
||||||
'fakefakefake')
|
|
||||||
|
|
||||||
@ddt.data(
|
@ddt.data(
|
||||||
("new_name", "new_description", "wrong_bool"),
|
("new_name", "new_description", "wrong_bool"),
|
||||||
(" ", "new_description", "true"),
|
(" ", "new_description", "true"),
|
||||||
|
@ -102,7 +102,7 @@ class ShareGroupTypesTestCase(test.TestCase):
|
|||||||
|
|
||||||
def test_get_all_types_search(self):
|
def test_get_all_types_search(self):
|
||||||
share_group_type = self.fake_type_w_extra
|
share_group_type = self.fake_type_w_extra
|
||||||
search_filter = {"group_specs": {"gold": "True"}, 'is_public': True}
|
search_filter = {'group_specs': {'gold': 'True'}, 'is_public': True}
|
||||||
self.mock_object(
|
self.mock_object(
|
||||||
db, 'share_group_type_get_all',
|
db, 'share_group_type_get_all',
|
||||||
mock.Mock(return_value=share_group_type))
|
mock.Mock(return_value=share_group_type))
|
||||||
@ -113,11 +113,17 @@ class ShareGroupTypesTestCase(test.TestCase):
|
|||||||
db.share_group_type_get_all.assert_called_once_with(
|
db.share_group_type_get_all.assert_called_once_with(
|
||||||
mock.ANY, 0, filters={'is_public': True})
|
mock.ANY, 0, filters={'is_public': True})
|
||||||
self.assertEqual(sorted(share_group_type), sorted(returned_type))
|
self.assertEqual(sorted(share_group_type), sorted(returned_type))
|
||||||
search_filter = {"group_specs": {"gold": "False"}}
|
search_filter = {'group_specs': {'gold': 'False'}}
|
||||||
returned_type = share_group_types.get_all(
|
returned_type = share_group_types.get_all(
|
||||||
self.context, search_opts=search_filter)
|
self.context, search_opts=search_filter)
|
||||||
self.assertEqual({}, returned_type)
|
self.assertEqual({}, returned_type)
|
||||||
|
|
||||||
|
share_group_type = self.fake_type_w_extra
|
||||||
|
search_filter = {'group_specs': {'gold': 'True'}}
|
||||||
|
returned_type = share_group_types.get_all(
|
||||||
|
self.context, search_opts=search_filter)
|
||||||
|
self.assertItemsEqual(share_group_type, returned_type)
|
||||||
|
|
||||||
def test_add_access(self):
|
def test_add_access(self):
|
||||||
project_id = '456'
|
project_id = '456'
|
||||||
share_group_type = share_group_types.create(self.context, 'type2', [])
|
share_group_type = share_group_types.create(self.context, 'type2', [])
|
||||||
|
@ -0,0 +1,3 @@
|
|||||||
|
---
|
||||||
|
features:
|
||||||
|
- Share group types can now be filtered with its group_specs.
|
Loading…
Reference in New Issue
Block a user