quotas for snapshot

This commit is contained in:
Yulia Portnova 2013-09-16 10:55:45 +03:00
parent 6026fc0244
commit d20f8e92ab
4 changed files with 78 additions and 29 deletions

View File

@ -972,19 +972,16 @@ def share_snapshot_create(context, values):
@require_admin_context
def snapshot_data_get_for_project(context, project_id, session=None):
# TODO(yportnova): Uncomment when snapshot size implemented
raise NotImplementedError()
#
# query = model_query(context,
# func.count(models.ShareSnapshot.id),
# func.sum(models.ShareSnapshot.size),
# read_deleted="no",
# session=session).\
# filter_by(project_id=project_id)
#
# result = query.first()
#
# return (result[0] or 0, result[1] or 0)
query = model_query(context,
func.count(models.ShareSnapshot.id),
func.sum(models.ShareSnapshot.size),
read_deleted="no",
session=session).\
filter_by(project_id=project_id)
result = query.first()
return (result[0] or 0, result[1] or 0)
@require_context

View File

@ -16,7 +16,7 @@
# License for the specific language governing permissions and limitations
# under the License.
"""Quotas for volumes."""
"""Quotas for shares."""
import datetime
@ -775,10 +775,10 @@ class QuotaEngine(object):
def _sync_shares(context, project_id, session):
(volumes, gigs) = db.share_data_get_for_project(context,
project_id,
session=session)
return {'volumes': volumes}
(shares, gigs) = db.share_data_get_for_project(context,
project_id,
session=session)
return {'shares': shares}
def _sync_snapshots(context, project_id, session):
@ -790,17 +790,15 @@ def _sync_snapshots(context, project_id, session):
def _sync_gigabytes(context, project_id, session):
(_junk, share_gigs) = db.share_data_get_for_project(context,
project_id,
session=session)
project_id,
session=session)
if FLAGS.no_snapshot_gb_quota:
return {'gigabytes': share_gigs}
# TODO(yportnova): Uncomment when Snapshot size is implemented
# (_junk, snap_gigs) = db.snapshot_data_get_for_project(context,
# project_id,
# session=session)
# return {'gigabytes': share_gigs + snap_gigs}
return {'gigabytes': share_gigs}
(_junk, snap_gigs) = db.snapshot_data_get_for_project(context,
project_id,
session=session)
return {'gigabytes': share_gigs + snap_gigs}
QUOTAS = QuotaEngine()
@ -808,8 +806,7 @@ QUOTAS = QuotaEngine()
resources = [
ReservableResource('shares', _sync_shares, 'quota_shares'),
# TODO(yportnova): Uncomment when Snapshot size is implemented
# ReservableResource('snapshots', _sync_snapshots, 'quota_snapshots'),
ReservableResource('snapshots', _sync_snapshots, 'quota_snapshots'),
ReservableResource('gigabytes', _sync_gigabytes, 'quota_gigabytes'), ]

View File

@ -227,6 +227,35 @@ class API(base.Base):
msg = _("must be available")
raise exception.InvalidShare(reason=msg)
size = share['size']
try:
reservations = QUOTAS.reserve(context, snapshots=1, gigabytes=size)
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 'gigabytes' in overs:
msg = _("Quota exceeded for %(s_pid)s, tried to create "
"%(s_size)sG snapshot (%(d_consumed)dG of %(d_quota)dG "
"already consumed)")
LOG.warn(msg % {'s_pid': context.project_id,
's_size': size,
'd_consumed': _consumed('gigabytes'),
'd_quota': quotas['gigabytes']})
raise exception.ShareSizeExceedsAvailableQuota()
elif 'snapshots' in overs:
msg = _("Quota exceeded for %(s_pid)s, tried to create "
"snapshot (%(d_consumed)d snapshots "
"already consumed)")
LOG.warn(msg % {'s_pid': context.project_id,
'd_consumed': _consumed('snapshots')})
raise exception.SnapshotLimitExceeded(
allowed=quotas['snapshots'])
options = {'share_id': share['id'],
'size': share['size'],
'user_id': context.user_id,
@ -239,7 +268,16 @@ class API(base.Base):
'share_proto': share['share_proto'],
'export_location': share['export_location']}
snapshot = self.db.share_snapshot_create(context, options)
try:
snapshot = self.db.share_snapshot_create(context, options)
QUOTAS.commit(context, reservations)
except Exception:
with excutils.save_and_reraise_exception():
try:
self.db.snapshot_delete(context, share['id'])
finally:
QUOTAS.rollback(context, reservations)
self.share_rpcapi.create_snapshot(context, share, snapshot)
return snapshot

View File

@ -185,8 +185,14 @@ class ShareManager(manager.SchedulerDependentManager):
def delete_snapshot(self, context, snapshot_id):
"""Delete share snapshot."""
context = context.elevated()
snapshot_ref = self.db.share_snapshot_get(context, snapshot_id)
if context.project_id != snapshot_ref['project_id']:
project_id = snapshot_ref['project_id']
else:
project_id = context.project_id
try:
self.driver.delete_snapshot(context, snapshot_ref)
except exception.ShareSnapshotIsBusy:
@ -198,6 +204,17 @@ class ShareManager(manager.SchedulerDependentManager):
{'status': 'error_deleting'})
else:
self.db.share_snapshot_destroy(context, snapshot_id)
try:
reservations = QUOTAS.reserve(context,
project_id=project_id,
shares=-1,
gigabytes=-snapshot_ref['size'])
except Exception:
reservations = None
LOG.exception(_("Failed to update usages deleting snapshot"))
if reservations:
QUOTAS.commit(context, reservations, project_id=project_id)
def allow_access(self, context, access_id):
"""Allow access to some share."""