Merge "Remove experimental flag from share groups feature"

This commit is contained in:
Zuul 2020-04-10 10:36:56 +00:00 committed by Gerrit Code Review
commit ea90fd17b8
11 changed files with 615 additions and 177 deletions

View File

@ -147,13 +147,14 @@ REST_API_VERSION_HISTORY = """
* 2.54 - Share and share instance objects include a new field called * 2.54 - Share and share instance objects include a new field called
"progress" which indicates the completion of a share creation "progress" which indicates the completion of a share creation
operation as a percentage. operation as a percentage.
* 2.55 - Share groups feature is no longer considered experimental.
""" """
# 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.54" _MAX_API_VERSION = "2.55"
DEFAULT_API_VERSION = _MIN_API_VERSION DEFAULT_API_VERSION = _MIN_API_VERSION

View File

@ -301,3 +301,7 @@ user documentation.
---- ----
Share and share instance objects include a new field called "progress" which Share and share instance objects include a new field called "progress" which
indicates the completion of a share creation operation as a percentage. indicates the completion of a share creation operation as a percentage.
2.55
----
Share groups feature is no longer considered experimental.

View File

@ -29,6 +29,7 @@ from manila.i18n import _
import manila.share_group.api as share_group_api import manila.share_group.api as share_group_api
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
SG_GRADUATION_VERSION = '2.55'
class ShareGroupSnapshotController(wsgi.Controller, wsgi.AdminActionsMixin): class ShareGroupSnapshotController(wsgi.Controller, wsgi.AdminActionsMixin):
@ -50,17 +51,23 @@ class ShareGroupSnapshotController(wsgi.Controller, wsgi.AdminActionsMixin):
msg = _("Share group snapshot %s not found.") % sg_snapshot_id msg = _("Share group snapshot %s not found.") % sg_snapshot_id
raise exc.HTTPNotFound(explanation=msg) raise exc.HTTPNotFound(explanation=msg)
@wsgi.Controller.api_version('2.31', experimental=True)
@wsgi.Controller.authorize('get') @wsgi.Controller.authorize('get')
def show(self, req, id): def _show(self, req, id):
"""Return data about the given share group snapshot.""" """Return data about the given share group snapshot."""
context = req.environ['manila.context'] context = req.environ['manila.context']
sg_snapshot = self._get_share_group_snapshot(context, id) sg_snapshot = self._get_share_group_snapshot(context, id)
return self._view_builder.detail(req, sg_snapshot) return self._view_builder.detail(req, sg_snapshot)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.Controller.authorize def show(self, req, id):
def delete(self, req, id): return self._show(req, id)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def show(self, req, id): # pylint: disable=function-redefined
return self._show(req, id)
@wsgi.Controller.authorize('delete')
def _delete_group_snapshot(self, req, id):
"""Delete a share group snapshot.""" """Delete a share group snapshot."""
context = req.environ['manila.context'] context = req.environ['manila.context']
LOG.info("Delete share group snapshot with id: %s", LOG.info("Delete share group snapshot with id: %s",
@ -73,18 +80,35 @@ class ShareGroupSnapshotController(wsgi.Controller, wsgi.AdminActionsMixin):
raise exc.HTTPConflict(explanation=six.text_type(e)) raise exc.HTTPConflict(explanation=six.text_type(e))
return webob.Response(status_int=http_client.ACCEPTED) return webob.Response(status_int=http_client.ACCEPTED)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.Controller.authorize('get_all') def delete(self, req, id):
return self._delete_group_snapshot(req, id)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def delete(self, req, id): # pylint: disable=function-redefined
return self._delete_group_snapshot(req, id)
@wsgi.Controller.api_version('2.31', '2.54', experimental=True)
def index(self, req): def index(self, req):
"""Returns a summary list of share group snapshots.""" """Returns a summary list of share group snapshots."""
return self._get_share_group_snaps(req, is_detail=False) return self._get_share_group_snaps(req, is_detail=False)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.Controller.authorize('get_all') def index(self, req): # pylint: disable=function-redefined
"""Returns a summary list of share group snapshots."""
return self._get_share_group_snaps(req, is_detail=False)
@wsgi.Controller.api_version('2.31', '2.54', experimental=True)
def detail(self, req): def detail(self, req):
"""Returns a detailed list of share group snapshots.""" """Returns a detailed list of share group snapshots."""
return self._get_share_group_snaps(req, is_detail=True) return self._get_share_group_snaps(req, is_detail=True)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def detail(self, req): # pylint: disable=function-redefined
"""Returns a detailed list of share group snapshots."""
return self._get_share_group_snaps(req, is_detail=True)
@wsgi.Controller.authorize('get_all')
def _get_share_group_snaps(self, req, is_detail): def _get_share_group_snaps(self, req, is_detail):
"""Returns a list of share group snapshots.""" """Returns a list of share group snapshots."""
context = req.environ['manila.context'] context = req.environ['manila.context']
@ -110,9 +134,8 @@ class ShareGroupSnapshotController(wsgi.Controller, wsgi.AdminActionsMixin):
snaps = self._view_builder.summary_list(req, limited_list) snaps = self._view_builder.summary_list(req, limited_list)
return snaps return snaps
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.authorize('update')
@wsgi.Controller.authorize def _update_group_snapshot(self, req, id, body):
def update(self, req, id, body):
"""Update a share group snapshot.""" """Update a share group snapshot."""
context = req.environ['manila.context'] context = req.environ['manila.context']
key = 'share_group_snapshot' key = 'share_group_snapshot'
@ -135,10 +158,16 @@ class ShareGroupSnapshotController(wsgi.Controller, wsgi.AdminActionsMixin):
context, sg_snapshot, sg_snapshot_data) context, sg_snapshot, sg_snapshot_data)
return self._view_builder.detail(req, sg_snapshot) return self._view_builder.detail(req, sg_snapshot)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.response(202) def update(self, req, id, body):
@wsgi.Controller.authorize return self._update_group_snapshot(req, id, body)
def create(self, req, body):
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def update(self, req, id, body): # pylint: disable=function-redefined
return self._update_group_snapshot(req, id, body)
@wsgi.Controller.authorize('create')
def _create(self, req, body):
"""Creates a new share group snapshot.""" """Creates a new share group snapshot."""
context = req.environ['manila.context'] context = req.environ['manila.context']
@ -172,9 +201,18 @@ class ShareGroupSnapshotController(wsgi.Controller, wsgi.AdminActionsMixin):
return self._view_builder.detail(req, dict(new_snapshot.items())) return self._view_builder.detail(req, dict(new_snapshot.items()))
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.response(202)
def create(self, req, body):
return self._create(req, body)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.response(202)
def create(self, req, body): # pylint: disable=function-redefined
return self._create(req, body)
@wsgi.Controller.authorize('get') @wsgi.Controller.authorize('get')
def members(self, req, id): def _members(self, req, id):
"""Returns a list of share group snapshot members.""" """Returns a list of share group snapshot members."""
context = req.environ['manila.context'] context = req.environ['manila.context']
@ -186,6 +224,14 @@ class ShareGroupSnapshotController(wsgi.Controller, wsgi.AdminActionsMixin):
snaps = self._view_builder.member_list(req, limited_list) snaps = self._view_builder.member_list(req, limited_list)
return snaps return snaps
@wsgi.Controller.api_version('2.31', '2.54', experimental=True)
def members(self, req, id):
return self._members(req, id)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def members(self, req, id): # pylint: disable=function-redefined
return self._members(req, id)
def _update(self, *args, **kwargs): def _update(self, *args, **kwargs):
db.share_group_snapshot_update(*args, **kwargs) db.share_group_snapshot_update(*args, **kwargs)
@ -195,12 +241,25 @@ class ShareGroupSnapshotController(wsgi.Controller, wsgi.AdminActionsMixin):
def _delete(self, context, resource, force=True): def _delete(self, context, resource, force=True):
db.share_group_snapshot_destroy(context.elevated(), resource['id']) db.share_group_snapshot_destroy(context.elevated(), resource['id'])
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.action('reset_status') @wsgi.action('reset_status')
def share_group_snapshot_reset_status(self, req, id, body): def share_group_snapshot_reset_status(self, req, id, body):
return self._reset_status(req, id, body) return self._reset_status(req, id, body)
@wsgi.Controller.api_version('2.31', experimental=True) # pylint: disable=function-redefined
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.action('reset_status')
def share_group_snapshot_reset_status(self, req, id, body):
return self._reset_status(req, id, body)
# pylint: enable=function-redefined
@wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.action('force_delete')
def share_group_snapshot_force_delete(self, req, id, body):
return self._force_delete(req, id, body)
# pylint: disable=function-redefined
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.action('force_delete') @wsgi.action('force_delete')
def share_group_snapshot_force_delete(self, req, id, body): def share_group_snapshot_force_delete(self, req, id, body):
return self._force_delete(req, id, body) return self._force_delete(req, id, body)

View File

@ -22,6 +22,8 @@ from manila import exception
from manila.i18n import _ from manila.i18n import _
from manila.share_group import share_group_types from manila.share_group import share_group_types
SG_GRADUATION_VERSION = '2.55'
class ShareGroupTypeSpecsController(wsgi.Controller): class ShareGroupTypeSpecsController(wsgi.Controller):
"""The share group type specs API controller for the OpenStack API.""" """The share group type specs API controller for the OpenStack API."""
@ -57,18 +59,24 @@ class ShareGroupTypeSpecsController(wsgi.Controller):
} }
raise webob.exc.HTTPBadRequest(explanation=expl) raise webob.exc.HTTPBadRequest(explanation=expl)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.authorize('index')
@wsgi.Controller.authorize def _index(self, req, id):
def index(self, req, id):
"""Returns the list of group specs for a given share group type.""" """Returns the list of group specs for a given share group type."""
context = req.environ['manila.context'] context = req.environ['manila.context']
self._assert_share_group_type_exists(context, id) self._assert_share_group_type_exists(context, id)
return self._get_group_specs(context, id) return self._get_group_specs(context, id)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.Controller.authorize def index(self, req, id):
def create(self, req, id, body=None): return self._index(req, id)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def index(self, req, id): # pylint: disable=function-redefined
return self._index(req, id)
@wsgi.Controller.authorize('create')
def _create(self, req, id, body=None):
context = req.environ['manila.context'] context = req.environ['manila.context']
if not self.is_valid_body(body, 'group_specs'): if not self.is_valid_body(body, 'group_specs'):
raise webob.exc.HTTPBadRequest() raise webob.exc.HTTPBadRequest()
@ -80,9 +88,16 @@ class ShareGroupTypeSpecsController(wsgi.Controller):
db.share_group_type_specs_update_or_create(context, id, specs) db.share_group_type_specs_update_or_create(context, id, specs)
return body return body
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.Controller.authorize def create(self, req, id, body=None):
def update(self, req, id, key, body=None): return self._create(req, id, body)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def create(self, req, id, body=None): # pylint: disable=function-redefined
return self._create(req, id, body)
@wsgi.Controller.authorize('update')
def _update(self, req, id, key, body=None):
context = req.environ['manila.context'] context = req.environ['manila.context']
if not body: if not body:
expl = _('Request body empty.') expl = _('Request body empty.')
@ -98,9 +113,17 @@ class ShareGroupTypeSpecsController(wsgi.Controller):
db.share_group_type_specs_update_or_create(context, id, body) db.share_group_type_specs_update_or_create(context, id, body)
return body return body
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.Controller.authorize def update(self, req, id, key, body=None):
def show(self, req, id, key): return self._update(req, id, key, body)
# pylint: disable=function-redefined
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def update(self, req, id, key, body=None):
return self._update(req, id, key, body)
@wsgi.Controller.authorize('show')
def _show(self, req, id, key):
"""Return a single group spec item.""" """Return a single group spec item."""
context = req.environ['manila.context'] context = req.environ['manila.context']
self._assert_share_group_type_exists(context, id) self._assert_share_group_type_exists(context, id)
@ -110,9 +133,17 @@ class ShareGroupTypeSpecsController(wsgi.Controller):
else: else:
raise webob.exc.HTTPNotFound() raise webob.exc.HTTPNotFound()
@wsgi.Controller.api_version('2.31', experimental=True) # pylint: enable=function-redefined
@wsgi.Controller.authorize @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
def delete(self, req, id, key): def show(self, req, id, key):
return self._show(req, id, key)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def show(self, req, id, key): # pylint: disable=function-redefined
return self._show(req, id, key)
@wsgi.Controller.authorize('delete')
def _delete(self, req, id, key):
"""Deletes an existing group spec.""" """Deletes an existing group spec."""
context = req.environ['manila.context'] context = req.environ['manila.context']
self._assert_share_group_type_exists(context, id) self._assert_share_group_type_exists(context, id)
@ -122,6 +153,14 @@ class ShareGroupTypeSpecsController(wsgi.Controller):
raise webob.exc.HTTPNotFound(explanation=error.msg) raise webob.exc.HTTPNotFound(explanation=error.msg)
return webob.Response(status_int=http_client.NO_CONTENT) return webob.Response(status_int=http_client.NO_CONTENT)
@wsgi.Controller.api_version('2.31', '2.54', experimental=True)
def delete(self, req, id, key):
return self._delete(req, id, key)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def delete(self, req, id, key): # pylint: disable=function-redefined
return self._delete(req, id, key)
def _check_key_names(self, keys): def _check_key_names(self, keys):
if not common.validate_key_names(keys): if not common.validate_key_names(keys):
expl = _('Key names can only contain alphanumeric characters, ' expl = _('Key names can only contain alphanumeric characters, '

View File

@ -25,6 +25,8 @@ from manila import exception
from manila.i18n import _ from manila.i18n import _
from manila.share_group import share_group_types from manila.share_group import share_group_types
SG_GRADUATION_VERSION = '2.55'
class ShareGroupTypesController(wsgi.Controller): class ShareGroupTypesController(wsgi.Controller):
"""The share group types API controller for the OpenStack API.""" """The share group types API controller for the OpenStack API."""
@ -41,16 +43,22 @@ class ShareGroupTypesController(wsgi.Controller):
msg = _("Project value (%s) must be in uuid format.") % project msg = _("Project value (%s) must be in uuid format.") % project
raise webob.exc.HTTPBadRequest(explanation=msg) raise webob.exc.HTTPBadRequest(explanation=msg)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.authorize('index')
@wsgi.Controller.authorize def _index(self, req):
def index(self, req):
"""Returns the list of share group types.""" """Returns the list of share group types."""
limited_types = self._get_share_group_types(req) limited_types = self._get_share_group_types(req)
return self._view_builder.index(req, limited_types) return self._view_builder.index(req, limited_types)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.Controller.authorize def index(self, req):
def show(self, req, id): return self._index(req)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def index(self, req): # pylint: disable=function-redefined
return self._index(req)
@wsgi.Controller.authorize('show')
def _show(self, req, id):
"""Return a single share group type item.""" """Return a single share group type item."""
context = req.environ['manila.context'] context = req.environ['manila.context']
try: try:
@ -62,9 +70,16 @@ class ShareGroupTypesController(wsgi.Controller):
share_group_type['id'] = six.text_type(share_group_type['id']) share_group_type['id'] = six.text_type(share_group_type['id'])
return self._view_builder.show(req, share_group_type) return self._view_builder.show(req, share_group_type)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.Controller.authorize def show(self, req, id):
def default(self, req): return self._show(req, id)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def show(self, req, id): # pylint: disable=function-redefined
return self._show(req, id)
@wsgi.Controller.authorize('default')
def _default(self, req):
"""Return default share group type.""" """Return default share group type."""
context = req.environ['manila.context'] context = req.environ['manila.context']
share_group_type = share_group_types.get_default(context) share_group_type = share_group_types.get_default(context)
@ -75,6 +90,14 @@ class ShareGroupTypesController(wsgi.Controller):
share_group_type['id'] = six.text_type(share_group_type['id']) share_group_type['id'] = six.text_type(share_group_type['id'])
return self._view_builder.show(req, share_group_type) return self._view_builder.show(req, share_group_type)
@wsgi.Controller.api_version('2.31', '2.54', experimental=True)
def default(self, req):
return self._default(req)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def default(self, req): # pylint: disable=function-redefined
return self._default(req)
def _get_share_group_types(self, req): def _get_share_group_types(self, req):
"""Helper function that returns a list of share group type dicts.""" """Helper function that returns a list of share group type dicts."""
filters = {} filters = {}
@ -110,8 +133,6 @@ class ShareGroupTypesController(wsgi.Controller):
msg = _('Invalid is_public filter [%s]') % is_public msg = _('Invalid is_public filter [%s]') % is_public
raise exc.HTTPBadRequest(explanation=msg) raise exc.HTTPBadRequest(explanation=msg)
@wsgi.Controller.api_version('2.31', experimental=True)
@wsgi.action("create")
@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."""
@ -153,8 +174,16 @@ class ShareGroupTypesController(wsgi.Controller):
raise webob.exc.HTTPNotFound() raise webob.exc.HTTPNotFound()
return self._view_builder.show(req, share_group_type) return self._view_builder.show(req, share_group_type)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.action("delete") @wsgi.action("create")
def create(self, req, body):
return self._create(req, body)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.action("create")
def create(self, req, body): # pylint: disable=function-redefined
return self._create(req, body)
@wsgi.Controller.authorize('delete') @wsgi.Controller.authorize('delete')
def _delete(self, req, id): def _delete(self, req, id):
"""Deletes an existing group type.""" """Deletes an existing group type."""
@ -169,9 +198,18 @@ class ShareGroupTypesController(wsgi.Controller):
raise webob.exc.HTTPNotFound() raise webob.exc.HTTPNotFound()
return webob.Response(status_int=http_client.NO_CONTENT) return webob.Response(status_int=http_client.NO_CONTENT)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.action("delete")
def delete(self, req, id):
return self._delete(req, id)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.action("delete")
def delete(self, req, id): # pylint: disable=function-redefined
return self._delete(req, id)
@wsgi.Controller.authorize('list_project_access') @wsgi.Controller.authorize('list_project_access')
def share_group_type_access(self, req, id): def _share_group_type_access(self, req, id):
context = req.environ['manila.context'] context = req.environ['manila.context']
try: try:
share_group_type = share_group_types.get( share_group_type = share_group_types.get(
@ -192,8 +230,15 @@ class ShareGroupTypesController(wsgi.Controller):
) )
return {'share_group_type_access': projects} return {'share_group_type_access': projects}
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.action('addProjectAccess') def share_group_type_access(self, req, id):
return self._share_group_type_access(req, id)
# pylint: disable=function-redefined
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def share_group_type_access(self, req, id):
return self._share_group_type_access(req, id)
@wsgi.Controller.authorize('add_project_access') @wsgi.Controller.authorize('add_project_access')
def _add_project_access(self, req, id, body): def _add_project_access(self, req, id, body):
context = req.environ['manila.context'] context = req.environ['manila.context']
@ -207,8 +252,18 @@ class ShareGroupTypesController(wsgi.Controller):
raise webob.exc.HTTPConflict(explanation=six.text_type(err)) raise webob.exc.HTTPConflict(explanation=six.text_type(err))
return webob.Response(status_int=http_client.ACCEPTED) return webob.Response(status_int=http_client.ACCEPTED)
@wsgi.Controller.api_version('2.31', experimental=True) # pylint: enable=function-redefined
@wsgi.action('removeProjectAccess') @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.action('addProjectAccess')
def add_project_access(self, req, id, body):
return self._add_project_access(req, id, body)
# pylint: disable=function-redefined
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.action('addProjectAccess')
def add_project_access(self, req, id, body):
return self._add_project_access(req, id, body)
@wsgi.Controller.authorize('remove_project_access') @wsgi.Controller.authorize('remove_project_access')
def _remove_project_access(self, req, id, body): def _remove_project_access(self, req, id, body):
context = req.environ['manila.context'] context = req.environ['manila.context']
@ -222,6 +277,18 @@ class ShareGroupTypesController(wsgi.Controller):
raise webob.exc.HTTPNotFound(explanation=six.text_type(err)) raise webob.exc.HTTPNotFound(explanation=six.text_type(err))
return webob.Response(status_int=http_client.ACCEPTED) return webob.Response(status_int=http_client.ACCEPTED)
# pylint: enable=function-redefined
@wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.action('removeProjectAccess')
def remove_project_access(self, req, id, body):
return self._remove_project_access(req, id, body)
# pylint: disable=function-redefined
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.action('removeProjectAccess')
def remove_project_access(self, req, id, body):
return self._remove_project_access(req, id, body)
def _assert_non_public_share_group_type(self, context, type_id): def _assert_non_public_share_group_type(self, context, type_id):
try: try:
share_group_type = share_group_types.get( share_group_type = share_group_types.get(

View File

@ -33,6 +33,7 @@ from manila.share_group import share_group_types
LOG = log.getLogger(__name__) LOG = log.getLogger(__name__)
SG_GRADUATION_VERSION = '2.55'
class ShareGroupController(wsgi.Controller, wsgi.AdminActionsMixin): class ShareGroupController(wsgi.Controller, wsgi.AdminActionsMixin):
@ -52,17 +53,23 @@ class ShareGroupController(wsgi.Controller, wsgi.AdminActionsMixin):
msg = _("Share group %s not found.") % share_group_id msg = _("Share group %s not found.") % share_group_id
raise exc.HTTPNotFound(explanation=msg) raise exc.HTTPNotFound(explanation=msg)
@wsgi.Controller.api_version('2.31', experimental=True)
@wsgi.Controller.authorize('get') @wsgi.Controller.authorize('get')
def show(self, req, id): def _show(self, req, id):
"""Return data about the given share group.""" """Return data about the given share group."""
context = req.environ['manila.context'] context = req.environ['manila.context']
share_group = self._get_share_group(context, id) share_group = self._get_share_group(context, id)
return self._view_builder.detail(req, share_group) return self._view_builder.detail(req, share_group)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.Controller.authorize def show(self, req, id):
def delete(self, req, id): return self._show(req, id)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def show(self, req, id): # pylint: disable=function-redefined
return self._show(req, id)
@wsgi.Controller.authorize('delete')
def _delete_share_group(self, req, id):
"""Delete a share group.""" """Delete a share group."""
context = req.environ['manila.context'] context = req.environ['manila.context']
@ -74,20 +81,33 @@ class ShareGroupController(wsgi.Controller, wsgi.AdminActionsMixin):
raise exc.HTTPConflict(explanation=six.text_type(e)) raise exc.HTTPConflict(explanation=six.text_type(e))
return webob.Response(status_int=http_client.ACCEPTED) return webob.Response(status_int=http_client.ACCEPTED)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.Controller.authorize('get_all') def delete(self, req, id):
return self._delete_share_group(req, id)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def delete(self, req, id): # pylint: disable=function-redefined
return self._delete_share_group(req, id)
@wsgi.Controller.api_version('2.31', '2.54', experimental=True)
def index(self, req): def index(self, req):
"""Returns a summary list of share groups."""
return self._get_share_groups(req, is_detail=False) return self._get_share_groups(req, is_detail=False)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.Controller.authorize('get_all') def index(self, req): # pylint: disable=function-redefined
return self._get_share_groups(req, is_detail=False)
@wsgi.Controller.api_version('2.31', '2.54', experimental=True)
def detail(self, req): def detail(self, req):
"""Returns a detailed list of share groups."""
return self._get_share_groups(req, is_detail=True) return self._get_share_groups(req, is_detail=True)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def detail(self, req): # pylint: disable=function-redefined
return self._get_share_groups(req, is_detail=True)
@wsgi.Controller.authorize('get_all')
def _get_share_groups(self, req, is_detail): def _get_share_groups(self, req, is_detail):
"""Returns a list of share groups, transformed through view builder.""" """Returns a summary or detail list of share groups."""
context = req.environ['manila.context'] context = req.environ['manila.context']
search_opts = {} search_opts = {}
@ -118,9 +138,8 @@ class ShareGroupController(wsgi.Controller, wsgi.AdminActionsMixin):
share_groups = self._view_builder.summary_list(req, limited_list) share_groups = self._view_builder.summary_list(req, limited_list)
return share_groups return share_groups
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.authorize('update')
@wsgi.Controller.authorize def _update_share_group(self, req, id, body):
def update(self, req, id, body):
"""Update a share group.""" """Update a share group."""
context = req.environ['manila.context'] context = req.environ['manila.context']
@ -140,10 +159,16 @@ class ShareGroupController(wsgi.Controller, wsgi.AdminActionsMixin):
context, share_group, share_group_data) context, share_group, share_group_data)
return self._view_builder.detail(req, share_group) return self._view_builder.detail(req, share_group)
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.response(202) def update(self, req, id, body):
@wsgi.Controller.authorize return self._update_share_group(req, id, body)
def create(self, req, body):
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
def update(self, req, id, body): # pylint: disable=function-redefined
return self._update_share_group(req, id, body)
@wsgi.Controller.authorize('create')
def _create(self, req, body):
"""Creates a new share group.""" """Creates a new share group."""
context = req.environ['manila.context'] context = req.environ['manila.context']
@ -260,6 +285,16 @@ class ShareGroupController(wsgi.Controller, wsgi.AdminActionsMixin):
return self._view_builder.detail( return self._view_builder.detail(
req, {k: v for k, v in new_share_group.items()}) req, {k: v for k, v in new_share_group.items()})
@wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.response(202)
def create(self, req, body):
return self._create(req, body)
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.response(202)
def create(self, req, body): # pylint: disable=function-redefined
return self._create(req, body)
def _update(self, *args, **kwargs): def _update(self, *args, **kwargs):
db.share_group_update(*args, **kwargs) db.share_group_update(*args, **kwargs)
@ -277,12 +312,25 @@ class ShareGroupController(wsgi.Controller, wsgi.AdminActionsMixin):
db.share_group_destroy(context.elevated(), resource['id']) db.share_group_destroy(context.elevated(), resource['id'])
@wsgi.Controller.api_version('2.31', experimental=True) @wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.action('reset_status') @wsgi.action('reset_status')
def share_group_reset_status(self, req, id, body): def share_group_reset_status(self, req, id, body):
return self._reset_status(req, id, body) return self._reset_status(req, id, body)
@wsgi.Controller.api_version('2.31', experimental=True) # pylint: disable=function-redefined
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.action('reset_status')
def share_group_reset_status(self, req, id, body):
return self._reset_status(req, id, body)
# pylint: enable=function-redefined
@wsgi.Controller.api_version('2.31', '2.54', experimental=True)
@wsgi.action('force_delete')
def share_group_force_delete(self, req, id, body):
return self._force_delete(req, id, body)
# pylint: disable=function-redefined
@wsgi.Controller.api_version(SG_GRADUATION_VERSION) # noqa
@wsgi.action('force_delete') @wsgi.action('force_delete')
def share_group_force_delete(self, req, id, body): def share_group_force_delete(self, req, id, body):
return self._force_delete(req, id, body) return self._force_delete(req, id, body)

