Add new URLs for APIs ported from extensions
After port of extensions to core API we need to rename their URLs. So, rename URLs and bump microversion for it. Make new URLs work only with new microversion(s) 2.7+ and old with old microversions 1.0-2.6. Add separate API router for v2 API as now we should split v1 and v2 logic. Also, move updated APIs under v2 directory that will be used by both API routers - v1 and v2. List of updated collections is following: - os-availability-zone -> availability-zones - os-services -> services - os-quota-sets -> quota-sets - os-quota-class-sets -> quota-class-sets - os-share-manage -> shares/manage - os-share-unmanage -> shares/%s/action List of updated member actions is following: - os-share-unmanage/%(share_id)s/unmanage -> shares/%(share_id)s/action - types/%(id)s/os-share-type-access -> types/%(id)s/share_type_access List of updated action names is following: - os-access_allow -> access_allow - os-access_deny -> access_deny - os-access_list -> access_list - os-reset_status -> reset_status - os-force_delete -> force_delete - os-migrate_share -> migrate_share - os-extend -> extend - os-shrink -> shrink List of updated attribute names is following: - os-share-type-access -> share-type-access Partially implements bp ext-to-core Change-Id: I82f00114db985b4b3bf4db0a64191559508ac600
This commit is contained in:
parent
56ccb015c8
commit
2467ccf223
@ -6,7 +6,7 @@
|
||||
use = call:manila.api:root_app_factory
|
||||
/: apiversions
|
||||
/v1: openstack_share_api
|
||||
/v2: openstack_share_api
|
||||
/v2: openstack_share_api_v2
|
||||
|
||||
[composite:openstack_share_api]
|
||||
use = call:manila.api.middleware.auth:pipeline_factory
|
||||
@ -14,6 +14,12 @@ noauth = cors faultwrap ssl sizelimit noauth api
|
||||
keystone = cors faultwrap ssl sizelimit authtoken keystonecontext api
|
||||
keystone_nolimit = cors faultwrap ssl sizelimit authtoken keystonecontext api
|
||||
|
||||
[composite:openstack_share_api_v2]
|
||||
use = call:manila.api.middleware.auth:pipeline_factory
|
||||
noauth = cors faultwrap ssl sizelimit noauth apiv2
|
||||
keystone = cors faultwrap ssl sizelimit authtoken keystonecontext apiv2
|
||||
keystone_nolimit = cors faultwrap ssl sizelimit authtoken keystonecontext apiv2
|
||||
|
||||
[filter:faultwrap]
|
||||
paste.filter_factory = manila.api.middleware.fault:FaultWrapper.factory
|
||||
|
||||
@ -29,6 +35,9 @@ paste.filter_factory = oslo_middleware.ssl:SSLMiddleware.factory
|
||||
[app:api]
|
||||
paste.app_factory = manila.api.v1.router:APIRouter.factory
|
||||
|
||||
[app:apiv2]
|
||||
paste.app_factory = manila.api.v2.router:APIRouter.factory
|
||||
|
||||
[pipeline:apiversions]
|
||||
pipeline = cors faultwrap osshareversionapp
|
||||
|
||||
|
@ -52,6 +52,7 @@ REST_API_VERSION_HISTORY = """
|
||||
* 2.4 - Consistency Group support
|
||||
* 2.5 - Share Migration admin API
|
||||
* 2.6 - Return share_type UUID instead of name in Share API
|
||||
* 2.7 - Rename old extension-like API URLs to core-API-like
|
||||
|
||||
"""
|
||||
|
||||
@ -59,7 +60,7 @@ REST_API_VERSION_HISTORY = """
|
||||
# The default api version request is defined to be the
|
||||
# the minimum version of the API supported.
|
||||
_MIN_API_VERSION = "2.0"
|
||||
_MAX_API_VERSION = "2.6"
|
||||
_MAX_API_VERSION = "2.7"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
|
||||
|
@ -61,3 +61,7 @@ user documentation.
|
||||
---
|
||||
Return share_type UUID instead of name in Share API and add share_type_name
|
||||
field.
|
||||
|
||||
2.7
|
||||
---
|
||||
Rename old extension-like API URLs to core-API-like.
|
||||
|
@ -1199,12 +1199,12 @@ class AdminActionsMixin(object):
|
||||
raise webob.exc.HTTPBadRequest(explanation=expl)
|
||||
return update
|
||||
|
||||
@action('os-reset_status')
|
||||
@Controller.authorize('reset_status')
|
||||
def _reset_status(self, req, id, body):
|
||||
"""Reset status on the resource."""
|
||||
context = req.environ['manila.context']
|
||||
update = self.validate_update(body['os-reset_status'])
|
||||
update = self.validate_update(
|
||||
body.get('reset_status', body.get('os-reset_status')))
|
||||
msg = "Updating %(resource)s '%(id)s' with '%(update)r'"
|
||||
LOG.debug(msg, {'resource': self.resource_name, 'id': id,
|
||||
'update': update})
|
||||
@ -1214,7 +1214,6 @@ class AdminActionsMixin(object):
|
||||
raise webob.exc.HTTPNotFound(six.text_type(e))
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
@action('os-force_delete')
|
||||
@Controller.authorize('force_delete')
|
||||
def _force_delete(self, req, id, body):
|
||||
"""Delete a resource, bypassing the check for status."""
|
||||
|
@ -16,32 +16,30 @@
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
WSGI middleware for OpenStack Share API.
|
||||
WSGI middleware for OpenStack Share API v1.
|
||||
"""
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
from manila.api import extensions
|
||||
import manila.api.openstack
|
||||
from manila.api.v1 import availability_zones
|
||||
from manila.api.v1 import cgsnapshots
|
||||
from manila.api.v1 import consistency_groups
|
||||
from manila.api.v1 import limits
|
||||
from manila.api.v1 import quota_class_sets
|
||||
from manila.api.v1 import quota_sets
|
||||
from manila.api.v1 import scheduler_stats
|
||||
from manila.api.v1 import security_service
|
||||
from manila.api.v1 import services
|
||||
from manila.api.v1 import share_instances
|
||||
from manila.api.v1 import share_manage
|
||||
from manila.api.v1 import share_metadata
|
||||
from manila.api.v1 import share_networks
|
||||
from manila.api.v1 import share_servers
|
||||
from manila.api.v1 import share_snapshots
|
||||
from manila.api.v1 import share_types
|
||||
from manila.api.v1 import share_types_extra_specs
|
||||
from manila.api.v1 import share_unmanage
|
||||
from manila.api.v1 import shares
|
||||
from manila.api.v2 import availability_zones
|
||||
from manila.api.v2 import quota_class_sets
|
||||
from manila.api.v2 import quota_sets
|
||||
from manila.api.v2 import services
|
||||
from manila.api.v2 import share_types
|
||||
from manila.api import versions
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
@ -64,46 +62,35 @@ class APIRouter(manila.api.openstack.APIRouter):
|
||||
mapper.redirect("", "/")
|
||||
|
||||
self.resources["availability_zones"] = (
|
||||
availability_zones.create_resource())
|
||||
availability_zones.create_resource_legacy())
|
||||
mapper.resource("availability-zone",
|
||||
# TODO(vponomaryov): rename 'os-availability-zone' to
|
||||
# 'availability-zones' when API urls rename happens.
|
||||
"os-availability-zone",
|
||||
controller=self.resources["availability_zones"])
|
||||
|
||||
self.resources["services"] = services.create_resource()
|
||||
self.resources["services"] = services.create_resource_legacy()
|
||||
mapper.resource("service",
|
||||
# TODO(vponomaryov): rename 'os-services' to
|
||||
# 'services' when API urls rename happens.
|
||||
"os-services",
|
||||
controller=self.resources["services"])
|
||||
|
||||
self.resources["quota_sets"] = quota_sets.create_resource()
|
||||
self.resources["quota_sets"] = quota_sets.create_resource_legacy()
|
||||
mapper.resource("quota-set",
|
||||
# TODO(vponomaryov): rename 'os-quota-sets' to
|
||||
# 'quota-sets' when API urls rename happens.
|
||||
"os-quota-sets",
|
||||
controller=self.resources["quota_sets"],
|
||||
member={'defaults': 'GET'})
|
||||
|
||||
self.resources["quota_class_sets"] = quota_class_sets.create_resource()
|
||||
self.resources["quota_class_sets"] = (
|
||||
quota_class_sets.create_resource_legacy())
|
||||
mapper.resource("quota-class-set",
|
||||
# TODO(vponomaryov): rename 'os-quota-class-sets' to
|
||||
# 'quota-class-sets' when API urls rename happens.
|
||||
"os-quota-class-sets",
|
||||
controller=self.resources["quota_class_sets"])
|
||||
|
||||
self.resources["share_manage"] = share_manage.create_resource()
|
||||
mapper.resource("share_manage",
|
||||
# TODO(vponomaryov): remove it when it is ported
|
||||
# to shares controller.
|
||||
"os-share-manage",
|
||||
controller=self.resources["share_manage"])
|
||||
|
||||
self.resources["share_unmanage"] = share_unmanage.create_resource()
|
||||
mapper.resource("share_unmanage",
|
||||
# TODO(vponomaryov): remove it when it is ported
|
||||
# to shares controller.
|
||||
"os-share-unmanage",
|
||||
controller=self.resources["share_unmanage"],
|
||||
member={'unmanage': 'POST'})
|
||||
@ -196,20 +183,3 @@ class APIRouter(manila.api.openstack.APIRouter):
|
||||
controller=self.resources['scheduler_stats'],
|
||||
action='pools_detail',
|
||||
conditions={'method': ['GET']})
|
||||
|
||||
self.resources['consistency-groups'] = (
|
||||
consistency_groups.create_resource())
|
||||
mapper.resource('consistency-group', 'consistency-groups',
|
||||
controller=self.resources['consistency-groups'],
|
||||
collection={'detail': 'GET'})
|
||||
mapper.connect('consistency-groups',
|
||||
'/{project_id}/consistency-groups/{id}/action',
|
||||
controller=self.resources['consistency-groups'],
|
||||
action='action',
|
||||
conditions={"action": ['POST']})
|
||||
|
||||
self.resources['cgsnapshots'] = cgsnapshots.create_resource()
|
||||
mapper.resource('cgsnapshot', 'cgsnapshots',
|
||||
controller=self.resources['cgsnapshots'],
|
||||
collection={'detail': 'GET'},
|
||||
member={'members': 'GET', 'action': 'POST'})
|
||||
|
@ -41,6 +41,26 @@ class ShareInstancesController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
def _delete(self, *args, **kwargs):
|
||||
return self.share_api.delete_instance(*args, **kwargs)
|
||||
|
||||
@wsgi.Controller.api_version('2.3', '2.6')
|
||||
@wsgi.action('os-reset_status')
|
||||
def instance_reset_status_legacy(self, req, id, body):
|
||||
return self._reset_status(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('reset_status')
|
||||
def instance_reset_status(self, req, id, body):
|
||||
return self._reset_status(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.3', '2.6')
|
||||
@wsgi.action('os-force_delete')
|
||||
def instance_force_delete_legacy(self, req, id, body):
|
||||
return self._force_delete(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('force_delete')
|
||||
def instance_force_delete(self, req, id, body):
|
||||
return self._force_delete(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version("2.3")
|
||||
@wsgi.Controller.authorize
|
||||
def index(self, req):
|
||||
@ -74,18 +94,6 @@ class ShareInstancesController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
view = instance_view.ViewBuilder()
|
||||
return view.detail_list(req, share.instances)
|
||||
|
||||
@wsgi.Controller.api_version('2.3')
|
||||
@wsgi.action('os-reset_status')
|
||||
@wsgi.response(202)
|
||||
def share_instance_reset_status(self, req, id, body):
|
||||
super(self.__class__, self)._reset_status(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.3')
|
||||
@wsgi.action('os-force_delete')
|
||||
@wsgi.response(202)
|
||||
def share_instance_force_delete(self, req, id, body):
|
||||
super(self.__class__, self)._force_delete(req, id, body)
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(ShareInstancesController())
|
||||
|
@ -25,20 +25,10 @@ from manila.share import utils as share_utils
|
||||
from manila import utils
|
||||
|
||||
|
||||
class ShareManageController(wsgi.Controller):
|
||||
"""Allows existing share to be 'managed' by Manila."""
|
||||
|
||||
resource_name = "share"
|
||||
_view_builder_class = share_views.ViewBuilder
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(self.__class__, self).__init__(*args, **kwargs)
|
||||
self.share_api = share.API()
|
||||
class ShareManageMixin(object):
|
||||
|
||||
@wsgi.Controller.authorize('manage')
|
||||
def create(self, req, body):
|
||||
# TODO(vponomaryov): move it to shares controller.
|
||||
|
||||
def _manage(self, req, body):
|
||||
context = req.environ['manila.context']
|
||||
share_data = self._validate_manage_parameters(context, body)
|
||||
|
||||
@ -118,5 +108,25 @@ class ShareManageController(wsgi.Controller):
|
||||
raise exc.HTTPNotFound(explanation=six.text_type(e))
|
||||
|
||||
|
||||
class ShareManageController(ShareManageMixin, wsgi.Controller):
|
||||
"""Allows existing share to be 'managed' by Manila."""
|
||||
|
||||
resource_name = "share"
|
||||
_view_builder_class = share_views.ViewBuilder
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(self.__class__, self).__init__(*args, **kwargs)
|
||||
self.share_api = share.API()
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def create(self, req, body):
|
||||
"""Legacy method for 'manage share' operation.
|
||||
|
||||
Should be removed when minimum API version becomes equal to or
|
||||
greater than v2.7
|
||||
"""
|
||||
return self._manage(req, body)
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(ShareManageController())
|
||||
|
@ -50,15 +50,25 @@ class ShareSnapshotsController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
def _delete(self, *args, **kwargs):
|
||||
return self.share_api.delete_snapshot(*args, **kwargs)
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
@wsgi.action('os-reset_status')
|
||||
@wsgi.response(202)
|
||||
def share_snapshot_reset_status(self, req, id, body):
|
||||
super(self.__class__, self)._reset_status(req, id, body)
|
||||
def snapshot_reset_status_legacy(self, req, id, body):
|
||||
return self._reset_status(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('reset_status')
|
||||
def snapshot_reset_status(self, req, id, body):
|
||||
return self._reset_status(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
@wsgi.action('os-force_delete')
|
||||
@wsgi.response(202)
|
||||
def share_snapshot_force_delete(self, req, id, body):
|
||||
super(self.__class__, self)._force_delete(req, id, body)
|
||||
def snapshot_force_delete_legacy(self, req, id, body):
|
||||
return self._force_delete(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('force_delete')
|
||||
def snapshot_force_delete(self, req, id, body):
|
||||
return self._force_delete(req, id, body)
|
||||
|
||||
def show(self, req, id):
|
||||
"""Return data about the given snapshot."""
|
||||
|
@ -26,20 +26,11 @@ from manila import share
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class ShareUnmanageController(wsgi.Controller):
|
||||
"""The Unmanage API controller for the OpenStack API."""
|
||||
class ShareUnmanageMixin(object):
|
||||
|
||||
resource_name = "share"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(self.__class__, self).__init__(*args, **kwargs)
|
||||
self.share_api = share.API()
|
||||
|
||||
@wsgi.action("unmanage")
|
||||
@wsgi.Controller.authorize
|
||||
def unmanage(self, req, id):
|
||||
@wsgi.Controller.authorize("unmanage")
|
||||
def _unmanage(self, req, id, body=None):
|
||||
"""Unmanage a share."""
|
||||
# TODO(vponomaryov): move it to shares controller as 'unmanage' action.
|
||||
context = req.environ['manila.context']
|
||||
|
||||
LOG.info(_LI("Unmanage share with id: %s"), id, context=context)
|
||||
@ -72,5 +63,19 @@ class ShareUnmanageController(wsgi.Controller):
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
|
||||
class ShareUnmanageController(ShareUnmanageMixin, wsgi.Controller):
|
||||
"""The Unmanage API controller for the OpenStack API."""
|
||||
|
||||
resource_name = "share"
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(self.__class__, self).__init__(*args, **kwargs)
|
||||
self.share_api = share.API()
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def unmanage(self, req, id):
|
||||
return self._unmanage(req, id)
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(ShareUnmanageController())
|
||||
|
@ -38,15 +38,8 @@ from manila.share import share_types
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
"""The Shares API controller for the OpenStack API."""
|
||||
|
||||
resource_name = 'share'
|
||||
_view_builder_class = share_views.ViewBuilder
|
||||
|
||||
def __init__(self):
|
||||
super(ShareController, self).__init__()
|
||||
self.share_api = share.API()
|
||||
class ShareMixin(object):
|
||||
"""Mixin class for Share API Controllers."""
|
||||
|
||||
def _update(self, *args, **kwargs):
|
||||
db.share_update(*args, **kwargs)
|
||||
@ -60,16 +53,6 @@ class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
def _migrate(self, *args, **kwargs):
|
||||
return self.share_api.migrate_share(*args, **kwargs)
|
||||
|
||||
@wsgi.action('os-reset_status')
|
||||
@wsgi.response(202)
|
||||
def share_reset_status(self, req, id, body):
|
||||
super(self.__class__, self)._reset_status(req, id, body)
|
||||
|
||||
@wsgi.action('os-force_delete')
|
||||
@wsgi.response(202)
|
||||
def share_force_delete(self, req, id, body):
|
||||
super(self.__class__, self)._force_delete(req, id, body)
|
||||
|
||||
def show(self, req, id):
|
||||
"""Return data about the given share."""
|
||||
context = req.environ['manila.context']
|
||||
@ -113,9 +96,7 @@ class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
@wsgi.Controller.api_version("2.5", None, True)
|
||||
@wsgi.action("os-migrate_share")
|
||||
def migrate_share(self, req, id, body):
|
||||
def _migrate_share(self, req, id, body):
|
||||
"""Migrate a share to the specified host."""
|
||||
context = req.environ['manila.context']
|
||||
try:
|
||||
@ -123,7 +104,7 @@ class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
except exception.NotFound:
|
||||
msg = _("Share %s not found.") % id
|
||||
raise exc.HTTPNotFound(explanation=msg)
|
||||
params = body['os-migrate_share']
|
||||
params = body.get('migrate_share', body.get('os-migrate_share'))
|
||||
try:
|
||||
host = params['host']
|
||||
except KeyError:
|
||||
@ -229,12 +210,7 @@ class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
share.update(update_dict)
|
||||
return self._view_builder.detail(req, share)
|
||||
|
||||
@wsgi.Controller.api_version("2.4")
|
||||
def create(self, req, body):
|
||||
return self._create(req, body)
|
||||
|
||||
@wsgi.Controller.api_version("1.0", "2.3") # noqa
|
||||
def create(self, req, body): # pylint: disable=E0102
|
||||
# Remove consistency group attributes
|
||||
body.get('share', {}).pop('consistency_group_id', None)
|
||||
share = self._create(req, body)
|
||||
@ -400,11 +376,10 @@ class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
except ValueError:
|
||||
raise webob.exc.HTTPBadRequest(explanation=exc_str)
|
||||
|
||||
@wsgi.action('os-allow_access')
|
||||
def _allow_access(self, req, id, body):
|
||||
"""Add share access rule."""
|
||||
context = req.environ['manila.context']
|
||||
access_data = body['os-allow_access']
|
||||
access_data = body.get('allow_access', body.get('os-allow_access'))
|
||||
share = self.share_api.get(context, id)
|
||||
|
||||
access_type = access_data['access_type']
|
||||
@ -427,12 +402,12 @@ class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
raise webob.exc.HTTPBadRequest(explanation=e.msg)
|
||||
return {'access': access}
|
||||
|
||||
@wsgi.action('os-deny_access')
|
||||
def _deny_access(self, req, id, body):
|
||||
"""Remove share access rule."""
|
||||
context = req.environ['manila.context']
|
||||
|
||||
access_id = body['os-deny_access']['access_id']
|
||||
access_id = body.get(
|
||||
'deny_access', body.get('os-deny_access'))['access_id']
|
||||
|
||||
try:
|
||||
access = self.share_api.access_get(context, access_id)
|
||||
@ -444,7 +419,6 @@ class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
self.share_api.deny_access(context, share, access)
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
@wsgi.action('os-access_list')
|
||||
def _access_list(self, req, id, body):
|
||||
"""list share access rules."""
|
||||
context = req.environ['manila.context']
|
||||
@ -453,7 +427,6 @@ class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
access_list = self.share_api.access_get_all(context, share)
|
||||
return {'access_list': access_list}
|
||||
|
||||
@wsgi.action('os-extend')
|
||||
def _extend(self, req, id, body):
|
||||
"""Extend size of a share."""
|
||||
context = req.environ['manila.context']
|
||||
@ -469,7 +442,6 @@ class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
@wsgi.action('os-shrink')
|
||||
def _shrink(self, req, id, body):
|
||||
"""Shrink size of a share."""
|
||||
context = req.environ['manila.context']
|
||||
@ -490,7 +462,7 @@ class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
raise webob.exc.HTTPNotFound(explanation=six.text_type(e))
|
||||
|
||||
try:
|
||||
size = int(body[action]['new_size'])
|
||||
size = int(body.get(action, action.split('os-')[-1])['new_size'])
|
||||
except (KeyError, ValueError, TypeError):
|
||||
msg = _("New share size must be specified as an integer.")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
@ -498,5 +470,50 @@ class ShareController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
return share, size
|
||||
|
||||
|
||||
class ShareController(wsgi.Controller, ShareMixin, wsgi.AdminActionsMixin):
|
||||
"""The Shares API v1 controller for the OpenStack API."""
|
||||
resource_name = 'share'
|
||||
_view_builder_class = share_views.ViewBuilder
|
||||
|
||||
def __init__(self):
|
||||
super(self.__class__, self).__init__()
|
||||
self.share_api = share.API()
|
||||
|
||||
@wsgi.action('os-reset_status')
|
||||
def share_reset_status(self, req, id, body):
|
||||
"""Reset status of a share."""
|
||||
return self._reset_status(req, id, body)
|
||||
|
||||
@wsgi.action('os-force_delete')
|
||||
def share_force_delete(self, req, id, body):
|
||||
"""Delete a share, bypassing the check for status."""
|
||||
return self._force_delete(req, id, body)
|
||||
|
||||
@wsgi.action('os-allow_access')
|
||||
def allow_access(self, req, id, body):
|
||||
"""Add share access rule."""
|
||||
return self._allow_access(req, id, body)
|
||||
|
||||
@wsgi.action('os-deny_access')
|
||||
def deny_access(self, req, id, body):
|
||||
"""Remove share access rule."""
|
||||
return self._deny_access(req, id, body)
|
||||
|
||||
@wsgi.action('os-access_list')
|
||||
def access_list(self, req, id, body):
|
||||
"""List share access rules."""
|
||||
return self._access_list(req, id, body)
|
||||
|
||||
@wsgi.action('os-extend')
|
||||
def extend(self, req, id, body):
|
||||
"""Extend size of a share."""
|
||||
return self._extend(req, id, body)
|
||||
|
||||
@wsgi.action('os-shrink')
|
||||
def shrink(self, req, id, body):
|
||||
"""Shrink size of a share."""
|
||||
return self._shrink(req, id, body)
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(ShareController())
|
||||
|
0
manila/api/v2/__init__.py
Normal file
0
manila/api/v2/__init__.py
Normal file
@ -18,21 +18,50 @@ from manila.api.views import availability_zones as availability_zones_views
|
||||
from manila import db
|
||||
|
||||
|
||||
class AvailabilityZoneController(wsgi.Controller):
|
||||
"""The Availability Zone API controller for the OpenStack API."""
|
||||
class AvailabilityZoneMixin(object):
|
||||
"""The Availability Zone API controller common logic.
|
||||
|
||||
Mixin class that should be inherited by Availability Zone API controllers,
|
||||
which are used for different API URLs and microversions.
|
||||
"""
|
||||
|
||||
resource_name = "availability_zone"
|
||||
_view_builder_class = availability_zones_views.ViewBuilder
|
||||
|
||||
@wsgi.Controller.authorize
|
||||
def index(self, req):
|
||||
return self._index(req)
|
||||
|
||||
@wsgi.Controller.authorize("index")
|
||||
def _index(self, req):
|
||||
"""Describe all known availability zones."""
|
||||
views = db.availability_zone_get_all(req.environ['manila.context'])
|
||||
return self._view_builder.detail_list(views)
|
||||
|
||||
|
||||
class AvailabilityZoneControllerLegacy(AvailabilityZoneMixin, wsgi.Controller):
|
||||
"""Deprecated Availability Zone API controller.
|
||||
|
||||
Used by legacy API v1 and v2 microversions from 2.0 to 2.6.
|
||||
Registered under deprecated API URL 'os-availability-zone'.
|
||||
"""
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def index(self, req):
|
||||
return self._index(req)
|
||||
|
||||
|
||||
class AvailabilityZoneController(AvailabilityZoneMixin, wsgi.Controller):
|
||||
"""Availability Zone API controller.
|
||||
|
||||
Used only by API v2 starting from microversion 2.7.
|
||||
Registered under API URL 'availability-zones'.
|
||||
"""
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
def index(self, req):
|
||||
return self._index(req)
|
||||
|
||||
|
||||
def create_resource_legacy():
|
||||
return wsgi.Resource(AvailabilityZoneControllerLegacy())
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(AvailabilityZoneController())
|
@ -211,17 +211,25 @@ class CGSnapshotController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
def _delete(self, context, resource, force=True):
|
||||
db.cgsnapshot_destroy(context.elevated(), resource['id'])
|
||||
|
||||
@wsgi.Controller.api_version('2.4', experimental=True)
|
||||
@wsgi.Controller.api_version('2.4', '2.6', experimental=True)
|
||||
@wsgi.action('os-reset_status')
|
||||
@wsgi.response(202)
|
||||
def cgsnapshot_reset_status(self, req, id, body):
|
||||
super(self.__class__, self)._reset_status(req, id, body)
|
||||
def cgsnapshot_reset_status_legacy(self, req, id, body):
|
||||
return self._reset_status(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.4', experimental=True)
|
||||
@wsgi.Controller.api_version('2.7', experimental=True)
|
||||
@wsgi.action('reset_status')
|
||||
def cgsnapshot_reset_status(self, req, id, body):
|
||||
return self._reset_status(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.4', '2.6', experimental=True)
|
||||
@wsgi.action('os-force_delete')
|
||||
@wsgi.response(202)
|
||||
def cgsnapshot_force_delete_legacy(self, req, id, body):
|
||||
return self._force_delete(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7', experimental=True)
|
||||
@wsgi.action('force_delete')
|
||||
def cgsnapshot_force_delete(self, req, id, body):
|
||||
super(self.__class__, self)._force_delete(req, id, body)
|
||||
return self._force_delete(req, id, body)
|
||||
|
||||
|
||||
def create_resource():
|
@ -224,17 +224,25 @@ class CGController(wsgi.Controller, wsgi.AdminActionsMixin):
|
||||
def _delete(self, context, resource, force=True):
|
||||
db.consistency_group_destroy(context.elevated(), resource['id'])
|
||||
|
||||
@wsgi.Controller.api_version('2.4', experimental=True)
|
||||
@wsgi.Controller.api_version('2.4', '2.6', experimental=True)
|
||||
@wsgi.action('os-reset_status')
|
||||
@wsgi.response(202)
|
||||
def cg_reset_status(self, req, id, body):
|
||||
super(self.__class__, self)._reset_status(req, id, body)
|
||||
def cg_reset_status_legacy(self, req, id, body):
|
||||
return self._reset_status(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.4', experimental=True)
|
||||
@wsgi.Controller.api_version('2.7', experimental=True)
|
||||
@wsgi.action('reset_status')
|
||||
def cg_reset_status(self, req, id, body):
|
||||
return self._reset_status(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.4', '2.6', experimental=True)
|
||||
@wsgi.action('os-force_delete')
|
||||
@wsgi.response(202)
|
||||
def cg_force_delete_legacy(self, req, id, body):
|
||||
return self._force_delete(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7', experimental=True)
|
||||
@wsgi.action('force_delete')
|
||||
def cg_force_delete(self, req, id, body):
|
||||
super(self.__class__, self)._force_delete(req, id, body)
|
||||
return self._force_delete(req, id, body)
|
||||
|
||||
|
||||
def create_resource():
|
@ -25,13 +25,18 @@ from manila import quota
|
||||
QUOTAS = quota.QUOTAS
|
||||
|
||||
|
||||
class QuotaClassSetsController(wsgi.Controller):
|
||||
class QuotaClassSetsMixin(object):
|
||||
"""The Quota Class Sets API controller common logic.
|
||||
|
||||
Mixin class that should be inherited by Quota Class Sets API controllers,
|
||||
which are used for different API URLs and microversions.
|
||||
"""
|
||||
|
||||
resource_name = "quota_class_set"
|
||||
_view_builder_class = quota_class_sets_views.ViewBuilder
|
||||
|
||||
@wsgi.Controller.authorize
|
||||
def show(self, req, id):
|
||||
@wsgi.Controller.authorize("show")
|
||||
def _show(self, req, id):
|
||||
context = req.environ['manila.context']
|
||||
try:
|
||||
db.authorize_quota_class_context(context, id)
|
||||
@ -41,8 +46,8 @@ class QuotaClassSetsController(wsgi.Controller):
|
||||
return self._view_builder.detail_list(
|
||||
QUOTAS.get_class_quotas(context, id), id)
|
||||
|
||||
@wsgi.Controller.authorize
|
||||
def update(self, req, id, body):
|
||||
@wsgi.Controller.authorize("update")
|
||||
def _update(self, req, id, body):
|
||||
context = req.environ['manila.context']
|
||||
quota_class = id
|
||||
for key in body.get(self.resource_name, {}).keys():
|
||||
@ -58,5 +63,41 @@ class QuotaClassSetsController(wsgi.Controller):
|
||||
QUOTAS.get_class_quotas(context, quota_class))
|
||||
|
||||
|
||||
class QuotaClassSetsControllerLegacy(QuotaClassSetsMixin, wsgi.Controller):
|
||||
"""Deprecated Quota Class Sets API controller.
|
||||
|
||||
Used by legacy API v1 and v2 microversions from 2.0 to 2.6.
|
||||
Registered under deprecated API URL 'os-quota-class-sets'.
|
||||
"""
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def show(self, req, id):
|
||||
return self._show(req, id)
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def update(self, req, id, body):
|
||||
return self._update(req, id, body)
|
||||
|
||||
|
||||
class QuotaClassSetsController(QuotaClassSetsMixin, wsgi.Controller):
|
||||
"""Quota Class Sets API controller.
|
||||
|
||||
Used only by API v2 starting from microversion 2.7.
|
||||
Registered under API URL 'quota-class-sets'.
|
||||
"""
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
def show(self, req, id):
|
||||
return self._show(req, id)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
def update(self, req, id, body):
|
||||
return self._update(req, id, body)
|
||||
|
||||
|
||||
def create_resource_legacy():
|
||||
return wsgi.Resource(QuotaClassSetsControllerLegacy())
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(QuotaClassSetsController())
|
@ -31,8 +31,12 @@ LOG = log.getLogger(__name__)
|
||||
NON_QUOTA_KEYS = ('tenant_id', 'id', 'force')
|
||||
|
||||
|
||||
class QuotaSetsController(wsgi.Controller):
|
||||
"""The Quota Sets API controller for the OpenStack API."""
|
||||
class QuotaSetsMixin(object):
|
||||
"""The Quota Sets API controller common logic.
|
||||
|
||||
Mixin class that should be inherited by Quota Sets API controllers,
|
||||
which are used for different API URLs and microversions.
|
||||
"""
|
||||
|
||||
resource_name = "quota_set"
|
||||
_view_builder_class = quota_sets_views.ViewBuilder
|
||||
@ -61,8 +65,8 @@ class QuotaSetsController(wsgi.Controller):
|
||||
return values
|
||||
return dict((k, v['limit']) for k, v in values.items())
|
||||
|
||||
@wsgi.Controller.authorize
|
||||
def show(self, req, id):
|
||||
@wsgi.Controller.authorize("show")
|
||||
def _show(self, req, id):
|
||||
context = req.environ['manila.context']
|
||||
params = parse.parse_qs(req.environ.get('QUERY_STRING', ''))
|
||||
user_id = params.get('user_id', [None])[0]
|
||||
@ -74,12 +78,12 @@ class QuotaSetsController(wsgi.Controller):
|
||||
raise webob.exc.HTTPForbidden()
|
||||
|
||||
@wsgi.Controller.authorize('show')
|
||||
def defaults(self, req, id):
|
||||
def _defaults(self, req, id):
|
||||
context = req.environ['manila.context']
|
||||
return self._view_builder.detail_list(QUOTAS.get_defaults(context), id)
|
||||
|
||||
@wsgi.Controller.authorize
|
||||
def update(self, req, id, body):
|
||||
@wsgi.Controller.authorize("update")
|
||||
def _update(self, req, id, body):
|
||||
context = req.environ['manila.context']
|
||||
project_id = id
|
||||
bad_keys = []
|
||||
@ -166,8 +170,8 @@ class QuotaSetsController(wsgi.Controller):
|
||||
return self._view_builder.detail_list(
|
||||
self._get_quotas(context, id, user_id=user_id))
|
||||
|
||||
@wsgi.Controller.authorize
|
||||
def delete(self, req, id):
|
||||
@wsgi.Controller.authorize("delete")
|
||||
def _delete(self, req, id):
|
||||
context = req.environ['manila.context']
|
||||
params = parse.parse_qs(req.environ.get('QUERY_STRING', ''))
|
||||
user_id = params.get('user_id', [None])[0]
|
||||
@ -182,5 +186,57 @@ class QuotaSetsController(wsgi.Controller):
|
||||
raise webob.exc.HTTPForbidden()
|
||||
|
||||
|
||||
class QuotaSetsControllerLegacy(QuotaSetsMixin, wsgi.Controller):
|
||||
"""Deprecated Quota Sets API controller.
|
||||
|
||||
Used by legacy API v1 and v2 microversions from 2.0 to 2.6.
|
||||
Registered under deprecated API URL 'os-quota-sets'.
|
||||
"""
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def show(self, req, id):
|
||||
return self._show(req, id)
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def defaults(self, req, id):
|
||||
return self._defaults(req, id)
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def update(self, req, id, body):
|
||||
return self._update(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def delete(self, req, id):
|
||||
return self._delete(req, id)
|
||||
|
||||
|
||||
class QuotaSetsController(QuotaSetsMixin, wsgi.Controller):
|
||||
"""Quota Sets API controller.
|
||||
|
||||
Used only by API v2 starting from microversion 2.7.
|
||||
Registered under API URL 'quota-sets'.
|
||||
"""
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
def show(self, req, id):
|
||||
return self._show(req, id)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
def defaults(self, req, id):
|
||||
return self._defaults(req, id)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
def update(self, req, id, body):
|
||||
return self._update(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
def delete(self, req, id):
|
||||
return self._delete(req, id)
|
||||
|
||||
|
||||
def create_resource_legacy():
|
||||
return wsgi.Resource(QuotaSetsControllerLegacy())
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(QuotaSetsController())
|
253
manila/api/v2/router.py
Normal file
253
manila/api/v2/router.py
Normal file
@ -0,0 +1,253 @@
|
||||
# Copyright 2011 OpenStack LLC.
|
||||
# Copyright 2011 United States Government as represented by the
|
||||
# Administrator of the National Aeronautics and Space Administration.
|
||||
# Copyright (c) 2015 Mirantis inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
WSGI middleware for OpenStack Share API v2.
|
||||
"""
|
||||
|
||||
from oslo_log import log
|
||||
|
||||
from manila.api import extensions
|
||||
import manila.api.openstack
|
||||
from manila.api.v1 import limits
|
||||
from manila.api.v1 import scheduler_stats
|
||||
from manila.api.v1 import security_service
|
||||
from manila.api.v1 import share_instances
|
||||
from manila.api.v1 import share_manage
|
||||
from manila.api.v1 import share_metadata
|
||||
from manila.api.v1 import share_networks
|
||||
from manila.api.v1 import share_servers
|
||||
from manila.api.v1 import share_snapshots
|
||||
from manila.api.v1 import share_types_extra_specs
|
||||
from manila.api.v1 import share_unmanage
|
||||
from manila.api.v2 import availability_zones
|
||||
from manila.api.v2 import cgsnapshots
|
||||
from manila.api.v2 import consistency_groups
|
||||
from manila.api.v2 import quota_class_sets
|
||||
from manila.api.v2 import quota_sets
|
||||
from manila.api.v2 import services
|
||||
from manila.api.v2 import share_types
|
||||
from manila.api.v2 import shares
|
||||
from manila.api import versions
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class APIRouter(manila.api.openstack.APIRouter):
|
||||
"""Route API requests.
|
||||
|
||||
Routes requests on the OpenStack API to the appropriate controller
|
||||
and method.
|
||||
"""
|
||||
ExtensionManager = extensions.ExtensionManager
|
||||
|
||||
def _setup_routes(self, mapper, ext_mgr):
|
||||
self.resources["versions"] = versions.create_resource()
|
||||
mapper.connect("versions", "/",
|
||||
controller=self.resources["versions"],
|
||||
action="index")
|
||||
|
||||
mapper.redirect("", "/")
|
||||
|
||||
self.resources["availability_zones_legacy"] = (
|
||||
availability_zones.create_resource_legacy())
|
||||
# TODO(vponomaryov): "os-availability-zone" is deprecated
|
||||
# since v2.7. Remove it when minimum API version becomes equal to
|
||||
# or greater than v2.7.
|
||||
mapper.resource("availability-zone",
|
||||
"os-availability-zone",
|
||||
controller=self.resources["availability_zones_legacy"])
|
||||
|
||||
self.resources["availability_zones"] = (
|
||||
availability_zones.create_resource())
|
||||
mapper.resource("availability-zone",
|
||||
"availability-zones",
|
||||
controller=self.resources["availability_zones"])
|
||||
|
||||
self.resources["services_legacy"] = services.create_resource_legacy()
|
||||
# TODO(vponomaryov): "os-services" is deprecated
|
||||
# since v2.7. Remove it when minimum API version becomes equal to
|
||||
# or greater than v2.7.
|
||||
mapper.resource("service",
|
||||
"os-services",
|
||||
controller=self.resources["services_legacy"])
|
||||
|
||||
self.resources["services"] = services.create_resource()
|
||||
mapper.resource("service",
|
||||
"services",
|
||||
controller=self.resources["services"])
|
||||
|
||||
self.resources["quota_sets_legacy"] = (
|
||||
quota_sets.create_resource_legacy())
|
||||
# TODO(vponomaryov): "os-quota-sets" is deprecated
|
||||
# since v2.7. Remove it when minimum API version becomes equal to
|
||||
# or greater than v2.7.
|
||||
mapper.resource("quota-set",
|
||||
"os-quota-sets",
|
||||
controller=self.resources["quota_sets_legacy"],
|
||||
member={"defaults": "GET"})
|
||||
|
||||
self.resources["quota_sets"] = quota_sets.create_resource()
|
||||
mapper.resource("quota-set",
|
||||
"quota-sets",
|
||||
controller=self.resources["quota_sets"],
|
||||
member={"defaults": "GET"})
|
||||
|
||||
self.resources["quota_class_sets_legacy"] = (
|
||||
quota_class_sets.create_resource_legacy())
|
||||
# TODO(vponomaryov): "os-quota-class-sets" is deprecated
|
||||
# since v2.7. Remove it when minimum API version becomes equal to
|
||||
# or greater than v2.7.
|
||||
mapper.resource("quota-class-set",
|
||||
"os-quota-class-sets",
|
||||
controller=self.resources["quota_class_sets_legacy"])
|
||||
|
||||
self.resources["quota_class_sets"] = quota_class_sets.create_resource()
|
||||
mapper.resource("quota-class-set",
|
||||
"quota-class-sets",
|
||||
controller=self.resources["quota_class_sets"])
|
||||
|
||||
self.resources["share_manage"] = share_manage.create_resource()
|
||||
# TODO(vponomaryov): "os-share-manage" is deprecated
|
||||
# since v2.7. Remove it when minimum API version becomes equal to
|
||||
# or greater than v2.7.
|
||||
mapper.resource("share_manage",
|
||||
"os-share-manage",
|
||||
controller=self.resources["share_manage"])
|
||||
|
||||
self.resources["share_unmanage"] = share_unmanage.create_resource()
|
||||
# TODO(vponomaryov): "os-share-unmanage" is deprecated
|
||||
# since v2.7. Remove it when minimum API version becomes equal to
|
||||
# or greater than v2.7.
|
||||
mapper.resource("share_unmanage",
|
||||
"os-share-unmanage",
|
||||
controller=self.resources["share_unmanage"],
|
||||
member={"unmanage": "POST"})
|
||||
|
||||
self.resources["shares"] = shares.create_resource()
|
||||
mapper.resource("share", "shares",
|
||||
controller=self.resources["shares"],
|
||||
collection={"detail": "GET"},
|
||||
member={"action": "POST"})
|
||||
|
||||
mapper.connect("shares",
|
||||
"/{project_id}/shares/manage",
|
||||
controller=self.resources["shares"],
|
||||
action="manage",
|
||||
conditions={"method": ["POST"]})
|
||||
|
||||
self.resources["share_instances"] = share_instances.create_resource()
|
||||
mapper.resource("share_instance", "share_instances",
|
||||
controller=self.resources["share_instances"],
|
||||
collection={"detail": "GET"},
|
||||
member={"action": "POST"})
|
||||
|
||||
mapper.connect("share_instance",
|
||||
"/{project_id}/shares/{share_id}/instances",
|
||||
controller=self.resources["share_instances"],
|
||||
action="get_share_instances",
|
||||
conditions={"method": ["GET"]})
|
||||
|
||||
self.resources["snapshots"] = share_snapshots.create_resource()
|
||||
mapper.resource("snapshot", "snapshots",
|
||||
controller=self.resources["snapshots"],
|
||||
collection={"detail": "GET"},
|
||||
member={"action": "POST"})
|
||||
|
||||
self.resources["share_metadata"] = share_metadata.create_resource()
|
||||
share_metadata_controller = self.resources["share_metadata"]
|
||||
|
||||
mapper.resource("share_metadata", "metadata",
|
||||
controller=share_metadata_controller,
|
||||
parent_resource=dict(member_name="share",
|
||||
collection_name="shares"))
|
||||
|
||||
mapper.connect("metadata",
|
||||
"/{project_id}/shares/{share_id}/metadata",
|
||||
controller=share_metadata_controller,
|
||||
action="update_all",
|
||||
conditions={"method": ["PUT"]})
|
||||
|
||||
self.resources["limits"] = limits.create_resource()
|
||||
mapper.resource("limit", "limits",
|
||||
controller=self.resources["limits"])
|
||||
|
||||
self.resources["security_services"] = (
|
||||
security_service.create_resource())
|
||||
mapper.resource("security-service", "security-services",
|
||||
controller=self.resources["security_services"],
|
||||
collection={"detail": "GET"})
|
||||
|
||||
self.resources["share_networks"] = share_networks.create_resource()
|
||||
mapper.resource(share_networks.RESOURCE_NAME,
|
||||
"share-networks",
|
||||
controller=self.resources["share_networks"],
|
||||
collection={"detail": "GET"},
|
||||
member={"action": "POST"})
|
||||
|
||||
self.resources["share_servers"] = share_servers.create_resource()
|
||||
mapper.resource("share_server",
|
||||
"share-servers",
|
||||
controller=self.resources["share_servers"])
|
||||
mapper.connect("details",
|
||||
"/{project_id}/share-servers/{id}/details",
|
||||
controller=self.resources["share_servers"],
|
||||
action="details",
|
||||
conditions={"method": ["GET"]})
|
||||
|
||||
self.resources["types"] = share_types.create_resource()
|
||||
mapper.resource("type", "types",
|
||||
controller=self.resources["types"],
|
||||
collection={"detail": "GET", "default": "GET"},
|
||||
member={"action": "POST",
|
||||
"os-share-type-access": "GET",
|
||||
"share_type_access": "GET"})
|
||||
|
||||
self.resources["extra_specs"] = (
|
||||
share_types_extra_specs.create_resource())
|
||||
mapper.resource("extra_spec", "extra_specs",
|
||||
controller=self.resources["extra_specs"],
|
||||
parent_resource=dict(member_name="type",
|
||||
collection_name="types"))
|
||||
|
||||
self.resources["scheduler_stats"] = scheduler_stats.create_resource()
|
||||
mapper.connect("pools", "/{project_id}/scheduler-stats/pools",
|
||||
controller=self.resources["scheduler_stats"],
|
||||
action="pools_index",
|
||||
conditions={"method": ["GET"]})
|
||||
mapper.connect("pools", "/{project_id}/scheduler-stats/pools/detail",
|
||||
controller=self.resources["scheduler_stats"],
|
||||
action="pools_detail",
|
||||
conditions={"method": ["GET"]})
|
||||
|
||||
self.resources["consistency-groups"] = (
|
||||
consistency_groups.create_resource())
|
||||
mapper.resource("consistency-group", "consistency-groups",
|
||||
controller=self.resources["consistency-groups"],
|
||||
collection={"detail": "GET"})
|
||||
mapper.connect("consistency-groups",
|
||||
"/{project_id}/consistency-groups/{id}/action",
|
||||
controller=self.resources["consistency-groups"],
|
||||
action="action",
|
||||
conditions={"action": ["POST"]})
|
||||
|
||||
self.resources["cgsnapshots"] = cgsnapshots.create_resource()
|
||||
mapper.resource("cgsnapshot", "cgsnapshots",
|
||||
controller=self.resources["cgsnapshots"],
|
||||
collection={"detail": "GET"},
|
||||
member={"members": "GET", "action": "POST"})
|
@ -25,14 +25,18 @@ from manila import utils
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class ServiceController(wsgi.Controller):
|
||||
"""The Services API controller for the OpenStack API."""
|
||||
class ServiceMixin(object):
|
||||
"""The Services API controller common logic.
|
||||
|
||||
Mixin class that should be inherited by Services API controllers,
|
||||
which are used for different API URLs and microversions.
|
||||
"""
|
||||
|
||||
resource_name = "service"
|
||||
_view_builder_class = services_views.ViewBuilder
|
||||
|
||||
@wsgi.Controller.authorize
|
||||
def index(self, req):
|
||||
@wsgi.Controller.authorize("index")
|
||||
def _index(self, req):
|
||||
"""Return a list of all running services."""
|
||||
|
||||
context = req.environ['manila.context']
|
||||
@ -68,8 +72,8 @@ class ServiceController(wsgi.Controller):
|
||||
|
||||
return self._view_builder.detail_list(services)
|
||||
|
||||
@wsgi.Controller.authorize
|
||||
def update(self, req, id, body):
|
||||
@wsgi.Controller.authorize("update")
|
||||
def _update(self, req, id, body):
|
||||
"""Enable/Disable scheduling for a service."""
|
||||
context = req.environ['manila.context']
|
||||
|
||||
@ -93,5 +97,41 @@ class ServiceController(wsgi.Controller):
|
||||
return self._view_builder.summary(data)
|
||||
|
||||
|
||||
class ServiceControllerLegacy(ServiceMixin, wsgi.Controller):
|
||||
"""Deprecated Services API controller.
|
||||
|
||||
Used by legacy API v1 and v2 microversions from 2.0 to 2.6.
|
||||
Registered under deprecated API URL 'os-services'.
|
||||
"""
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def index(self, req):
|
||||
return self._index(req)
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def update(self, req, id, body):
|
||||
return self._update(req, id, body)
|
||||
|
||||
|
||||
class ServiceController(ServiceMixin, wsgi.Controller):
|
||||
"""Services API controller.
|
||||
|
||||
Used only by API v2 starting from microversion 2.7.
|
||||
Registered under API URL 'services'.
|
||||
"""
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
def index(self, req):
|
||||
return self._index(req)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
def update(self, req, id, body):
|
||||
return self._update(req, id, body)
|
||||
|
||||
|
||||
def create_resource_legacy():
|
||||
return wsgi.Resource(ServiceControllerLegacy())
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(ServiceController())
|
@ -37,7 +37,7 @@ class ShareTypesController(wsgi.Controller):
|
||||
|
||||
def __getattr__(self, key):
|
||||
if key == 'os-share-type-access':
|
||||
return self._list_project_access
|
||||
return self.share_type_access
|
||||
return super(self.__class__, self).__getattr__(key)
|
||||
|
||||
def _notify_share_type_error(self, context, method, payload):
|
||||
@ -143,7 +143,10 @@ class ShareTypesController(wsgi.Controller):
|
||||
share_type = body['volume_type']
|
||||
name = share_type.get('name', None)
|
||||
specs = share_type.get('extra_specs', {})
|
||||
is_public = share_type.get('os-share-type-access:is_public', True)
|
||||
is_public = share_type.get(
|
||||
'os-share-type-access:is_public',
|
||||
share_type.get('share_type_access:is_public', True),
|
||||
)
|
||||
|
||||
if name is None or name == "" or len(name) > 255:
|
||||
msg = _("Type name is not valid.")
|
||||
@ -209,7 +212,7 @@ class ShareTypesController(wsgi.Controller):
|
||||
return webob.Response(status_int=202)
|
||||
|
||||
@wsgi.Controller.authorize('list_project_access')
|
||||
def _list_project_access(self, req, id):
|
||||
def share_type_access(self, req, id):
|
||||
context = req.environ['manila.context']
|
||||
|
||||
try:
|
150
manila/api/v2/shares.py
Normal file
150
manila/api/v2/shares.py
Normal file
@ -0,0 +1,150 @@
|
||||
# Copyright (c) 2015 Mirantis inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from manila.api.openstack import wsgi
|
||||
from manila.api.v1 import share_manage
|
||||
from manila.api.v1 import share_unmanage
|
||||
from manila.api.v1 import shares
|
||||
from manila.api.views import shares as share_views
|
||||
from manila import share
|
||||
|
||||
|
||||
class ShareController(shares.ShareMixin,
|
||||
share_manage.ShareManageMixin,
|
||||
share_unmanage.ShareUnmanageMixin,
|
||||
wsgi.Controller,
|
||||
wsgi.AdminActionsMixin):
|
||||
"""The Shares API v2 controller for the OpenStack API."""
|
||||
|
||||
resource_name = 'share'
|
||||
_view_builder_class = share_views.ViewBuilder
|
||||
|
||||
def __init__(self):
|
||||
super(self.__class__, self).__init__()
|
||||
self.share_api = share.API()
|
||||
|
||||
@wsgi.Controller.api_version("2.4")
|
||||
def create(self, req, body):
|
||||
return self._create(req, body)
|
||||
|
||||
@wsgi.Controller.api_version("2.0", "2.3") # noqa
|
||||
def create(self, req, body): # pylint: disable=E0102
|
||||
# Remove consistency group attributes
|
||||
body.get('share', {}).pop('consistency_group_id', None)
|
||||
share = self._create(req, body)
|
||||
return share
|
||||
|
||||
@wsgi.Controller.api_version('2.0', '2.6')
|
||||
@wsgi.action('os-reset_status')
|
||||
def share_reset_status_legacy(self, req, id, body):
|
||||
return self._reset_status(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('reset_status')
|
||||
def share_reset_status(self, req, id, body):
|
||||
return self._reset_status(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.0', '2.6')
|
||||
@wsgi.action('os-force_delete')
|
||||
def share_force_delete_legacy(self, req, id, body):
|
||||
return self._force_delete(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('force_delete')
|
||||
def share_force_delete(self, req, id, body):
|
||||
return self._force_delete(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.5', '2.6', experimental=True)
|
||||
@wsgi.action("os-migrate_share")
|
||||
def migrate_share_legacy(self, req, id, body):
|
||||
return self._migrate_share(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7', experimental=True)
|
||||
@wsgi.action("migrate_share")
|
||||
def migrate_share(self, req, id, body):
|
||||
return self._migrate_share(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.0', '2.6')
|
||||
@wsgi.action('os-allow_access')
|
||||
def allow_access_legacy(self, req, id, body):
|
||||
"""Add share access rule."""
|
||||
return self._allow_access(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('allow_access')
|
||||
def allow_access(self, req, id, body):
|
||||
"""Add share access rule."""
|
||||
return self._allow_access(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.0', '2.6')
|
||||
@wsgi.action('os-deny_access')
|
||||
def deny_access_legacy(self, req, id, body):
|
||||
"""Remove share access rule."""
|
||||
return self._deny_access(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('deny_access')
|
||||
def deny_access(self, req, id, body):
|
||||
"""Remove share access rule."""
|
||||
return self._deny_access(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.0', '2.6')
|
||||
@wsgi.action('os-access_list')
|
||||
def access_list_legacy(self, req, id, body):
|
||||
"""List share access rules."""
|
||||
return self._access_list(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('access_list')
|
||||
def access_list(self, req, id, body):
|
||||
"""List share access rules."""
|
||||
return self._access_list(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.0', '2.6')
|
||||
@wsgi.action('os-extend')
|
||||
def extend_legacy(self, req, id, body):
|
||||
"""Extend size of a share."""
|
||||
return self._extend(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('extend')
|
||||
def extend(self, req, id, body):
|
||||
"""Extend size of a share."""
|
||||
return self._extend(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.0', '2.6')
|
||||
@wsgi.action('os-shrink')
|
||||
def shrink_legacy(self, req, id, body):
|
||||
"""Shrink size of a share."""
|
||||
return self._shrink(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('shrink')
|
||||
def shrink(self, req, id, body):
|
||||
"""Shrink size of a share."""
|
||||
return self._shrink(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
def manage(self, req, body):
|
||||
return self._manage(req, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
@wsgi.action('unmanage')
|
||||
def unmanage(self, req, id, body=None):
|
||||
return self._unmanage(req, id, body)
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(ShareController())
|
@ -21,6 +21,11 @@ class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
_collection_name = 'types'
|
||||
|
||||
_detail_version_modifiers = [
|
||||
"add_is_public_attr_core_api_like",
|
||||
"add_is_public_attr_extension_like",
|
||||
]
|
||||
|
||||
def show(self, request, share_type, brief=False):
|
||||
"""Trim away extraneous share type attributes."""
|
||||
|
||||
@ -38,16 +43,25 @@ class ViewBuilder(common.ViewBuilder):
|
||||
trimmed = {
|
||||
'id': share_type.get('id'),
|
||||
'name': share_type.get('name'),
|
||||
'os-share-type-access:is_public': share_type.get(
|
||||
'is_public', True),
|
||||
'extra_specs': extra_specs,
|
||||
'required_extra_specs': required_extra_specs,
|
||||
}
|
||||
self.update_versioned_resource_dict(request, trimmed, share_type)
|
||||
if brief:
|
||||
return trimmed
|
||||
else:
|
||||
return dict(volume_type=trimmed, share_type=trimmed)
|
||||
|
||||
@common.ViewBuilder.versioned_method("2.7")
|
||||
def add_is_public_attr_core_api_like(self, share_type_dict, share_type):
|
||||
share_type_dict['share_type_access:is_public'] = share_type.get(
|
||||
'is_public', True)
|
||||
|
||||
@common.ViewBuilder.versioned_method("1.0", "2.6")
|
||||
def add_is_public_attr_extension_like(self, share_type_dict, share_type):
|
||||
share_type_dict['os-share-type-access:is_public'] = share_type.get(
|
||||
'is_public', True)
|
||||
|
||||
def index(self, request, share_types):
|
||||
"""Index over trimmed share types."""
|
||||
share_types_list = [self.show(request, share_type, True)
|
||||
|
@ -28,7 +28,8 @@ from manila.api.openstack import api_version_request as api_version
|
||||
from manila.api.openstack import wsgi as os_wsgi
|
||||
from manila.api import urlmap
|
||||
from manila.api.v1 import limits
|
||||
from manila.api.v1 import router
|
||||
from manila.api.v1 import router as router_v1
|
||||
from manila.api.v2 import router as router_v2
|
||||
from manila.api import versions
|
||||
from manila.common import constants
|
||||
from manila import context
|
||||
@ -64,7 +65,7 @@ def fake_wsgi(self, req):
|
||||
def wsgi_app(inner_app_v2=None, fake_auth=True, fake_auth_context=None,
|
||||
use_no_auth=False, ext_mgr=None):
|
||||
if not inner_app_v2:
|
||||
inner_app_v2 = router.APIRouter(ext_mgr)
|
||||
inner_app_v2 = router_v2.APIRouter(ext_mgr)
|
||||
|
||||
if fake_auth:
|
||||
if fake_auth_context is not None:
|
||||
@ -174,28 +175,45 @@ def app():
|
||||
|
||||
No auth, just let environ['manila.context'] pass through.
|
||||
"""
|
||||
api = router.APIRouter()
|
||||
mapper = urlmap.URLMap()
|
||||
mapper['/v2'] = api
|
||||
mapper['/v1'] = api
|
||||
mapper['/v1'] = router_v1.APIRouter()
|
||||
mapper['/v2'] = router_v2.APIRouter()
|
||||
return mapper
|
||||
|
||||
|
||||
fixture_reset_status_with_different_roles = (
|
||||
{
|
||||
'role': 'admin', 'valid_code': 202,
|
||||
'role': 'admin',
|
||||
'valid_code': 202,
|
||||
'valid_status': constants.STATUS_ERROR,
|
||||
'version': '2.6',
|
||||
},
|
||||
{
|
||||
'role': 'member', 'valid_code': 403,
|
||||
'role': 'admin',
|
||||
'valid_code': 202,
|
||||
'valid_status': constants.STATUS_ERROR,
|
||||
'version': '2.7',
|
||||
},
|
||||
{
|
||||
'role': 'member',
|
||||
'valid_code': 403,
|
||||
'valid_status': constants.STATUS_AVAILABLE,
|
||||
'version': '2.6',
|
||||
},
|
||||
{
|
||||
'role': 'member',
|
||||
'valid_code': 403,
|
||||
'valid_status': constants.STATUS_AVAILABLE,
|
||||
'version': '2.7',
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
fixture_force_delete_with_different_roles = (
|
||||
{'role': 'admin', 'resp_code': 202},
|
||||
{'role': 'member', 'resp_code': 403},
|
||||
{'role': 'admin', 'resp_code': 202, 'version': '2.6'},
|
||||
{'role': 'admin', 'resp_code': 202, 'version': '2.7'},
|
||||
{'role': 'member', 'resp_code': 403, 'version': '2.6'},
|
||||
{'role': 'member', 'resp_code': 403, 'version': '2.7'},
|
||||
)
|
||||
|
||||
|
||||
|
@ -15,7 +15,6 @@ import mock
|
||||
from oslo_config import cfg
|
||||
from oslo_serialization import jsonutils
|
||||
import six
|
||||
import webob
|
||||
from webob import exc as webob_exc
|
||||
|
||||
from manila.api.v1 import share_instances
|
||||
@ -48,12 +47,13 @@ class ShareInstancesAPITest(test.TestCase):
|
||||
def _get_context(self, role):
|
||||
return getattr(self, '%s_context' % role)
|
||||
|
||||
def _setup_share_instance_data(self, instance=None):
|
||||
def _setup_share_instance_data(self, instance=None, version='2.7'):
|
||||
if instance is None:
|
||||
instance = db_utils.create_share(status=constants.STATUS_AVAILABLE,
|
||||
size='1').instance
|
||||
req = webob.Request.blank(
|
||||
'/v2/fake/share_instances/%s/action' % instance['id'])
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/v2/fake/share_instances/%s/action' % instance['id'],
|
||||
version=version)
|
||||
return instance, req
|
||||
|
||||
def _get_request(self, uri, context=None):
|
||||
@ -139,11 +139,16 @@ class ShareInstancesAPITest(test.TestCase):
|
||||
webob_exc.HTTPForbidden, target_method, req, *args)
|
||||
|
||||
def _reset_status(self, ctxt, model, req, db_access_method,
|
||||
valid_code, valid_status=None, body=None):
|
||||
valid_code, valid_status=None, body=None, version='2.7'):
|
||||
if float(version) > 2.6:
|
||||
action_name = 'reset_status'
|
||||
else:
|
||||
action_name = 'os-reset_status'
|
||||
if body is None:
|
||||
body = {'os-reset_status': {'status': constants.STATUS_ERROR}}
|
||||
body = {action_name: {'status': constants.STATUS_ERROR}}
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.headers['X-Openstack-Manila-Api-Version'] = version
|
||||
req.body = six.b(jsonutils.dumps(body))
|
||||
req.environ['manila.context'] = ctxt
|
||||
|
||||
@ -167,29 +172,40 @@ class ShareInstancesAPITest(test.TestCase):
|
||||
@ddt.unpack
|
||||
def test_share_instances_reset_status_with_different_roles(self, role,
|
||||
valid_code,
|
||||
valid_status):
|
||||
valid_status,
|
||||
version):
|
||||
ctxt = self._get_context(role)
|
||||
instance, req = self._setup_share_instance_data()
|
||||
req.headers['X-Openstack-Manila-Api-Version'] = '2.3'
|
||||
instance, req = self._setup_share_instance_data(version=version)
|
||||
|
||||
self._reset_status(ctxt, instance, req, db.share_instance_get,
|
||||
valid_code, valid_status)
|
||||
valid_code, valid_status, version=version)
|
||||
|
||||
@ddt.data(*fakes.fixture_invalid_reset_status_body)
|
||||
def test_share_instance_invalid_reset_status_body(self, body):
|
||||
@ddt.data(
|
||||
({'os-reset_status': {'x-status': 'bad'}}, '2.6'),
|
||||
({'os-reset_status': {'status': 'invalid'}}, '2.6'),
|
||||
({'reset_status': {'x-status': 'bad'}}, '2.7'),
|
||||
({'reset_status': {'status': 'invalid'}}, '2.7'),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_share_instance_invalid_reset_status_body(self, body, version):
|
||||
instance, req = self._setup_share_instance_data()
|
||||
req.headers['X-Openstack-Manila-Api-Version'] = '2.3'
|
||||
req.headers['X-Openstack-Manila-Api-Version'] = version
|
||||
|
||||
self._reset_status(self.admin_context, instance, req,
|
||||
db.share_instance_get, 400,
|
||||
constants.STATUS_AVAILABLE, body)
|
||||
constants.STATUS_AVAILABLE, body, version=version)
|
||||
|
||||
def _force_delete(self, ctxt, model, req, db_access_method, valid_code,
|
||||
check_model_in_db=False):
|
||||
check_model_in_db=False, version='2.7'):
|
||||
if float(version) > 2.6:
|
||||
action_name = 'force_delete'
|
||||
else:
|
||||
action_name = 'os-force_delete'
|
||||
body = {action_name: {'status': constants.STATUS_ERROR}}
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.headers['X-Openstack-Manila-Api-Version'] = '2.3'
|
||||
req.body = six.b(jsonutils.dumps({'os-force_delete': {}}))
|
||||
req.headers['X-Openstack-Manila-Api-Version'] = version
|
||||
req.body = six.b(jsonutils.dumps(body))
|
||||
req.environ['manila.context'] = ctxt
|
||||
|
||||
with mock.patch.object(
|
||||
@ -207,12 +223,13 @@ class ShareInstancesAPITest(test.TestCase):
|
||||
|
||||
@ddt.data(*fakes.fixture_force_delete_with_different_roles)
|
||||
@ddt.unpack
|
||||
def test_instance_force_delete_with_different_roles(self, role, resp_code):
|
||||
instance, req = self._setup_share_instance_data()
|
||||
def test_instance_force_delete_with_different_roles(self, role, resp_code,
|
||||
version):
|
||||
instance, req = self._setup_share_instance_data(version=version)
|
||||
ctxt = self._get_context(role)
|
||||
|
||||
self._force_delete(ctxt, instance, req, db.share_instance_get,
|
||||
resp_code)
|
||||
resp_code, version=version)
|
||||
|
||||
def test_instance_force_delete_missing(self):
|
||||
instance, req = self._setup_share_instance_data(
|
||||
|
@ -390,21 +390,26 @@ class ShareSnapshotAdminActionsAPITest(test.TestCase):
|
||||
def _get_context(self, role):
|
||||
return getattr(self, '%s_context' % role)
|
||||
|
||||
def _setup_snapshot_data(self, snapshot=None):
|
||||
def _setup_snapshot_data(self, snapshot=None, version='2.7'):
|
||||
if snapshot is None:
|
||||
share = db_utils.create_share()
|
||||
snapshot = db_utils.create_snapshot(
|
||||
status=constants.STATUS_AVAILABLE, share_id=share['id'])
|
||||
req = webob.Request.blank('/v2/fake/snapshots/%s/action' %
|
||||
snapshot['id'])
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/snapshots/%s/action' %
|
||||
snapshot['id'], version=version)
|
||||
return snapshot, req
|
||||
|
||||
def _reset_status(self, ctxt, model, req, db_access_method,
|
||||
valid_code, valid_status=None, body=None):
|
||||
valid_code, valid_status=None, body=None, version='2.7'):
|
||||
if float(version) > 2.6:
|
||||
action_name = 'reset_status'
|
||||
else:
|
||||
action_name = 'os-reset_status'
|
||||
if body is None:
|
||||
body = {'os-reset_status': {'status': constants.STATUS_ERROR}}
|
||||
body = {action_name: {'status': constants.STATUS_ERROR}}
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.headers['X-Openstack-Manila-Api-Version'] = version
|
||||
req.body = six.b(jsonutils.dumps(body))
|
||||
req.environ['manila.context'] = ctxt
|
||||
|
||||
@ -425,25 +430,37 @@ class ShareSnapshotAdminActionsAPITest(test.TestCase):
|
||||
@ddt.data(*fakes.fixture_reset_status_with_different_roles)
|
||||
@ddt.unpack
|
||||
def test_snapshot_reset_status_with_different_roles(self, role, valid_code,
|
||||
valid_status):
|
||||
valid_status, version):
|
||||
ctxt = self._get_context(role)
|
||||
snapshot, req = self._setup_snapshot_data()
|
||||
snapshot, req = self._setup_snapshot_data(version=version)
|
||||
|
||||
self._reset_status(ctxt, snapshot, req, db.share_snapshot_get,
|
||||
valid_code, valid_status)
|
||||
valid_code, valid_status, version=version)
|
||||
|
||||
@ddt.data(*fakes.fixture_invalid_reset_status_body)
|
||||
def test_snapshot_invalid_reset_status_body(self, body):
|
||||
snapshot, req = self._setup_snapshot_data()
|
||||
@ddt.data(
|
||||
({'os-reset_status': {'x-status': 'bad'}}, '2.6'),
|
||||
({'reset_status': {'x-status': 'bad'}}, '2.7'),
|
||||
({'os-reset_status': {'status': 'invalid'}}, '2.6'),
|
||||
({'reset_status': {'status': 'invalid'}}, '2.7'),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_snapshot_invalid_reset_status_body(self, body, version):
|
||||
snapshot, req = self._setup_snapshot_data(version=version)
|
||||
|
||||
self._reset_status(self.admin_context, snapshot, req,
|
||||
db.share_snapshot_get, 400,
|
||||
constants.STATUS_AVAILABLE, body)
|
||||
constants.STATUS_AVAILABLE, body, version=version)
|
||||
|
||||
def _force_delete(self, ctxt, model, req, db_access_method, valid_code):
|
||||
def _force_delete(self, ctxt, model, req, db_access_method, valid_code,
|
||||
version='2.7'):
|
||||
if float(version) > 2.6:
|
||||
action_name = 'force_delete'
|
||||
else:
|
||||
action_name = 'os-force_delete'
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.body = six.b(jsonutils.dumps({'os-force_delete': {}}))
|
||||
req.headers['X-Openstack-Manila-Api-Version'] = version
|
||||
req.body = six.b(jsonutils.dumps({action_name: {}}))
|
||||
req.environ['manila.context'] = ctxt
|
||||
|
||||
resp = req.get_response(fakes.app())
|
||||
@ -453,12 +470,13 @@ class ShareSnapshotAdminActionsAPITest(test.TestCase):
|
||||
|
||||
@ddt.data(*fakes.fixture_force_delete_with_different_roles)
|
||||
@ddt.unpack
|
||||
def test_snapshot_force_delete_with_different_roles(self, role, resp_code):
|
||||
def test_snapshot_force_delete_with_different_roles(self, role, resp_code,
|
||||
version):
|
||||
ctxt = self._get_context(role)
|
||||
snapshot, req = self._setup_snapshot_data()
|
||||
snapshot, req = self._setup_snapshot_data(version=version)
|
||||
|
||||
self._force_delete(ctxt, snapshot, req, db.share_snapshot_get,
|
||||
resp_code)
|
||||
resp_code, version=version)
|
||||
|
||||
def test_snapshot_force_delete_missing(self):
|
||||
ctxt = self._get_context('admin')
|
||||
|
@ -41,14 +41,6 @@ from manila import utils
|
||||
CONF = cfg.CONF
|
||||
|
||||
|
||||
def app():
|
||||
# no auth, just let environ['manila.context'] pass through
|
||||
api = fakes.router.APIRouter()
|
||||
mapper = fakes.urlmap.URLMap()
|
||||
mapper['/v1'] = api
|
||||
return mapper
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareAPITest(test.TestCase):
|
||||
"""Share API Test."""
|
||||
@ -230,62 +222,6 @@ class ShareAPITest(test.TestCase):
|
||||
self.assertEqual("fakenetid",
|
||||
create_mock.call_args[1]['share_network_id'])
|
||||
|
||||
def test_migrate_share(self):
|
||||
share = db_utils.create_share()
|
||||
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
|
||||
use_admin_context=True)
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.api_version_request = api_version.APIVersionRequest('2.5')
|
||||
req.api_version_request.experimental = True
|
||||
body = {'os-migrate_share': {'host': 'fake_host'}}
|
||||
self.mock_object(share_api.API, 'migrate_share')
|
||||
self.controller.migrate_share(req, share['id'], body)
|
||||
|
||||
def test_migrate_share_no_share_id(self):
|
||||
req = fakes.HTTPRequest.blank('/shares/%s/action' % 'fake_id',
|
||||
use_admin_context=True)
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.api_version_request = api_version.APIVersionRequest('2.5')
|
||||
req.api_version_request.experimental = True
|
||||
body = {'os-migrate_share': {'host': 'fake_host'}}
|
||||
self.mock_object(share_api.API, 'migrate_share')
|
||||
self.mock_object(share_api.API, 'get',
|
||||
mock.Mock(side_effect=[exception.NotFound]))
|
||||
self.assertRaises(webob.exc.HTTPNotFound,
|
||||
self.controller.migrate_share,
|
||||
req, 'fake_id', body)
|
||||
|
||||
def test_migrate_share_no_host(self):
|
||||
share = db_utils.create_share()
|
||||
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
|
||||
use_admin_context=True)
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.api_version_request = api_version.APIVersionRequest('2.5')
|
||||
req.api_version_request.experimental = True
|
||||
body = {'os-migrate_share': {}}
|
||||
self.mock_object(share_api.API, 'migrate_share')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.migrate_share,
|
||||
req, share['id'], body)
|
||||
|
||||
def test_migrate_share_no_host_invalid_force_host_copy(self):
|
||||
share = db_utils.create_share()
|
||||
req = fakes.HTTPRequest.blank('/shares/%s/action' % share['id'],
|
||||
use_admin_context=True)
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.api_version_request = api_version.APIVersionRequest('2.5')
|
||||
req.api_version_request.experimental = True
|
||||
body = {'os-migrate_share': {'host': 'fake_host',
|
||||
'force_host_copy': 'fake'}}
|
||||
self.mock_object(share_api.API, 'migrate_share')
|
||||
self.assertRaises(webob.exc.HTTPBadRequest,
|
||||
self.controller.migrate_share,
|
||||
req, share['id'], body)
|
||||
|
||||
def test_share_create_from_snapshot_without_share_net_no_parent(self):
|
||||
shr = {
|
||||
"size": 100,
|
||||
@ -1059,6 +995,27 @@ class ShareAdminActionsAPITest(test.TestCase):
|
||||
actual_model = db_access_method(ctxt, model['id'])
|
||||
self.assertEqual(valid_status, actual_model['status'])
|
||||
|
||||
@ddt.data(
|
||||
{
|
||||
'role': 'admin',
|
||||
'valid_code': 202,
|
||||
'valid_status': constants.STATUS_ERROR,
|
||||
},
|
||||
{
|
||||
'role': 'member',
|
||||
'valid_code': 403,
|
||||
'valid_status': constants.STATUS_AVAILABLE,
|
||||
},
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_share_reset_status_with_different_roles(self, role, valid_code,
|
||||
valid_status):
|
||||
share, req = self._setup_share_data()
|
||||
ctxt = self._get_context(role)
|
||||
|
||||
self._reset_status(ctxt, share, req, db.share_get, valid_code,
|
||||
valid_status)
|
||||
|
||||
@ddt.data(*fakes.fixture_invalid_reset_status_body)
|
||||
def test_share_invalid_reset_status_body(self, body):
|
||||
share, req = self._setup_share_data()
|
||||
@ -1093,17 +1050,10 @@ class ShareAdminActionsAPITest(test.TestCase):
|
||||
ctxt,
|
||||
model['id'])
|
||||
|
||||
@ddt.data(*fakes.fixture_reset_status_with_different_roles)
|
||||
@ddt.unpack
|
||||
def test_share_reset_status_with_different_roles(self, role, valid_code,
|
||||
valid_status):
|
||||
share, req = self._setup_share_data()
|
||||
ctxt = self._get_context(role)
|
||||
|
||||
self._reset_status(ctxt, share, req, db.share_get, valid_code,
|
||||
valid_status)
|
||||
|
||||
@ddt.data(*fakes.fixture_force_delete_with_different_roles)
|
||||
@ddt.data(
|
||||
{'role': 'admin', 'resp_code': 202},
|
||||
{'role': 'member', 'resp_code': 403},
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_share_force_delete_with_different_roles(self, role, resp_code):
|
||||
share, req = self._setup_share_data()
|
||||
|
0
manila/tests/api/v2/__init__.py
Normal file
0
manila/tests/api/v2/__init__.py
Normal file
@ -15,8 +15,9 @@
|
||||
import ddt
|
||||
import mock
|
||||
|
||||
from manila.api.v1 import availability_zones
|
||||
from manila.api.v2 import availability_zones
|
||||
from manila import context
|
||||
from manila import exception
|
||||
from manila import policy
|
||||
from manila import test
|
||||
from manila.tests.api import fakes
|
||||
@ -25,16 +26,26 @@ from manila.tests.api import fakes
|
||||
@ddt.ddt
|
||||
class AvailabilityZonesAPITest(test.TestCase):
|
||||
|
||||
def test_instantiate_controller(self):
|
||||
controller = availability_zones.AvailabilityZoneController()
|
||||
@ddt.data(
|
||||
availability_zones.AvailabilityZoneControllerLegacy,
|
||||
availability_zones.AvailabilityZoneController,
|
||||
)
|
||||
def test_instantiate_controller(self, controller):
|
||||
az_controller = controller()
|
||||
|
||||
self.assertTrue(hasattr(controller, "resource_name"))
|
||||
self.assertEqual("availability_zone", controller.resource_name)
|
||||
self.assertTrue(hasattr(controller, "_view_builder"))
|
||||
self.assertTrue(hasattr(controller._view_builder, "detail_list"))
|
||||
self.assertTrue(hasattr(az_controller, "resource_name"))
|
||||
self.assertEqual("availability_zone", az_controller.resource_name)
|
||||
self.assertTrue(hasattr(az_controller, "_view_builder"))
|
||||
self.assertTrue(hasattr(az_controller._view_builder, "detail_list"))
|
||||
|
||||
@ddt.data('1.0', '2.0', '2.6')
|
||||
def test_index(self, version):
|
||||
@ddt.data(
|
||||
('1.0', availability_zones.AvailabilityZoneControllerLegacy),
|
||||
('2.0', availability_zones.AvailabilityZoneControllerLegacy),
|
||||
('2.6', availability_zones.AvailabilityZoneControllerLegacy),
|
||||
('2.7', availability_zones.AvailabilityZoneController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_index(self, version, controller):
|
||||
azs = [
|
||||
{
|
||||
"id": "fake_id1",
|
||||
@ -54,12 +65,12 @@ class AvailabilityZonesAPITest(test.TestCase):
|
||||
mock_policy_check = self.mock_object(policy, 'check_policy')
|
||||
self.mock_object(availability_zones.db, 'availability_zone_get_all',
|
||||
mock.Mock(return_value=azs))
|
||||
controller = availability_zones.AvailabilityZoneController()
|
||||
az_controller = controller()
|
||||
ctxt = context.RequestContext("admin", "fake", True)
|
||||
req = fakes.HTTPRequest.blank('/shares', version=version)
|
||||
req.environ['manila.context'] = ctxt
|
||||
|
||||
result = controller.index(req)
|
||||
result = az_controller.index(req)
|
||||
|
||||
availability_zones.db.availability_zone_get_all.\
|
||||
assert_called_once_with(ctxt)
|
||||
@ -73,3 +84,19 @@ class AvailabilityZonesAPITest(test.TestCase):
|
||||
azs[1].pop("deleted")
|
||||
azs[1].pop("redundant_key")
|
||||
self.assertTrue(azs[1] in result["availability_zones"])
|
||||
|
||||
@ddt.data(
|
||||
('1.0', availability_zones.AvailabilityZoneController),
|
||||
('2.0', availability_zones.AvailabilityZoneController),
|
||||
('2.6', availability_zones.AvailabilityZoneController),
|
||||
('2.7', availability_zones.AvailabilityZoneControllerLegacy),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_index_with_unsupported_versions(self, version, controller):
|
||||
ctxt = context.RequestContext("admin", "fake", True)
|
||||
req = fakes.HTTPRequest.blank('/shares', version=version)
|
||||
req.environ['manila.context'] = ctxt
|
||||
az_controller = controller()
|
||||
|
||||
self.assertRaises(
|
||||
exception.VersionNotFoundForAPIMethod, az_controller.index, req)
|
@ -25,7 +25,7 @@ import six
|
||||
import webob
|
||||
|
||||
from manila.api.openstack import wsgi
|
||||
import manila.api.v1.cgsnapshots as cgs
|
||||
import manila.api.v2.cgsnapshots as cgs
|
||||
from manila.common import constants
|
||||
from manila import context
|
||||
from manila import db
|
||||
@ -518,25 +518,31 @@ class CGSnapshotApiTest(test.TestCase):
|
||||
def _get_context(self, role):
|
||||
return getattr(self, '%s_context' % role)
|
||||
|
||||
def _setup_cgsnapshot_data(self, cgsnapshot=None):
|
||||
def _setup_cgsnapshot_data(self, cgsnapshot=None, version='2.7'):
|
||||
if cgsnapshot is None:
|
||||
cgsnapshot = db_utils.create_cgsnapshot(
|
||||
'fake_id', status=constants.STATUS_AVAILABLE)
|
||||
req = webob.Request.blank('/v2/fake/cgsnapshots/%s/action' %
|
||||
cgsnapshot['id'])
|
||||
req.headers[wsgi.API_VERSION_REQUEST_HEADER] = '2.4'
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/cgsnapshots/%s/action' %
|
||||
cgsnapshot['id'], version=version)
|
||||
req.headers[wsgi.API_VERSION_REQUEST_HEADER] = version
|
||||
req.headers[wsgi.EXPERIMENTAL_API_REQUEST_HEADER] = 'True'
|
||||
return cgsnapshot, req
|
||||
|
||||
@ddt.data(*fakes.fixture_force_delete_with_different_roles)
|
||||
@ddt.unpack
|
||||
def test_cgsnapshot_force_delete_with_different_roles(self, role,
|
||||
resp_code):
|
||||
resp_code, version):
|
||||
cgsnap, req = self._setup_cgsnapshot_data()
|
||||
ctxt = self._get_context(role)
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.body = six.b(jsonutils.dumps({'os-force_delete': {}}))
|
||||
if float(version) > 2.6:
|
||||
action_name = 'force_delete'
|
||||
else:
|
||||
action_name = 'os-force_delete'
|
||||
body = {action_name: {'status': constants.STATUS_ERROR}}
|
||||
req.body = six.b(jsonutils.dumps(body))
|
||||
req.headers['X-Openstack-Manila-Api-Version'] = version
|
||||
req.environ['manila.context'] = ctxt
|
||||
|
||||
with mock.patch.object(
|
||||
@ -549,13 +555,18 @@ class CGSnapshotApiTest(test.TestCase):
|
||||
@ddt.data(*fakes.fixture_reset_status_with_different_roles)
|
||||
@ddt.unpack
|
||||
def test_cgsnapshot_reset_status_with_different_roles(
|
||||
self, role, valid_code, valid_status):
|
||||
self, role, valid_code, valid_status, version):
|
||||
ctxt = self._get_context(role)
|
||||
cgsnap, req = self._setup_cgsnapshot_data()
|
||||
body = {'os-reset_status': {'status': constants.STATUS_ERROR}}
|
||||
cgsnap, req = self._setup_cgsnapshot_data(version=version)
|
||||
if float(version) > 2.6:
|
||||
action_name = 'reset_status'
|
||||
else:
|
||||
action_name = 'os-reset_status'
|
||||
body = {action_name: {'status': constants.STATUS_ERROR}}
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.body = six.b(jsonutils.dumps(body))
|
||||
req.headers['X-Openstack-Manila-Api-Version'] = version
|
||||
req.environ['manila.context'] = ctxt
|
||||
|
||||
with mock.patch.object(
|
@ -25,7 +25,7 @@ import six
|
||||
import webob
|
||||
|
||||
from manila.api.openstack import wsgi
|
||||
import manila.api.v1.consistency_groups as cgs
|
||||
import manila.api.v2.consistency_groups as cgs
|
||||
from manila.common import constants
|
||||
import manila.consistency_group.api as cg_api
|
||||
from manila import context
|
||||
@ -64,13 +64,13 @@ class CGApiTest(test.TestCase):
|
||||
def _get_context(self, role):
|
||||
return getattr(self, '%s_context' % role)
|
||||
|
||||
def _setup_cg_data(self, cg=None):
|
||||
def _setup_cg_data(self, cg=None, version='2.7'):
|
||||
if cg is None:
|
||||
cg = db_utils.create_consistency_group(
|
||||
status=constants.STATUS_AVAILABLE)
|
||||
req = webob.Request.blank('/v2/fake/consistency-groups/%s/action' %
|
||||
cg['id'])
|
||||
req.headers[wsgi.API_VERSION_REQUEST_HEADER] = '2.4'
|
||||
req = fakes.HTTPRequest.blank('/v2/fake/consistency-groups/%s/action' %
|
||||
cg['id'], version=version)
|
||||
req.headers[wsgi.API_VERSION_REQUEST_HEADER] = version
|
||||
req.headers[wsgi.EXPERIMENTAL_API_REQUEST_HEADER] = 'True'
|
||||
|
||||
return cg, req
|
||||
@ -629,14 +629,19 @@ class CGApiTest(test.TestCase):
|
||||
@ddt.data(*fakes.fixture_reset_status_with_different_roles)
|
||||
@ddt.unpack
|
||||
def test_consistency_groups_reset_status_with_different_roles(
|
||||
self, role, valid_code, valid_status):
|
||||
self, role, valid_code, valid_status, version):
|
||||
ctxt = self._get_context(role)
|
||||
cg, req = self._setup_cg_data()
|
||||
cg, req = self._setup_cg_data(version=version)
|
||||
|
||||
body = {'os-reset_status': {'status': constants.STATUS_ERROR}}
|
||||
if float(version) > 2.6:
|
||||
action_name = 'reset_status'
|
||||
else:
|
||||
action_name = 'os-reset_status'
|
||||
body = {action_name: {'status': constants.STATUS_ERROR}}
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.body = six.b(jsonutils.dumps(body))
|
||||
req.headers['X-Openstack-Manila-Api-Version'] = version
|
||||
req.environ['manila.context'] = ctxt
|
||||
|
||||
with mock.patch.object(
|
||||
@ -658,12 +663,18 @@ class CGApiTest(test.TestCase):
|
||||
@ddt.data(*fakes.fixture_force_delete_with_different_roles)
|
||||
@ddt.unpack
|
||||
def test_consistency_group_force_delete_with_different_roles(self, role,
|
||||
resp_code):
|
||||
resp_code,
|
||||
version):
|
||||
ctxt = self._get_context(role)
|
||||
cg, req = self._setup_cg_data()
|
||||
cg, req = self._setup_cg_data(version=version)
|
||||
req.method = 'POST'
|
||||
req.headers['content-type'] = 'application/json'
|
||||
req.body = six.b(jsonutils.dumps({'os-force_delete': {}}))
|
||||
if float(version) > 2.6:
|
||||
action_name = 'force_delete'
|
||||
else:
|
||||
action_name = 'os-force_delete'
|
||||
body = {action_name: {}}
|
||||
req.body = six.b(jsonutils.dumps(body))
|
||||
req.environ['manila.context'] = ctxt
|
||||
|
||||
with mock.patch.object(
|
@ -26,11 +26,12 @@ from oslo_config import cfg
|
||||
import webob.exc
|
||||
import webob.response
|
||||
|
||||
from manila.api.v1 import quota_class_sets
|
||||
from manila.api.v2 import quota_class_sets
|
||||
from manila import context
|
||||
from manila import exception
|
||||
from manila import policy
|
||||
from manila import test
|
||||
from manila.tests.api import fakes
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
@ -55,7 +56,16 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
self.mock_policy_check = self.mock_object(
|
||||
policy, 'check_policy', mock.Mock(return_value=True))
|
||||
|
||||
def test_show_quota(self):
|
||||
@ddt.data(
|
||||
('os-', '1.0', quota_class_sets.QuotaClassSetsControllerLegacy),
|
||||
('os-', '2.6', quota_class_sets.QuotaClassSetsControllerLegacy),
|
||||
('', '2.7', quota_class_sets.QuotaClassSetsController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_show_quota(self, url, version, controller):
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/fooproject/%squota-class-sets' % url,
|
||||
version=version, use_admin_context=True)
|
||||
quotas = {
|
||||
"shares": 23,
|
||||
"snapshots": 34,
|
||||
@ -76,11 +86,11 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
for k, v in quotas.items():
|
||||
CONF.set_default('quota_' + k, v)
|
||||
|
||||
result = self.controller.show(REQ, self.class_name)
|
||||
result = controller().show(req, self.class_name)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ.environ['manila.context'], self.resource_name, 'show')
|
||||
req.environ['manila.context'], self.resource_name, 'show')
|
||||
|
||||
def test_show_quota_not_authorized(self):
|
||||
self.mock_object(
|
||||
@ -95,7 +105,16 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ.environ['manila.context'], self.resource_name, 'show')
|
||||
|
||||
def test_update_quota(self):
|
||||
@ddt.data(
|
||||
('os-', '1.0', quota_class_sets.QuotaClassSetsControllerLegacy),
|
||||
('os-', '2.6', quota_class_sets.QuotaClassSetsControllerLegacy),
|
||||
('', '2.7', quota_class_sets.QuotaClassSetsController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_update_quota(self, url, version, controller):
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/fooproject/%squota-class-sets' % url,
|
||||
version=version, use_admin_context=True)
|
||||
CONF.set_default('quota_shares', 789)
|
||||
body = {
|
||||
'quota_class_set': {
|
||||
@ -113,17 +132,17 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
}
|
||||
}
|
||||
|
||||
update_result = self.controller.update(
|
||||
REQ, self.class_name, body=body)
|
||||
update_result = controller().update(
|
||||
req, self.class_name, body=body)
|
||||
|
||||
self.assertEqual(expected, update_result)
|
||||
|
||||
show_result = self.controller.show(REQ, self.class_name)
|
||||
show_result = controller().show(req, self.class_name)
|
||||
|
||||
expected['quota_class_set']['id'] = self.class_name
|
||||
self.assertEqual(expected, show_result)
|
||||
self.mock_policy_check.assert_has_calls([mock.call(
|
||||
REQ.environ['manila.context'], self.resource_name, action_name)
|
||||
req.environ['manila.context'], self.resource_name, action_name)
|
||||
for action_name in ('update', 'show')])
|
||||
|
||||
def test_update_quota_not_authorized(self):
|
||||
@ -140,3 +159,32 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
REQ_MEMBER, self.class_name, body=body)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ_MEMBER.environ['manila.context'], self.resource_name, 'update')
|
||||
|
||||
@ddt.data(
|
||||
('os-', '2.7', quota_class_sets.QuotaClassSetsControllerLegacy),
|
||||
('', '2.6', quota_class_sets.QuotaClassSetsController),
|
||||
('', '2.0', quota_class_sets.QuotaClassSetsController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_api_not_found(self, url, version, controller):
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/fooproject/%squota-class-sets' % url, version=version)
|
||||
for method_name in ('show', 'update'):
|
||||
self.assertRaises(
|
||||
exception.VersionNotFoundForAPIMethod,
|
||||
getattr(controller(), method_name),
|
||||
req, self.class_name)
|
||||
|
||||
@ddt.data(
|
||||
('os-', '2.7', quota_class_sets.QuotaClassSetsControllerLegacy),
|
||||
('', '2.6', quota_class_sets.QuotaClassSetsController),
|
||||
('', '2.0', quota_class_sets.QuotaClassSetsController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_update_api_not_found(self, url, version, controller):
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/fooproject/%squota-class-sets' % url, version=version)
|
||||
self.assertRaises(
|
||||
exception.VersionNotFoundForAPIMethod,
|
||||
controller().update,
|
||||
req, self.class_name)
|
@ -26,11 +26,12 @@ from oslo_config import cfg
|
||||
import webob.exc
|
||||
import webob.response
|
||||
|
||||
from manila.api.v1 import quota_sets
|
||||
from manila.api.v2 import quota_sets
|
||||
from manila import context
|
||||
from manila import exception
|
||||
from manila import policy
|
||||
from manila import test
|
||||
from manila.tests.api import fakes
|
||||
from manila import utils
|
||||
|
||||
CONF = cfg.CONF
|
||||
@ -91,6 +92,35 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ.environ['manila.context'], self.resource_name, 'show')
|
||||
|
||||
@ddt.data(
|
||||
('os-', '1.0', quota_sets.QuotaSetsControllerLegacy, 'defaults'),
|
||||
('os-', '2.6', quota_sets.QuotaSetsControllerLegacy, 'defaults'),
|
||||
('', '2.7', quota_sets.QuotaSetsController, 'defaults'),
|
||||
('os-', '1.0', quota_sets.QuotaSetsControllerLegacy, 'show'),
|
||||
('os-', '2.6', quota_sets.QuotaSetsControllerLegacy, 'show'),
|
||||
('', '2.7', quota_sets.QuotaSetsController, 'show'),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_get_quotas_with_different_api_versions(self, url, version,
|
||||
controller, method_name):
|
||||
expected = {
|
||||
'quota_set': {
|
||||
'id': self.project_id,
|
||||
'shares': 50,
|
||||
'gigabytes': 1000,
|
||||
'snapshots': 50,
|
||||
'snapshot_gigabytes': 1000,
|
||||
'share_networks': 10,
|
||||
}
|
||||
}
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/fooproject/%squota-sets' % url,
|
||||
version=version, use_admin_context=True)
|
||||
|
||||
result = getattr(controller(), method_name)(req, self.project_id)
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
@ddt.data(REQ, REQ_WITH_USER)
|
||||
def test_show_quota(self, request):
|
||||
quotas = {
|
||||
@ -216,7 +246,15 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ_MEMBER.environ['manila.context'], self.resource_name, 'update')
|
||||
|
||||
def test_update_all_quotas_with_force(self):
|
||||
@ddt.data(
|
||||
('os-quota-sets', '1.0', quota_sets.QuotaSetsControllerLegacy),
|
||||
('os-quota-sets', '2.6', quota_sets.QuotaSetsControllerLegacy),
|
||||
('quota-sets', '2.7', quota_sets.QuotaSetsController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_update_all_quotas_with_force(self, url, version, controller):
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/fooproject/%s' % url, version=version, use_admin_context=True)
|
||||
quotas = (
|
||||
('quota_shares', 13),
|
||||
('quota_gigabytes', 14),
|
||||
@ -237,30 +275,37 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
'force': True,
|
||||
}
|
||||
}
|
||||
mock_policy_update_check_call = mock.call(
|
||||
REQ.environ['manila.context'], self.resource_name, 'update')
|
||||
mock_policy_show_check_call = mock.call(
|
||||
REQ.environ['manila.context'], self.resource_name, 'show')
|
||||
|
||||
update_result = self.controller.update(
|
||||
REQ, self.project_id, body=expected)
|
||||
update_result = controller().update(
|
||||
req, self.project_id, body=expected)
|
||||
|
||||
expected['quota_set'].pop('force')
|
||||
expected['quota_set'].pop('tenant_id')
|
||||
self.assertEqual(expected, update_result)
|
||||
|
||||
show_result = self.controller.show(REQ, self.project_id)
|
||||
show_result = controller().show(req, self.project_id)
|
||||
|
||||
expected['quota_set']['id'] = self.project_id
|
||||
self.assertEqual(expected, show_result)
|
||||
self.mock_policy_check.assert_has_calls([
|
||||
mock_policy_update_check_call, mock_policy_show_check_call])
|
||||
mock.call(req.environ['manila.context'],
|
||||
self.resource_name, action)
|
||||
for action in ('update', 'show')
|
||||
])
|
||||
|
||||
def test_delete_tenant_quota(self):
|
||||
@ddt.data(
|
||||
('os-quota-sets', '1.0', quota_sets.QuotaSetsControllerLegacy),
|
||||
('os-quota-sets', '2.6', quota_sets.QuotaSetsControllerLegacy),
|
||||
('quota-sets', '2.7', quota_sets.QuotaSetsController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_delete_tenant_quota(self, url, version, controller):
|
||||
self.mock_object(quota_sets.QUOTAS, 'destroy_all_by_project_and_user')
|
||||
self.mock_object(quota_sets.QUOTAS, 'destroy_all_by_project')
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/fooproject/%s' % url, version=version, use_admin_context=True)
|
||||
|
||||
result = self.controller.delete(REQ, self.project_id)
|
||||
result = controller().delete(req, self.project_id)
|
||||
|
||||
self.assertTrue(
|
||||
utils.IsAMatcher(webob.response.Response) == result
|
||||
@ -270,9 +315,9 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
self.assertFalse(
|
||||
quota_sets.QUOTAS.destroy_all_by_project_and_user.called)
|
||||
quota_sets.QUOTAS.destroy_all_by_project.assert_called_once_with(
|
||||
REQ.environ['manila.context'], self.project_id)
|
||||
req.environ['manila.context'], self.project_id)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ.environ['manila.context'], self.resource_name, 'delete')
|
||||
req.environ['manila.context'], self.resource_name, 'delete')
|
||||
|
||||
def test_delete_user_quota(self):
|
||||
project_id = 'foo_project_id'
|
||||
@ -303,3 +348,30 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
REQ_MEMBER, self.project_id)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ_MEMBER.environ['manila.context'], self.resource_name, 'delete')
|
||||
|
||||
@ddt.data(
|
||||
('os-quota-sets', '2.7', quota_sets.QuotaSetsControllerLegacy),
|
||||
('quota-sets', '2.6', quota_sets.QuotaSetsController),
|
||||
('quota-sets', '2.0', quota_sets.QuotaSetsController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_api_not_found(self, url, version, controller):
|
||||
req = fakes.HTTPRequest.blank('/fooproject/%s' % url, version=version)
|
||||
for method_name in ('show', 'defaults', 'delete'):
|
||||
self.assertRaises(
|
||||
exception.VersionNotFoundForAPIMethod,
|
||||
getattr(controller(), method_name),
|
||||
req, self.project_id)
|
||||
|
||||
@ddt.data(
|
||||
('os-quota-sets', '2.7', quota_sets.QuotaSetsControllerLegacy),
|
||||
('quota-sets', '2.6', quota_sets.QuotaSetsController),
|
||||
('quota-sets', '2.0', quota_sets.QuotaSetsController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_update_api_not_found(self, url, version, controller):
|
||||
req = fakes.HTTPRequest.blank('/fooproject/%s' % url, version=version)
|
||||
self.assertRaises(
|
||||
exception.VersionNotFoundForAPIMethod,
|
||||
controller().update,
|
||||
req, self.project_id)
|
@ -17,10 +17,11 @@
|
||||
|
||||
import datetime
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from manila.api.v1 import services
|
||||
from manila.api.v2 import services
|
||||
from manila import context
|
||||
from manila import db
|
||||
from manila import exception
|
||||
@ -106,41 +107,6 @@ fake_response_service_list = {'services': [
|
||||
]}
|
||||
|
||||
|
||||
class FakeRequest(object):
|
||||
environ = {"manila.context": context.get_admin_context()}
|
||||
GET = {}
|
||||
|
||||
|
||||
class FakeRequestWithBinary(object):
|
||||
environ = {"manila.context": context.get_admin_context()}
|
||||
GET = {"binary": "manila-share"}
|
||||
|
||||
|
||||
class FakeRequestWithHost(object):
|
||||
environ = {"manila.context": context.get_admin_context()}
|
||||
GET = {"host": "host1"}
|
||||
|
||||
|
||||
class FakeRequestWithZone(object):
|
||||
environ = {"manila.context": context.get_admin_context()}
|
||||
GET = {"zone": "manila1"}
|
||||
|
||||
|
||||
class FakeRequestWithStatus(object):
|
||||
environ = {"manila.context": context.get_admin_context()}
|
||||
GET = {"status": "enabled"}
|
||||
|
||||
|
||||
class FakeRequestWithState(object):
|
||||
environ = {"manila.context": context.get_admin_context()}
|
||||
GET = {"state": "up"}
|
||||
|
||||
|
||||
class FakeRequestWithHostBinary(object):
|
||||
environ = {"manila.context": context.get_admin_context()}
|
||||
GET = {"host": "host1", "binary": "manila-share"}
|
||||
|
||||
|
||||
def fake_service_get_all(context):
|
||||
return fake_services_list
|
||||
|
||||
@ -172,10 +138,11 @@ def fake_utcnow():
|
||||
return datetime.datetime(2012, 10, 29, 13, 42, 11)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ServicesTest(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ServicesTest, self).setUp()
|
||||
super(self.__class__, self).setUp()
|
||||
|
||||
self.mock_object(db, "service_get_all", fake_service_get_all)
|
||||
self.mock_object(timeutils, "utcnow", fake_utcnow)
|
||||
@ -184,22 +151,31 @@ class ServicesTest(test.TestCase):
|
||||
self.mock_object(db, "service_update", fake_service_update)
|
||||
self.context = context.get_admin_context()
|
||||
self.controller = services.ServiceController()
|
||||
self.controller_legacy = services.ServiceControllerLegacy()
|
||||
self.resource_name = self.controller.resource_name
|
||||
self.mock_policy_check = self.mock_object(
|
||||
policy, 'check_policy', mock.Mock(return_value=True))
|
||||
|
||||
def tearDown(self):
|
||||
super(ServicesTest, self).tearDown()
|
||||
@ddt.data(
|
||||
('os-services', '1.0', services.ServiceControllerLegacy),
|
||||
('os-services', '2.6', services.ServiceControllerLegacy),
|
||||
('services', '2.7', services.ServiceController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_services_list(self, url, version, controller):
|
||||
req = fakes.HTTPRequest.blank('/%s' % url, version=version)
|
||||
req.environ['manila.context'] = self.context
|
||||
|
||||
res_dict = controller().index(req)
|
||||
|
||||
def test_services_list(self):
|
||||
req = FakeRequest()
|
||||
res_dict = self.controller.index(req)
|
||||
self.assertEqual(fake_response_service_list, res_dict)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
req.environ['manila.context'], self.resource_name, 'index')
|
||||
|
||||
def test_services_list_with_host(self):
|
||||
req = FakeRequestWithHost()
|
||||
req = fakes.HTTPRequest.blank('/services?host=host1', version='2.7')
|
||||
req.environ['manila.context'] = self.context
|
||||
|
||||
res_dict = self.controller.index(req)
|
||||
|
||||
response = {'services': [
|
||||
@ -211,8 +187,12 @@ class ServicesTest(test.TestCase):
|
||||
req.environ['manila.context'], self.resource_name, 'index')
|
||||
|
||||
def test_services_list_with_binary(self):
|
||||
req = FakeRequestWithBinary()
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/services?binary=manila-share', version='2.7')
|
||||
req.environ['manila.context'] = self.context
|
||||
|
||||
res_dict = self.controller.index(req)
|
||||
|
||||
response = {'services': [
|
||||
fake_response_service_list['services'][1],
|
||||
fake_response_service_list['services'][3],
|
||||
@ -223,8 +203,11 @@ class ServicesTest(test.TestCase):
|
||||
req.environ['manila.context'], self.resource_name, 'index')
|
||||
|
||||
def test_services_list_with_zone(self):
|
||||
req = FakeRequestWithZone()
|
||||
req = fakes.HTTPRequest.blank('/services?zone=manila1', version='2.7')
|
||||
req.environ['manila.context'] = self.context
|
||||
|
||||
res_dict = self.controller.index(req)
|
||||
|
||||
response = {'services': [
|
||||
fake_response_service_list['services'][0],
|
||||
fake_response_service_list['services'][1],
|
||||
@ -234,8 +217,12 @@ class ServicesTest(test.TestCase):
|
||||
req.environ['manila.context'], self.resource_name, 'index')
|
||||
|
||||
def test_services_list_with_status(self):
|
||||
req = FakeRequestWithStatus()
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/services?status=enabled', version='2.7')
|
||||
req.environ['manila.context'] = self.context
|
||||
|
||||
res_dict = self.controller.index(req)
|
||||
|
||||
response = {'services': [
|
||||
fake_response_service_list['services'][2],
|
||||
]}
|
||||
@ -244,8 +231,11 @@ class ServicesTest(test.TestCase):
|
||||
req.environ['manila.context'], self.resource_name, 'index')
|
||||
|
||||
def test_services_list_with_state(self):
|
||||
req = FakeRequestWithState()
|
||||
req = fakes.HTTPRequest.blank('/services?state=up', version='2.7')
|
||||
req.environ['manila.context'] = self.context
|
||||
|
||||
res_dict = self.controller.index(req)
|
||||
|
||||
response = {'services': [
|
||||
fake_response_service_list['services'][0],
|
||||
fake_response_service_list['services'][1],
|
||||
@ -255,25 +245,77 @@ class ServicesTest(test.TestCase):
|
||||
req.environ['manila.context'], self.resource_name, 'index')
|
||||
|
||||
def test_services_list_with_host_binary(self):
|
||||
req = FakeRequestWithHostBinary()
|
||||
req = fakes.HTTPRequest.blank(
|
||||
"/services?binary=manila-share&state=up", version='2.7')
|
||||
req.environ['manila.context'] = self.context
|
||||
|
||||
res_dict = self.controller.index(req)
|
||||
|
||||
response = {'services': [fake_response_service_list['services'][1], ]}
|
||||
self.assertEqual(response, res_dict)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
req.environ['manila.context'], self.resource_name, 'index')
|
||||
|
||||
def test_services_enable(self):
|
||||
@ddt.data(
|
||||
('os-services', '1.0', services.ServiceControllerLegacy),
|
||||
('os-services', '2.6', services.ServiceControllerLegacy),
|
||||
('services', '2.7', services.ServiceController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_services_enable(self, url, version, controller):
|
||||
body = {'host': 'host1', 'binary': 'manila-share'}
|
||||
req = fakes.HTTPRequest.blank('/v1/fake/os-services/enable')
|
||||
res_dict = self.controller.update(req, "enable", body)
|
||||
req = fakes.HTTPRequest.blank('/fooproject/%s' % url, version=version)
|
||||
|
||||
res_dict = controller().update(req, "enable", body)
|
||||
|
||||
self.assertFalse(res_dict['disabled'])
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
req.environ['manila.context'], self.resource_name, 'update')
|
||||
|
||||
def test_services_disable(self):
|
||||
req = fakes.HTTPRequest.blank('/v1/fake/os-services/disable')
|
||||
@ddt.data(
|
||||
('os-services', '1.0', services.ServiceControllerLegacy),
|
||||
('os-services', '2.6', services.ServiceControllerLegacy),
|
||||
('services', '2.7', services.ServiceController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_services_disable(self, url, version, controller):
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/fooproject/%s/disable' % url, version=version)
|
||||
body = {'host': 'host1', 'binary': 'manila-share'}
|
||||
res_dict = self.controller.update(req, "disable", body)
|
||||
|
||||
res_dict = controller().update(req, "disable", body)
|
||||
|
||||
self.assertTrue(res_dict['disabled'])
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
req.environ['manila.context'], self.resource_name, 'update')
|
||||
|
||||
@ddt.data(
|
||||
('os-services', '2.7', services.ServiceControllerLegacy),
|
||||
('services', '2.6', services.ServiceController),
|
||||
('services', '1.0', services.ServiceController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_services_update_legacy_url_2_dot_7_api_not_found(self, url,
|
||||
version,
|
||||
controller):
|
||||
req = fakes.HTTPRequest.blank(
|
||||
'/fooproject/%s/fake' % url, version=version)
|
||||
body = {'host': 'host1', 'binary': 'manila-share'}
|
||||
|
||||
self.assertRaises(
|
||||
exception.VersionNotFoundForAPIMethod,
|
||||
controller().update,
|
||||
req, "disable", body,
|
||||
)
|
||||
|
||||
@ddt.data(
|
||||
('os-services', '2.7', services.ServiceControllerLegacy),
|
||||
('services', '2.6', services.ServiceController),
|
||||
('services', '1.0', services.ServiceController),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_services_list_api_not_found(self, url, version, controller):
|
||||
req = fakes.HTTPRequest.blank('/fooproject/%s' % url, version=version)
|
||||
|
||||
self.assertRaises(
|
||||
exception.VersionNotFoundForAPIMethod, controller().index, req)
|
@ -21,7 +21,7 @@ from oslo_utils import timeutils
|
||||
import six
|
||||
import webob
|
||||
|
||||
from manila.api.v1 import share_types as types
|
||||
from manila.api.v2 import share_types as types
|
||||
from manila.api.views import types as views_types
|
||||
from manila.common import constants
|
||||
from manila import context
|
||||
@ -217,7 +217,14 @@ class ShareTypesAPITest(test.TestCase):
|
||||
policy.check_policy.assert_called_once_with(
|
||||
req.environ['manila.context'], self.resource_name, 'default')
|
||||
|
||||
def test_view_builder_show(self):
|
||||
@ddt.data(
|
||||
('1.0', 'os-share-type-access'),
|
||||
('2.0', 'os-share-type-access'),
|
||||
('2.6', 'os-share-type-access'),
|
||||
('2.7', 'share_type_access'),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_view_builder_show(self, version, prefix):
|
||||
view_builder = views_types.ViewBuilder()
|
||||
|
||||
now = timeutils.isotime()
|
||||
@ -232,14 +239,16 @@ class ShareTypesAPITest(test.TestCase):
|
||||
id=42,
|
||||
)
|
||||
|
||||
request = fakes.HTTPRequest.blank("/v2")
|
||||
request = fakes.HTTPRequest.blank("/v%s" % version[0], version=version)
|
||||
request.headers['X-Openstack-Manila-Api-Version'] = version
|
||||
|
||||
output = view_builder.show(request, raw_share_type)
|
||||
|
||||
self.assertIn('share_type', output)
|
||||
expected_share_type = {
|
||||
'name': 'new_type',
|
||||
'extra_specs': {},
|
||||
'os-share-type-access:is_public': True,
|
||||
'%s:is_public' % prefix: True,
|
||||
'required_extra_specs': {},
|
||||
'id': 42,
|
||||
}
|
||||
@ -444,7 +453,7 @@ class ShareTypeAccessTest(test.TestCase):
|
||||
use_admin_context=True)
|
||||
|
||||
self.assertRaises(webob.exc.HTTPNotFound,
|
||||
self.controller._list_project_access,
|
||||
self.controller.share_type_access,
|
||||
req, '1')
|
||||
|
||||
def test_list_type_access_private(self):
|
||||
@ -453,7 +462,7 @@ class ShareTypeAccessTest(test.TestCase):
|
||||
{'share_type_id': '2', 'project_id': PROJ3_UUID},
|
||||
]}
|
||||
|
||||
result = self.controller._list_project_access(self.req, '2')
|
||||
result = self.controller.share_type_access(self.req, '2')
|
||||
|
||||
self.assertEqual(expected, result)
|
||||
|
||||
@ -464,7 +473,7 @@ class ShareTypeAccessTest(test.TestCase):
|
||||
raise exception.PolicyNotAuthorized(action='index')
|
||||
|
||||
self.assertRaises(webob.exc.HTTPForbidden,
|
||||
self.controller._list_project_access,
|
||||
self.controller.share_type_access,
|
||||
req, 'fake')
|
||||
|
||||
def test_list_type_with_admin_default_proj1(self):
|
1446
manila/tests/api/v2/test_shares.py
Normal file
1446
manila/tests/api/v2/test_shares.py
Normal file
File diff suppressed because it is too large
Load Diff
@ -36,7 +36,7 @@ ShareGroup = [
|
||||
help="The minimum api microversion is configured to be the "
|
||||
"value of the minimum microversion supported by Manila."),
|
||||
cfg.StrOpt("max_api_microversion",
|
||||
default="2.6",
|
||||
default="2.7",
|
||||
help="The maximum api microversion is configured to be the "
|
||||
"value of the latest microversion supported by Manila."),
|
||||
cfg.StrOpt("region",
|
||||
|
@ -96,14 +96,20 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
return super(SharesV2Client, self).copy(url, headers=headers)
|
||||
|
||||
def reset_state(self, s_id, status="error", s_type="shares",
|
||||
headers=None, version=LATEST_MICROVERSION):
|
||||
headers=None, version=LATEST_MICROVERSION,
|
||||
action_name=None):
|
||||
"""Resets the state of a share, snapshot, cg, or a cgsnapshot.
|
||||
|
||||
status: available, error, creating, deleting, error_deleting
|
||||
s_type: shares, share_instances, snapshots, consistency-groups,
|
||||
cgsnapshots.
|
||||
"""
|
||||
body = {"os-reset_status": {"status": status}}
|
||||
if action_name is None:
|
||||
if float(version) > 2.6:
|
||||
action_name = 'reset_status'
|
||||
else:
|
||||
action_name = 'os-reset_status'
|
||||
body = {action_name: {"status": status}}
|
||||
body = json.dumps(body)
|
||||
resp, body = self.post("%s/%s/action" % (s_type, s_id), body,
|
||||
headers=headers, extra_headers=True,
|
||||
@ -112,12 +118,17 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
return body
|
||||
|
||||
def force_delete(self, s_id, s_type="shares", headers=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
version=LATEST_MICROVERSION, action_name=None):
|
||||
"""Force delete share or snapshot.
|
||||
|
||||
s_type: shares, snapshots
|
||||
"""
|
||||
body = {"os-force_delete": None}
|
||||
if action_name is None:
|
||||
if float(version) > 2.6:
|
||||
action_name = 'force_delete'
|
||||
else:
|
||||
action_name = 'os-force_delete'
|
||||
body = {action_name: None}
|
||||
body = json.dumps(body)
|
||||
resp, body = self.post("%s/%s/action" % (s_type, s_id), body,
|
||||
headers=headers, extra_headers=True,
|
||||
@ -276,6 +287,267 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
(instance_id, status, self.build_timeout))
|
||||
raise exceptions.TimeoutException(message)
|
||||
|
||||
###############
|
||||
|
||||
def extend_share(self, share_id, new_size, version=LATEST_MICROVERSION,
|
||||
action_name=None):
|
||||
if action_name is None:
|
||||
action_name = 'extend' if float(version) > 2.6 else 'os-extend'
|
||||
post_body = {
|
||||
action_name: {
|
||||
"new_size": new_size,
|
||||
}
|
||||
}
|
||||
body = json.dumps(post_body)
|
||||
resp, body = self.post(
|
||||
"shares/%s/action" % share_id, body, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return body
|
||||
|
||||
def shrink_share(self, share_id, new_size, version=LATEST_MICROVERSION,
|
||||
action_name=None):
|
||||
if action_name is None:
|
||||
action_name = 'shrink' if float(version) > 2.6 else 'os-shrnk'
|
||||
post_body = {
|
||||
action_name: {
|
||||
"new_size": new_size,
|
||||
}
|
||||
}
|
||||
body = json.dumps(post_body)
|
||||
resp, body = self.post(
|
||||
"shares/%s/action" % share_id, body, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return body
|
||||
|
||||
###############
|
||||
|
||||
def manage_share(self, service_host, protocol, export_path,
|
||||
share_type_id, name=None, description=None,
|
||||
version=LATEST_MICROVERSION, url=None):
|
||||
post_body = {
|
||||
"share": {
|
||||
"export_path": export_path,
|
||||
"service_host": service_host,
|
||||
"protocol": protocol,
|
||||
"share_type": share_type_id,
|
||||
"name": name,
|
||||
"description": description,
|
||||
}
|
||||
}
|
||||
if url is None:
|
||||
if float(version) > 2.6:
|
||||
url = 'shares/manage'
|
||||
else:
|
||||
url = 'os-share-manage'
|
||||
body = json.dumps(post_body)
|
||||
resp, body = self.post(url, body, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def unmanage_share(self, share_id, version=LATEST_MICROVERSION, url=None,
|
||||
action_name=None, body=None):
|
||||
if url is None:
|
||||
url = 'shares' if float(version) > 2.6 else 'os-share-unmanage'
|
||||
if action_name is None:
|
||||
action_name = 'action' if float(version) > 2.6 else 'unmanage'
|
||||
if body is None and float(version) > 2.6:
|
||||
body = json.dumps({'unmanage': {}})
|
||||
resp, body = self.post(
|
||||
"%(url)s/%(share_id)s/%(action_name)s" % {
|
||||
'url': url, 'share_id': share_id, 'action_name': action_name},
|
||||
body,
|
||||
version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return body
|
||||
|
||||
###############
|
||||
|
||||
def _get_access_action_name(self, version):
|
||||
if float(version) > 2.6:
|
||||
return 'allow_access'
|
||||
return 'os-allow_access'
|
||||
|
||||
def create_access_rule(self, share_id, access_type="ip",
|
||||
access_to="0.0.0.0", access_level=None,
|
||||
version=LATEST_MICROVERSION, action_name=None):
|
||||
post_body = {
|
||||
self._get_access_action_name(version): {
|
||||
"access_type": access_type,
|
||||
"access_to": access_to,
|
||||
"access_level": access_level,
|
||||
}
|
||||
}
|
||||
body = json.dumps(post_body)
|
||||
resp, body = self.post(
|
||||
"shares/%s/action" % share_id, body, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def list_access_rules(self, share_id, version=LATEST_MICROVERSION,
|
||||
action_name=None):
|
||||
body = {self._get_access_action_name(version): None}
|
||||
resp, body = self.post(
|
||||
"shares/%s/action" % share_id, json.dumps(body), version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def delete_access_rule(self, share_id, rule_id,
|
||||
version=LATEST_MICROVERSION, action_name=None):
|
||||
post_body = {
|
||||
self._get_access_action_name(version): {
|
||||
"access_id": rule_id,
|
||||
}
|
||||
}
|
||||
body = json.dumps(post_body)
|
||||
resp, body = self.post(
|
||||
"shares/%s/action" % share_id, body, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return body
|
||||
|
||||
###############
|
||||
|
||||
def list_availability_zones(self, url='availability-zones',
|
||||
version=LATEST_MICROVERSION):
|
||||
"""Get list of availability zones."""
|
||||
if url is None:
|
||||
if float(version) > 2.6:
|
||||
url = 'availability-zones'
|
||||
else:
|
||||
url = 'os-availability-zone'
|
||||
resp, body = self.get(url, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
###############
|
||||
|
||||
def list_services(self, params=None, url=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
"""List services."""
|
||||
if url is None:
|
||||
url = 'services' if float(version) > 2.6 else 'os-services'
|
||||
if params:
|
||||
url += '?%s' % urllib.urlencode(params)
|
||||
resp, body = self.get(url, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
###############
|
||||
|
||||
def list_share_types(self, params=None, version=LATEST_MICROVERSION):
|
||||
uri = 'types'
|
||||
if params is not None:
|
||||
uri += '?%s' % urllib.urlencode(params)
|
||||
resp, body = self.get(uri, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def create_share_type(self, name, is_public=True,
|
||||
version=LATEST_MICROVERSION, **kwargs):
|
||||
if float(version) > 2.6:
|
||||
is_public_keyname = 'share_type_access:is_public'
|
||||
else:
|
||||
is_public_keyname = 'os-share-type-access:is_public'
|
||||
post_body = {
|
||||
'name': name,
|
||||
'extra_specs': kwargs.get('extra_specs'),
|
||||
is_public_keyname: is_public,
|
||||
}
|
||||
post_body = json.dumps({'share_type': post_body})
|
||||
resp, body = self.post('types', post_body, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def delete_share_type(self, share_type_id, version=LATEST_MICROVERSION):
|
||||
resp, body = self.delete("types/%s" % share_type_id, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return body
|
||||
|
||||
def get_share_type(self, share_type_id, version=LATEST_MICROVERSION):
|
||||
resp, body = self.get("types/%s" % share_type_id, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def list_access_to_share_type(self, share_type_id,
|
||||
version=LATEST_MICROVERSION,
|
||||
action_name=None):
|
||||
if action_name is None:
|
||||
if float(version) > 2.6:
|
||||
action_name = 'share_type_access'
|
||||
else:
|
||||
action_name = 'os-share-type-access'
|
||||
url = 'types/%(st_id)s/%(action_name)s' % {
|
||||
'st_id': share_type_id, 'action_name': action_name}
|
||||
resp, body = self.get(url, version=version)
|
||||
# [{"share_type_id": "%st_id%", "project_id": "%project_id%"}, ]
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
###############
|
||||
|
||||
def _get_quotas_url(self, version):
|
||||
if float(version) > 2.6:
|
||||
return 'quota-sets'
|
||||
return 'os-quota-sets'
|
||||
|
||||
def default_quotas(self, tenant_id, url=None, version=LATEST_MICROVERSION):
|
||||
if url is None:
|
||||
url = self._get_quotas_url(version)
|
||||
url += '/%s' % tenant_id
|
||||
resp, body = self.get("%s/defaults" % url, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def show_quotas(self, tenant_id, user_id=None, url=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
if url is None:
|
||||
url = self._get_quotas_url(version)
|
||||
url += '/%s' % tenant_id
|
||||
if user_id is not None:
|
||||
url += "?user_id=%s" % user_id
|
||||
resp, body = self.get(url, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
def reset_quotas(self, tenant_id, user_id=None, url=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
if url is None:
|
||||
url = self._get_quotas_url(version)
|
||||
url += '/%s' % tenant_id
|
||||
if user_id is not None:
|
||||
url += "?user_id=%s" % user_id
|
||||
resp, body = self.delete(url, version=version)
|
||||
self.expected_success(202, resp.status)
|
||||
return body
|
||||
|
||||
def update_quotas(self, tenant_id, user_id=None, shares=None,
|
||||
snapshots=None, gigabytes=None, snapshot_gigabytes=None,
|
||||
share_networks=None, force=True, url=None,
|
||||
version=LATEST_MICROVERSION):
|
||||
if url is None:
|
||||
url = self._get_quotas_url(version)
|
||||
url += '/%s' % tenant_id
|
||||
if user_id is not None:
|
||||
url += "?user_id=%s" % user_id
|
||||
|
||||
put_body = {"tenant_id": tenant_id}
|
||||
if force:
|
||||
put_body["force"] = "true"
|
||||
if shares is not None:
|
||||
put_body["shares"] = shares
|
||||
if snapshots is not None:
|
||||
put_body["snapshots"] = snapshots
|
||||
if gigabytes is not None:
|
||||
put_body["gigabytes"] = gigabytes
|
||||
if snapshot_gigabytes is not None:
|
||||
put_body["snapshot_gigabytes"] = snapshot_gigabytes
|
||||
if share_networks is not None:
|
||||
put_body["share_networks"] = share_networks
|
||||
put_body = json.dumps({"quota_set": put_body})
|
||||
|
||||
resp, body = self.put(url, put_body, version=version)
|
||||
self.expected_success(200, resp.status)
|
||||
return self._parse_resp(body)
|
||||
|
||||
###############
|
||||
|
||||
def create_consistency_group(self, name=None, description=None,
|
||||
@ -481,9 +753,15 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
|
||||
###############
|
||||
|
||||
def migrate_share(self, share_id, host, version=LATEST_MICROVERSION):
|
||||
def migrate_share(self, share_id, host, version=LATEST_MICROVERSION,
|
||||
action_name=None):
|
||||
if action_name is None:
|
||||
if float(version) > 2.6:
|
||||
action_name = 'migrate_share'
|
||||
else:
|
||||
action_name = 'os-migrate_share'
|
||||
post_body = {
|
||||
'os-migrate_share': {
|
||||
action_name: {
|
||||
'host': host,
|
||||
}
|
||||
}
|
||||
|
@ -28,12 +28,12 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest):
|
||||
def resource_setup(cls):
|
||||
cls.os = clients.AdminManager()
|
||||
super(SharesAdminQuotasTest, cls).resource_setup()
|
||||
cls.user_id = cls.shares_client.user_id
|
||||
cls.tenant_id = cls.shares_client.tenant_id
|
||||
cls.user_id = cls.shares_v2_client.user_id
|
||||
cls.tenant_id = cls.shares_v2_client.tenant_id
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_default_quotas(self):
|
||||
quotas = self.shares_client.default_quotas(self.tenant_id)
|
||||
quotas = self.shares_v2_client.default_quotas(self.tenant_id)
|
||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||
self.assertGreater(int(quotas["shares"]), -2)
|
||||
@ -42,7 +42,7 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest):
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_show_quotas(self):
|
||||
quotas = self.shares_client.show_quotas(self.tenant_id)
|
||||
quotas = self.shares_v2_client.show_quotas(self.tenant_id)
|
||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||
self.assertGreater(int(quotas["shares"]), -2)
|
||||
@ -51,7 +51,8 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest):
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_show_quotas_for_user(self):
|
||||
quotas = self.shares_client.show_quotas(self.tenant_id, self.user_id)
|
||||
quotas = self.shares_v2_client.show_quotas(
|
||||
self.tenant_id, self.user_id)
|
||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||
self.assertGreater(int(quotas["shares"]), -2)
|
||||
@ -62,159 +63,145 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest):
|
||||
class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
||||
|
||||
force_tenant_isolation = True
|
||||
client_version = '2'
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.client = self.get_client_with_isolated_creds(
|
||||
client_version=self.client_version)
|
||||
self.tenant_id = self.client.tenant_id
|
||||
self.user_id = self.client.user_id
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_update_tenant_quota_shares(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
|
||||
# get current quotas
|
||||
quotas = client.show_quotas(client.tenant_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id)
|
||||
new_quota = int(quotas["shares"]) + 2
|
||||
|
||||
# set new quota for shares
|
||||
updated = client.update_quotas(client.tenant_id, shares=new_quota)
|
||||
updated = self.client.update_quotas(self.tenant_id, shares=new_quota)
|
||||
self.assertEqual(int(updated["shares"]), new_quota)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_update_user_quota_shares(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
|
||||
# get current quotas
|
||||
quotas = client.show_quotas(client.tenant_id, client.user_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
|
||||
new_quota = int(quotas["shares"]) - 1
|
||||
|
||||
# set new quota for shares
|
||||
updated = client.update_quotas(
|
||||
client.tenant_id, client.user_id, shares=new_quota)
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id, self.user_id, shares=new_quota)
|
||||
self.assertEqual(int(updated["shares"]), new_quota)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_update_tenant_quota_snapshots(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
|
||||
# get current quotas
|
||||
quotas = client.show_quotas(client.tenant_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id)
|
||||
new_quota = int(quotas["snapshots"]) + 2
|
||||
|
||||
# set new quota for snapshots
|
||||
updated = client.update_quotas(client.tenant_id, snapshots=new_quota)
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id, snapshots=new_quota)
|
||||
self.assertEqual(int(updated["snapshots"]), new_quota)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_update_user_quota_snapshots(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
|
||||
# get current quotas
|
||||
quotas = client.show_quotas(client.tenant_id, client.user_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
|
||||
new_quota = int(quotas["snapshots"]) - 1
|
||||
|
||||
# set new quota for snapshots
|
||||
updated = client.update_quotas(
|
||||
client.tenant_id, client.user_id, snapshots=new_quota)
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id, self.user_id, snapshots=new_quota)
|
||||
self.assertEqual(int(updated["snapshots"]), new_quota)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_update_tenant_quota_gigabytes(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
|
||||
# get current quotas
|
||||
custom = client.show_quotas(client.tenant_id)
|
||||
custom = self.client.show_quotas(self.tenant_id)
|
||||
|
||||
# make quotas for update
|
||||
gigabytes = int(custom["gigabytes"]) + 2
|
||||
|
||||
# set new quota for shares
|
||||
updated = client.update_quotas(
|
||||
client.tenant_id, gigabytes=gigabytes)
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id, gigabytes=gigabytes)
|
||||
self.assertEqual(int(updated["gigabytes"]), gigabytes)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_update_tenant_quota_snapshot_gigabytes(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
|
||||
# get current quotas
|
||||
custom = client.show_quotas(client.tenant_id)
|
||||
custom = self.client.show_quotas(self.tenant_id)
|
||||
|
||||
# make quotas for update
|
||||
snapshot_gigabytes = int(custom["snapshot_gigabytes"]) + 2
|
||||
|
||||
# set new quota for shares
|
||||
updated = client.update_quotas(
|
||||
client.tenant_id,
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id,
|
||||
snapshot_gigabytes=snapshot_gigabytes)
|
||||
self.assertEqual(
|
||||
int(updated["snapshot_gigabytes"]), snapshot_gigabytes)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_update_user_quota_gigabytes(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
|
||||
# get current quotas
|
||||
custom = client.show_quotas(client.tenant_id, client.user_id)
|
||||
custom = self.client.show_quotas(self.tenant_id, self.user_id)
|
||||
|
||||
# make quotas for update
|
||||
gigabytes = int(custom["gigabytes"]) - 1
|
||||
|
||||
# set new quota for shares
|
||||
updated = client.update_quotas(
|
||||
client.tenant_id, client.user_id,
|
||||
gigabytes=gigabytes)
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id, self.user_id, gigabytes=gigabytes)
|
||||
self.assertEqual(int(updated["gigabytes"]), gigabytes)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_update_user_quota_snapshot_gigabytes(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
|
||||
# get current quotas
|
||||
custom = client.show_quotas(client.tenant_id, client.user_id)
|
||||
custom = self.client.show_quotas(self.tenant_id, self.user_id)
|
||||
|
||||
# make quotas for update
|
||||
snapshot_gigabytes = int(custom["snapshot_gigabytes"]) - 1
|
||||
|
||||
# set new quota for shares
|
||||
updated = client.update_quotas(
|
||||
client.tenant_id, client.user_id,
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id, self.user_id,
|
||||
snapshot_gigabytes=snapshot_gigabytes)
|
||||
self.assertEqual(
|
||||
int(updated["snapshot_gigabytes"]), snapshot_gigabytes)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_update_tenant_quota_share_networks(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
|
||||
# get current quotas
|
||||
quotas = client.show_quotas(client.tenant_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id)
|
||||
new_quota = int(quotas["share_networks"]) + 2
|
||||
|
||||
# set new quota for share-networks
|
||||
updated = client.update_quotas(
|
||||
client.tenant_id, share_networks=new_quota)
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id, share_networks=new_quota)
|
||||
self.assertEqual(int(updated["share_networks"]), new_quota)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_update_user_quota_share_networks(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
|
||||
# get current quotas
|
||||
quotas = client.show_quotas(
|
||||
client.tenant_id, client.user_id)
|
||||
quotas = self.client.show_quotas(
|
||||
self.tenant_id, self.user_id)
|
||||
new_quota = int(quotas["share_networks"]) - 1
|
||||
|
||||
# set new quota for share-networks
|
||||
updated = client.update_quotas(
|
||||
client.tenant_id, client.user_id,
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id, self.user_id,
|
||||
share_networks=new_quota)
|
||||
self.assertEqual(int(updated["share_networks"]), new_quota)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_reset_tenant_quotas(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
|
||||
# get default_quotas
|
||||
default = client.default_quotas(client.tenant_id)
|
||||
default = self.client.default_quotas(self.tenant_id)
|
||||
|
||||
# get current quotas
|
||||
custom = client.show_quotas(client.tenant_id)
|
||||
custom = self.client.show_quotas(self.tenant_id)
|
||||
|
||||
# make quotas for update
|
||||
shares = int(custom["shares"]) + 2
|
||||
@ -224,8 +211,8 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
||||
share_networks = int(custom["share_networks"]) + 2
|
||||
|
||||
# set new quota
|
||||
updated = client.update_quotas(
|
||||
client.tenant_id,
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id,
|
||||
shares=shares,
|
||||
snapshots=snapshots,
|
||||
gigabytes=gigabytes,
|
||||
@ -239,10 +226,10 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
||||
self.assertEqual(int(updated["share_networks"]), share_networks)
|
||||
|
||||
# reset customized quotas
|
||||
client.reset_quotas(client.tenant_id)
|
||||
self.client.reset_quotas(self.tenant_id)
|
||||
|
||||
# verify quotas
|
||||
reseted = client.show_quotas(client.tenant_id)
|
||||
reseted = self.client.show_quotas(self.tenant_id)
|
||||
self.assertEqual(int(reseted["shares"]), int(default["shares"]))
|
||||
self.assertEqual(int(reseted["snapshots"]), int(default["snapshots"]))
|
||||
self.assertEqual(int(reseted["gigabytes"]), int(default["gigabytes"]))
|
||||
@ -251,101 +238,86 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_unlimited_quota_for_shares(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
client.update_quotas(client.tenant_id, shares=-1)
|
||||
self.client.update_quotas(self.tenant_id, shares=-1)
|
||||
|
||||
quotas = client.show_quotas(client.tenant_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('shares'))
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_unlimited_user_quota_for_shares(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
client.update_quotas(
|
||||
client.tenant_id, client.user_id,
|
||||
shares=-1)
|
||||
self.client.update_quotas(
|
||||
self.tenant_id, self.user_id, shares=-1)
|
||||
|
||||
quotas = client.show_quotas(client.tenant_id, client.user_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('shares'))
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_unlimited_quota_for_snapshots(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
client.update_quotas(client.tenant_id, snapshots=-1)
|
||||
self.client.update_quotas(self.tenant_id, snapshots=-1)
|
||||
|
||||
quotas = client.show_quotas(client.tenant_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('snapshots'))
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_unlimited_user_quota_for_snapshots(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
client.update_quotas(
|
||||
client.tenant_id, client.user_id,
|
||||
snapshots=-1)
|
||||
self.client.update_quotas(
|
||||
self.tenant_id, self.user_id, snapshots=-1)
|
||||
|
||||
quotas = client.show_quotas(client.tenant_id, client.user_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('snapshots'))
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_unlimited_quota_for_gigabytes(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
client.update_quotas(client.tenant_id, gigabytes=-1)
|
||||
self.client.update_quotas(self.tenant_id, gigabytes=-1)
|
||||
|
||||
quotas = client.show_quotas(client.tenant_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('gigabytes'))
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_unlimited_quota_for_snapshot_gigabytes(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
client.update_quotas(
|
||||
client.tenant_id, snapshot_gigabytes=-1)
|
||||
self.client.update_quotas(
|
||||
self.tenant_id, snapshot_gigabytes=-1)
|
||||
|
||||
quotas = client.show_quotas(client.tenant_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('snapshot_gigabytes'))
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_unlimited_user_quota_for_gigabytes(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
client.update_quotas(
|
||||
client.tenant_id, client.user_id,
|
||||
gigabytes=-1)
|
||||
self.client.update_quotas(
|
||||
self.tenant_id, self.user_id, gigabytes=-1)
|
||||
|
||||
quotas = client.show_quotas(client.tenant_id, client.user_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('gigabytes'))
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_unlimited_user_quota_for_snapshot_gigabytes(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
client.update_quotas(
|
||||
client.tenant_id, client.user_id,
|
||||
snapshot_gigabytes=-1)
|
||||
self.client.update_quotas(
|
||||
self.tenant_id, self.user_id, snapshot_gigabytes=-1)
|
||||
|
||||
quotas = client.show_quotas(client.tenant_id, client.user_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('snapshot_gigabytes'))
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_unlimited_quota_for_share_networks(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
client.update_quotas(client.tenant_id, share_networks=-1)
|
||||
self.client.update_quotas(self.tenant_id, share_networks=-1)
|
||||
|
||||
quotas = client.show_quotas(client.tenant_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('share_networks'))
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_unlimited_user_quota_for_share_networks(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
client.update_quotas(
|
||||
client.tenant_id, client.user_id,
|
||||
share_networks=-1)
|
||||
self.client.update_quotas(
|
||||
self.tenant_id, self.user_id, share_networks=-1)
|
||||
|
||||
quotas = client.show_quotas(client.tenant_id, client.user_id)
|
||||
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('share_networks'))
|
||||
|
@ -13,11 +13,13 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tempest import test # noqa
|
||||
import ddt
|
||||
from tempest import test
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ServicesAdminTest(base.BaseSharesAdminTest):
|
||||
|
||||
def setUp(self):
|
||||
@ -25,60 +27,67 @@ class ServicesAdminTest(base.BaseSharesAdminTest):
|
||||
self.services = self.shares_client.list_services()
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_list_services(self):
|
||||
services = self.shares_client.list_services()
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_list_services(self, client_name):
|
||||
services = getattr(self, client_name).list_services()
|
||||
self.assertNotEqual(0, len(services))
|
||||
|
||||
for service in services:
|
||||
self.assertIsNotNone(service['id'])
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_get_services_by_host_name(self):
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_get_services_by_host_name(self, client_name):
|
||||
host = self.services[0]["host"]
|
||||
params = {"host": host}
|
||||
services = self.shares_client.list_services(params)
|
||||
services = getattr(self, client_name).list_services(params)
|
||||
self.assertNotEqual(0, len(services))
|
||||
for service in services:
|
||||
self.assertEqual(host, service["host"])
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_get_services_by_binary_name(self):
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_get_services_by_binary_name(self, client_name):
|
||||
binary = self.services[0]["binary"]
|
||||
params = {"binary": binary, }
|
||||
services = self.shares_client.list_services(params)
|
||||
services = getattr(self, client_name).list_services(params)
|
||||
self.assertNotEqual(0, len(services))
|
||||
for service in services:
|
||||
self.assertEqual(binary, service["binary"])
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_get_services_by_availability_zone(self):
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_get_services_by_availability_zone(self, client_name):
|
||||
zone = self.services[0]["zone"]
|
||||
params = {"zone": zone, }
|
||||
services = self.shares_client.list_services(params)
|
||||
services = getattr(self, client_name).list_services(params)
|
||||
self.assertNotEqual(0, len(services))
|
||||
for service in services:
|
||||
self.assertEqual(zone, service["zone"])
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_get_services_by_status(self):
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_get_services_by_status(self, client_name):
|
||||
status = self.services[0]["status"]
|
||||
params = {"status": status, }
|
||||
services = self.shares_client.list_services(params)
|
||||
services = getattr(self, client_name).list_services(params)
|
||||
self.assertNotEqual(0, len(services))
|
||||
for service in services:
|
||||
self.assertEqual(status, service["status"])
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_get_services_by_state(self):
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_get_services_by_state(self, client_name):
|
||||
state = self.services[0]["state"]
|
||||
params = {"state": state, }
|
||||
services = self.shares_client.list_services(params)
|
||||
services = getattr(self, client_name).list_services(params)
|
||||
self.assertNotEqual(0, len(services))
|
||||
for service in services:
|
||||
self.assertEqual(state, service["state"])
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_get_services_by_all_filters(self):
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_get_services_by_all_filters(self, client_name):
|
||||
params = {
|
||||
"host": self.services[0]["host"],
|
||||
"binary": self.services[0]["binary"],
|
||||
@ -86,7 +95,7 @@ class ServicesAdminTest(base.BaseSharesAdminTest):
|
||||
"status": self.services[0]["status"],
|
||||
"state": self.services[0]["state"],
|
||||
}
|
||||
services = self.shares_client.list_services(params)
|
||||
services = getattr(self, client_name).list_services(params)
|
||||
self.assertNotEqual(0, len(services))
|
||||
for service in services:
|
||||
self.assertEqual(params["host"], service["host"])
|
||||
|
@ -13,13 +13,15 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tempest import test # noqa
|
||||
from tempest_lib import exceptions as lib_exc # noqa
|
||||
import ddt
|
||||
from tempest import test
|
||||
from tempest_lib import exceptions as lib_exc
|
||||
|
||||
from manila_tempest_tests import clients_share as clients
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ServicesAdminNegativeTest(base.BaseSharesAdminTest):
|
||||
|
||||
@classmethod
|
||||
@ -76,3 +78,18 @@ class ServicesAdminNegativeTest(base.BaseSharesAdminTest):
|
||||
params = {'state': 'fake_state'}
|
||||
services_fake = self.shares_client.list_services(params)
|
||||
self.assertEqual(0, len(services_fake))
|
||||
|
||||
@test.attr(type=["gate", "smoke", "negative", ])
|
||||
@ddt.data(
|
||||
('os-services', '2.7'),
|
||||
('services', '2.6'),
|
||||
('services', '2.0'),
|
||||
)
|
||||
@ddt.unpack
|
||||
@base.skip_if_microversion_not_supported("2.7")
|
||||
def test_list_services_with_wrong_versions(self, url, version):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.list_services,
|
||||
version=version, url=url,
|
||||
)
|
||||
|
@ -79,14 +79,13 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||
cls.shares = cls.create_shares([creation_data, creation_data])
|
||||
|
||||
# Load all share data (host, etc.)
|
||||
cls.share1 = cls.shares_client.get_share(cls.shares[0]['id'])
|
||||
cls.share2 = cls.shares_client.get_share(cls.shares[1]['id'])
|
||||
cls.share1 = cls.shares_v2_client.get_share(cls.shares[0]['id'])
|
||||
cls.share2 = cls.shares_v2_client.get_share(cls.shares[1]['id'])
|
||||
|
||||
# Unmanage shares from manila
|
||||
cls.shares_client.unmanage_share(cls.share1['id'])
|
||||
cls.shares_client.wait_for_resource_deletion(share_id=cls.share1['id'])
|
||||
cls.shares_client.unmanage_share(cls.share2['id'])
|
||||
cls.shares_client.wait_for_resource_deletion(share_id=cls.share2['id'])
|
||||
for share_id in (cls.share1['id'], cls.share2['id']):
|
||||
cls.shares_v2_client.unmanage_share(share_id)
|
||||
cls.shares_v2_client.wait_for_resource_deletion(share_id=share_id)
|
||||
|
||||
@test.attr(type=["gate", "smoke"])
|
||||
def test_manage(self):
|
||||
@ -94,7 +93,7 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||
description = "Description for 'managed' share"
|
||||
|
||||
# Manage share
|
||||
share = self.shares_client.manage_share(
|
||||
share = self.shares_v2_client.manage_share(
|
||||
service_host=self.share1['host'],
|
||||
export_path=self.share1['export_locations'][0],
|
||||
protocol=self.share1['share_proto'],
|
||||
@ -109,7 +108,7 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||
'client': self.shares_client})
|
||||
|
||||
# Wait for success
|
||||
self.shares_client.wait_for_share_status(share['id'], 'available')
|
||||
self.shares_v2_client.wait_for_share_status(share['id'], 'available')
|
||||
|
||||
# Verify data of managed share
|
||||
get = self.shares_v2_client.get_share(share['id'], version="2.5")
|
||||
@ -123,10 +122,10 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||
self.assertEqual(self.st['share_type']['id'], get['share_type'])
|
||||
|
||||
# Delete share
|
||||
self.shares_client.delete_share(share['id'])
|
||||
self.shares_client.wait_for_resource_deletion(share_id=share['id'])
|
||||
self.shares_v2_client.delete_share(share['id'])
|
||||
self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_share,
|
||||
self.shares_v2_client.get_share,
|
||||
share['id'])
|
||||
|
||||
@test.attr(type=["gate", "smoke"])
|
||||
@ -137,7 +136,7 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||
(self.st['share_type']['id'], 'available')]
|
||||
|
||||
for share_type_id, status in parameters:
|
||||
share = self.shares_client.manage_share(
|
||||
share = self.shares_v2_client.manage_share(
|
||||
service_host=self.share2['host'],
|
||||
export_path=self.share2['export_locations'][0],
|
||||
protocol=self.share2['share_proto'],
|
||||
@ -146,16 +145,16 @@ class ManageNFSShareTest(base.BaseSharesAdminTest):
|
||||
# Add managed share to cleanup queue
|
||||
self.method_resources.insert(
|
||||
0, {'type': 'share', 'id': share['id'],
|
||||
'client': self.shares_client})
|
||||
'client': self.shares_v2_client})
|
||||
|
||||
# Wait for success
|
||||
self.shares_client.wait_for_share_status(share['id'], status)
|
||||
self.shares_v2_client.wait_for_share_status(share['id'], status)
|
||||
|
||||
# Delete share
|
||||
self.shares_client.delete_share(share['id'])
|
||||
self.shares_client.wait_for_resource_deletion(share_id=share['id'])
|
||||
self.shares_v2_client.delete_share(share['id'])
|
||||
self.shares_v2_client.wait_for_resource_deletion(share_id=share['id'])
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_share,
|
||||
self.shares_v2_client.get_share,
|
||||
share['id'])
|
||||
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ddt
|
||||
from tempest import config # noqa
|
||||
from tempest import test # noqa
|
||||
from tempest_lib.common.utils import data_utils # noqa
|
||||
@ -24,6 +25,7 @@ from manila_tempest_tests.tests.api import base
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ShareTypesAdminTest(base.BaseSharesAdminTest):
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
@ -32,53 +34,76 @@ class ShareTypesAdminTest(base.BaseSharesAdminTest):
|
||||
extra_specs = self.add_required_extra_specs_to_dict()
|
||||
|
||||
# Create share type
|
||||
st_create = self.shares_client.create_share_type(
|
||||
st_create = self.shares_v2_client.create_share_type(
|
||||
name, extra_specs=extra_specs)
|
||||
self.assertEqual(name, st_create['share_type']['name'])
|
||||
st_id = st_create['share_type']['id']
|
||||
|
||||
# Delete share type
|
||||
self.shares_client.delete_share_type(st_id)
|
||||
self.shares_v2_client.delete_share_type(st_id)
|
||||
|
||||
# Verify deletion of share type
|
||||
self.shares_client.wait_for_resource_deletion(st_id=st_id)
|
||||
self.shares_v2_client.wait_for_resource_deletion(st_id=st_id)
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.get_share_type,
|
||||
self.shares_v2_client.get_share_type,
|
||||
st_id)
|
||||
|
||||
def _verify_is_public_key_name(self, share_type, version):
|
||||
old_key_name = 'os-share-type-access:is_public'
|
||||
new_key_name = 'share_type_access:is_public'
|
||||
if float(version) > 2.6:
|
||||
self.assertIn(new_key_name, share_type)
|
||||
self.assertNotIn(old_key_name, share_type)
|
||||
else:
|
||||
self.assertIn(old_key_name, share_type)
|
||||
self.assertNotIn(new_key_name, share_type)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_share_type_create_get(self):
|
||||
@ddt.data('2.0', '2.6', '2.7')
|
||||
def test_share_type_create_get(self, version):
|
||||
self.skip_if_microversion_not_supported(version)
|
||||
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = self.add_required_extra_specs_to_dict({"key": "value", })
|
||||
|
||||
# Create share type
|
||||
st_create = self.create_share_type(name, extra_specs=extra_specs)
|
||||
st_create = self.create_share_type(
|
||||
name, extra_specs=extra_specs, version=version)
|
||||
self.assertEqual(name, st_create['share_type']['name'])
|
||||
self._verify_is_public_key_name(st_create['share_type'], version)
|
||||
st_id = st_create["share_type"]["id"]
|
||||
|
||||
# Get share type
|
||||
get = self.shares_client.get_share_type(st_id)
|
||||
get = self.shares_v2_client.get_share_type(st_id, version=version)
|
||||
self.assertEqual(name, get["share_type"]["name"])
|
||||
self.assertEqual(st_id, get["share_type"]["id"])
|
||||
self.assertEqual(extra_specs, get["share_type"]["extra_specs"])
|
||||
self._verify_is_public_key_name(get['share_type'], version)
|
||||
|
||||
# Check that backwards compatibility didn't break
|
||||
self.assertDictMatch(get["volume_type"], get["share_type"])
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_share_type_create_list(self):
|
||||
@ddt.data('2.0', '2.6', '2.7')
|
||||
def test_share_type_create_list(self, version):
|
||||
self.skip_if_microversion_not_supported(version)
|
||||
|
||||
name = data_utils.rand_name("tempest-manila")
|
||||
extra_specs = self.add_required_extra_specs_to_dict()
|
||||
|
||||
# Create share type
|
||||
st_create = self.create_share_type(name, extra_specs=extra_specs)
|
||||
st_create = self.create_share_type(
|
||||
name, extra_specs=extra_specs, version=version)
|
||||
self._verify_is_public_key_name(st_create['share_type'], version)
|
||||
st_id = st_create["share_type"]["id"]
|
||||
|
||||
# list share types
|
||||
st_list = self.shares_client.list_share_types()
|
||||
st_list = self.shares_v2_client.list_share_types(version=version)
|
||||
sts = st_list["share_types"]
|
||||
self.assertTrue(len(sts) >= 1)
|
||||
self.assertTrue(any(st_id in st["id"] for st in sts))
|
||||
for st in sts:
|
||||
self._verify_is_public_key_name(st, version)
|
||||
|
||||
# Check that backwards compatibility didn't break
|
||||
vts = st_list["volume_types"]
|
||||
@ -128,16 +153,16 @@ class ShareTypesAdminTest(base.BaseSharesAdminTest):
|
||||
st_id = st_create["share_type"]["id"]
|
||||
|
||||
# It should not be listed without access
|
||||
st_list = self.shares_client.list_share_types()
|
||||
st_list = self.shares_v2_client.list_share_types()
|
||||
sts = st_list["share_types"]
|
||||
self.assertFalse(any(st_id in st["id"] for st in sts))
|
||||
|
||||
# List projects that have access for share type - none expected
|
||||
access = self.shares_client.list_access_to_share_type(st_id)
|
||||
access = self.shares_v2_client.list_access_to_share_type(st_id)
|
||||
self.assertEqual([], access)
|
||||
|
||||
# Add project access to share type
|
||||
access = self.shares_client.add_access_to_share_type(
|
||||
access = self.shares_v2_client.add_access_to_share_type(
|
||||
st_id, project_id)
|
||||
|
||||
# Now it should be listed
|
||||
@ -146,12 +171,12 @@ class ShareTypesAdminTest(base.BaseSharesAdminTest):
|
||||
self.assertTrue(any(st_id in st["id"] for st in sts))
|
||||
|
||||
# List projects that have access for share type - one expected
|
||||
access = self.shares_client.list_access_to_share_type(st_id)
|
||||
access = self.shares_v2_client.list_access_to_share_type(st_id)
|
||||
expected = [{'share_type_id': st_id, 'project_id': project_id}, ]
|
||||
self.assertEqual(expected, access)
|
||||
|
||||
# Remove project access from share type
|
||||
access = self.shares_client.remove_access_from_share_type(
|
||||
access = self.shares_v2_client.remove_access_from_share_type(
|
||||
st_id, project_id)
|
||||
|
||||
# It should not be listed without access
|
||||
@ -160,5 +185,5 @@ class ShareTypesAdminTest(base.BaseSharesAdminTest):
|
||||
self.assertFalse(any(st_id in st["id"] for st in sts))
|
||||
|
||||
# List projects that have access for share type - none expected
|
||||
access = self.shares_client.list_access_to_share_type(st_id)
|
||||
access = self.shares_v2_client.list_access_to_share_type(st_id)
|
||||
self.assertEqual([], access)
|
||||
|
@ -26,6 +26,7 @@ from tempest import config
|
||||
from tempest import test
|
||||
from tempest_lib.common.utils import data_utils
|
||||
from tempest_lib import exceptions
|
||||
import testtools
|
||||
|
||||
from manila_tempest_tests import clients_share as clients
|
||||
from manila_tempest_tests import share_exceptions
|
||||
@ -89,6 +90,21 @@ def network_synchronized(f):
|
||||
return wrapped_func
|
||||
|
||||
|
||||
def is_microversion_supported(microversion):
|
||||
if (float(microversion) > float(CONF.share.max_api_microversion) or
|
||||
float(microversion) < float(CONF.share.min_api_microversion)):
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def skip_if_microversion_not_supported(microversion):
|
||||
"""Decorator for tests that are microversion-specific."""
|
||||
if not is_microversion_supported(microversion):
|
||||
reason = ("Skipped. Test requires microversion '%s'." % microversion)
|
||||
return testtools.skip(reason)
|
||||
return lambda f: f
|
||||
|
||||
|
||||
class BaseSharesTest(test.BaseTestCase):
|
||||
"""Base test case class for all Manila API tests."""
|
||||
|
||||
@ -107,6 +123,11 @@ class BaseSharesTest(test.BaseTestCase):
|
||||
# Will be cleaned up in tearDown method
|
||||
method_isolated_creds = []
|
||||
|
||||
def skip_if_microversion_not_supported(self, microversion):
|
||||
if not is_microversion_supported(microversion):
|
||||
raise self.skipException(
|
||||
"Microversion '%s' is not supported." % microversion)
|
||||
|
||||
@classmethod
|
||||
def get_client_with_isolated_creds(cls,
|
||||
name=None,
|
||||
@ -525,7 +546,7 @@ class BaseSharesTest(test.BaseTestCase):
|
||||
def create_share_type(cls, name, is_public=True, client=None,
|
||||
cleanup_in_class=True, **kwargs):
|
||||
if client is None:
|
||||
client = cls.shares_client
|
||||
client = cls.shares_v2_client
|
||||
share_type = client.create_share_type(name, is_public, **kwargs)
|
||||
resource = {
|
||||
"type": "share_type",
|
||||
|
@ -29,8 +29,23 @@ class AvailabilityZonesTest(base.BaseSharesTest):
|
||||
self.assertIn(key, az)
|
||||
|
||||
@test.attr(type=["smoke", "gate"])
|
||||
def test_list_availability_zones_extension_url(self):
|
||||
def test_list_availability_zones_legacy_url_api_v1(self):
|
||||
# NOTE(vponomaryov): remove this test with removal of availability zone
|
||||
# extension url support.
|
||||
azs = self.shares_client.list_availability_zones()
|
||||
self._list_availability_zones_assertions(azs)
|
||||
|
||||
@test.attr(type=["smoke", "gate"])
|
||||
@base.skip_if_microversion_not_supported("2.6")
|
||||
def test_list_availability_zones_legacy_url_api_v2(self):
|
||||
# NOTE(vponomaryov): remove this test with removal of availability zone
|
||||
# extension url support.
|
||||
azs = self.shares_v2_client.list_availability_zones(
|
||||
url='os-availability-zone', version='2.6')
|
||||
self._list_availability_zones_assertions(azs)
|
||||
|
||||
@test.attr(type=["smoke", "gate"])
|
||||
@base.skip_if_microversion_not_supported("2.7")
|
||||
def test_list_availability_zones(self):
|
||||
azs = self.shares_v2_client.list_availability_zones(version='2.7')
|
||||
self._list_availability_zones_assertions(azs)
|
||||
|
@ -0,0 +1,43 @@
|
||||
# Copyright 2015 Mirantis Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tempest import test
|
||||
from tempest_lib import exceptions as lib_exc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
|
||||
@base.skip_if_microversion_not_supported("2.7")
|
||||
class AvailabilityZonesNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@test.attr(type=["smoke", "gate"])
|
||||
def test_list_availability_zones_api_not_found_with_legacy_url(self):
|
||||
# NOTE(vponomaryov): remove this test with removal of availability zone
|
||||
# extension url support.
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.list_availability_zones,
|
||||
url='os-availability-zone',
|
||||
version='2.7',
|
||||
)
|
||||
|
||||
@test.attr(type=["smoke", "gate"])
|
||||
def test_list_availability_zones_api_not_found(self):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
self.shares_v2_client.list_availability_zones,
|
||||
url='availability-zones',
|
||||
version='2.6',
|
||||
)
|
@ -13,22 +13,25 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import ddt
|
||||
from tempest import test # noqa
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
|
||||
@ddt.data
|
||||
class SharesQuotasTest(base.BaseSharesTest):
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super(SharesQuotasTest, cls).resource_setup()
|
||||
cls.user_id = cls.shares_client.user_id
|
||||
cls.tenant_id = cls.shares_client.tenant_id
|
||||
cls.user_id = cls.shares_v2_client.user_id
|
||||
cls.tenant_id = cls.shares_v2_client.tenant_id
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_default_quotas(self):
|
||||
quotas = self.shares_client.default_quotas(self.tenant_id)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_default_quotas(self, client_name):
|
||||
quotas = getattr(self, client_name).default_quotas(self.tenant_id)
|
||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||
self.assertGreater(int(quotas["shares"]), -2)
|
||||
@ -36,8 +39,9 @@ class SharesQuotasTest(base.BaseSharesTest):
|
||||
self.assertGreater(int(quotas["share_networks"]), -2)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_show_quotas(self):
|
||||
quotas = self.shares_client.show_quotas(self.tenant_id)
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_show_quotas(self, client_name):
|
||||
quotas = getattr(self, client_name).show_quotas(self.tenant_id)
|
||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||
self.assertGreater(int(quotas["shares"]), -2)
|
||||
@ -45,8 +49,9 @@ class SharesQuotasTest(base.BaseSharesTest):
|
||||
self.assertGreater(int(quotas["share_networks"]), -2)
|
||||
|
||||
@test.attr(type=["gate", "smoke", ])
|
||||
def test_show_quotas_for_user(self):
|
||||
quotas = self.shares_client.show_quotas(
|
||||
@ddt.data('shares_client', 'shares_v2_client')
|
||||
def test_show_quotas_for_user(self, client_name):
|
||||
quotas = getattr(self, client_name).show_quotas(
|
||||
self.tenant_id, self.user_id)
|
||||
self.assertGreater(int(quotas["gigabytes"]), -2)
|
||||
self.assertGreater(int(quotas["snapshot_gigabytes"]), -2)
|
||||
|
@ -13,29 +13,55 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from tempest import test # noqa
|
||||
from tempest_lib import exceptions as lib_exc # noqa
|
||||
import testtools # noqa
|
||||
import ddt
|
||||
from tempest import test
|
||||
from tempest_lib import exceptions as lib_exc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SharesQuotasNegativeTest(base.BaseSharesTest):
|
||||
|
||||
@test.attr(type=["gate", "smoke", "negative"])
|
||||
def test_get_quotas_with_empty_tenant_id(self):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.shares_client.show_quotas, "")
|
||||
self.shares_v2_client.show_quotas, "")
|
||||
|
||||
@test.attr(type=["gate", "smoke", "negative", ])
|
||||
def test_try_reset_quotas_with_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.reset_quotas,
|
||||
self.shares_client.tenant_id)
|
||||
self.shares_v2_client.reset_quotas,
|
||||
self.shares_v2_client.tenant_id)
|
||||
|
||||
@test.attr(type=["gate", "smoke", "negative", ])
|
||||
def test_try_update_quotas_with_user(self):
|
||||
self.assertRaises(lib_exc.Forbidden,
|
||||
self.shares_client.update_quotas,
|
||||
self.shares_client.tenant_id,
|
||||
self.shares_v2_client.update_quotas,
|
||||
self.shares_v2_client.tenant_id,
|
||||
shares=9)
|
||||
|
||||
@ddt.data(
|
||||
('services', '2.0', 'show_quotas'),
|
||||
('services', '2.0', 'default_quotas'),
|
||||
('services', '2.0', 'reset_quotas'),
|
||||
('services', '2.0', 'update_quotas'),
|
||||
('services', '2.6', 'show_quotas'),
|
||||
('services', '2.6', 'default_quotas'),
|
||||
('services', '2.6', 'reset_quotas'),
|
||||
('services', '2.6', 'update_quotas'),
|
||||
('os-services', '2.7', 'show_quotas'),
|
||||
('os-services', '2.7', 'default_quotas'),
|
||||
('os-services', '2.7', 'reset_quotas'),
|
||||
('os-services', '2.7', 'update_quotas'),
|
||||
)
|
||||
@ddt.unpack
|
||||
@test.attr(type=["gate", "smoke", "negative", ])
|
||||
@base.skip_if_microversion_not_supported("2.7")
|
||||
def test_show_quotas_with_wrong_versions(self, url, version, method_name):
|
||||
self.assertRaises(
|
||||
lib_exc.NotFound,
|
||||
getattr(self.shares_v2_client, method_name),
|
||||
self.shares_v2_client.tenant_id,
|
||||
version=version, url=url,
|
||||
)
|
||||
|
Loading…
Reference in New Issue
Block a user