Add share groups and share group snapshots quotas
"Quota" APIs now will return two new following keys: - 'share_groups' - 'share_group_snapshots' For user and project, but not share type. Default values can be configured using following config options: - 'quota_share_groups' - 'quota_share_group_snapshots' APIImpact DocImpact Implements BluePrint add-share-groups-quota Change-Id: I397a8e886226cb22fa50abdf2a4a938bb04c655d
This commit is contained in:
parent
7a979c2f1b
commit
256b5c84ba
@ -110,13 +110,14 @@ REST_API_VERSION_HISTORY = """
|
||||
* 2.38 - Support IPv6 validation in allow_access API to enable IPv6 in
|
||||
manila.
|
||||
* 2.39 - Added share-type quotas.
|
||||
* 2.40 - Added share group and share group snapshot quotas.
|
||||
"""
|
||||
|
||||
# The minimum and maximum versions of the API supported
|
||||
# The default api version request is defined to be the
|
||||
# minimum version of the API supported.
|
||||
_MIN_API_VERSION = "2.0"
|
||||
_MAX_API_VERSION = "2.39"
|
||||
_MAX_API_VERSION = "2.40"
|
||||
DEFAULT_API_VERSION = _MIN_API_VERSION
|
||||
|
||||
|
||||
|
@ -222,3 +222,7 @@ user documentation.
|
||||
2.39
|
||||
----
|
||||
Added share-type quotas.
|
||||
|
||||
2.40
|
||||
----
|
||||
Added share group and share group snapshot quotas.
|
||||
|
@ -44,7 +44,7 @@ class QuotaClassSetsMixin(object):
|
||||
raise webob.exc.HTTPForbidden()
|
||||
|
||||
return self._view_builder.detail_list(
|
||||
QUOTAS.get_class_quotas(context, id), id)
|
||||
req, QUOTAS.get_class_quotas(context, id), id)
|
||||
|
||||
@wsgi.Controller.authorize("update")
|
||||
def _update(self, req, id, body):
|
||||
@ -60,7 +60,7 @@ class QuotaClassSetsMixin(object):
|
||||
except exception.AdminRequired:
|
||||
raise webob.exc.HTTPForbidden()
|
||||
return self._view_builder.detail_list(
|
||||
QUOTAS.get_class_quotas(context, quota_class))
|
||||
req, QUOTAS.get_class_quotas(context, quota_class))
|
||||
|
||||
|
||||
class QuotaClassSetsControllerLegacy(QuotaClassSetsMixin, wsgi.Controller):
|
||||
|
@ -79,10 +79,20 @@ class QuotaSetsMixin(object):
|
||||
share_type = params.get('share_type', [None])[0]
|
||||
if share_type:
|
||||
msg = _("'share_type' key is not supported by this microversion. "
|
||||
"Use 2.38 or greater microversion to be able "
|
||||
"Use 2.39 or greater microversion to be able "
|
||||
"to use 'share_type' quotas.")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
@staticmethod
|
||||
def _ensure_share_group_related_args_are_absent(body):
|
||||
body = body.get('quota_set', body)
|
||||
for key in ('share_groups', 'share_group_snapshots'):
|
||||
if body.get(key):
|
||||
msg = _("'%(key)s' key is not supported by this microversion. "
|
||||
"Use 2.40 or greater microversion to be able "
|
||||
"to use '%(key)s' quotas.") % {"key": key}
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
def _get_quotas(self, context, project_id, user_id=None,
|
||||
share_type_id=None, usages=False):
|
||||
self._validate_user_id_and_share_type_args(user_id, share_type_id)
|
||||
@ -112,14 +122,16 @@ class QuotaSetsMixin(object):
|
||||
share_type_id = self._get_share_type_id(context, share_type)
|
||||
quotas = self._get_quotas(
|
||||
context, id, user_id, share_type_id, usages=detail)
|
||||
return self._view_builder.detail_list(quotas, id, share_type_id)
|
||||
return self._view_builder.detail_list(
|
||||
req, quotas, id, share_type_id)
|
||||
except exception.NotAuthorized:
|
||||
raise webob.exc.HTTPForbidden()
|
||||
|
||||
@wsgi.Controller.authorize('show')
|
||||
def _defaults(self, req, id):
|
||||
context = req.environ['manila.context']
|
||||
return self._view_builder.detail_list(QUOTAS.get_defaults(context), id)
|
||||
return self._view_builder.detail_list(
|
||||
req, QUOTAS.get_defaults(context), id)
|
||||
|
||||
@wsgi.Controller.authorize("update")
|
||||
def _update(self, req, id, body):
|
||||
@ -132,6 +144,12 @@ class QuotaSetsMixin(object):
|
||||
share_type = params.get('share_type', [None])[0]
|
||||
self._validate_user_id_and_share_type_args(user_id, share_type)
|
||||
share_type_id = self._get_share_type_id(context, share_type)
|
||||
body = body.get('quota_set', {})
|
||||
if share_type and body.get('share_groups',
|
||||
body.get('share_group_snapshots')):
|
||||
msg = _("Share type quotas handle only 'shares', 'gigabytes', "
|
||||
"'snapshots' and 'snapshot_gigabytes' quotas.")
|
||||
raise webob.exc.HTTPBadRequest(explanation=msg)
|
||||
|
||||
try:
|
||||
settable_quotas = QUOTAS.get_settable_quotas(
|
||||
@ -140,7 +158,7 @@ class QuotaSetsMixin(object):
|
||||
except exception.NotAuthorized:
|
||||
raise webob.exc.HTTPForbidden()
|
||||
|
||||
for key, value in body.get('quota_set', {}).items():
|
||||
for key, value in body.items():
|
||||
if key == 'share_networks' and share_type_id:
|
||||
msg = _("'share_networks' quota cannot be set for share type. "
|
||||
"It can be set only for project or user.")
|
||||
@ -171,7 +189,7 @@ class QuotaSetsMixin(object):
|
||||
except exception.NotAuthorized:
|
||||
raise webob.exc.HTTPForbidden()
|
||||
|
||||
for key, value in body.get('quota_set', {}).items():
|
||||
for key, value in body.items():
|
||||
if key in NON_QUOTA_KEYS or (not value and value != 0):
|
||||
continue
|
||||
# validate whether already used and reserved exceeds the new
|
||||
@ -216,6 +234,7 @@ class QuotaSetsMixin(object):
|
||||
except exception.AdminRequired:
|
||||
raise webob.exc.HTTPForbidden()
|
||||
return self._view_builder.detail_list(
|
||||
req,
|
||||
self._get_quotas(
|
||||
context, id, user_id=user_id, share_type_id=share_type_id),
|
||||
share_type=share_type_id,
|
||||
@ -262,6 +281,7 @@ class QuotaSetsControllerLegacy(QuotaSetsMixin, wsgi.Controller):
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
def update(self, req, id, body):
|
||||
self._ensure_share_type_arg_is_absent(req)
|
||||
self._ensure_share_group_related_args_are_absent(body)
|
||||
return self._update(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('1.0', '2.6')
|
||||
@ -297,6 +317,8 @@ class QuotaSetsController(QuotaSetsMixin, wsgi.Controller):
|
||||
def update(self, req, id, body):
|
||||
if req.api_version_request < api_version.APIVersionRequest("2.39"):
|
||||
self._ensure_share_type_arg_is_absent(req)
|
||||
elif req.api_version_request < api_version.APIVersionRequest("2.40"):
|
||||
self._ensure_share_group_related_args_are_absent(body)
|
||||
return self._update(req, id, body)
|
||||
|
||||
@wsgi.Controller.api_version('2.7')
|
||||
|
@ -19,8 +19,11 @@ from manila.api import common
|
||||
class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
_collection_name = "quota_class_set"
|
||||
_detail_version_modifiers = [
|
||||
"add_share_group_quotas",
|
||||
]
|
||||
|
||||
def detail_list(self, quota_set, quota_class=None):
|
||||
def detail_list(self, request, quota_class_set, quota_class=None):
|
||||
"""Detailed view of quota class set."""
|
||||
keys = (
|
||||
'shares',
|
||||
@ -29,7 +32,17 @@ class ViewBuilder(common.ViewBuilder):
|
||||
'snapshot_gigabytes',
|
||||
'share_networks',
|
||||
)
|
||||
view = {key: quota_set.get(key) for key in keys}
|
||||
view = {key: quota_class_set.get(key) for key in keys}
|
||||
if quota_class:
|
||||
view['id'] = quota_class
|
||||
self.update_versioned_resource_dict(request, view, quota_class_set)
|
||||
return {self._collection_name: view}
|
||||
|
||||
@common.ViewBuilder.versioned_method("2.40")
|
||||
def add_share_group_quotas(self, context, view, quota_class_set):
|
||||
share_groups = quota_class_set.get('share_groups')
|
||||
share_group_snapshots = quota_class_set.get('share_group_snapshots')
|
||||
if share_groups is not None:
|
||||
view['share_groups'] = share_groups
|
||||
if share_group_snapshots is not None:
|
||||
view['share_group_snapshots'] = share_group_snapshots
|
||||
|
@ -19,8 +19,12 @@ from manila.api import common
|
||||
class ViewBuilder(common.ViewBuilder):
|
||||
|
||||
_collection_name = "quota_set"
|
||||
_detail_version_modifiers = [
|
||||
"add_share_group_quotas",
|
||||
]
|
||||
|
||||
def detail_list(self, quota_set, project_id=None, share_type=None):
|
||||
def detail_list(self, request, quota_set, project_id=None,
|
||||
share_type=None):
|
||||
"""Detailed view of quota set."""
|
||||
keys = (
|
||||
'shares',
|
||||
@ -31,6 +35,21 @@ class ViewBuilder(common.ViewBuilder):
|
||||
view = {key: quota_set.get(key) for key in keys}
|
||||
if project_id:
|
||||
view['id'] = project_id
|
||||
if not share_type:
|
||||
if share_type:
|
||||
# NOTE(vponomaryov): remove share groups related data for quotas
|
||||
# that are share-type based.
|
||||
quota_set.pop('share_groups', None)
|
||||
quota_set.pop('share_group_snapshots', None)
|
||||
else:
|
||||
view['share_networks'] = quota_set.get('share_networks')
|
||||
self.update_versioned_resource_dict(request, view, quota_set)
|
||||
return {self._collection_name: view}
|
||||
|
||||
@common.ViewBuilder.versioned_method("2.40")
|
||||
def add_share_group_quotas(self, context, view, quota_set):
|
||||
share_groups = quota_set.get('share_groups')
|
||||
share_group_snapshots = quota_set.get('share_group_snapshots')
|
||||
if share_groups is not None:
|
||||
view['share_groups'] = share_groups
|
||||
if share_group_snapshots is not None:
|
||||
view['share_group_snapshots'] = share_group_snapshots
|
||||
|
@ -317,12 +317,30 @@ def _sync_share_networks(context, project_id, user_id, session,
|
||||
return {'share_networks': share_networks_count}
|
||||
|
||||
|
||||
def _sync_share_groups(context, project_id, user_id, session,
|
||||
share_type_id=None):
|
||||
share_groups_count = count_share_groups(
|
||||
context, project_id, user_id, share_type_id=share_type_id,
|
||||
session=session)
|
||||
return {'share_groups': share_groups_count}
|
||||
|
||||
|
||||
def _sync_share_group_snapshots(context, project_id, user_id, session,
|
||||
share_type_id=None):
|
||||
share_group_snapshots_count = count_share_group_snapshots(
|
||||
context, project_id, user_id, share_type_id=share_type_id,
|
||||
session=session)
|
||||
return {'share_group_snapshots': share_group_snapshots_count}
|
||||
|
||||
|
||||
QUOTA_SYNC_FUNCTIONS = {
|
||||
'_sync_shares': _sync_shares,
|
||||
'_sync_snapshots': _sync_snapshots,
|
||||
'_sync_gigabytes': _sync_gigabytes,
|
||||
'_sync_snapshot_gigabytes': _sync_snapshot_gigabytes,
|
||||
'_sync_share_networks': _sync_share_networks,
|
||||
'_sync_share_groups': _sync_share_groups,
|
||||
'_sync_share_group_snapshots': _sync_share_group_snapshots,
|
||||
}
|
||||
|
||||
|
||||
@ -4223,6 +4241,41 @@ def get_all_shares_by_share_group(context, share_group_id, session=None):
|
||||
all())
|
||||
|
||||
|
||||
@require_context
|
||||
def count_share_groups(context, project_id, user_id=None,
|
||||
share_type_id=None, session=None):
|
||||
query = model_query(
|
||||
context, models.ShareGroup,
|
||||
func.count(models.ShareGroup.id),
|
||||
read_deleted="no",
|
||||
session=session).filter_by(project_id=project_id)
|
||||
if share_type_id:
|
||||
query = query.join("share_group_share_type_mappings").filter_by(
|
||||
share_type_id=share_type_id)
|
||||
elif user_id is not None:
|
||||
query = query.filter_by(user_id=user_id)
|
||||
return query.first()[0]
|
||||
|
||||
|
||||
@require_context
|
||||
def count_share_group_snapshots(context, project_id, user_id=None,
|
||||
share_type_id=None, session=None):
|
||||
query = model_query(
|
||||
context, models.ShareGroupSnapshot,
|
||||
func.count(models.ShareGroupSnapshot.id),
|
||||
read_deleted="no",
|
||||
session=session).filter_by(project_id=project_id)
|
||||
if share_type_id:
|
||||
query = query.join(
|
||||
"share_group"
|
||||
).join(
|
||||
"share_group_share_type_mappings"
|
||||
).filter_by(share_type_id=share_type_id)
|
||||
elif user_id is not None:
|
||||
query = query.filter_by(user_id=user_id)
|
||||
return query.first()[0]
|
||||
|
||||
|
||||
@require_context
|
||||
def count_share_group_snapshots_in_share_group(context, share_group_id,
|
||||
session=None):
|
||||
|
@ -428,6 +428,16 @@ class ShareNetworksLimitExceeded(QuotaError):
|
||||
"allowed (%(allowed)d) exceeded.")
|
||||
|
||||
|
||||
class ShareGroupsLimitExceeded(QuotaError):
|
||||
message = _(
|
||||
"Maximum number of allowed share-groups is exceeded.")
|
||||
|
||||
|
||||
class ShareGroupSnapshotsLimitExceeded(QuotaError):
|
||||
message = _(
|
||||
"Maximum number of allowed share-group-snapshots is exceeded.")
|
||||
|
||||
|
||||
class GlusterfsException(ManilaException):
|
||||
message = _("Unknown Gluster exception.")
|
||||
|
||||
|
@ -45,6 +45,14 @@ quota_opts = [
|
||||
cfg.IntOpt('quota_share_networks',
|
||||
default=10,
|
||||
help='Number of share-networks allowed per project.'),
|
||||
|
||||
cfg.IntOpt('quota_share_groups',
|
||||
default=50,
|
||||
help='Number of share groups allowed.'),
|
||||
cfg.IntOpt('quota_share_group_snapshots',
|
||||
default=50,
|
||||
help='Number of share group snapshots allowed.'),
|
||||
|
||||
cfg.IntOpt('reservation_expire',
|
||||
default=86400,
|
||||
help='Number of seconds until a reservation expires.'),
|
||||
@ -1047,6 +1055,10 @@ resources = [
|
||||
'quota_snapshot_gigabytes'),
|
||||
ReservableResource('share_networks', '_sync_share_networks',
|
||||
'quota_share_networks'),
|
||||
ReservableResource('share_groups', '_sync_share_groups',
|
||||
'quota_share_groups'),
|
||||
ReservableResource('share_group_snapshots', '_sync_share_group_snapshots',
|
||||
'quota_share_group_snapshots'),
|
||||
]
|
||||
|
||||
|
||||
|
@ -27,15 +27,15 @@ from manila.common import constants
|
||||
from manila.db import base
|
||||
from manila import exception
|
||||
from manila.i18n import _
|
||||
from manila import quota
|
||||
from manila.scheduler import rpcapi as scheduler_rpcapi
|
||||
from manila import share
|
||||
from manila.share import rpcapi as share_rpcapi
|
||||
from manila.share import share_types
|
||||
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
QUOTAS = quota.QUOTAS
|
||||
|
||||
|
||||
class API(base.Base):
|
||||
@ -138,6 +138,28 @@ class API(base.Base):
|
||||
"types supported by the share group type.")
|
||||
raise exception.InvalidInput(reason=msg)
|
||||
|
||||
try:
|
||||
reservations = QUOTAS.reserve(context, share_groups=1)
|
||||
except exception.OverQuota as e:
|
||||
overs = e.kwargs['overs']
|
||||
usages = e.kwargs['usages']
|
||||
quotas = e.kwargs['quotas']
|
||||
|
||||
def _consumed(name):
|
||||
return (usages[name]['reserved'] + usages[name]['in_use'])
|
||||
|
||||
if 'share_groups' in overs:
|
||||
msg = ("Quota exceeded for '%(s_uid)s' user in '%(s_pid)s' "
|
||||
"project. (%(d_consumed)d of "
|
||||
"%(d_quota)d already consumed).")
|
||||
LOG.warning(msg, {
|
||||
's_pid': context.project_id,
|
||||
's_uid': context.user_id,
|
||||
'd_consumed': _consumed('share_groups'),
|
||||
'd_quota': quotas['share_groups'],
|
||||
})
|
||||
raise exception.ShareGroupsLimitExceeded()
|
||||
|
||||
options = {
|
||||
'share_group_type_id': share_group_type_id,
|
||||
'source_share_group_snapshot_id': source_share_group_snapshot_id,
|
||||
@ -154,9 +176,9 @@ class API(base.Base):
|
||||
if original_share_group:
|
||||
options['host'] = original_share_group['host']
|
||||
|
||||
share_group = self.db.share_group_create(context, options)
|
||||
|
||||
share_group = None
|
||||
try:
|
||||
share_group = self.db.share_group_create(context, options)
|
||||
if share_group_snapshot:
|
||||
members = self.db.share_group_snapshot_members_get_all(
|
||||
context, source_share_group_snapshot_id)
|
||||
@ -178,8 +200,16 @@ class API(base.Base):
|
||||
share_network_id=share_network_id)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
self.db.share_group_destroy(
|
||||
context.elevated(), share_group['id'])
|
||||
if share_group:
|
||||
self.db.share_group_destroy(
|
||||
context.elevated(), share_group['id'])
|
||||
QUOTAS.rollback(context, reservations)
|
||||
|
||||
try:
|
||||
QUOTAS.commit(context, reservations)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
QUOTAS.rollback(context, reservations)
|
||||
|
||||
request_spec = {'share_group_id': share_group['id']}
|
||||
request_spec.update(options)
|
||||
@ -224,7 +254,30 @@ class API(base.Base):
|
||||
share_group = self.db.share_group_update(
|
||||
context, share_group_id, {'status': constants.STATUS_DELETING})
|
||||
|
||||
self.share_rpcapi.delete_share_group(context, share_group)
|
||||
try:
|
||||
reservations = QUOTAS.reserve(
|
||||
context,
|
||||
share_groups=-1,
|
||||
project_id=share_group['project_id'],
|
||||
user_id=share_group['user_id'],
|
||||
)
|
||||
except exception.OverQuota as e:
|
||||
reservations = None
|
||||
LOG.exception(
|
||||
("Failed to update quota for deleting share group: %s"), e)
|
||||
|
||||
try:
|
||||
self.share_rpcapi.delete_share_group(context, share_group)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
QUOTAS.rollback(context, reservations)
|
||||
|
||||
if reservations:
|
||||
QUOTAS.commit(
|
||||
context, reservations,
|
||||
project_id=share_group['project_id'],
|
||||
user_id=share_group['user_id'],
|
||||
)
|
||||
|
||||
def update(self, context, group, fields):
|
||||
return self.db.share_group_update(context, group['id'], fields)
|
||||
@ -285,8 +338,31 @@ class API(base.Base):
|
||||
"status": constants.STATUS_AVAILABLE})
|
||||
raise exception.InvalidShareGroup(reason=msg)
|
||||
|
||||
snap = self.db.share_group_snapshot_create(context, options)
|
||||
try:
|
||||
reservations = QUOTAS.reserve(context, share_group_snapshots=1)
|
||||
except exception.OverQuota as e:
|
||||
overs = e.kwargs['overs']
|
||||
usages = e.kwargs['usages']
|
||||
quotas = e.kwargs['quotas']
|
||||
|
||||
def _consumed(name):
|
||||
return (usages[name]['reserved'] + usages[name]['in_use'])
|
||||
|
||||
if 'share_group_snapshots' in overs:
|
||||
msg = ("Quota exceeded for '%(s_uid)s' user in '%(s_pid)s' "
|
||||
"project. (%(d_consumed)d of "
|
||||
"%(d_quota)d already consumed).")
|
||||
LOG.warning(msg, {
|
||||
's_pid': context.project_id,
|
||||
's_uid': context.user_id,
|
||||
'd_consumed': _consumed('share_group_snapshots'),
|
||||
'd_quota': quotas['share_group_snapshots'],
|
||||
})
|
||||
raise exception.ShareGroupSnapshotsLimitExceeded()
|
||||
|
||||
snap = None
|
||||
try:
|
||||
snap = self.db.share_group_snapshot_create(context, options)
|
||||
members = []
|
||||
for s in shares:
|
||||
member_options = {
|
||||
@ -308,7 +384,15 @@ class API(base.Base):
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
# This will delete the snapshot and all of it's members
|
||||
self.db.share_group_snapshot_destroy(context, snap['id'])
|
||||
if snap:
|
||||
self.db.share_group_snapshot_destroy(context, snap['id'])
|
||||
QUOTAS.rollback(context, reservations)
|
||||
|
||||
try:
|
||||
QUOTAS.commit(context, reservations)
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
QUOTAS.rollback(context, reservations)
|
||||
|
||||
return snap
|
||||
|
||||
@ -325,10 +409,30 @@ class API(base.Base):
|
||||
self.db.share_group_snapshot_update(
|
||||
context, snap_id, {'status': constants.STATUS_DELETING})
|
||||
|
||||
try:
|
||||
reservations = QUOTAS.reserve(
|
||||
context,
|
||||
share_group_snapshots=-1,
|
||||
project_id=snap['project_id'],
|
||||
user_id=snap['user_id'],
|
||||
)
|
||||
except exception.OverQuota as e:
|
||||
reservations = None
|
||||
LOG.exception(
|
||||
("Failed to update quota for deleting share group snapshot: "
|
||||
"%s"), e)
|
||||
|
||||
# Cast to share manager
|
||||
self.share_rpcapi.delete_share_group_snapshot(
|
||||
context, snap, share_group['host'])
|
||||
|
||||
if reservations:
|
||||
QUOTAS.commit(
|
||||
context, reservations,
|
||||
project_id=snap['project_id'],
|
||||
user_id=snap['user_id'],
|
||||
)
|
||||
|
||||
def update_share_group_snapshot(self, context, share_group_snapshot,
|
||||
fields):
|
||||
return self.db.share_group_snapshot_update(
|
||||
|
@ -18,8 +18,6 @@
|
||||
Tests for manila.api.v2.quota_sets.py
|
||||
"""
|
||||
|
||||
import copy
|
||||
|
||||
import ddt
|
||||
import mock
|
||||
from oslo_config import cfg
|
||||
@ -37,18 +35,18 @@ from manila import utils
|
||||
|
||||
CONF = cfg.CONF
|
||||
|
||||
REQ = mock.MagicMock(api_version_request=api_version.APIVersionRequest("2.39"))
|
||||
REQ.environ = {'manila.context': context.get_admin_context()}
|
||||
REQ.environ['manila.context'].is_admin = True
|
||||
REQ.environ['manila.context'].auth_token = 'foo_auth_token'
|
||||
REQ.environ['manila.context'].project_id = 'foo_project_id'
|
||||
|
||||
REQ_WITH_USER = copy.deepcopy(REQ)
|
||||
REQ_WITH_USER.environ['manila.context'].user_id = 'foo_user_id'
|
||||
REQ_WITH_USER.environ['QUERY_STRING'] = 'user_id=foo_user_id'
|
||||
|
||||
REQ_MEMBER = copy.deepcopy(REQ)
|
||||
REQ_MEMBER.environ['manila.context'].is_admin = False
|
||||
def _get_request(is_admin, user_in_url):
|
||||
req = mock.MagicMock(
|
||||
api_version_request=api_version.APIVersionRequest("2.40"))
|
||||
req.environ = {'manila.context': context.get_admin_context()}
|
||||
req.environ['manila.context'].is_admin = is_admin
|
||||
req.environ['manila.context'].auth_token = 'foo_auth_token'
|
||||
req.environ['manila.context'].project_id = 'foo_project_id'
|
||||
if user_in_url:
|
||||
req.environ['manila.context'].user_id = 'foo_user_id'
|
||||
req.environ['QUERY_STRING'] = 'user_id=foo_user_id'
|
||||
return req
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@ -72,8 +70,11 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
{"gigabytes": 7},
|
||||
{"snapshot_gigabytes": 10001},
|
||||
{"share_networks": 12345},
|
||||
{"share_groups": 123456},
|
||||
{"share_group_snapshots": 123456},
|
||||
)
|
||||
def test_defaults(self, quotas):
|
||||
req = _get_request(True, False)
|
||||
for k, v in quotas.items():
|
||||
CONF.set_default('quota_' + k, v)
|
||||
expected = {
|
||||
@ -84,14 +85,17 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
'snapshots': quotas.get('snapshots', 50),
|
||||
'snapshot_gigabytes': quotas.get('snapshot_gigabytes', 1000),
|
||||
'share_networks': quotas.get('share_networks', 10),
|
||||
'share_groups': quotas.get('share_groups', 50),
|
||||
'share_group_snapshots': quotas.get(
|
||||
'share_group_snapshots', 50),
|
||||
}
|
||||
}
|
||||
|
||||
result = self.controller.defaults(REQ, self.project_id)
|
||||
result = self.controller.defaults(req, self.project_id)
|
||||
|
||||
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')
|
||||
|
||||
@ddt.data(
|
||||
('os-', '1.0', quota_sets.QuotaSetsControllerLegacy, 'defaults'),
|
||||
@ -124,17 +128,18 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
|
||||
@staticmethod
|
||||
def _get_share_type_request_object(microversion=None):
|
||||
req = copy.deepcopy(REQ)
|
||||
req = _get_request(True, False)
|
||||
req.environ['QUERY_STRING'] = 'share_type=fake_share_type_name_or_id'
|
||||
req.api_version_request = api_version.APIVersionRequest(
|
||||
microversion or '2.39')
|
||||
return req
|
||||
|
||||
def test_share_type_quota_detail(self):
|
||||
@ddt.data('2.39', '2.40')
|
||||
def test_share_type_quota_detail(self, microversion):
|
||||
self.mock_object(
|
||||
quota_sets.db, 'share_type_get_by_name_or_id',
|
||||
mock.Mock(return_value={'id': 'fake_st_id'}))
|
||||
req = self._get_share_type_request_object('2.39')
|
||||
req = self._get_share_type_request_object(microversion)
|
||||
quotas = {
|
||||
"shares": 23,
|
||||
"snapshots": 34,
|
||||
@ -176,11 +181,12 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
quota_sets.db.share_type_get_by_name_or_id.assert_called_once_with(
|
||||
req.environ['manila.context'], 'fake_share_type_name_or_id')
|
||||
|
||||
def test_show_share_type_quota(self):
|
||||
@ddt.data('2.39', '2.40')
|
||||
def test_show_share_type_quota(self, microversion):
|
||||
self.mock_object(
|
||||
quota_sets.db, 'share_type_get_by_name_or_id',
|
||||
mock.Mock(return_value={'id': 'fake_st_id'}))
|
||||
req = self._get_share_type_request_object('2.39')
|
||||
req = self._get_share_type_request_object(microversion)
|
||||
quotas = {
|
||||
"shares": 23,
|
||||
"snapshots": 34,
|
||||
@ -262,7 +268,30 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
|
||||
self.assertIsNone(result)
|
||||
|
||||
@ddt.data(REQ, REQ_WITH_USER)
|
||||
@ddt.data(
|
||||
{},
|
||||
{"quota_set": {}},
|
||||
{"quota_set": {"foo": "bar"}},
|
||||
{"foo": "bar"},
|
||||
)
|
||||
def test__ensure_share_group_related_args_are_absent_success(self, body):
|
||||
result = self.controller._ensure_share_group_related_args_are_absent(
|
||||
body)
|
||||
|
||||
self.assertIsNone(result)
|
||||
|
||||
@ddt.data(
|
||||
{"share_groups": 5},
|
||||
{"share_group_snapshots": 6},
|
||||
{"quota_set": {"share_groups": 7}},
|
||||
{"quota_set": {"share_group_snapshots": 8}},
|
||||
)
|
||||
def test__ensure_share_group_related_args_are_absent_error(self, body):
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPBadRequest,
|
||||
self.controller._ensure_share_group_related_args_are_absent, body)
|
||||
|
||||
@ddt.data(_get_request(True, True), _get_request(True, False))
|
||||
def test__ensure_share_type_arg_is_absent(self, req):
|
||||
result = self.controller._ensure_share_type_arg_is_absent(req)
|
||||
|
||||
@ -276,7 +305,7 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
self.controller._ensure_share_type_arg_is_absent,
|
||||
req)
|
||||
|
||||
@ddt.data(REQ, REQ_WITH_USER)
|
||||
@ddt.data(_get_request(True, True), _get_request(True, False))
|
||||
def test_quota_detail(self, request):
|
||||
request.api_version_request = api_version.APIVersionRequest('2.25')
|
||||
quotas = {
|
||||
@ -318,7 +347,7 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
request.environ['manila.context'], self.resource_name, 'show')
|
||||
|
||||
@ddt.data(REQ, REQ_WITH_USER)
|
||||
@ddt.data(_get_request(True, True), _get_request(True, False))
|
||||
def test_show_quota(self, request):
|
||||
quotas = {
|
||||
"shares": 23,
|
||||
@ -326,6 +355,8 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
"gigabytes": 45,
|
||||
"snapshot_gigabytes": 56,
|
||||
"share_networks": 67,
|
||||
"share_groups": 53,
|
||||
"share_group_snapshots": 57,
|
||||
}
|
||||
expected = {
|
||||
'quota_set': {
|
||||
@ -335,6 +366,9 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
'snapshots': quotas.get('snapshots', 50),
|
||||
'snapshot_gigabytes': quotas.get('snapshot_gigabytes', 1000),
|
||||
'share_networks': quotas.get('share_networks', 10),
|
||||
'share_groups': quotas.get('share_groups', 50),
|
||||
'share_group_snapshots': quotas.get(
|
||||
'share_group_snapshots', 50),
|
||||
}
|
||||
}
|
||||
for k, v in quotas.items():
|
||||
@ -347,6 +381,7 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
request.environ['manila.context'], self.resource_name, 'show')
|
||||
|
||||
def test_show_quota_not_authorized(self):
|
||||
req = _get_request(True, False)
|
||||
self.mock_object(
|
||||
quota_sets.db,
|
||||
'authorize_project_context',
|
||||
@ -355,11 +390,11 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPForbidden,
|
||||
self.controller.show,
|
||||
REQ, self.project_id)
|
||||
req, self.project_id)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ.environ['manila.context'], self.resource_name, 'show')
|
||||
req.environ['manila.context'], self.resource_name, 'show')
|
||||
|
||||
@ddt.data(REQ, REQ_WITH_USER)
|
||||
@ddt.data(_get_request(True, True), _get_request(True, False))
|
||||
def test_update_quota(self, request):
|
||||
self.mock_object(
|
||||
quota_sets.db, 'share_type_get_by_name_or_id',
|
||||
@ -374,6 +409,8 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
'snapshots': 50,
|
||||
'snapshot_gigabytes': 1000,
|
||||
'share_networks': 10,
|
||||
'share_groups': 50,
|
||||
'share_group_snapshots': 50,
|
||||
}
|
||||
}
|
||||
mock_policy_update_check_call = mock.call(
|
||||
@ -394,12 +431,13 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
mock_policy_update_check_call, mock_policy_show_check_call])
|
||||
quota_sets.db.share_type_get_by_name_or_id.assert_not_called()
|
||||
|
||||
def test_update_share_type_quota(self):
|
||||
@ddt.data('2.39', '2.40')
|
||||
def test_update_share_type_quota(self, microversion):
|
||||
self.mock_object(
|
||||
quota_sets.db, 'share_type_get_by_name_or_id',
|
||||
mock.Mock(
|
||||
return_value={'id': 'fake_st_id', 'name': 'fake_st_name'}))
|
||||
req = self._get_share_type_request_object('2.39')
|
||||
req = self._get_share_type_request_object(microversion)
|
||||
|
||||
CONF.set_default('quota_shares', 789)
|
||||
body = {'quota_set': {'tenant_id': self.project_id, 'shares': 788}}
|
||||
@ -468,14 +506,15 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
|
||||
@ddt.data(-2, 'foo', {1: 2}, [1])
|
||||
def test_update_quota_with_invalid_value(self, value):
|
||||
req = _get_request(True, False)
|
||||
body = {'quota_set': {'tenant_id': self.project_id, 'shares': value}}
|
||||
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPBadRequest,
|
||||
self.controller.update,
|
||||
REQ, self.project_id, body=body)
|
||||
req, self.project_id, body=body)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ.environ['manila.context'], self.resource_name, 'update')
|
||||
req.environ['manila.context'], self.resource_name, 'update')
|
||||
|
||||
def test_user_quota_can_not_be_bigger_than_tenant_quota(self):
|
||||
value = 777
|
||||
@ -486,14 +525,14 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
'shares': value + 1,
|
||||
}
|
||||
}
|
||||
req = _get_request(True, True)
|
||||
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPBadRequest,
|
||||
self.controller.update,
|
||||
REQ_WITH_USER, self.project_id, body=body)
|
||||
req, self.project_id, body=body)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ_WITH_USER.environ['manila.context'], self.resource_name,
|
||||
'update')
|
||||
req.environ['manila.context'], self.resource_name, 'update')
|
||||
|
||||
def test_update_inexistent_quota(self):
|
||||
body = {
|
||||
@ -502,23 +541,25 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
'fake_quota': 13,
|
||||
}
|
||||
}
|
||||
req = _get_request(True, False)
|
||||
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPBadRequest,
|
||||
self.controller.update,
|
||||
REQ, self.project_id, body=body)
|
||||
req, self.project_id, body=body)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ.environ['manila.context'], self.resource_name, 'update')
|
||||
req.environ['manila.context'], self.resource_name, 'update')
|
||||
|
||||
def test_update_quota_not_authorized(self):
|
||||
body = {'quota_set': {'tenant_id': self.project_id, 'shares': 13}}
|
||||
req = _get_request(False, False)
|
||||
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPForbidden,
|
||||
self.controller.update,
|
||||
REQ_MEMBER, self.project_id, body=body)
|
||||
req, self.project_id, body=body)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ_MEMBER.environ['manila.context'], self.resource_name, 'update')
|
||||
req.environ['manila.context'], self.resource_name, 'update')
|
||||
|
||||
@ddt.data(
|
||||
('os-quota-sets', '1.0', quota_sets.QuotaSetsControllerLegacy),
|
||||
@ -597,8 +638,9 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
project_id = 'foo_project_id'
|
||||
self.mock_object(quota_sets.QUOTAS, 'destroy_all_by_project_and_user')
|
||||
self.mock_object(quota_sets.QUOTAS, 'destroy_all_by_project')
|
||||
req = _get_request(True, True)
|
||||
|
||||
result = self.controller.delete(REQ_WITH_USER, project_id)
|
||||
result = self.controller.delete(req, project_id)
|
||||
|
||||
self.assertTrue(
|
||||
utils.IsAMatcher(webob.response.Response) == result
|
||||
@ -607,13 +649,12 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
self.assertEqual(202, result.status_code)
|
||||
(quota_sets.QUOTAS.destroy_all_by_project_and_user.
|
||||
assert_called_once_with(
|
||||
REQ_WITH_USER.environ['manila.context'],
|
||||
req.environ['manila.context'],
|
||||
project_id,
|
||||
REQ_WITH_USER.environ['manila.context'].user_id))
|
||||
req.environ['manila.context'].user_id))
|
||||
self.assertFalse(quota_sets.QUOTAS.destroy_all_by_project.called)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ_WITH_USER.environ['manila.context'], self.resource_name,
|
||||
'delete')
|
||||
req.environ['manila.context'], self.resource_name, 'delete')
|
||||
|
||||
def test_delete_share_type_quota(self):
|
||||
req = self._get_share_type_request_object('2.39')
|
||||
@ -656,12 +697,13 @@ class QuotaSetsControllerTest(test.TestCase):
|
||||
quota_sets.db.share_type_get_by_name_or_id.assert_not_called()
|
||||
|
||||
def test_delete_not_authorized(self):
|
||||
req = _get_request(False, False)
|
||||
self.assertRaises(
|
||||
webob.exc.HTTPForbidden,
|
||||
self.controller.delete,
|
||||
REQ_MEMBER, self.project_id)
|
||||
req, self.project_id)
|
||||
self.mock_policy_check.assert_called_once_with(
|
||||
REQ_MEMBER.environ['manila.context'], self.resource_name, 'delete')
|
||||
req.environ['manila.context'], self.resource_name, 'delete')
|
||||
|
||||
@ddt.data(
|
||||
('os-quota-sets', '2.7', quota_sets.QuotaSetsControllerLegacy),
|
||||
|
70
manila/tests/api/views/test_quota_class_sets.py
Normal file
70
manila/tests/api/views/test_quota_class_sets.py
Normal file
@ -0,0 +1,70 @@
|
||||
# Copyright (c) 2017 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.
|
||||
|
||||
import ddt
|
||||
|
||||
from manila.api.openstack import api_version_request as api_version
|
||||
from manila.api.views import quota_class_sets
|
||||
from manila import test
|
||||
from manila.tests.api import fakes
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ViewBuilderTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ViewBuilderTestCase, self).setUp()
|
||||
self.builder = quota_class_sets.ViewBuilder()
|
||||
|
||||
def test__collection_name(self):
|
||||
self.assertEqual('quota_class_set', self.builder._collection_name)
|
||||
|
||||
@ddt.data(
|
||||
("fake_quota_class", "2.40"), (None, "2.40"),
|
||||
("fake_quota_class", "2.39"), (None, "2.39"),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_detail_list_with_share_type(self, quota_class, microversion):
|
||||
req = fakes.HTTPRequest.blank('/quota-sets', version=microversion)
|
||||
quota_class_set = {
|
||||
"shares": 13,
|
||||
"gigabytes": 31,
|
||||
"snapshots": 14,
|
||||
"snapshot_gigabytes": 41,
|
||||
"share_groups": 15,
|
||||
"share_group_snapshots": 51,
|
||||
"share_networks": 16,
|
||||
}
|
||||
expected = {self.builder._collection_name: {
|
||||
"shares": quota_class_set["shares"],
|
||||
"gigabytes": quota_class_set["gigabytes"],
|
||||
"snapshots": quota_class_set["snapshots"],
|
||||
"snapshot_gigabytes": quota_class_set["snapshot_gigabytes"],
|
||||
"share_networks": quota_class_set["share_networks"],
|
||||
}}
|
||||
if quota_class:
|
||||
expected[self.builder._collection_name]['id'] = quota_class
|
||||
if (api_version.APIVersionRequest(microversion) >= (
|
||||
api_version.APIVersionRequest("2.40"))):
|
||||
expected[self.builder._collection_name][
|
||||
"share_groups"] = quota_class_set["share_groups"]
|
||||
expected[self.builder._collection_name][
|
||||
"share_group_snapshots"] = quota_class_set[
|
||||
"share_group_snapshots"]
|
||||
|
||||
result = self.builder.detail_list(
|
||||
req, quota_class_set, quota_class=quota_class)
|
||||
|
||||
self.assertEqual(expected, result)
|
79
manila/tests/api/views/test_quota_sets.py
Normal file
79
manila/tests/api/views/test_quota_sets.py
Normal file
@ -0,0 +1,79 @@
|
||||
# Copyright (c) 2017 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.
|
||||
|
||||
import ddt
|
||||
|
||||
from manila.api.openstack import api_version_request as api_version
|
||||
from manila.api.views import quota_sets
|
||||
from manila import test
|
||||
from manila.tests.api import fakes
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class ViewBuilderTestCase(test.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(ViewBuilderTestCase, self).setUp()
|
||||
self.builder = quota_sets.ViewBuilder()
|
||||
|
||||
def test__collection_name(self):
|
||||
self.assertEqual('quota_set', self.builder._collection_name)
|
||||
|
||||
@ddt.data(
|
||||
('fake_project_id', 'fake_share_type_id', "2.40"),
|
||||
(None, 'fake_share_type_id', "2.40"),
|
||||
('fake_project_id', None, "2.40"),
|
||||
(None, None, "2.40"),
|
||||
('fake_project_id', 'fake_share_type_id', "2.39"),
|
||||
(None, 'fake_share_type_id', "2.39"),
|
||||
('fake_project_id', None, "2.39"),
|
||||
(None, None, "2.39"),
|
||||
)
|
||||
@ddt.unpack
|
||||
def test_detail_list_with_share_type(self, project_id, share_type,
|
||||
microversion):
|
||||
req = fakes.HTTPRequest.blank('/quota-sets', version=microversion)
|
||||
quota_set = {
|
||||
"shares": 13,
|
||||
"gigabytes": 31,
|
||||
"snapshots": 14,
|
||||
"snapshot_gigabytes": 41,
|
||||
"share_groups": 15,
|
||||
"share_group_snapshots": 51,
|
||||
"share_networks": 16,
|
||||
}
|
||||
expected = {self.builder._collection_name: {
|
||||
"shares": quota_set["shares"],
|
||||
"gigabytes": quota_set["gigabytes"],
|
||||
"snapshots": quota_set["snapshots"],
|
||||
"snapshot_gigabytes": quota_set["snapshot_gigabytes"],
|
||||
}}
|
||||
if project_id:
|
||||
expected[self.builder._collection_name]['id'] = project_id
|
||||
if not share_type:
|
||||
expected[self.builder._collection_name][
|
||||
"share_networks"] = quota_set["share_networks"]
|
||||
if (api_version.APIVersionRequest(microversion) >= (
|
||||
api_version.APIVersionRequest("2.40"))):
|
||||
expected[self.builder._collection_name][
|
||||
"share_groups"] = quota_set["share_groups"]
|
||||
expected[self.builder._collection_name][
|
||||
"share_group_snapshots"] = quota_set[
|
||||
"share_group_snapshots"]
|
||||
|
||||
result = self.builder.detail_list(
|
||||
req, quota_set, project_id=project_id, share_type=share_type)
|
||||
|
||||
self.assertEqual(expected, result)
|
@ -79,7 +79,10 @@ def fake_share_group_snapshot(id, **kwargs):
|
||||
class ShareGroupsAPITestCase(test.TestCase):
|
||||
def setUp(self):
|
||||
super(ShareGroupsAPITestCase, self).setUp()
|
||||
self.context = context.get_admin_context()
|
||||
self.user_id = 'fake_user_id'
|
||||
self.project_id = 'fake_project_id'
|
||||
self.context = context.RequestContext(
|
||||
user_id=self.user_id, project_id=self.project_id, is_admin=True)
|
||||
self.scheduler_rpcapi = mock.Mock()
|
||||
self.share_rpcapi = mock.Mock()
|
||||
self.share_api = mock.Mock()
|
||||
@ -108,8 +111,12 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
{'share_type_id': self.fake_share_type_2['id']},
|
||||
]
|
||||
}
|
||||
self.mock_object(db_driver, 'share_group_type_get',
|
||||
mock.Mock(return_value=self.fake_share_group_type))
|
||||
self.mock_object(
|
||||
db_driver, 'share_group_type_get',
|
||||
mock.Mock(return_value=self.fake_share_group_type))
|
||||
self.mock_object(share_group_api.QUOTAS, 'reserve')
|
||||
self.mock_object(share_group_api.QUOTAS, 'commit')
|
||||
self.mock_object(share_group_api.QUOTAS, 'rollback')
|
||||
|
||||
def test_create_empty_request(self):
|
||||
share_group = fake_share_group(
|
||||
@ -126,6 +133,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_create.assert_called_once_with(
|
||||
self.context, expected_values)
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_request_spec(self):
|
||||
"""Ensure the correct values are sent to the scheduler."""
|
||||
@ -150,6 +162,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.scheduler_rpcapi.create_share_group.assert_called_once_with(
|
||||
self.context, share_group_id=share_group['id'],
|
||||
request_spec=expected_request_spec, filter_properties={})
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_name(self):
|
||||
fake_name = 'fake_name'
|
||||
@ -172,6 +189,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.scheduler_rpcapi.create_share_group.assert_called_once_with(
|
||||
self.context, share_group_id=share_group['id'],
|
||||
request_spec=mock.ANY, filter_properties={})
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_description(self):
|
||||
fake_desc = 'fake_desc'
|
||||
@ -190,6 +212,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_create.assert_called_once_with(
|
||||
self.context, expected_values)
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_multiple_share_types(self):
|
||||
fake_share_types = [self.fake_share_type, self.fake_share_type_2]
|
||||
@ -213,6 +240,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_create.assert_called_once_with(
|
||||
self.context, expected_values)
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_share_type_not_found(self):
|
||||
self.mock_object(share_types, 'get_share_type',
|
||||
@ -234,6 +266,31 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.api.create,
|
||||
self.context, share_type_ids=[self.fake_share_type['id']])
|
||||
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_error_on_quota_reserve(self):
|
||||
overs = ["share_groups"]
|
||||
usages = {"share_groups": {"reserved": 1, "in_use": 3, "limit": 4}}
|
||||
quotas = {"share_groups": 5}
|
||||
share_group_api.QUOTAS.reserve.side_effect = exception.OverQuota(
|
||||
overs=overs,
|
||||
usages=usages,
|
||||
quotas=quotas,
|
||||
)
|
||||
self.mock_object(share_group_api.LOG, "warning")
|
||||
|
||||
self.assertRaises(
|
||||
exception.ShareGroupsLimitExceeded,
|
||||
self.api.create, self.context)
|
||||
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=1)
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
share_group_api.LOG.warning.assert_called_once_with(mock.ANY, mock.ANY)
|
||||
|
||||
def test_create_driver_handles_share_servers_is_false_with_net_id(self):
|
||||
fake_share_types = [self.fake_share_type]
|
||||
self.mock_object(share_types, 'get_share_type')
|
||||
@ -266,6 +323,10 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.api.create,
|
||||
self.context, share_type_ids=fake_share_type_ids)
|
||||
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_conflicting_share_type_and_share_network(self):
|
||||
fake_share_type = {
|
||||
'name': 'default',
|
||||
@ -283,6 +344,10 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.context, share_type_ids=fake_share_types,
|
||||
share_network_id="fake_sn")
|
||||
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_source_share_group_snapshot_id(self):
|
||||
snap = fake_share_group_snapshot(
|
||||
"fake_source_share_group_snapshot_id",
|
||||
@ -341,6 +406,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.context, expected_values)
|
||||
self.share_rpcapi.create_share_group.assert_called_once_with(
|
||||
self.context, share_group, orig_share_group['host'])
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_source_share_group_snapshot_id_with_member(self):
|
||||
snap = fake_share_group_snapshot(
|
||||
@ -403,6 +473,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.assertTrue(self.share_api.create.called)
|
||||
self.share_rpcapi.create_share_group.assert_called_once_with(
|
||||
self.context, share_group, orig_share_group['host'])
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_source_sg_snapshot_id_with_members_error(self):
|
||||
snap = fake_share_group_snapshot(
|
||||
@ -465,6 +540,12 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.assertEqual(2, self.share_api.create.call_count)
|
||||
self.assertEqual(1, db_driver.share_group_destroy.call_count)
|
||||
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=1)
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
|
||||
def test_create_with_source_sg_snapshot_id_error_snapshot_status(self):
|
||||
snap = fake_share_group_snapshot(
|
||||
"fake_source_share_group_snapshot_id",
|
||||
@ -478,6 +559,10 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.api.create,
|
||||
self.context, source_share_group_snapshot_id=snap['id'])
|
||||
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_source_sg_snapshot_id_snap_not_found(self):
|
||||
snap = fake_share_group_snapshot(
|
||||
"fake_source_share_group_snapshot_id",
|
||||
@ -492,6 +577,10 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.api.create,
|
||||
self.context, source_share_group_snapshot_id=snap['id'])
|
||||
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_multiple_fields(self):
|
||||
fake_desc = 'fake_desc'
|
||||
fake_name = 'fake_name'
|
||||
@ -512,6 +601,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_create.assert_called_once_with(
|
||||
self.context, expected_values)
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_with_error_on_creation(self):
|
||||
share_group = fake_share_group(
|
||||
@ -528,11 +622,16 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_create.assert_called_once_with(
|
||||
self.context, expected_values)
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=1)
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
|
||||
def test_delete_creating_no_host(self):
|
||||
share_group = fake_share_group(
|
||||
'fakeid', user_id=self.context.user_id,
|
||||
project_id=self.context.project_id,
|
||||
'fakeid', user_id=self.user_id + '_different_user',
|
||||
project_id=self.project_id + '_in_different_project',
|
||||
status=constants.STATUS_CREATING)
|
||||
self.mock_object(db_driver, 'share_group_destroy')
|
||||
|
||||
@ -540,6 +639,9 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_destroy.assert_called_once_with(
|
||||
mock.ANY, share_group['id'])
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_delete_creating_with_host(self):
|
||||
share_group = fake_share_group(
|
||||
@ -553,8 +655,8 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
def test_delete_available(self):
|
||||
share_group = fake_share_group(
|
||||
'fakeid', user_id=self.context.user_id,
|
||||
project_id=self.context.project_id,
|
||||
'fakeid', user_id=self.user_id + '_different_user',
|
||||
project_id=self.project_id + '_in_different_project',
|
||||
status=constants.STATUS_AVAILABLE, host="fake_host")
|
||||
deleted_share_group = copy.deepcopy(share_group)
|
||||
deleted_share_group['status'] = constants.STATUS_DELETING
|
||||
@ -570,6 +672,16 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
{'status': constants.STATUS_DELETING})
|
||||
self.share_rpcapi.delete_share_group.assert_called_once_with(
|
||||
self.context, deleted_share_group)
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=-1,
|
||||
project_id=share_group['project_id'],
|
||||
user_id=share_group['user_id'])
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context,
|
||||
share_group_api.QUOTAS.reserve.return_value,
|
||||
project_id=share_group['project_id'],
|
||||
user_id=share_group['user_id'])
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_delete_error_with_host(self):
|
||||
share_group = fake_share_group(
|
||||
@ -591,6 +703,16 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
{'status': constants.STATUS_DELETING})
|
||||
self.api.share_rpcapi.delete_share_group.assert_called_once_with(
|
||||
self.context, deleted_share_group)
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_groups=-1,
|
||||
project_id=share_group['project_id'],
|
||||
user_id=share_group['user_id'])
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context,
|
||||
share_group_api.QUOTAS.reserve.return_value,
|
||||
project_id=share_group['project_id'],
|
||||
user_id=share_group['user_id'])
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_delete_error_without_host(self):
|
||||
share_group = fake_share_group(
|
||||
@ -603,6 +725,9 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_destroy.assert_called_once_with(
|
||||
mock.ANY, share_group['id'])
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_delete_with_shares(self):
|
||||
share_group = fake_share_group(
|
||||
@ -617,6 +742,10 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
exception.InvalidShareGroup,
|
||||
self.api.delete, self.context, share_group)
|
||||
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_delete_with_share_group_snapshots(self):
|
||||
share_group = fake_share_group(
|
||||
'fakeid', user_id=self.context.user_id,
|
||||
@ -630,6 +759,10 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
exception.InvalidShareGroup,
|
||||
self.api.delete, self.context, share_group)
|
||||
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
@ddt.data({}, {"name": "fake_name"}, {"description": "fake_description"})
|
||||
def test_update(self, expected_values):
|
||||
share_group = fake_share_group(
|
||||
@ -739,6 +872,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.context, expected_values)
|
||||
self.share_rpcapi.create_share_group_snapshot.assert_called_once_with(
|
||||
self.context, snap, share_group['host'])
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_group_snapshots=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_sg_snapshot_minimal_request_no_members_with_name(self):
|
||||
fake_name = 'fake_name'
|
||||
@ -772,6 +910,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.context, expected_values)
|
||||
self.share_rpcapi.create_share_group_snapshot.assert_called_once_with(
|
||||
self.context, snap, share_group['host'])
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_group_snapshots=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_group_snapshot_minimal_request_no_members_with_desc(self):
|
||||
fake_description = 'fake_description'
|
||||
@ -807,6 +950,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.context, expected_values)
|
||||
self.share_rpcapi.create_share_group_snapshot.assert_called_once_with(
|
||||
self.context, snap, share_group['host'])
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_group_snapshots=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_share_group_snapshot_group_does_not_exist(self):
|
||||
share_group = fake_share_group(
|
||||
@ -837,6 +985,46 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_get.assert_called_once_with(
|
||||
self.context, share_group['id'])
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_share_group_snapshot_failure_reserving_quota(self):
|
||||
overs = ["share_group_snapshots"]
|
||||
usages = {"share_group_snapshots": {
|
||||
"reserved": 1,
|
||||
"in_use": 3,
|
||||
"limit": 4,
|
||||
}}
|
||||
quotas = {"share_group_snapshots": 5}
|
||||
share_group = fake_share_group(
|
||||
"fake_group_id", user_id=self.context.user_id,
|
||||
project_id=self.context.project_id,
|
||||
status=constants.STATUS_AVAILABLE)
|
||||
self.mock_object(
|
||||
db_driver, "share_group_get", mock.Mock(return_value=share_group))
|
||||
self.mock_object(
|
||||
db_driver, "share_get_all_by_share_group_id",
|
||||
mock.Mock(return_value=[]))
|
||||
share_group_api.QUOTAS.reserve.side_effect = exception.OverQuota(
|
||||
overs=overs,
|
||||
usages=usages,
|
||||
quotas=quotas,
|
||||
)
|
||||
self.mock_object(share_group_api.LOG, "warning")
|
||||
|
||||
self.assertRaises(
|
||||
exception.ShareGroupSnapshotsLimitExceeded,
|
||||
self.api.create_share_group_snapshot,
|
||||
self.context, share_group_id=share_group["id"])
|
||||
|
||||
db_driver.share_group_get.assert_called_once_with(
|
||||
self.context, share_group["id"])
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_group_snapshots=1)
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
share_group_api.LOG.warning.assert_called_once_with(mock.ANY, mock.ANY)
|
||||
|
||||
def test_create_share_group_snapshot_group_in_creating(self):
|
||||
self.mock_object(
|
||||
@ -851,6 +1039,9 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_get.assert_called_once_with(
|
||||
self.context, "fake_id")
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_share_group_snapshot_with_member(self):
|
||||
share_group = fake_share_group(
|
||||
@ -898,6 +1089,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.context, expected_member_values)
|
||||
self.share_rpcapi.create_share_group_snapshot.assert_called_once_with(
|
||||
self.context, snap, share_group['host'])
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_group_snapshots=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_share_group_snapshot_with_member_share_in_creating(self):
|
||||
share_group = fake_share_group(
|
||||
@ -919,6 +1115,9 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_get.assert_called_once_with(
|
||||
self.context, share_group['id'])
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_share_group_snapshot_with_two_members(self):
|
||||
share_group = fake_share_group(
|
||||
@ -979,6 +1178,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.context, expected_member_2_values)
|
||||
self.share_rpcapi.create_share_group_snapshot.assert_called_once_with(
|
||||
self.context, snap, share_group['host'])
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_group_snapshots=1)
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_create_share_group_snapshot_error_creating_member(self):
|
||||
share_group = fake_share_group(
|
||||
@ -1031,6 +1235,11 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.context, expected_member_values)
|
||||
db_driver.share_group_snapshot_destroy.assert_called_once_with(
|
||||
self.context, snap['id'])
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_group_snapshots=1)
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value)
|
||||
|
||||
def test_delete_share_group_snapshot(self):
|
||||
share_group = fake_share_group('fake_id', host="fake_host")
|
||||
@ -1049,6 +1258,44 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
self.context, sg_snap['id'], {'status': constants.STATUS_DELETING})
|
||||
self.share_rpcapi.delete_share_group_snapshot.assert_called_once_with(
|
||||
self.context, sg_snap, share_group['host'])
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_group_snapshots=-1,
|
||||
project_id=share_group['project_id'],
|
||||
user_id=share_group['user_id'])
|
||||
share_group_api.QUOTAS.commit.assert_called_once_with(
|
||||
self.context, share_group_api.QUOTAS.reserve.return_value,
|
||||
project_id=share_group['project_id'],
|
||||
user_id=share_group['user_id'])
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_delete_share_group_snapshot_fail_on_quota_reserve(self):
|
||||
share_group = fake_share_group('fake_id', host="fake_host")
|
||||
sg_snap = fake_share_group_snapshot(
|
||||
'fake_groupsnap_id', share_group_id='fake_id',
|
||||
status=constants.STATUS_AVAILABLE)
|
||||
self.mock_object(db_driver, 'share_group_get',
|
||||
mock.Mock(return_value=share_group))
|
||||
self.mock_object(db_driver, 'share_group_snapshot_update')
|
||||
share_group_api.QUOTAS.reserve.side_effect = exception.OverQuota(
|
||||
'Failure')
|
||||
self.mock_object(share_group_api.LOG, 'exception')
|
||||
|
||||
self.api.delete_share_group_snapshot(self.context, sg_snap)
|
||||
|
||||
db_driver.share_group_get.assert_called_once_with(
|
||||
self.context, "fake_id")
|
||||
db_driver.share_group_snapshot_update.assert_called_once_with(
|
||||
self.context, sg_snap['id'], {'status': constants.STATUS_DELETING})
|
||||
self.share_rpcapi.delete_share_group_snapshot.assert_called_once_with(
|
||||
self.context, sg_snap, share_group['host'])
|
||||
share_group_api.QUOTAS.reserve.assert_called_once_with(
|
||||
self.context, share_group_snapshots=-1,
|
||||
project_id=share_group['project_id'],
|
||||
user_id=share_group['user_id'])
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
share_group_api.LOG.exception.assert_called_once_with(
|
||||
mock.ANY, mock.ANY)
|
||||
|
||||
def test_delete_share_group_snapshot_group_does_not_exist(self):
|
||||
snap = fake_share_group_snapshot(
|
||||
@ -1064,6 +1311,9 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_get.assert_called_once_with(
|
||||
self.context, "fake_id")
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
def test_delete_share_group_snapshot_creating_status(self):
|
||||
snap = fake_share_group_snapshot(
|
||||
@ -1077,6 +1327,9 @@ class ShareGroupsAPITestCase(test.TestCase):
|
||||
|
||||
db_driver.share_group_get.assert_called_once_with(
|
||||
self.context, snap['share_group_id'])
|
||||
share_group_api.QUOTAS.reserve.assert_not_called()
|
||||
share_group_api.QUOTAS.commit.assert_not_called()
|
||||
share_group_api.QUOTAS.rollback.assert_not_called()
|
||||
|
||||
@ddt.data({}, {"name": "fake_name"})
|
||||
def test_update_share_group_snapshot_no_values(self, expected_values):
|
||||
|
@ -711,6 +711,6 @@ class QuotaEngineTestCase(test.TestCase):
|
||||
|
||||
def test_current_common_resources(self):
|
||||
self.assertEqual(
|
||||
['gigabytes', 'share_networks', 'shares',
|
||||
'snapshot_gigabytes', 'snapshots'],
|
||||
['gigabytes', 'share_group_snapshots', 'share_groups',
|
||||
'share_networks', 'shares', 'snapshot_gigabytes', 'snapshots'],
|
||||
quota.QUOTAS.resources)
|
||||
|
@ -30,7 +30,7 @@ ShareGroup = [
|
||||
help="The minimum api microversion is configured to be the "
|
||||
"value of the minimum microversion supported by Manila."),
|
||||
cfg.StrOpt("max_api_microversion",
|
||||
default="2.39",
|
||||
default="2.40",
|
||||
help="The maximum api microversion is configured to be the "
|
||||
"value of the latest microversion supported by Manila."),
|
||||
cfg.StrOpt("region",
|
||||
|
@ -909,7 +909,9 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
|
||||
def update_quotas(self, tenant_id, user_id=None, shares=None,
|
||||
snapshots=None, gigabytes=None, snapshot_gigabytes=None,
|
||||
share_networks=None, force=True, share_type=None,
|
||||
share_networks=None,
|
||||
share_groups=None, share_group_snapshots=None,
|
||||
force=True, share_type=None,
|
||||
url=None, version=LATEST_MICROVERSION):
|
||||
if url is None:
|
||||
url = self._get_quotas_url(version)
|
||||
@ -929,6 +931,10 @@ class SharesV2Client(shares_client.SharesClient):
|
||||
put_body["snapshot_gigabytes"] = snapshot_gigabytes
|
||||
if share_networks is not None:
|
||||
put_body["share_networks"] = share_networks
|
||||
if share_groups is not None:
|
||||
put_body["share_groups"] = share_groups
|
||||
if share_group_snapshots is not None:
|
||||
put_body["share_group_snapshots"] = share_group_snapshots
|
||||
put_body = json.dumps({"quota_set": put_body})
|
||||
|
||||
resp, body = self.put(url, put_body, version=version)
|
||||
|
@ -17,11 +17,15 @@ import ddt
|
||||
from tempest import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
from manila_tempest_tests import utils
|
||||
|
||||
CONF = config.CONF
|
||||
PRE_SHARE_GROUPS_MICROVERSION = "2.39"
|
||||
SHARE_GROUPS_MICROVERSION = "2.40"
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@ -44,6 +48,9 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest):
|
||||
self.assertGreater(int(quotas["shares"]), -2)
|
||||
self.assertGreater(int(quotas["snapshots"]), -2)
|
||||
self.assertGreater(int(quotas["share_networks"]), -2)
|
||||
if utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION):
|
||||
self.assertGreater(int(quotas["share_groups"]), -2)
|
||||
self.assertGreater(int(quotas["share_group_snapshots"]), -2)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_show_quotas(self):
|
||||
@ -53,6 +60,9 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest):
|
||||
self.assertGreater(int(quotas["shares"]), -2)
|
||||
self.assertGreater(int(quotas["snapshots"]), -2)
|
||||
self.assertGreater(int(quotas["share_networks"]), -2)
|
||||
if utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION):
|
||||
self.assertGreater(int(quotas["share_groups"]), -2)
|
||||
self.assertGreater(int(quotas["share_group_snapshots"]), -2)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_show_quotas_for_user(self):
|
||||
@ -63,6 +73,28 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest):
|
||||
self.assertGreater(int(quotas["shares"]), -2)
|
||||
self.assertGreater(int(quotas["snapshots"]), -2)
|
||||
self.assertGreater(int(quotas["share_networks"]), -2)
|
||||
if utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION):
|
||||
self.assertGreater(int(quotas["share_groups"]), -2)
|
||||
self.assertGreater(int(quotas["share_group_snapshots"]), -2)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@base.skip_if_microversion_not_supported(PRE_SHARE_GROUPS_MICROVERSION)
|
||||
def test_show_sg_quotas_using_too_old_microversion(self):
|
||||
quotas = self.shares_v2_client.show_quotas(
|
||||
self.tenant_id, version=PRE_SHARE_GROUPS_MICROVERSION)
|
||||
|
||||
for key in ('share_groups', 'share_group_snapshots'):
|
||||
self.assertNotIn(key, quotas)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@base.skip_if_microversion_not_supported(PRE_SHARE_GROUPS_MICROVERSION)
|
||||
def test_show_sg_quotas_for_user_using_too_old_microversion(self):
|
||||
quotas = self.shares_v2_client.show_quotas(
|
||||
self.tenant_id, self.user_id,
|
||||
version=PRE_SHARE_GROUPS_MICROVERSION)
|
||||
|
||||
for key in ('share_groups', 'share_group_snapshots'):
|
||||
self.assertNotIn(key, quotas)
|
||||
|
||||
@ddt.data(
|
||||
('id', True),
|
||||
@ -93,12 +125,16 @@ class SharesAdminQuotasTest(base.BaseSharesAdminTest):
|
||||
for key in ('shares', 'gigabytes', 'snapshots', 'snapshot_gigabytes'):
|
||||
self.assertEqual(st_quotas[key], p_quotas[key])
|
||||
|
||||
# Verify that we do not have share groups related quotas
|
||||
# for share types.
|
||||
for key in ('share_groups', 'share_group_snapshots'):
|
||||
self.assertNotIn(key, st_quotas)
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
||||
|
||||
force_tenant_isolation = True
|
||||
client_version = '2'
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
@ -109,8 +145,7 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
||||
|
||||
def setUp(self):
|
||||
super(self.__class__, self).setUp()
|
||||
self.client = self.get_client_with_isolated_creds(
|
||||
client_version=self.client_version)
|
||||
self.client = self.get_client_with_isolated_creds(client_version='2')
|
||||
self.tenant_id = self.client.tenant_id
|
||||
self.user_id = self.client.user_id
|
||||
|
||||
@ -124,6 +159,24 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
||||
updated = self.client.update_quotas(self.tenant_id, shares=new_quota)
|
||||
self.assertEqual(new_quota, int(updated["shares"]))
|
||||
|
||||
@ddt.data(
|
||||
"share_groups",
|
||||
"share_group_snapshots",
|
||||
)
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
|
||||
def test_update_tenant_quota_share_groups(self, quota_key):
|
||||
# Get current quotas
|
||||
quotas = self.client.show_quotas(self.tenant_id)
|
||||
new_quota = int(quotas[quota_key]) + 2
|
||||
|
||||
# Set new quota
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id, **{quota_key: new_quota})
|
||||
self.assertEqual(new_quota, int(updated[quota_key]))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_update_user_quota_shares(self):
|
||||
# get current quotas
|
||||
@ -135,6 +188,24 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
||||
self.tenant_id, self.user_id, shares=new_quota)
|
||||
self.assertEqual(new_quota, int(updated["shares"]))
|
||||
|
||||
@ddt.data(
|
||||
"share_groups",
|
||||
"share_group_snapshots",
|
||||
)
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
|
||||
def test_update_user_quota_share_groups(self, quota_key):
|
||||
# Get current quotas
|
||||
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
|
||||
new_quota = int(quotas[quota_key]) - 1
|
||||
|
||||
# Set new quota
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id, self.user_id, **{quota_key: new_quota})
|
||||
self.assertEqual(new_quota, int(updated[quota_key]))
|
||||
|
||||
def _create_share_type(self):
|
||||
share_type = self.create_share_type(
|
||||
data_utils.rand_name("tempest-manila"),
|
||||
@ -280,44 +351,63 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
def test_reset_tenant_quotas(self):
|
||||
# get default_quotas
|
||||
# Get default_quotas
|
||||
default = self.client.default_quotas(self.tenant_id)
|
||||
|
||||
# get current quotas
|
||||
# Get current quotas
|
||||
custom = self.client.show_quotas(self.tenant_id)
|
||||
|
||||
# make quotas for update
|
||||
shares = int(custom["shares"]) + 2
|
||||
snapshots = int(custom["snapshots"]) + 2
|
||||
gigabytes = int(custom["gigabytes"]) + 2
|
||||
snapshot_gigabytes = int(custom["snapshot_gigabytes"]) + 2
|
||||
share_networks = int(custom["share_networks"]) + 2
|
||||
# Make quotas for update
|
||||
data = {
|
||||
"shares": int(custom["shares"]) + 2,
|
||||
"snapshots": int(custom["snapshots"]) + 2,
|
||||
"gigabytes": int(custom["gigabytes"]) + 2,
|
||||
"snapshot_gigabytes": int(custom["snapshot_gigabytes"]) + 2,
|
||||
"share_networks": int(custom["share_networks"]) + 2,
|
||||
}
|
||||
if (utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION) and
|
||||
CONF.share.run_share_group_tests):
|
||||
data["share_groups"] = int(custom["share_groups"]) + 2
|
||||
data["share_group_snapshots"] = (
|
||||
int(custom["share_group_snapshots"]) + 2)
|
||||
|
||||
# set new quota
|
||||
updated = self.client.update_quotas(
|
||||
self.tenant_id,
|
||||
shares=shares,
|
||||
snapshots=snapshots,
|
||||
gigabytes=gigabytes,
|
||||
snapshot_gigabytes=snapshot_gigabytes,
|
||||
share_networks=share_networks)
|
||||
self.assertEqual(shares, int(updated["shares"]))
|
||||
self.assertEqual(snapshots, int(updated["snapshots"]))
|
||||
self.assertEqual(gigabytes, int(updated["gigabytes"]))
|
||||
self.assertEqual(snapshot_gigabytes,
|
||||
int(updated["snapshot_gigabytes"]))
|
||||
self.assertEqual(share_networks, int(updated["share_networks"]))
|
||||
updated = self.client.update_quotas(self.tenant_id, **data)
|
||||
self.assertEqual(data["shares"], int(updated["shares"]))
|
||||
self.assertEqual(data["snapshots"], int(updated["snapshots"]))
|
||||
self.assertEqual(data["gigabytes"], int(updated["gigabytes"]))
|
||||
self.assertEqual(
|
||||
data["snapshot_gigabytes"], int(updated["snapshot_gigabytes"]))
|
||||
self.assertEqual(
|
||||
data["share_networks"], int(updated["share_networks"]))
|
||||
if (utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION) and
|
||||
CONF.share.run_share_group_tests):
|
||||
self.assertEqual(
|
||||
data["share_groups"], int(updated["share_groups"]))
|
||||
self.assertEqual(
|
||||
data["share_group_snapshots"],
|
||||
int(updated["share_group_snapshots"]))
|
||||
|
||||
# reset customized quotas
|
||||
# Reset customized quotas
|
||||
self.client.reset_quotas(self.tenant_id)
|
||||
|
||||
# verify quotas
|
||||
# Verify quotas
|
||||
reseted = self.client.show_quotas(self.tenant_id)
|
||||
self.assertEqual(int(default["shares"]), int(reseted["shares"]))
|
||||
self.assertEqual(int(default["snapshots"]), int(reseted["snapshots"]))
|
||||
self.assertEqual(int(default["gigabytes"]), int(reseted["gigabytes"]))
|
||||
self.assertEqual(int(default["share_networks"]),
|
||||
int(reseted["share_networks"]))
|
||||
self.assertEqual(
|
||||
int(default["snapshot_gigabytes"]),
|
||||
int(reseted["snapshot_gigabytes"]))
|
||||
self.assertEqual(
|
||||
int(default["share_networks"]), int(reseted["share_networks"]))
|
||||
if (utils.is_microversion_supported(SHARE_GROUPS_MICROVERSION) and
|
||||
CONF.share.run_share_group_tests):
|
||||
self.assertEqual(
|
||||
int(default["share_groups"]), int(reseted["share_groups"]))
|
||||
self.assertEqual(
|
||||
int(default["share_group_snapshots"]),
|
||||
int(reseted["share_group_snapshots"]))
|
||||
|
||||
@ddt.data(
|
||||
('id', True),
|
||||
@ -450,6 +540,29 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
||||
|
||||
self.assertEqual(-1, quotas.get('share_networks'))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
|
||||
def test_unlimited_quota_for_share_groups(self):
|
||||
self.client.update_quotas(self.tenant_id, share_groups=-1)
|
||||
|
||||
quotas = self.client.show_quotas(self.tenant_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('share_groups'))
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
|
||||
def test_unlimited_user_quota_for_share_group_snapshots(self):
|
||||
self.client.update_quotas(
|
||||
self.tenant_id, self.user_id, share_group_snapshots=-1)
|
||||
|
||||
quotas = self.client.show_quotas(self.tenant_id, self.user_id)
|
||||
|
||||
self.assertEqual(-1, quotas.get('share_group_snapshots'))
|
||||
|
||||
@ddt.data(11, -1)
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_update_user_quotas_bigger_than_project_quota(self, user_quota):
|
||||
@ -541,3 +654,82 @@ class SharesAdminQuotasUpdateTest(base.BaseSharesAdminTest):
|
||||
for key in ('shares', 'gigabytes'):
|
||||
self.assertEqual(0, quotas[key]['reserved'])
|
||||
self.assertEqual(0, quotas[key]['in_use'])
|
||||
|
||||
def _check_sg_usages(self, quotas, in_use, limit):
|
||||
"""Helper method for 'test_share_group_quotas_usages' test."""
|
||||
self.assertEqual(0, int(quotas['share_groups']['reserved']))
|
||||
self.assertEqual(in_use, int(quotas['share_groups']['in_use']))
|
||||
self.assertEqual(limit, int(quotas['share_groups']['limit']))
|
||||
|
||||
def _check_sgs_usages(self, quotas, in_use):
|
||||
"""Helper method for 'test_share_group_quotas_usages' test."""
|
||||
self.assertEqual(0, int(quotas['share_group_snapshots']['reserved']))
|
||||
self.assertEqual(
|
||||
in_use, int(quotas['share_group_snapshots']['in_use']))
|
||||
self.assertEqual(1, int(quotas['share_group_snapshots']['limit']))
|
||||
|
||||
def _check_usages(self, sg_in_use, sgs_in_use):
|
||||
"""Helper method for 'test_share_group_quotas_usages' test."""
|
||||
p_quotas = self.client.detail_quotas(tenant_id=self.tenant_id)
|
||||
u_quotas = self.client.detail_quotas(
|
||||
tenant_id=self.tenant_id, user_id=self.user_id)
|
||||
self._check_sg_usages(p_quotas, sg_in_use, 3)
|
||||
self._check_sg_usages(u_quotas, sg_in_use, 2)
|
||||
self._check_sgs_usages(p_quotas, sgs_in_use)
|
||||
self._check_sgs_usages(u_quotas, sgs_in_use)
|
||||
|
||||
@tc.attr(base.TAG_POSITIVE, base.TAG_API_WITH_BACKEND)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@base.skip_if_microversion_lt(SHARE_GROUPS_MICROVERSION)
|
||||
def test_share_group_quotas_usages(self):
|
||||
# Set quotas for project (3 SG, 1 SGS) and user (2 SG, 1 SGS)
|
||||
self.client.update_quotas(
|
||||
self.tenant_id, share_groups=3, share_group_snapshots=1)
|
||||
self.client.update_quotas(
|
||||
self.tenant_id, user_id=self.user_id,
|
||||
share_groups=2, share_group_snapshots=1)
|
||||
|
||||
# Check usages, they should be 0s
|
||||
self._check_usages(0, 0)
|
||||
|
||||
# Create SG1 and check usages
|
||||
share_group1 = self.create_share_group(
|
||||
cleanup_in_class=False, client=self.client)
|
||||
self._check_usages(1, 0)
|
||||
|
||||
# Create SGS1 and check usages
|
||||
sg_snapshot = self.create_share_group_snapshot_wait_for_active(
|
||||
share_group1['id'], cleanup_in_class=False, client=self.client)
|
||||
self._check_usages(1, 1)
|
||||
|
||||
# Create SG2 from SGS1 and check usages
|
||||
share_group2 = self.create_share_group(
|
||||
cleanup_in_class=False, client=self.client,
|
||||
source_share_group_snapshot_id=sg_snapshot['id'])
|
||||
self._check_usages(2, 1)
|
||||
|
||||
# Try create SGS2, fail, then check usages
|
||||
self.assertRaises(
|
||||
lib_exc.OverLimit,
|
||||
self.create_share_group,
|
||||
client=self.client, cleanup_in_class=False)
|
||||
self._check_usages(2, 1)
|
||||
|
||||
# Delete SG2 and check usages
|
||||
self.client.delete_share_group(share_group2['id'])
|
||||
self.client.wait_for_resource_deletion(
|
||||
share_group_id=share_group2['id'])
|
||||
self._check_usages(1, 1)
|
||||
|
||||
# Delete SGS1 and check usages
|
||||
self.client.delete_share_group_snapshot(sg_snapshot['id'])
|
||||
self.client.wait_for_resource_deletion(
|
||||
share_group_snapshot_id=sg_snapshot['id'])
|
||||
self._check_usages(1, 0)
|
||||
|
||||
# Delete SG1 and check usages
|
||||
self.client.delete_share_group(share_group1['id'])
|
||||
self.client.wait_for_resource_deletion(
|
||||
share_group_id=share_group1['id'])
|
||||
self._check_usages(0, 0)
|
||||
|
@ -17,11 +17,15 @@ import ddt
|
||||
from tempest import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
import testtools
|
||||
from testtools import testcase as tc
|
||||
|
||||
from manila_tempest_tests.tests.api import base
|
||||
from manila_tempest_tests import utils
|
||||
|
||||
CONF = config.CONF
|
||||
PRE_SHARE_GROUPS_MICROVERSION = "2.39"
|
||||
SHARE_GROUPS_MICROVERSION = "2.40"
|
||||
|
||||
|
||||
@ddt.ddt
|
||||
@ -49,50 +53,35 @@ class SharesAdminQuotasNegativeTest(base.BaseSharesAdminTest):
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
client.reset_quotas, "")
|
||||
|
||||
@ddt.data(
|
||||
{"shares": -2},
|
||||
{"snapshots": -2},
|
||||
{"gigabytes": -2},
|
||||
{"snapshot_gigabytes": -2},
|
||||
{"share_networks": -2},
|
||||
)
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_update_shares_quota_with_wrong_data(self):
|
||||
def test_update_quota_with_wrong_data(self, kwargs):
|
||||
# -1 is acceptable value as unlimited
|
||||
client = self.get_client_with_isolated_creds()
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
client.update_quotas,
|
||||
client.tenant_id,
|
||||
shares=-2)
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
client.update_quotas, client.tenant_id, **kwargs)
|
||||
|
||||
@ddt.data(
|
||||
{"share_groups": -2},
|
||||
{"share_group_snapshots": -2},
|
||||
)
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_update_snapshots_quota_with_wrong_data(self):
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
|
||||
def test_update_sg_quota_with_wrong_data(self, kwargs):
|
||||
# -1 is acceptable value as unlimited
|
||||
client = self.get_client_with_isolated_creds()
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
client.update_quotas,
|
||||
client.tenant_id,
|
||||
snapshots=-2)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_update_gigabytes_quota_with_wrong_data(self):
|
||||
# -1 is acceptable value as unlimited
|
||||
client = self.get_client_with_isolated_creds()
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
client.update_quotas,
|
||||
client.tenant_id,
|
||||
gigabytes=-2)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_update_snapshot_gigabytes_quota_with_wrong_data(self):
|
||||
# -1 is acceptable value as unlimited
|
||||
client = self.get_client_with_isolated_creds()
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
client.update_quotas,
|
||||
client.tenant_id,
|
||||
snapshot_gigabytes=-2)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_update_share_networks_quota_with_wrong_data(self):
|
||||
# -1 is acceptable value as unlimited
|
||||
client = self.get_client_with_isolated_creds()
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
client.update_quotas,
|
||||
client.tenant_id,
|
||||
share_networks=-2)
|
||||
client = self.get_client_with_isolated_creds(client_version='2')
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
client.update_quotas, client.tenant_id, **kwargs)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_create_share_with_size_bigger_than_quota(self):
|
||||
@ -105,6 +94,21 @@ class SharesAdminQuotasNegativeTest(base.BaseSharesAdminTest):
|
||||
self.create_share,
|
||||
size=overquota)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
@testtools.skipUnless(
|
||||
CONF.share.run_share_group_tests, 'Share Group tests disabled.')
|
||||
@utils.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
|
||||
def test_create_share_group_with_exceeding_quota_limit(self):
|
||||
client = self.get_client_with_isolated_creds(client_version='2')
|
||||
client.update_quotas(client.tenant_id, share_groups=0)
|
||||
|
||||
# Try schedule share group creation
|
||||
self.assertRaises(
|
||||
lib_exc.OverLimit,
|
||||
self.create_share_group,
|
||||
client=client,
|
||||
cleanup_in_class=False)
|
||||
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
def test_try_set_user_quota_shares_bigger_than_tenant_quota(self):
|
||||
client = self.get_client_with_isolated_creds()
|
||||
@ -267,6 +271,41 @@ class SharesAdminQuotasNegativeTest(base.BaseSharesAdminTest):
|
||||
share_networks=int(tenant_quotas["share_networks"]),
|
||||
)
|
||||
|
||||
@ddt.data('share_groups', 'share_group_snapshots')
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
@base.skip_if_microversion_lt(SHARE_GROUPS_MICROVERSION)
|
||||
def test_try_update_share_type_quota_for_share_groups(self, quota_name):
|
||||
client = self.get_client_with_isolated_creds(client_version='2')
|
||||
share_type = self._create_share_type()
|
||||
tenant_quotas = client.show_quotas(client.tenant_id)
|
||||
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
client.update_quotas,
|
||||
client.tenant_id,
|
||||
share_type=share_type["name"],
|
||||
**{quota_name: int(tenant_quotas[quota_name])}
|
||||
)
|
||||
|
||||
@ddt.data('share_groups', 'share_group_snapshots')
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
@base.skip_if_microversion_not_supported(PRE_SHARE_GROUPS_MICROVERSION)
|
||||
@base.skip_if_microversion_not_supported(SHARE_GROUPS_MICROVERSION)
|
||||
def test_share_group_quotas_using_too_old_microversion(self, quota_key):
|
||||
client = self.get_client_with_isolated_creds(client_version='2')
|
||||
tenant_quotas = client.show_quotas(
|
||||
client.tenant_id, version=SHARE_GROUPS_MICROVERSION)
|
||||
kwargs = {
|
||||
"version": PRE_SHARE_GROUPS_MICROVERSION,
|
||||
quota_key: tenant_quotas[quota_key],
|
||||
}
|
||||
|
||||
self.assertRaises(
|
||||
lib_exc.BadRequest,
|
||||
client.update_quotas,
|
||||
client.tenant_id,
|
||||
**kwargs)
|
||||
|
||||
@ddt.data('show', 'reset', 'update')
|
||||
@tc.attr(base.TAG_NEGATIVE, base.TAG_API)
|
||||
@base.skip_if_microversion_lt("2.38")
|
||||
|
@ -0,0 +1,7 @@
|
||||
---
|
||||
features:
|
||||
- Added quotas for amount of share groups and share group snapshots.
|
||||
upgrade:
|
||||
- Two new config options are available for setting default quotas for share
|
||||
groups and share group snapshots - 'quota_share_groups' and
|
||||
'quota_share_group_snapshots'.
|
Loading…
Reference in New Issue
Block a user