Files
neutron/neutron/core_extensions/qos.py
T
Slawek Kaplonski 062336e59b Set system_scope='all' in elevated context
In case when enforce_new_defaults is set to True and new policy rules
are used, context.is_admin flag isn't really working as it was with old
rules.
But in case when elevated context is needed, it means that we need
context which has full rights to the system. So we should also set
"system_scope" parameter to "all" to be sure that system scope queries
can be done with such elevated context always.

It is needed e.g. when elevated context is used to get some data from
db. In such case we need to have db query which will not be scoped to
the single project_id and with new defaults to achieve that system_scope
has to be set to "all".

Proper fix for that should be done in neutron-lib and it is proposed
in [1] already but as we are have frozen neutron-lib version for
stable/wallaby already this patch for neutron is temporary fix for that
issue.
We can revert that patch as soon as we will be in Xena development cycle
and [1] will be merged and released.

[1] https://review.opendev.org/c/openstack/neutron-lib/+/781625

Related-Bug: #1920001
Change-Id: I0068c1de09f5c6fae5bb5cd0d6f26f451e701939
2021-03-19 12:05:56 +01:00

118 lines
5.0 KiB
Python

# Copyright (c) 2015 Red Hat 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.
from neutron_lib.db import api as db_api
from neutron_lib.exceptions import qos as qos_exc
from neutron_lib.plugins import constants as plugin_constants
from neutron_lib.plugins import directory
from neutron_lib.services.qos import constants as qos_consts
from neutron.common import utils as common_utils
from neutron.core_extensions import base
from neutron.objects.qos import policy as policy_object
class QosCoreResourceExtension(base.CoreResourceExtension):
@property
def plugin_loaded(self):
if not hasattr(self, '_plugin_loaded'):
self._plugin_loaded = (
plugin_constants.QOS in directory.get_plugins())
return self._plugin_loaded
def _check_policy_change_permission(self, context, old_policy):
"""An existing policy can be modified only if one of the following is
true:
the policy's tenant is the context's tenant
the policy is shared with the tenant
Using is_accessible expresses these conditions.
"""
if not (policy_object.QosPolicy.is_accessible(context, old_policy)):
raise qos_exc.PolicyRemoveAuthorizationError(
policy_id=old_policy.id)
def _update_port_policy(self, context, port, port_changes):
old_policy = policy_object.QosPolicy.get_port_policy(
common_utils.get_elevated_context(context), port['id'])
if old_policy:
self._check_policy_change_permission(context, old_policy)
old_policy.detach_port(port['id'])
qos_policy_id = port_changes.get(qos_consts.QOS_POLICY_ID)
if qos_policy_id is not None:
policy = policy_object.QosPolicy.get_policy_obj(
context, qos_policy_id)
policy.attach_port(port['id'])
port[qos_consts.QOS_POLICY_ID] = qos_policy_id
def _create_network_policy(self, context, network, network_changes):
qos_policy_id = network_changes.get(qos_consts.QOS_POLICY_ID)
if not qos_policy_id:
policy_obj = policy_object.QosPolicyDefault.get_object(
context, project_id=network['project_id'])
if policy_obj is not None:
qos_policy_id = policy_obj.qos_policy_id
if qos_policy_id is not None:
policy = policy_object.QosPolicy.get_policy_obj(
context, qos_policy_id)
policy.attach_network(network['id'])
network[qos_consts.QOS_POLICY_ID] = qos_policy_id
def _update_network_policy(self, context, network, network_changes):
old_policy = policy_object.QosPolicy.get_network_policy(
common_utils.get_elevated_context(context), network['id'])
if old_policy:
self._check_policy_change_permission(context, old_policy)
old_policy.detach_network(network['id'])
qos_policy_id = network_changes.get(qos_consts.QOS_POLICY_ID)
if qos_policy_id is not None:
policy = policy_object.QosPolicy.get_policy_obj(
context, qos_policy_id)
policy.attach_network(network['id'])
network[qos_consts.QOS_POLICY_ID] = qos_policy_id
def _exec(self, method_name, context, kwargs):
with db_api.CONTEXT_WRITER.using(context):
return getattr(self, method_name)(context=context, **kwargs)
def process_fields(self, context, resource_type, event_type,
requested_resource, actual_resource):
if (qos_consts.QOS_POLICY_ID in requested_resource and
self.plugin_loaded):
method_name = ('_%(event)s_%(resource)s_policy' %
{'event': event_type, 'resource': resource_type})
self._exec(method_name, context,
{resource_type: actual_resource,
"%s_changes" % resource_type: requested_resource})
def extract_fields(self, resource_type, resource):
if not self.plugin_loaded:
return {}
binding = resource['qos_policy_binding']
qos_policy_id = binding['policy_id'] if binding else None
retval = {qos_consts.QOS_POLICY_ID: qos_policy_id}
if resource_type == base.PORT:
network_binding = resource.get('qos_network_policy_binding')
qos_net_policy_id = (network_binding['policy_id'] if
network_binding else None)
retval[qos_consts.QOS_NETWORK_POLICY_ID] = qos_net_policy_id
return retval