Merge "Remove experimental flag from share groups feature"
This commit is contained in:
commit
ea90fd17b8
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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, '
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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"}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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.
|
Loading…
Reference in New Issue