View File

@ -36,6 +36,7 @@ from manila.tests.api import fakes
from manila.tests import db_utils from manila.tests import db_utils
CONF = cfg.CONF CONF = cfg.CONF
SG_GRADUATION_VERSION = '2.55'
@ddt.ddt @ddt.ddt
@ -106,6 +107,13 @@ class ShareGroupSnapshotAPITest(test.TestCase):
del expected_member['share_proto'] del expected_member['share_proto']
return member, expected_member return member, expected_member
def _get_fake_custom_request_and_context(self, microversion, experimental):
req = fakes.HTTPRequest.blank(
'/share-group-snapshots', version=microversion,
experimental=experimental)
req_context = req.environ['manila.context']
return req, req_context
def test_create_invalid_body(self): def test_create_invalid_body(self):
body = {"not_group_snapshot": {}} body = {"not_group_snapshot": {}}
@ -126,20 +134,25 @@ class ShareGroupSnapshotAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'create') self.context, self.resource_name, 'create')
def test_create(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_create(self, microversion, experimental):
fake_snap, expected_snap = self._get_fake_share_group_snapshot() fake_snap, expected_snap = self._get_fake_share_group_snapshot()
fake_id = six.text_type(uuidutils.generate_uuid()) fake_id = six.text_type(uuidutils.generate_uuid())
body = {"share_group_snapshot": {"share_group_id": fake_id}} body = {"share_group_snapshot": {"share_group_id": fake_id}}
mock_create = self.mock_object( mock_create = self.mock_object(
self.controller.share_group_api, 'create_share_group_snapshot', self.controller.share_group_api, 'create_share_group_snapshot',
mock.Mock(return_value=fake_snap)) mock.Mock(return_value=fake_snap))
req, req_context = self._get_fake_custom_request_and_context(
microversion, experimental)
res_dict = self.controller.create(self.request, body) res_dict = self.controller.create(req, body)
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'create') req_context, self.resource_name, 'create')
mock_create.assert_called_once_with( mock_create.assert_called_once_with(
self.context, share_group_id=fake_id) req_context, share_group_id=fake_id)
res_dict['share_group_snapshot'].pop('links') res_dict['share_group_snapshot'].pop('links')
self.assertEqual(expected_snap, res_dict['share_group_snapshot']) self.assertEqual(expected_snap, res_dict['share_group_snapshot'])
@ -265,7 +278,11 @@ class ShareGroupSnapshotAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'create') self.context, self.resource_name, 'create')
def test_update_with_name_and_description(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_update_with_name_and_description(self, microversion,
experimental):
fake_name = 'fake_name' fake_name = 'fake_name'
fake_description = 'fake_description' fake_description = 'fake_description'
fake_id = six.text_type(uuidutils.generate_uuid()) fake_id = six.text_type(uuidutils.generate_uuid())
@ -277,6 +294,8 @@ class ShareGroupSnapshotAPITest(test.TestCase):
mock_update = self.mock_object( mock_update = self.mock_object(
self.controller.share_group_api, 'update_share_group_snapshot', self.controller.share_group_api, 'update_share_group_snapshot',
mock.Mock(return_value=fake_snap)) mock.Mock(return_value=fake_snap))
req, req_context = self._get_fake_custom_request_and_context(
microversion, experimental)
body = { body = {
"share_group_snapshot": { "share_group_snapshot": {
@ -284,16 +303,16 @@ class ShareGroupSnapshotAPITest(test.TestCase):
"name": fake_name, "name": fake_name,
} }
} }
res_dict = self.controller.update(self.request, fake_id, body) res_dict = self.controller.update(req, fake_id, body)
res_dict['share_group_snapshot'].pop('links') res_dict['share_group_snapshot'].pop('links')
mock_update.assert_called_once_with( mock_update.assert_called_once_with(
self.context, fake_snap, req_context, fake_snap,
{"name": fake_name, "description": fake_description}) {"name": fake_name, "description": fake_description})
self.assertEqual(expected_snap, res_dict['share_group_snapshot']) self.assertEqual(expected_snap, res_dict['share_group_snapshot'])
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'update') req_context, self.resource_name, 'update')
def test_update_snapshot_not_found(self): def test_update_snapshot_not_found(self):
body = {"share_group_snapshot": {}} body = {"share_group_snapshot": {}}
@ -334,19 +353,24 @@ class ShareGroupSnapshotAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'update') self.context, self.resource_name, 'update')
def test_list_index(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_list_index(self, microversion, experimental):
fake_snap, expected_snap = self._get_fake_simple_share_group_snapshot() fake_snap, expected_snap = self._get_fake_simple_share_group_snapshot()
self.mock_object( self.mock_object(
self.controller.share_group_api, 'get_all_share_group_snapshots', self.controller.share_group_api, 'get_all_share_group_snapshots',
mock.Mock(return_value=[fake_snap])) mock.Mock(return_value=[fake_snap]))
req, req_context = self._get_fake_custom_request_and_context(
microversion, experimental)
res_dict = self.controller.index(self.request) res_dict = self.controller.index(req)
res_dict['share_group_snapshots'][0].pop('links') res_dict['share_group_snapshots'][0].pop('links')
self.assertEqual([expected_snap], res_dict['share_group_snapshots']) self.assertEqual([expected_snap], res_dict['share_group_snapshots'])
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'get_all') req_context, self.resource_name, 'get_all')
def test_list_index_no_share_groups(self): def test_list_index_no_share_groups(self):
self.mock_object( self.mock_object(
@ -402,20 +426,25 @@ class ShareGroupSnapshotAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
req_context, self.resource_name, 'get_all') req_context, self.resource_name, 'get_all')
def test_list_detail(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_list_detail(self, microversion, experimental):
fake_snap, expected_snap = self._get_fake_share_group_snapshot() fake_snap, expected_snap = self._get_fake_share_group_snapshot()
self.mock_object( self.mock_object(
self.controller.share_group_api, 'get_all_share_group_snapshots', self.controller.share_group_api, 'get_all_share_group_snapshots',
mock.Mock(return_value=[fake_snap])) mock.Mock(return_value=[fake_snap]))
req, context = self._get_fake_custom_request_and_context(
microversion, experimental)
res_dict = self.controller.detail(self.request) res_dict = self.controller.detail(req)
res_dict['share_group_snapshots'][0].pop('links') res_dict['share_group_snapshots'][0].pop('links')
self.assertEqual(1, len(res_dict['share_group_snapshots'])) self.assertEqual(1, len(res_dict['share_group_snapshots']))
self.assertEqual(expected_snap, res_dict['share_group_snapshots'][0]) self.assertEqual(expected_snap, res_dict['share_group_snapshots'][0])
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'get_all') context, self.resource_name, 'get_all')
def test_list_detail_no_share_groups(self): def test_list_detail_no_share_groups(self):
self.mock_object( self.mock_object(
@ -456,8 +485,7 @@ class ShareGroupSnapshotAPITest(test.TestCase):
mock.Mock(return_value=[fake_snap, fake_snap2])) mock.Mock(return_value=[fake_snap, fake_snap2]))
req = fakes.HTTPRequest.blank( req = fakes.HTTPRequest.blank(
'/share-group-snapshots?limit=1&offset=1', '/share-group-snapshots?limit=1&offset=1',
version=self.api_version, version=self.api_version, experimental=True)
experimental=True)
req_context = req.environ['manila.context'] req_context = req.environ['manila.context']
res_dict = self.controller.detail(req) res_dict = self.controller.detail(req)
@ -469,19 +497,24 @@ class ShareGroupSnapshotAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
req_context, self.resource_name, 'get_all') req_context, self.resource_name, 'get_all')
def test_delete(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_delete(self, microversion, experimental):
fake_snap, expected_snap = self._get_fake_share_group_snapshot() fake_snap, expected_snap = self._get_fake_share_group_snapshot()
self.mock_object( self.mock_object(
self.controller.share_group_api, 'get_share_group_snapshot', self.controller.share_group_api, 'get_share_group_snapshot',
mock.Mock(return_value=fake_snap)) mock.Mock(return_value=fake_snap))
self.mock_object( self.mock_object(
self.controller.share_group_api, 'delete_share_group_snapshot') self.controller.share_group_api, 'delete_share_group_snapshot')
req, req_context = self._get_fake_custom_request_and_context(
microversion, experimental)
res = self.controller.delete(self.request, fake_snap['id']) res = self.controller.delete(req, fake_snap['id'])
self.assertEqual(202, res.status_code) self.assertEqual(202, res.status_code)
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'delete') req_context, self.resource_name, 'delete')
def test_delete_not_found(self): def test_delete_not_found(self):
fake_snap, expected_snap = self._get_fake_share_group_snapshot() fake_snap, expected_snap = self._get_fake_share_group_snapshot()
@ -513,19 +546,24 @@ class ShareGroupSnapshotAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'delete') self.context, self.resource_name, 'delete')
def test_show(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_show(self, microversion, experimental):
fake_snap, expected_snap = self._get_fake_share_group_snapshot() fake_snap, expected_snap = self._get_fake_share_group_snapshot()
self.mock_object( self.mock_object(
self.controller.share_group_api, 'get_share_group_snapshot', self.controller.share_group_api, 'get_share_group_snapshot',
mock.Mock(return_value=fake_snap)) mock.Mock(return_value=fake_snap))
req, req_context = self._get_fake_custom_request_and_context(
microversion, experimental)
res_dict = self.controller.show(self.request, fake_snap['id']) res_dict = self.controller.show(req, fake_snap['id'])
res_dict['share_group_snapshot'].pop('links') res_dict['share_group_snapshot'].pop('links')
self.assertEqual(expected_snap, res_dict['share_group_snapshot']) self.assertEqual(expected_snap, res_dict['share_group_snapshot'])
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'get') req_context, self.resource_name, 'get')
def test_show_share_group_not_found(self): def test_show_share_group_not_found(self):
fake_snap, expected_snap = self._get_fake_share_group_snapshot() fake_snap, expected_snap = self._get_fake_share_group_snapshot()
@ -553,7 +591,6 @@ class ShareGroupSnapshotAPITest(test.TestCase):
share_group_snapshot['id']) share_group_snapshot['id'])
req = fakes.HTTPRequest.blank(path, script_name=path, version=version) req = fakes.HTTPRequest.blank(path, script_name=path, version=version)
req.headers[wsgi.API_VERSION_REQUEST_HEADER] = version req.headers[wsgi.API_VERSION_REQUEST_HEADER] = version
req.headers[wsgi.EXPERIMENTAL_API_REQUEST_HEADER] = 'True'
return share_group_snapshot, req return share_group_snapshot, req
@ddt.data(*fakes.fixture_force_delete_with_different_roles) @ddt.data(*fakes.fixture_force_delete_with_different_roles)
@ -568,6 +605,7 @@ class ShareGroupSnapshotAPITest(test.TestCase):
body = {action_name: {'status': constants.STATUS_ERROR}} body = {action_name: {'status': constants.STATUS_ERROR}}
req.body = six.b(jsonutils.dumps(body)) req.body = six.b(jsonutils.dumps(body))
req.headers['X-Openstack-Manila-Api-Version'] = self.api_version req.headers['X-Openstack-Manila-Api-Version'] = self.api_version
req.headers['X-Openstack-Manila-Api-Experimental'] = True
req.environ['manila.context'] = ctxt req.environ['manila.context'] = ctxt
with mock.patch.object( with mock.patch.object(
@ -577,6 +615,19 @@ class ShareGroupSnapshotAPITest(test.TestCase):
# Validate response # Validate response
self.assertEqual(resp_code, resp.status_int) self.assertEqual(resp_code, resp.status_int)
@ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test__force_delete_call(self, microversion, experimental):
self.mock_object(self.controller, '_force_delete')
req, _junk = self._get_fake_custom_request_and_context(
microversion, experimental)
sg_id = 'fake'
body = {'force_delete': {}}
self.controller.share_group_snapshot_force_delete(req, sg_id, body)
self.controller._force_delete.assert_called_once_with(req, sg_id, body)
@ddt.data(*fakes.fixture_reset_status_with_different_roles) @ddt.data(*fakes.fixture_reset_status_with_different_roles)
@ddt.unpack @ddt.unpack
def test_share_group_snapshot_reset_status_with_different_roles( def test_share_group_snapshot_reset_status_with_different_roles(
@ -589,6 +640,7 @@ class ShareGroupSnapshotAPITest(test.TestCase):
req.headers['content-type'] = 'application/json' req.headers['content-type'] = 'application/json'
req.body = six.b(jsonutils.dumps(body)) req.body = six.b(jsonutils.dumps(body))
req.headers['X-Openstack-Manila-Api-Version'] = self.api_version req.headers['X-Openstack-Manila-Api-Version'] = self.api_version
req.headers['X-Openstack-Manila-Api-Experimental'] = True
req.environ['manila.context'] = ctxt req.environ['manila.context'] = ctxt
with mock.patch.object( with mock.patch.object(
@ -600,3 +652,16 @@ class ShareGroupSnapshotAPITest(test.TestCase):
actual_model = db.share_group_snapshot_get(ctxt, group_snap['id']) actual_model = db.share_group_snapshot_get(ctxt, group_snap['id'])
self.assertEqual(valid_status, actual_model['status']) self.assertEqual(valid_status, actual_model['status'])
@ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test__reset_status_call(self, microversion, experimental):
self.mock_object(self.controller, '_reset_status')
req, _junk = self._get_fake_custom_request_and_context(
microversion, experimental)
sg_id = 'fake'
body = {'reset_status': {'status': constants.STATUS_ERROR}}
self.controller.share_group_snapshot_reset_status(req, sg_id, body)
self.controller._reset_status.assert_called_once_with(req, sg_id, body)

View File

@ -62,11 +62,14 @@ def get_group_specs_dict(group_specs, include_required=True):
return {'group_specs': group_specs} return {'group_specs': group_specs}
def fake_request(url, admin=False, experimental=True, version='2.31', def fake_request(url, admin=False, version='2.31', experimental=True,
**kwargs): **kwargs):
return fakes.HTTPRequest.blank( return fakes.HTTPRequest.blank(
url, use_admin_context=admin, experimental=experimental, url, use_admin_context=admin, version=version,
version=version, **kwargs) experimental=experimental, **kwargs)
SG_GRADUATION_VERSION = '2.55'
@ddt.ddt @ddt.ddt
@ -82,11 +85,15 @@ class ShareGroupTypesSpecsTest(test.TestCase):
self.resource_name = self.controller.resource_name self.resource_name = self.controller.resource_name
self.mock_policy_check = self.mock_object(policy, 'check_policy') self.mock_policy_check = self.mock_object(policy, 'check_policy')
def test_index(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_index(self, microversion, experimental):
self.mock_object( self.mock_object(
manila.db, 'share_group_type_specs_get', manila.db, 'share_group_type_specs_get',
return_share_group_type_specs) return_share_group_type_specs)
req = fake_request(self.api_path) req = fake_request(self.api_path, version=microversion,
experimental=experimental)
req_context = req.environ['manila.context'] req_context = req.environ['manila.context']
res_dict = self.controller.index(req, 1) res_dict = self.controller.index(req, 1)
@ -107,10 +114,14 @@ class ShareGroupTypesSpecsTest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
req_context, self.resource_name, 'index') req_context, self.resource_name, 'index')
def test_show(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_show(self, microversion, experimental):
self.mock_object(manila.db, 'share_group_type_specs_get', self.mock_object(manila.db, 'share_group_type_specs_get',
return_share_group_type_specs) return_share_group_type_specs)
req = fake_request(self.api_path + '/key5') req = fake_request(self.api_path + '/key5', version=microversion,
experimental=experimental)
req_context = req.environ['manila.context'] req_context = req.environ['manila.context']
res_dict = self.controller.show(req, 1, 'key5') res_dict = self.controller.show(req, 1, 'key5')
@ -131,10 +142,14 @@ class ShareGroupTypesSpecsTest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
req_context, self.resource_name, 'show') req_context, self.resource_name, 'show')
def test_delete(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_delete(self, microversion, experimental):
self.mock_object(manila.db, 'share_group_type_specs_delete', self.mock_object(manila.db, 'share_group_type_specs_delete',
delete_share_group_type_specs) delete_share_group_type_specs)
req = fake_request(self.api_path + '/key5') req = fake_request(self.api_path + '/key5', version=microversion,
experimental=experimental)
req_context = req.environ['manila.context'] req_context = req.environ['manila.context']
self.controller.delete(req, 1, 'key5') self.controller.delete(req, 1, 'key5')
@ -162,12 +177,26 @@ class ShareGroupTypesSpecsTest(test.TestCase):
*[{CONSISTENT_SNAPSHOTS: v} *[{CONSISTENT_SNAPSHOTS: v}
for v in strutils.TRUE_STRINGS + strutils.FALSE_STRINGS] for v in strutils.TRUE_STRINGS + strutils.FALSE_STRINGS]
) )
def test_create(self, data): def test_create_experimental(self, data):
self._validate_create(data)
@ddt.data(
get_group_specs_dict({}),
{'foo': 'bar'},
{CONSISTENT_SNAPSHOTS + 'foo': True},
{'foo' + CONSISTENT_SNAPSHOTS: False}
)
def test_create_non_experimental(self, data):
self._validate_create(data, microversion=SG_GRADUATION_VERSION,
experimental=False)
def _validate_create(self, data, microversion='2.31', experimental=True):
body = {'group_specs': data} body = {'group_specs': data}
mock_spec_update_or_create = self.mock_object( mock_spec_update_or_create = self.mock_object(
manila.db, 'share_group_type_specs_update_or_create', manila.db, 'share_group_type_specs_update_or_create',
mock.Mock(return_value=return_create_share_group_type_specs)) mock.Mock(return_value=return_create_share_group_type_specs))
req = fake_request(self.api_path) req = fake_request(self.api_path, version=microversion,
experimental=experimental)
req_context = req.environ['manila.context'] req_context = req.environ['manila.context']
res_dict = self.controller.create(req, 1, body) res_dict = self.controller.create(req, 1, body)
@ -292,6 +321,21 @@ class ShareGroupTypesSpecsTest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
req_context, self.resource_name, 'create') req_context, self.resource_name, 'create')
@ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test__update_call(self, microversion, experimental):
req = fake_request(self.api_path + '/key1', version=microversion,
experimental=experimental)
sg_id = 'fake_id'
key = 'fake_key'
body = {"group_specs": {"key1": "fake_value"}}
self.mock_object(self.controller, '_update')
self.controller.update(req, sg_id, key, body)
self.controller._update.assert_called_once_with(req, sg_id, key, body)
def test_update_item_too_many_keys(self): def test_update_item_too_many_keys(self):
self.mock_object(manila.db, 'share_group_type_specs_update_or_create') self.mock_object(manila.db, 'share_group_type_specs_update_or_create')
body = {"key1": "value1", "key2": "value2"} body = {"key1": "value1", "key2": "value2"}

View File

@ -68,8 +68,10 @@ GROUP_TYPE_3 = {
'share_types': [], 'share_types': [],
} }
SG_GRADUATION_VERSION = '2.55'
def fake_request(url, admin=False, experimental=True, version='2.31',
def fake_request(url, admin=False, version='2.31', experimental=True,
**kwargs): **kwargs):
return fakes.HTTPRequest.blank( return fakes.HTTPRequest.blank(
@ -91,11 +93,15 @@ class ShareGroupTypesAPITest(test.TestCase):
self.resource_name = self.controller.resource_name self.resource_name = self.controller.resource_name
self.mock_object(policy, 'check_policy', mock.Mock(return_value=True)) self.mock_object(policy, 'check_policy', mock.Mock(return_value=True))
def test_share_group_types_index(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_share_group_types_index(self, microversion, experimental):
fake_types = {GROUP_TYPE_1['name']: GROUP_TYPE_1} fake_types = {GROUP_TYPE_1['name']: GROUP_TYPE_1}
mock_get_all = self.mock_object( mock_get_all = self.mock_object(
share_group_types, 'get_all', mock.Mock(return_value=fake_types)) share_group_types, 'get_all', mock.Mock(return_value=fake_types))
req = fake_request('/v2/fake/share-group-types', admin=False) req = fake_request('/v2/fake/share-group-types', admin=False,
version=microversion, experimental=experimental)
expected_list = [{ expected_list = [{
'id': GROUP_TYPE_1['id'], 'id': GROUP_TYPE_1['id'],
'name': GROUP_TYPE_1['name'], 'name': GROUP_TYPE_1['name'],
@ -103,6 +109,8 @@ class ShareGroupTypesAPITest(test.TestCase):
'group_specs': {}, 'group_specs': {},
'share_types': [], 'share_types': [],
}] }]
if self.is_microversion_ge(microversion, '2.46'):
expected_list[0]['is_default'] = False
res_dict = self.controller.index(req) res_dict = self.controller.index(req)
@ -159,7 +167,8 @@ class ShareGroupTypesAPITest(test.TestCase):
def test_share_group_types_index_not_experimental(self): def test_share_group_types_index_not_experimental(self):
self.mock_object( self.mock_object(
share_group_types, 'get_all', mock.Mock(return_value={})) share_group_types, 'get_all', mock.Mock(return_value={}))
req = fake_request('/v2/fake/share-group-types', experimental=False) req = fake_request('/v2/fake/share-group-types', experimental=False,
version='2.54')
self.assertRaises( self.assertRaises(
exception.VersionNotFoundForAPIMethod, self.controller.index, req) exception.VersionNotFoundForAPIMethod, self.controller.index, req)
@ -183,12 +192,16 @@ class ShareGroupTypesAPITest(test.TestCase):
self.assertEqual(0, len(res_dict['share_group_types'])) self.assertEqual(0, len(res_dict['share_group_types']))
def test_share_group_types_show(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_share_group_types_show(self, microversion, experimental):
mock_get = self.mock_object( mock_get = self.mock_object(
share_group_types, 'get', share_group_types, 'get',
mock.Mock(return_value=GROUP_TYPE_1)) mock.Mock(return_value=GROUP_TYPE_1))
req = fake_request( req = fake_request(
'/v2/fake/share-group-types/%s' % GROUP_TYPE_1['id']) '/v2/fake/share-group-types/%s' % GROUP_TYPE_1['id'],
version=microversion, experimental=experimental)
expected_type = { expected_type = {
'id': GROUP_TYPE_1['id'], 'id': GROUP_TYPE_1['id'],
'name': GROUP_TYPE_1['name'], 'name': GROUP_TYPE_1['name'],
@ -196,6 +209,8 @@ class ShareGroupTypesAPITest(test.TestCase):
'group_specs': {}, 'group_specs': {},
'share_types': [], 'share_types': [],
} }
if self.is_microversion_ge(microversion, '2.46'):
expected_type['is_default'] = False
res_dict = self.controller.show(req, GROUP_TYPE_1['id']) res_dict = self.controller.show(req, GROUP_TYPE_1['id'])
@ -233,11 +248,15 @@ class ShareGroupTypesAPITest(test.TestCase):
mock_get.assert_called_once_with(mock.ANY, GROUP_TYPE_2['id']) mock_get.assert_called_once_with(mock.ANY, GROUP_TYPE_2['id'])
def test_share_group_types_default(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_share_group_types_default(self, microversion, experimental):
mock_get = self.mock_object( mock_get = self.mock_object(
share_group_types, 'get_default', share_group_types, 'get_default',
mock.Mock(return_value=GROUP_TYPE_2)) mock.Mock(return_value=GROUP_TYPE_2))
req = fake_request('/v2/fake/share-group-types/default') req = fake_request('/v2/fake/share-group-types/default',
version=microversion, experimental=experimental)
expected_type = { expected_type = {
'id': GROUP_TYPE_2['id'], 'id': GROUP_TYPE_2['id'],
'name': GROUP_TYPE_2['name'], 'name': GROUP_TYPE_2['name'],
@ -245,6 +264,8 @@ class ShareGroupTypesAPITest(test.TestCase):
'group_specs': {'consistent_snapshots': 'true'}, 'group_specs': {'consistent_snapshots': 'true'},
'share_types': [SHARE_TYPE_ID], 'share_types': [SHARE_TYPE_ID],
} }
if self.is_microversion_ge(microversion, '2.46'):
expected_type['is_default'] = False
res_dict = self.controller.default(req) res_dict = self.controller.default(req)
@ -260,14 +281,18 @@ class ShareGroupTypesAPITest(test.TestCase):
mock_get.assert_called_once_with(mock.ANY) mock_get.assert_called_once_with(mock.ANY)
def test_share_group_types_delete(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_share_group_types_delete(self, microversion, experimental):
mock_get = self.mock_object( mock_get = self.mock_object(
share_group_types, 'get', mock.Mock(return_value=GROUP_TYPE_1)) share_group_types, 'get', mock.Mock(return_value=GROUP_TYPE_1))
mock_destroy = self.mock_object(share_group_types, 'destroy') mock_destroy = self.mock_object(share_group_types, 'destroy')
req = fake_request( req = fake_request(
'/v2/fake/share-group-types/%s' % GROUP_TYPE_1['id']) '/v2/fake/share-group-types/%s' % GROUP_TYPE_1['id'],
version=microversion, experimental=experimental)
self.controller._delete(req, GROUP_TYPE_1['id']) self.controller.delete(req, GROUP_TYPE_1['id'])
mock_get.assert_called_once_with(mock.ANY, GROUP_TYPE_1['id']) mock_get.assert_called_once_with(mock.ANY, GROUP_TYPE_1['id'])
mock_destroy.assert_called_once_with(mock.ANY, GROUP_TYPE_1['id']) mock_destroy.assert_called_once_with(mock.ANY, GROUP_TYPE_1['id'])
@ -280,19 +305,23 @@ class ShareGroupTypesAPITest(test.TestCase):
req = fake_request( req = fake_request(
'/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id']) '/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id'])
self.assertRaises(webob.exc.HTTPNotFound, self.controller._delete, self.assertRaises(webob.exc.HTTPNotFound, self.controller.delete,
req, GROUP_TYPE_2['id']) req, GROUP_TYPE_2['id'])
mock_get.assert_called_once_with(mock.ANY, GROUP_TYPE_2['id']) mock_get.assert_called_once_with(mock.ANY, GROUP_TYPE_2['id'])
def test_create_minimal(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_create_minimal(self, microversion, experimental):
fake_type = copy.deepcopy(GROUP_TYPE_1) fake_type = copy.deepcopy(GROUP_TYPE_1)
fake_type['share_types'] = [{'share_type_id': SHARE_TYPE_ID}] fake_type['share_types'] = [{'share_type_id': SHARE_TYPE_ID}]
mock_create = self.mock_object(share_group_types, 'create') mock_create = self.mock_object(share_group_types, 'create')
mock_get = self.mock_object( mock_get = self.mock_object(
share_group_types, 'get_by_name', share_group_types, 'get_by_name',
mock.Mock(return_value=fake_type)) mock.Mock(return_value=fake_type))
req = fake_request('/v2/fake/share-group-types') req = fake_request('/v2/fake/share-group-types', version=microversion,
experimental=experimental)
fake_body = {'share_group_type': { fake_body = {'share_group_type': {
'name': GROUP_TYPE_1['name'], 'name': GROUP_TYPE_1['name'],
'share_types': [SHARE_TYPE_ID], 'share_types': [SHARE_TYPE_ID],
@ -304,8 +333,10 @@ class ShareGroupTypesAPITest(test.TestCase):
'group_specs': {}, 'group_specs': {},
'share_types': [SHARE_TYPE_ID], 'share_types': [SHARE_TYPE_ID],
} }
if self.is_microversion_ge(microversion, '2.46'):
expected_type['is_default'] = False
res_dict = self.controller._create(req, fake_body) res_dict = self.controller.create(req, fake_body)
mock_create.assert_called_once_with( mock_create.assert_called_once_with(
mock.ANY, GROUP_TYPE_1['name'], mock.ANY, GROUP_TYPE_1['name'],
@ -338,7 +369,7 @@ class ShareGroupTypesAPITest(test.TestCase):
'share_types': [SHARE_TYPE_ID], 'share_types': [SHARE_TYPE_ID],
} }
res_dict = self.controller._create(req, fake_body) res_dict = self.controller.create(req, fake_body)
mock_create.assert_called_once_with( mock_create.assert_called_once_with(
mock.ANY, GROUP_TYPE_1['name'], [SHARE_TYPE_ID], specs, mock.ANY, GROUP_TYPE_1['name'], [SHARE_TYPE_ID], specs,
@ -366,7 +397,7 @@ class ShareGroupTypesAPITest(test.TestCase):
}} }}
self.assertRaises( self.assertRaises(
webob.exc.HTTPBadRequest, self.controller._create, req, fake_body) webob.exc.HTTPBadRequest, self.controller.create, req, fake_body)
self.assertEqual(0, mock_create.call_count) self.assertEqual(0, mock_create.call_count)
self.assertEqual(0, mock_get.call_count) self.assertEqual(0, mock_get.call_count)
@ -393,7 +424,7 @@ class ShareGroupTypesAPITest(test.TestCase):
'share_types': [SHARE_TYPE_ID], 'share_types': [SHARE_TYPE_ID],
} }
res_dict = self.controller._create(req, fake_body) res_dict = self.controller.create(req, fake_body)
mock_create.assert_called_once_with( mock_create.assert_called_once_with(
mock.ANY, GROUP_TYPE_1['name'], [SHARE_TYPE_ID], {}, False) mock.ANY, GROUP_TYPE_1['name'], [SHARE_TYPE_ID], {}, False)
@ -412,7 +443,7 @@ class ShareGroupTypesAPITest(test.TestCase):
}} }}
self.assertRaises( self.assertRaises(
webob.exc.HTTPConflict, self.controller._create, req, fake_body) webob.exc.HTTPConflict, self.controller.create, req, fake_body)
mock_create.assert_called_once_with( mock_create.assert_called_once_with(
mock.ANY, GROUP_TYPE_1['name'], [SHARE_TYPE_ID], {}, True) mock.ANY, GROUP_TYPE_1['name'], [SHARE_TYPE_ID], {}, True)
@ -422,7 +453,7 @@ class ShareGroupTypesAPITest(test.TestCase):
fake_body = {'share_group_type': {'share_types': [SHARE_TYPE_ID]}} fake_body = {'share_group_type': {'share_types': [SHARE_TYPE_ID]}}
self.assertRaises( self.assertRaises(
webob.exc.HTTPBadRequest, self.controller._create, req, fake_body) webob.exc.HTTPBadRequest, self.controller.create, req, fake_body)
def test_create_invalid_request_missing_share_types(self): def test_create_invalid_request_missing_share_types(self):
req = fake_request('/v2/fake/share-group-types') req = fake_request('/v2/fake/share-group-types')
@ -430,7 +461,7 @@ class ShareGroupTypesAPITest(test.TestCase):
self.assertRaises( self.assertRaises(
webob.exc.HTTPBadRequest, webob.exc.HTTPBadRequest,
self.controller._create, req, fake_body) self.controller.create, req, fake_body)
def test_create_provided_share_type_does_not_exist(self): def test_create_provided_share_type_does_not_exist(self):
req = fake_request('/v2/fake/share-group-types', admin=True) req = fake_request('/v2/fake/share-group-types', admin=True)
@ -443,7 +474,7 @@ class ShareGroupTypesAPITest(test.TestCase):
self.assertRaises( self.assertRaises(
webob.exc.HTTPNotFound, webob.exc.HTTPNotFound,
self.controller._create, req, fake_body) self.controller.create, req, fake_body)
@ddt.data(('2.45', True), ('2.45', False), @ddt.data(('2.45', True), ('2.45', False),
('2.46', True), ('2.46', False)) ('2.46', True), ('2.46', False))
@ -465,7 +496,7 @@ class ShareGroupTypesAPITest(test.TestCase):
'name': GROUP_TYPE_1['name'], 'name': GROUP_TYPE_1['name'],
'share_types': [SHARE_TYPE_ID], 'share_types': [SHARE_TYPE_ID],
}} }}
res_dict = self.controller._create(req, fake_body) res_dict = self.controller.create(req, fake_body)
if self.is_microversion_ge(version, '2.46'): if self.is_microversion_ge(version, '2.46'):
self.assertIn('is_default', res_dict['share_group_type']) self.assertIn('is_default', res_dict['share_group_type'])
self.assertIs(False, res_dict['share_group_type']['is_default']) self.assertIs(False, res_dict['share_group_type']['is_default'])
@ -489,7 +520,7 @@ class ShareGroupTypesAPITest(test.TestCase):
'name': GROUP_TYPE_3['name'], 'name': GROUP_TYPE_3['name'],
'share_types': [SHARE_TYPE_ID], 'share_types': [SHARE_TYPE_ID],
}} }}
res_dict = self.controller._create(req, fake_body) res_dict = self.controller.create(req, fake_body)
if self.is_microversion_ge(version, '2.46'): if self.is_microversion_ge(version, '2.46'):
self.assertIn('is_default', res_dict['share_group_type']) self.assertIn('is_default', res_dict['share_group_type'])
self.assertIs(True, res_dict['share_group_type']['is_default']) self.assertIs(True, res_dict['share_group_type']['is_default'])
@ -538,6 +569,7 @@ class ShareGroupTypesAPITest(test.TestCase):
self.assertNotIn('is_default', res_dict['share_group_type']) self.assertNotIn('is_default', res_dict['share_group_type'])
@ddt.ddt
class ShareGroupTypeAccessTest(test.TestCase): class ShareGroupTypeAccessTest(test.TestCase):
def setUp(self): def setUp(self):
@ -584,16 +616,21 @@ class ShareGroupTypeAccessTest(test.TestCase):
webob.exc.HTTPNotFound, webob.exc.HTTPNotFound,
self.controller.share_group_type_access, req, GROUP_TYPE_2['id']) self.controller.share_group_type_access, req, GROUP_TYPE_2['id'])
def test_add_project_access(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_add_project_access(self, microversion, experimental):
self.mock_object(share_group_types, 'get', self.mock_object(share_group_types, 'get',
mock.Mock(return_value=GROUP_TYPE_2)) mock.Mock(return_value=GROUP_TYPE_2))
mock_add_access = self.mock_object( mock_add_access = self.mock_object(
share_group_types, 'add_share_group_type_access') share_group_types, 'add_share_group_type_access')
body = {'addProjectAccess': {'project': PROJ1_UUID}} body = {'addProjectAccess': {'project': PROJ1_UUID}}
req = fake_request( req = fake_request(
'/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id'], admin=True) '/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id'], admin=True,
experimental=experimental, version=microversion
)
response = self.controller._add_project_access( response = self.controller.add_project_access(
req, GROUP_TYPE_2['id'], body) req, GROUP_TYPE_2['id'], body)
mock_add_access.assert_called_once_with( mock_add_access.assert_called_once_with(
@ -611,7 +648,7 @@ class ShareGroupTypeAccessTest(test.TestCase):
self.assertRaises( self.assertRaises(
webob.exc.HTTPNotFound, webob.exc.HTTPNotFound,
self.controller._add_project_access, req, GROUP_TYPE_2['id'], body) self.controller.add_project_access, req, GROUP_TYPE_2['id'], body)
def test_add_project_access_missing_project_in_body(self): def test_add_project_access_missing_project_in_body(self):
body = {'addProjectAccess': {}} body = {'addProjectAccess': {}}
@ -620,7 +657,7 @@ class ShareGroupTypeAccessTest(test.TestCase):
self.assertRaises( self.assertRaises(
webob.exc.HTTPBadRequest, webob.exc.HTTPBadRequest,
self.controller._add_project_access, req, GROUP_TYPE_2['id'], body) self.controller.add_project_access, req, GROUP_TYPE_2['id'], body)
def test_add_project_access_missing_add_project_access_in_body(self): def test_add_project_access_missing_add_project_access_in_body(self):
body = {} body = {}
@ -629,7 +666,7 @@ class ShareGroupTypeAccessTest(test.TestCase):
self.assertRaises( self.assertRaises(
webob.exc.HTTPBadRequest, webob.exc.HTTPBadRequest,
self.controller._add_project_access, req, GROUP_TYPE_2['id'], body) self.controller.add_project_access, req, GROUP_TYPE_2['id'], body)
def test_add_project_access_with_already_added_access(self): def test_add_project_access_with_already_added_access(self):
self.mock_object( self.mock_object(
@ -645,7 +682,7 @@ class ShareGroupTypeAccessTest(test.TestCase):
self.assertRaises( self.assertRaises(
webob.exc.HTTPConflict, webob.exc.HTTPConflict,
self.controller._add_project_access, req, GROUP_TYPE_2['id'], body) self.controller.add_project_access, req, GROUP_TYPE_2['id'], body)
mock_add_access.assert_called_once_with( mock_add_access.assert_called_once_with(
mock.ANY, GROUP_TYPE_2['id'], PROJ1_UUID) mock.ANY, GROUP_TYPE_2['id'], PROJ1_UUID)
@ -659,18 +696,22 @@ class ShareGroupTypeAccessTest(test.TestCase):
self.assertRaises( self.assertRaises(
webob.exc.HTTPConflict, webob.exc.HTTPConflict,
self.controller._add_project_access, req, GROUP_TYPE_1['id'], body) self.controller.add_project_access, req, GROUP_TYPE_1['id'], body)
def test_remove_project_access(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_remove_project_access(self, microversion, experimental):
self.mock_object( self.mock_object(
share_group_types, 'get', mock.Mock(return_value=GROUP_TYPE_2)) share_group_types, 'get', mock.Mock(return_value=GROUP_TYPE_2))
mock_remove_access = self.mock_object( mock_remove_access = self.mock_object(
share_group_types, 'remove_share_group_type_access') share_group_types, 'remove_share_group_type_access')
body = {'removeProjectAccess': {'project': PROJ1_UUID}} body = {'removeProjectAccess': {'project': PROJ1_UUID}}
req = fake_request( req = fake_request(
'/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id'], admin=True) '/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id'], admin=True,
version=microversion, experimental=experimental)
response = self.controller._remove_project_access( response = self.controller.remove_project_access(
req, GROUP_TYPE_2['id'], body) req, GROUP_TYPE_2['id'], body)
mock_remove_access.assert_called_once_with( mock_remove_access.assert_called_once_with(
@ -690,7 +731,7 @@ class ShareGroupTypeAccessTest(test.TestCase):
self.assertRaises( self.assertRaises(
webob.exc.HTTPNotFound, webob.exc.HTTPNotFound,
self.controller._remove_project_access, self.controller.remove_project_access,
req, GROUP_TYPE_2['id'], body) req, GROUP_TYPE_2['id'], body)
mock_remove_access.assert_called_once_with( mock_remove_access.assert_called_once_with(
@ -704,7 +745,7 @@ class ShareGroupTypeAccessTest(test.TestCase):
'/v2/fake/share-group-types/%s' % GROUP_TYPE_1['id'], admin=True) '/v2/fake/share-group-types/%s' % GROUP_TYPE_1['id'], admin=True)
self.assertRaises(webob.exc.HTTPConflict, self.assertRaises(webob.exc.HTTPConflict,
self.controller._remove_project_access, req, self.controller.remove_project_access, req,
GROUP_TYPE_1['id'], body) GROUP_TYPE_1['id'], body)
def test_remove_project_access_non_existent_type(self): def test_remove_project_access_non_existent_type(self):
@ -717,7 +758,7 @@ class ShareGroupTypeAccessTest(test.TestCase):
'/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id'], admin=True) '/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id'], admin=True)
self.assertRaises(webob.exc.HTTPNotFound, self.assertRaises(webob.exc.HTTPNotFound,
self.controller._remove_project_access, req, self.controller.remove_project_access, req,
GROUP_TYPE_2['id'], body) GROUP_TYPE_2['id'], body)
def test_remove_project_access_missing_project_in_body(self): def test_remove_project_access_missing_project_in_body(self):
@ -726,7 +767,7 @@ class ShareGroupTypeAccessTest(test.TestCase):
'/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id'], admin=True) '/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id'], admin=True)
self.assertRaises(webob.exc.HTTPBadRequest, self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._remove_project_access, req, self.controller.remove_project_access, req,
GROUP_TYPE_2['id'], body) GROUP_TYPE_2['id'], body)
def test_remove_project_access_missing_remove_project_access_in_body(self): def test_remove_project_access_missing_remove_project_access_in_body(self):
@ -735,5 +776,5 @@ class ShareGroupTypeAccessTest(test.TestCase):
'/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id'], admin=True) '/v2/fake/share-group-types/%s' % GROUP_TYPE_2['id'], admin=True)
self.assertRaises(webob.exc.HTTPBadRequest, self.assertRaises(webob.exc.HTTPBadRequest,
self.controller._remove_project_access, req, self.controller.remove_project_access, req,
GROUP_TYPE_2['id'], body) GROUP_TYPE_2['id'], body)

