if self._collection in body:
# Have to account for bulk create
items = body[self._collection]
+ deltas = {}
+ bulk = True
else:
items = [body]
+ bulk = False
# Ensure policy engine is initialized
policy.init()
- # Store requested resource amounts grouping them by tenant
- # This won't work with multiple resources. However because of the
- # current structure of this controller there will hardly be more than
- # one resource for which reservations are being made
- request_deltas = {}
for item in items:
self._validate_network_tenant_ownership(request,
item[self._resource])
if 'tenant_id' not in item[self._resource]:
# no tenant_id - no quota check
continue
- tenant_id = item[self._resource]['tenant_id']
- delta = request_deltas.get(tenant_id, 0)
- delta = delta + 1
- request_deltas[tenant_id] = delta
- # Quota enforcement
- reservations = []
- try:
- for tenant in request_deltas:
- reservation = quota.QUOTAS.make_reservation(
- request.context,
- tenant,
- {self._resource:
- request_deltas[tenant]},
- self._plugin)
- reservations.append(reservation)
- except exceptions.QuotaResourceUnknown as e:
+ try:
+ tenant_id = item[self._resource]['tenant_id']
+ count = quota.QUOTAS.count(request.context, self._resource,
+ self._plugin, tenant_id)
+ if bulk:
+ delta = deltas.get(tenant_id, 0) + 1
+ deltas[tenant_id] = delta
+ else:
+ delta = 1
+ kwargs = {self._resource: count + delta}
+ except exceptions.QuotaResourceUnknown as e:
# We don't want to quota this resource
LOG.debug(e)
+ else:
+ quota.QUOTAS.limit_check(request.context,
+ item[self._resource]['tenant_id'],
+ **kwargs)
def notify(create_result):
# Ensure usage trackers for all resources affected by this API
# operation are marked as dirty
- with request.context.session.begin():
- # Commit the reservation(s)
- for reservation in reservations:
- quota.QUOTAS.commit_reservation(
- request.context, reservation.reservation_id)
- resource_registry.set_resources_dirty(request.context)
+ # TODO(salv-orlando): This operation will happen in a single
+ # transaction with reservation commit once that is implemented
+ resource_registry.set_resources_dirty(request.context)
notifier_method = self._resource + '.create.end'
self._notifier.info(request.context,
notifier_method)
return create_result
- def do_create(body, bulk=False, emulated=False):
- kwargs = {self._parent_id_name: parent_id} if parent_id else {}
- if bulk and not emulated:
- obj_creator = getattr(self._plugin, "%s_bulk" % action)
- else:
- obj_creator = getattr(self._plugin, action)
- try:
- if emulated:
- return self._emulate_bulk_create(obj_creator, request,
- body, parent_id)
- else:
- if self._collection in body:
- # This is weird but fixing it requires changes to the
- # plugin interface
- kwargs.update({self._collection: body})
- else:
- kwargs.update({self._resource: body})
- return obj_creator(request.context, **kwargs)
- except Exception:
- # In case of failure the plugin will always raise an
- # exception. Cancel the reservation
- with excutils.save_and_reraise_exception():
- for reservation in reservations:
- quota.QUOTAS.cancel_reservation(
- request.context, reservation.reservation_id)
-
+ kwargs = {self._parent_id_name: parent_id} if parent_id else {}
if self._collection in body and self._native_bulk:
# plugin does atomic bulk create operations
- objs = do_create(body, bulk=True)
+ obj_creator = getattr(self._plugin, "%s_bulk" % action)
+ objs = obj_creator(request.context, body, **kwargs)
# Use first element of list to discriminate attributes which
# should be removed because of authZ policies
fields_to_strip = self._exclude_attributes_by_policy(
request.context, obj, fields_to_strip=fields_to_strip)
for obj in objs]})
else:
+ obj_creator = getattr(self._plugin, action)
if self._collection in body:
# Emulate atomic bulk behavior
- objs = do_create(body, bulk=True, emulated=True)
+ objs = self._emulate_bulk_create(obj_creator, request,
+ body, parent_id)
return notify({self._collection: objs})
else:
- obj = do_create(body)
+ kwargs.update({self._resource: body})
+ obj = obj_creator(request.context, **kwargs)
self._send_nova_notification(action, {},
{self._resource: obj})
return notify({self._resource: self._view(request.context,