2263
2295
quota_ref.delete(session=session)
2302
def quota_class_get(context, class_name, resource, session=None):
2303
result = model_query(context, models.QuotaClass, session=session,
2304
read_deleted="no").\
2305
filter_by(class_name=class_name).\
2306
filter_by(resource=resource).\
2310
raise exception.QuotaClassNotFound(class_name=class_name)
2316
def quota_class_get_all_by_name(context, class_name):
2317
authorize_quota_class_context(context, class_name)
2319
rows = model_query(context, models.QuotaClass, read_deleted="no").\
2320
filter_by(class_name=class_name).\
2323
result = {'class_name': class_name}
2325
result[row.resource] = row.hard_limit
2330
@require_admin_context
2331
def quota_class_create(context, class_name, resource, limit):
2332
quota_class_ref = models.QuotaClass()
2333
quota_class_ref.class_name = class_name
2334
quota_class_ref.resource = resource
2335
quota_class_ref.hard_limit = limit
2336
quota_class_ref.save()
2337
return quota_class_ref
2340
@require_admin_context
2341
def quota_class_update(context, class_name, resource, limit):
2342
session = get_session()
2343
with session.begin():
2344
quota_class_ref = quota_class_get(context, class_name, resource,
2346
quota_class_ref.hard_limit = limit
2347
quota_class_ref.save(session=session)
2350
@require_admin_context
2351
def quota_class_destroy(context, class_name, resource):
2352
session = get_session()
2353
with session.begin():
2354
quota_class_ref = quota_class_get(context, class_name, resource,
2356
quota_class_ref.delete(session=session)
2359
@require_admin_context
2360
def quota_class_destroy_all_by_name(context, class_name):
2361
session = get_session()
2362
with session.begin():
2363
quota_classes = model_query(context, models.QuotaClass,
2364
session=session, read_deleted="no").\
2365
filter_by(class_name=class_name).\
2368
for quota_class_ref in quota_classes:
2369
quota_class_ref.delete(session=session)
2376
def quota_usage_get(context, project_id, resource, session=None):
2377
result = model_query(context, models.QuotaUsage, session=session,
2378
read_deleted="no").\
2379
filter_by(project_id=project_id).\
2380
filter_by(resource=resource).\
2384
raise exception.QuotaUsageNotFound(project_id=project_id)
2390
def quota_usage_get_all_by_project(context, project_id):
2391
authorize_project_context(context, project_id)
2393
rows = model_query(context, models.QuotaUsage, read_deleted="no").\
2394
filter_by(project_id=project_id).\
2397
result = {'project_id': project_id}
2399
result[row.resource] = dict(in_use=row.in_use, reserved=row.reserved)
2404
@require_admin_context
2405
def quota_usage_create(context, project_id, resource, in_use, reserved,
2406
until_refresh, session=None, save=True):
2407
quota_usage_ref = models.QuotaUsage()
2408
quota_usage_ref.project_id = project_id
2409
quota_usage_ref.resource = resource
2410
quota_usage_ref.in_use = in_use
2411
quota_usage_ref.reserved = reserved
2412
quota_usage_ref.until_refresh = until_refresh
2414
# Allow us to hold the save operation until later; keeps the
2415
# transaction in quota_reserve() from breaking too early
2417
quota_usage_ref.save(session=session)
2419
return quota_usage_ref
2422
@require_admin_context
2423
def quota_usage_update(context, project_id, resource, in_use, reserved,
2424
until_refresh, session=None):
2425
def do_update(session):
2426
quota_usage_ref = quota_usage_get(context, project_id, resource,
2428
quota_usage_ref.in_use = in_use
2429
quota_usage_ref.reserved = reserved
2430
quota_usage_ref.until_refresh = until_refresh
2431
quota_usage_ref.save(session=session)
2434
# Assume caller started a transaction
2437
session = get_session()
2438
with session.begin():
2442
@require_admin_context
2443
def quota_usage_destroy(context, project_id, resource):
2444
session = get_session()
2445
with session.begin():
2446
quota_usage_ref = quota_usage_get(context, project_id, resource,
2448
quota_usage_ref.delete(session=session)
2455
def reservation_get(context, uuid, session=None):
2456
result = model_query(context, models.Reservation, session=session,
2457
read_deleted="no").\
2458
filter_by(uuid=uuid).\
2462
raise exception.ReservationNotFound(uuid=uuid)
2468
def reservation_get_all_by_project(context, project_id):
2469
authorize_project_context(context, project_id)
2471
rows = model_query(context, models.QuotaUsage, read_deleted="no").\
2472
filter_by(project_id=project_id).\
2475
result = {'project_id': project_id}
2477
result.setdefault(row.resource, {})
2478
result[row.resource][row.uuid] = row.delta
2483
@require_admin_context
2484
def reservation_create(context, uuid, usage, project_id, resource, delta,
2485
expire, session=None):
2486
reservation_ref = models.Reservation()
2487
reservation_ref.uuid = uuid
2488
reservation_ref.usage = usage
2489
reservation_ref.project_id = project_id
2490
reservation_ref.resource = resource
2491
reservation_ref.delta = delta
2492
reservation_ref.expire = expire
2493
reservation_ref.save(session=session)
2494
return reservation_ref
2497
@require_admin_context
2498
def reservation_destroy(context, uuid):
2499
session = get_session()
2500
with session.begin():
2501
reservation_ref = reservation_get(context, uuid, session=session)
2502
reservation_ref.delete(session=session)
2508
def _get_quota_usages(context, session, keys):
2509
# Broken out for testability
2510
rows = model_query(context, models.QuotaUsage,
2513
filter_by(project_id=context.project_id).\
2514
filter(models.QuotaUsage.resource.in_(keys)).\
2515
with_lockmode('update').\
2517
return dict((row.resource, row) for row in rows)
2521
def quota_reserve(context, resources, quotas, deltas, expire,
2522
until_refresh, max_age):
2523
elevated = context.elevated()
2524
session = get_session()
2525
with session.begin():
2526
# Get the current usages
2527
usages = _get_quota_usages(context, session, deltas.keys())
2529
# Handle usage refresh
2530
work = set(deltas.keys())
2532
resource = work.pop()
2534
# Do we need to refresh the usage?
2536
if resource not in usages:
2537
# Note we're inhibiting save...
2538
usages[resource] = quota_usage_create(elevated,
2542
until_refresh or None,
2546
elif usages[resource].until_refresh is not None:
2547
usages[resource].until_refresh -= 1
2548
if usages[resource].until_refresh <= 0:
2550
elif max_age and (usages[resource].updated_at -
2551
utils.utcnow()).seconds >= max_age:
2554
# OK, refresh the usage
2556
# Grab the sync routine
2557
sync = resources[resource].sync
2559
updates = sync(elevated, context.project_id, session)
2560
for res, in_use in updates.items():
2561
# Make sure we have a destination for the usage!
2562
if res not in usages:
2563
# Note we're inhibiting save...
2564
usages[res] = quota_usage_create(elevated,
2568
until_refresh or None,
2573
usages[res].in_use = in_use
2574
usages[res].until_refresh = until_refresh or None
2576
# Because more than one resource may be refreshed
2577
# by the call to the sync routine, and we don't
2578
# want to double-sync, we make sure all refreshed
2579
# resources are dropped from the work set.
2582
# NOTE(Vek): We make the assumption that the sync
2583
# routine actually refreshes the
2584
# resources that it is the sync routine
2585
# for. We don't check, because this is
2586
# a best-effort mechanism.
2588
# Check for deltas that would go negative
2589
unders = [resource for resource, delta in deltas.items()
2591
delta + usages[resource].in_use < 0]
2593
# Now, let's check the quotas
2594
# NOTE(Vek): We're only concerned about positive increments.
2595
# If a project has gone over quota, we want them to
2596
# be able to reduce their usage without any
2598
overs = [resource for resource, delta in deltas.items()
2599
if quotas[resource] >= 0 and delta >= 0 and
2600
quotas[resource] < delta + usages[resource].total]
2602
# NOTE(Vek): The quota check needs to be in the transaction,
2603
# but the transaction doesn't fail just because
2604
# we're over quota, so the OverQuota raise is
2605
# outside the transaction. If we did the raise
2606
# here, our usage updates would be discarded, but
2607
# they're not invalidated by being over-quota.
2609
# Create the reservations
2610
if not unders and not overs:
2612
for resource, delta in deltas.items():
2613
reservation = reservation_create(elevated,
2614
str(utils.gen_uuid()),
2617
resource, delta, expire,
2619
reservations.append(reservation.uuid)
2621
# Also update the reserved quantity
2622
# NOTE(Vek): Again, we are only concerned here about
2623
# positive increments. Here, though, we're
2624
# worried about the following scenario:
2626
# 1) User initiates resize down.
2627
# 2) User allocates a new instance.
2628
# 3) Resize down fails or is reverted.
2629
# 4) User is now over quota.
2631
# To prevent this, we only update the
2632
# reserved value if the delta is positive.
2634
usages[resource].reserved += delta
2636
# Apply updates to the usages table
2637
for usage_ref in usages.values():
2638
usage_ref.save(session=session)
2641
raise exception.InvalidQuotaValue(unders=sorted(unders))
2643
usages = dict((k, dict(in_use=v['in_use'], reserved=v['reserved']))
2644
for k, v in usages.items())
2645
raise exception.OverQuota(overs=sorted(overs), quotas=quotas,
2651
def _quota_reservations(session, context, reservations):
2652
"""Return the relevant reservations."""
2654
# Get the listed reservations
2655
return model_query(context, models.Reservation,
2658
options(joinedload('usage')).\
2659
filter(models.Reservation.uuid.in_(reservations)).\
2660
with_lockmode('update').\
2665
def reservation_commit(context, reservations):
2666
session = get_session()
2667
with session.begin():
2668
for reservation in _quota_reservations(session, context, reservations):
2669
if reservation.delta >= 0:
2670
reservation.usage.reserved -= reservation.delta
2671
reservation.usage.in_use += reservation.delta
2673
reservation.usage.save(session=session)
2674
reservation.delete(session=session)
2678
def reservation_rollback(context, reservations):
2679
session = get_session()
2680
with session.begin():
2681
for reservation in _quota_reservations(session, context, reservations):
2682
if reservation.delta >= 0:
2683
reservation.usage.reserved -= reservation.delta
2684
reservation.usage.save(session=session)
2686
reservation.delete(session=session)
2266
2689
@require_admin_context
2267
2690
def quota_destroy_all_by_project(context, project_id):
2268
2691
session = get_session()
3573
4123
return metadata
4126
#######################
4127
# System-owned metadata
4129
def _instance_system_metadata_get_query(context, instance_uuid, session=None):
4130
return model_query(context, models.InstanceSystemMetadata, session=session,
4131
read_deleted="no").\
4132
filter_by(instance_uuid=instance_uuid)
4136
@require_instance_exists_using_uuid
4137
def instance_system_metadata_get(context, instance_uuid):
4138
rows = _instance_system_metadata_get_query(context, instance_uuid).all()
4142
result[row['key']] = row['value']
4148
@require_instance_exists_using_uuid
4149
def instance_system_metadata_delete(context, instance_uuid, key):
4150
_instance_system_metadata_get_query(context, instance_uuid).\
4151
filter_by(key=key).\
4152
update({'deleted': True,
4153
'deleted_at': utils.utcnow(),
4154
'updated_at': literal_column('updated_at')})
4157
def _instance_system_metadata_get_item(context, instance_uuid, key,
4159
result = _instance_system_metadata_get_query(
4160
context, instance_uuid, session=session).\
4161
filter_by(key=key).\
4165
raise exception.InstanceSystemMetadataNotFound(
4166
metadata_key=key, instance_uuid=instance_uuid)
4172
@require_instance_exists_using_uuid
4173
def instance_system_metadata_update(context, instance_uuid, metadata, delete):
4174
session = get_session()
4176
# Set existing metadata to deleted if delete argument is True
4178
original_metadata = instance_system_metadata_get(
4179
context, instance_uuid)
4180
for meta_key, meta_value in original_metadata.iteritems():
4181
if meta_key not in metadata:
4182
meta_ref = _instance_system_metadata_get_item(
4183
context, instance_uuid, meta_key, session)
4184
meta_ref.update({'deleted': True})
4185
meta_ref.save(session=session)
4189
# Now update all existing items with new values, or create new meta objects
4190
for meta_key, meta_value in metadata.iteritems():
4192
# update the value whether it exists or not
4193
item = {"value": meta_value}
4196
meta_ref = _instance_system_metadata_get_item(
4197
context, instance_uuid, meta_key, session)
4198
except exception.InstanceSystemMetadataNotFound, e:
4199
meta_ref = models.InstanceSystemMetadata()
4200
item.update({"key": meta_key, "instance_uuid": instance_uuid})
4202
meta_ref.update(item)
4203
meta_ref.save(session=session)
3576
4208
####################