OpenStack Networking (Neutron)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

85 lines
3.5 KiB

# Copyright (c) 2015 Mirantis, Inc.
# All Rights Reserved.
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
# 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 collections
from neutron_lib.db import api as nlib_db_api
from oslo_log import log as logging
from pecan import hooks
from neutron.common import exceptions
from neutron.db import api as db_api
from neutron import manager
from neutron import quota
from neutron.quota import resource_registry
LOG = logging.getLogger(__name__)
class QuotaEnforcementHook(hooks.PecanHook):
priority = 130
def before(self, state):
collection = state.request.context.get('collection')
resource = state.request.context.get('resource')
items = state.request.context.get('resources')
if state.request.method != 'POST' or not resource or not items:
plugin = manager.NeutronManager.get_plugin_for_resource(collection)
# Store requested resource amounts grouping them by tenant
deltas = collections.Counter(map(lambda x: x['tenant_id'], items))
# Perform quota enforcement
reservations = []
neutron_context = state.request.context.get('neutron_context')
for (tenant_id, delta) in deltas.items():
reservation = quota.QUOTAS.make_reservation(
{resource: delta},
LOG.debug("Made reservation on behalf of %(tenant_id)s "
"for: %(delta)s",
{'tenant_id': tenant_id, 'delta': {resource: delta}})
except exceptions.QuotaResourceUnknown as e:
# Quotas cannot be enforced on this resource
# Save the reservations in the request context so that they can be
# retrieved in the 'after' hook
state.request.context['reservations'] = reservations
def after(self, state):
neutron_context = state.request.context.get('neutron_context')
if not neutron_context:
collection = state.request.context.get('collection')
resource = state.request.context.get('resource')
if state.request.method == 'GET' and collection:
# resync on list operations to preserve behavior of old API
neutron_context, resource, neutron_context.tenant_id)
# Commit reservation(s)
reservations = state.request.context.get('reservations') or []
if not reservations and state.request.method != 'DELETE':
with db_api.context_manager.writer.using(neutron_context):
# Commit the reservation(s)
for reservation in reservations:
neutron_context, reservation.reservation_id)