View File

@ -40,6 +40,7 @@ from manila.tests import db_utils
CONF = cfg.CONF CONF = cfg.CONF
SG_GRADUATION_VERSION = '2.55'
@ddt.ddt @ddt.ddt
@ -137,22 +138,33 @@ class ShareGroupAPITest(test.TestCase):
expected_share_group['links'] = mock.ANY expected_share_group['links'] = mock.ANY
return share_group, expected_share_group return share_group, expected_share_group
def test_share_group_create(self): def _get_fake_custom_request_and_context(self, microversion, experimental):
req = fakes.HTTPRequest.blank(
'/share-groups', version=microversion, experimental=experimental)
req_context = req.environ['manila.context']
return req, req_context
@ddt.data({'microversion': '2.34', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_share_group_create(self, microversion, experimental):
fake, expected = self._get_fake_share_group() fake, expected = self._get_fake_share_group()
self.mock_object(share_types, 'get_default_share_type', self.mock_object(share_types, 'get_default_share_type',
mock.Mock(return_value=self.fake_share_type)) mock.Mock(return_value=self.fake_share_type))
self.mock_object(self.controller.share_group_api, 'create', self.mock_object(self.controller.share_group_api, 'create',
mock.Mock(return_value=fake)) mock.Mock(return_value=fake))
req, req_context = self._get_fake_custom_request_and_context(
microversion, experimental)
body = {"share_group": {}} body = {"share_group": {}}
res_dict = self.controller.create(self.request, body) res_dict = self.controller.create(req, body)
self.controller.share_group_api.create.assert_called_once_with( self.controller.share_group_api.create.assert_called_once_with(
self.context, share_group_type_id=self.fake_share_group_type['id'], req_context, share_group_type_id=self.fake_share_group_type['id'],
share_type_ids=[self.fake_share_type['id']]) share_type_ids=[self.fake_share_type['id']])
self.assertEqual(expected, res_dict['share_group']) self.assertEqual(expected, res_dict['share_group'])
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'create') req_context, self.resource_name, 'create')
def test_group_create_invalid_group_snapshot_state(self): def test_group_create_invalid_group_snapshot_state(self):
fake_snap_id = six.text_type(uuidutils.generate_uuid()) fake_snap_id = six.text_type(uuidutils.generate_uuid())
@ -622,7 +634,11 @@ class ShareGroupAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'create') self.context, self.resource_name, 'create')
def test_share_group_update_with_name_and_description(self): @ddt.data({'microversion': '2.34', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_share_group_update_with_name_and_description(
self, microversion, experimental):
fake_name = 'fake_name' fake_name = 'fake_name'
fake_description = 'fake_description' fake_description = 'fake_description'
fake_group, expected_group = self._get_fake_share_group( fake_group, expected_group = self._get_fake_share_group(
@ -631,22 +647,23 @@ class ShareGroupAPITest(test.TestCase):
mock.Mock(return_value=fake_group)) mock.Mock(return_value=fake_group))
self.mock_object(self.controller.share_group_api, 'update', self.mock_object(self.controller.share_group_api, 'update',
mock.Mock(return_value=fake_group)) mock.Mock(return_value=fake_group))
req, req_context = self._get_fake_custom_request_and_context(
microversion, experimental)
body = { body = {
"share_group": { "share_group": {
"name": fake_name, "name": fake_name,
"description": fake_description, "description": fake_description,
} }
} }
context = self.request.environ['manila.context']
res_dict = self.controller.update(self.request, fake_group['id'], body) res_dict = self.controller.update(req, fake_group['id'], body)
self.controller.share_group_api.update.assert_called_once_with( self.controller.share_group_api.update.assert_called_once_with(
context, fake_group, req_context, fake_group,
{"name": fake_name, "description": fake_description}) {"name": fake_name, "description": fake_description})
self.assertEqual(expected_group, res_dict['share_group']) self.assertEqual(expected_group, res_dict['share_group'])
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'update') req_context, self.resource_name, 'update')
def test_share_group_update_group_not_found(self): def test_share_group_update_group_not_found(self):
body = {"share_group": {}} body = {"share_group": {}}
@ -692,16 +709,21 @@ class ShareGroupAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'update') self.context, self.resource_name, 'update')
def test_share_group_list_index(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_share_group_list_index(self, microversion, experimental):
fake, expected = self._get_fake_simple_share_group() fake, expected = self._get_fake_simple_share_group()
self.mock_object( self.mock_object(
share_group_api.API, 'get_all', mock.Mock(return_value=[fake])) share_group_api.API, 'get_all', mock.Mock(return_value=[fake]))
req, req_context = self._get_fake_custom_request_and_context(
microversion, experimental)
res_dict = self.controller.index(self.request) res_dict = self.controller.index(req)
self.assertEqual([expected], res_dict['share_groups']) self.assertEqual([expected], res_dict['share_groups'])
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'get_all') req_context, self.resource_name, 'get_all')
def test_share_group_list_index_no_groups(self): def test_share_group_list_index_no_groups(self):
self.mock_object( self.mock_object(
@ -758,8 +780,7 @@ class ShareGroupAPITest(test.TestCase):
mock.Mock(return_value=[fake, fake2])) mock.Mock(return_value=[fake, fake2]))
req = fakes.HTTPRequest.blank( req = fakes.HTTPRequest.blank(
'/share-groups?name~=fake&description~=fake', '/share-groups?name~=fake&description~=fake',
version='2.36', version='2.36', experimental=True)
experimental=True)
req_context = req.environ['manila.context'] req_context = req.environ['manila.context']
res_dict = self.controller.index(req) res_dict = self.controller.index(req)
@ -771,16 +792,21 @@ class ShareGroupAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
req_context, self.resource_name, 'get_all') req_context, self.resource_name, 'get_all')
def test_share_group_list_detail(self): @ddt.data({'microversion': '2.34', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_share_group_list_detail(self, microversion, experimental):
fake, expected = self._get_fake_share_group() fake, expected = self._get_fake_share_group()
self.mock_object( self.mock_object(
share_group_api.API, 'get_all', mock.Mock(return_value=[fake])) share_group_api.API, 'get_all', mock.Mock(return_value=[fake]))
req, req_context = self._get_fake_custom_request_and_context(
microversion, experimental)
res_dict = self.controller.detail(self.request) res_dict = self.controller.detail(req)
self.assertEqual([expected], res_dict['share_groups']) self.assertEqual([expected], res_dict['share_groups'])
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'get_all') req_context, self.resource_name, 'get_all')
def test_share_group_list_detail_no_groups(self): def test_share_group_list_detail_no_groups(self):
self.mock_object( self.mock_object(
@ -830,17 +856,22 @@ class ShareGroupAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
req_context, self.resource_name, 'get_all') req_context, self.resource_name, 'get_all')
def test_share_group_delete(self): @ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_share_group_delete(self, microversion, experimental):
fake_group, expected_group = self._get_fake_share_group() fake_group, expected_group = self._get_fake_share_group()
self.mock_object(share_group_api.API, 'get', self.mock_object(share_group_api.API, 'get',
mock.Mock(return_value=fake_group)) mock.Mock(return_value=fake_group))
self.mock_object(share_group_api.API, 'delete') self.mock_object(share_group_api.API, 'delete')
req, req_context = self._get_fake_custom_request_and_context(
microversion, experimental)
res = self.controller.delete(self.request, fake_group['id']) res = self.controller.delete(req, fake_group['id'])
self.assertEqual(202, res.status_code) self.assertEqual(202, res.status_code)
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'delete') req_context, self.resource_name, 'delete')
def test_share_group_delete_group_not_found(self): def test_share_group_delete_group_not_found(self):
fake_group, expected_group = self._get_fake_share_group() fake_group, expected_group = self._get_fake_share_group()
@ -866,13 +897,16 @@ class ShareGroupAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
self.context, self.resource_name, 'delete') self.context, self.resource_name, 'delete')
def test_share_group_show(self): @ddt.data({'microversion': '2.34', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test_share_group_show(self, microversion, experimental):
fake, expected = self._get_fake_share_group() fake, expected = self._get_fake_share_group()
self.mock_object( self.mock_object(
share_group_api.API, 'get', mock.Mock(return_value=fake)) share_group_api.API, 'get', mock.Mock(return_value=fake))
req = fakes.HTTPRequest.blank( req = fakes.HTTPRequest.blank(
'/share-groupss/%s' % fake['id'], version=self.api_version, '/share-groupss/%s' % fake['id'], version=microversion,
experimental=True) experimental=experimental)
req_context = req.environ['manila.context'] req_context = req.environ['manila.context']
res_dict = self.controller.show(req, fake['id']) res_dict = self.controller.show(req, fake['id'])
@ -883,8 +917,8 @@ class ShareGroupAPITest(test.TestCase):
def test_share_group_show_as_admin(self): def test_share_group_show_as_admin(self):
req = fakes.HTTPRequest.blank( req = fakes.HTTPRequest.blank(
'/share-groupss/my_group_id', '/share-groupss/my_group_id', version=self.api_version,
version=self.api_version, experimental=True) experimental=True)
admin_context = req.environ['manila.context'].elevated() admin_context = req.environ['manila.context'].elevated()
req.environ['manila.context'] = admin_context req.environ['manila.context'] = admin_context
fake_group, expected_group = self._get_fake_share_group( fake_group, expected_group = self._get_fake_share_group(
@ -901,8 +935,8 @@ class ShareGroupAPITest(test.TestCase):
def test_share_group_show_group_not_found(self): def test_share_group_show_group_not_found(self):
req = fakes.HTTPRequest.blank( req = fakes.HTTPRequest.blank(
'/share-groupss/myfakegroup', '/share-groupss/myfakegroup', version=self.api_version,
version=self.api_version, experimental=True) experimental=True)
req_context = req.environ['manila.context'] req_context = req.environ['manila.context']
fake, expected = self._get_fake_share_group( fake, expected = self._get_fake_share_group(
ctxt=req_context, id='myfakegroup') ctxt=req_context, id='myfakegroup')
@ -915,6 +949,19 @@ class ShareGroupAPITest(test.TestCase):
self.mock_policy_check.assert_called_once_with( self.mock_policy_check.assert_called_once_with(
req_context, self.resource_name, 'get') req_context, self.resource_name, 'get')
@ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test__reset_status_call(self, microversion, experimental):
self.mock_object(self.controller, '_reset_status')
req, _junk = self._get_fake_custom_request_and_context(
microversion, experimental)
sg_id = 'fake'
body = {'reset_status': {'status': constants.STATUS_ERROR}}
self.controller.share_group_reset_status(req, sg_id, body)
self.controller._reset_status.assert_called_once_with(req, sg_id, body)
@ddt.data(*fakes.fixture_reset_status_with_different_roles) @ddt.data(*fakes.fixture_reset_status_with_different_roles)
@ddt.unpack @ddt.unpack
def test_share_groups_reset_status_with_different_roles( def test_share_groups_reset_status_with_different_roles(
@ -960,3 +1007,16 @@ class ShareGroupAPITest(test.TestCase):
# validate response # validate response
self.assertEqual(resp_code, resp.status_int) self.assertEqual(resp_code, resp.status_int)
@ddt.data({'microversion': '2.31', 'experimental': True},
{'microversion': SG_GRADUATION_VERSION, 'experimental': False})
@ddt.unpack
def test__force_delete_call(self, microversion, experimental):
self.mock_object(self.controller, '_force_delete')
req, _junk = self._get_fake_custom_request_and_context(
microversion, experimental)
sg_id = 'fake'
body = {'force_delete': {}}
self.controller.share_group_force_delete(req, sg_id, body)
self.controller._force_delete.assert_called_once_with(req, sg_id, body)

View File

@ -0,0 +1,10 @@
---
prelude: >
- |
Share group APIs have graduated from their `experimental feature state
<https://docs.openstack.org/manila/latest/contributor/experimental_apis.html>`_
from API version ``2.55``. Share group types can be created to encompass
one or more share types, share groups can be created, updated, snapshotted
and deleted, and shares can be created within share groups. These actions
no longer require the inclusion of ``X-OpenStack-Manila-API-Experimental``
header in the API requests.