Skip to content

Commit

Permalink
Fix context problem
Browse files Browse the repository at this point in the history
On plugin side, we use normal API context if any to call RPC methods.
We use our plugin dispatcher to convert RPC context into quantum admin
context. After that the callback's functions have the first argument context
as normal quantum context.

On agent side, we use admin context without session property as its
RPC calling context. Call back context is default RPCCommonContext in
Openstack common modules.

This patch also fixes the problem in the following bug:

Bug #1077012

Change-Id: I913b48dcd84d275cd7de30ca990be00c243e63ea
  • Loading branch information
gongysh committed Nov 21, 2012
1 parent 1ebba20 commit 05383d1
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 82 deletions.
4 changes: 2 additions & 2 deletions quantum/agent/dhcp_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@
from quantum.agent import rpc as agent_rpc
from quantum.common import exceptions
from quantum.common import topics
from quantum import context
from quantum.openstack.common import cfg
from quantum.openstack.common import context
from quantum.openstack.common import importutils
from quantum.openstack.common import jsonutils
from quantum.openstack.common import log as logging
Expand Down Expand Up @@ -59,7 +59,7 @@ def __init__(self, conf):
self.cache = NetworkCache()

self.dhcp_driver_cls = importutils.import_class(conf.dhcp_driver)
ctx = context.RequestContext('quantum', 'quantum', is_admin=True)
ctx = context.get_admin_context_without_session()
self.plugin_rpc = DhcpPluginApi(topics.PLUGIN, ctx)

self.device_manager = DeviceManager(self.conf, self.plugin_rpc)
Expand Down
41 changes: 41 additions & 0 deletions quantum/common/rpc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright (c) 2012 OpenStack, LLC.
#
# 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 quantum.openstack.common import log as logging
from quantum.openstack.common.rpc import dispatcher
from quantum import context


LOG = logging.getLogger(__name__)


class PluginRpcDispatcher(dispatcher.RpcDispatcher):
"""This class is used to convert RPC common context into
Quantum Context."""

def __init__(self, callbacks):
super(PluginRpcDispatcher, self).__init__(callbacks)

def dispatch(self, rpc_ctxt, version, method, **kwargs):
rpc_ctxt_dict = rpc_ctxt.to_dict()
user_id = rpc_ctxt_dict.pop('user_id', None)
if not user_id:
user_id = rpc_ctxt_dict.pop('user', None)
tenant_id = rpc_ctxt_dict.pop('tenant_id', None)
if not tenant_id:
tenant_id = rpc_ctxt_dict.pop('project_id', None)
quantum_ctxt = context.Context(user_id, tenant_id, **rpc_ctxt_dict)
return super(PluginRpcDispatcher, self).dispatch(
quantum_ctxt, version, method, **kwargs)
50 changes: 39 additions & 11 deletions quantum/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
LOG = logging.getLogger(__name__)


class Context(common_context.RequestContext):
class ContextBase(common_context.RequestContext):
"""Security context and request information.
Represents the user taking a given action within the system.
Expand All @@ -46,10 +46,8 @@ def __init__(self, user_id, tenant_id, is_admin=None, read_deleted="no",
if kwargs:
LOG.warn(_('Arguments dropped when creating '
'context: %s') % str(kwargs))
super(Context, self).__init__(user=user_id, tenant=tenant_id,
is_admin=is_admin)
self.user_id = user_id
self.tenant_id = tenant_id
super(ContextBase, self).__init__(user=user_id, tenant=tenant_id,
is_admin=is_admin)
self.roles = roles or []
if self.is_admin is None:
self.is_admin = 'admin' in [x.lower() for x in self.roles]
Expand All @@ -61,6 +59,26 @@ def __init__(self, user_id, tenant_id, is_admin=None, read_deleted="no",
self.timestamp = timestamp
self._session = None

@property
def project_id(self):
return self.tenant

@property
def tenant_id(self):
return self.tenant

@tenant_id.setter
def tenant_id(self, tenant_id):
self.tenant = tenant_id

@property
def user_id(self):
return self.user

@user_id.setter
def user_id(self, user_id):
self.user = user_id

def _get_read_deleted(self):
return self._read_deleted

Expand All @@ -76,15 +94,10 @@ def _del_read_deleted(self):
read_deleted = property(_get_read_deleted, _set_read_deleted,
_del_read_deleted)

@property
def session(self):
if self._session is None:
self._session = db_api.get_session()
return self._session

def to_dict(self):
return {'user_id': self.user_id,
'tenant_id': self.tenant_id,
'project_id': self.project_id,
'is_admin': self.is_admin,
'read_deleted': self.read_deleted,
'roles': self.roles,
Expand All @@ -108,8 +121,23 @@ def elevated(self, read_deleted=None):
return context


class Context(ContextBase):
@property
def session(self):
if self._session is None:
self._session = db_api.get_session()
return self._session


def get_admin_context(read_deleted="no"):
return Context(user_id=None,
tenant_id=None,
is_admin=True,
read_deleted=read_deleted)


def get_admin_context_without_session(read_deleted="no"):
return ContextBase(user_id=None,
tenant_id=None,
is_admin=True,
read_deleted=read_deleted)
20 changes: 2 additions & 18 deletions quantum/db/dhcp_rpc_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,13 @@
from sqlalchemy.orm import exc

from quantum.api.v2 import attributes
from quantum import context as quantum_context
from quantum import manager
from quantum.openstack.common import context
from quantum.openstack.common import log as logging


LOG = logging.getLogger(__name__)


def augment_context(context):
"""Augments RPC with additional attributes, so that plugin calls work."""
return quantum_context.Context(context.user, None, is_admin=True,
roles=['admin'])


class DhcpRpcCallbackMixin(object):
"""A mix-in that enable DHCP agent support in plugin implementations."""

Expand All @@ -39,7 +31,6 @@ def get_active_networks(self, context, **kwargs):
host = kwargs.get('host')
LOG.debug('Network list requested from %s', host)
plugin = manager.QuantumManager.get_plugin()
context = augment_context(context)
filters = dict(admin_state_up=[True])

return [net['id'] for net in
Expand All @@ -48,7 +39,6 @@ def get_active_networks(self, context, **kwargs):
def get_network_info(self, context, **kwargs):
"""Retrieve and return a extended information about a network."""
network_id = kwargs.get('network_id')
context = augment_context(context)
plugin = manager.QuantumManager.get_plugin()
network = plugin.get_network(context, network_id)

Expand All @@ -68,12 +58,11 @@ def get_dhcp_port(self, context, **kwargs):
host = kwargs.get('host')
network_id = kwargs.get('network_id')
device_id = kwargs.get('device_id')
# There could be more than one dhcp server per network, so create
# a device id that combines host and network ids
# There could be more than one dhcp server per network, so create
# a device id that combines host and network ids

LOG.debug('Port %s for %s requested from %s', device_id, network_id,
host)
context = augment_context(context)
plugin = manager.QuantumManager.get_plugin()
retval = None

Expand Down Expand Up @@ -136,7 +125,6 @@ def release_dhcp_port(self, context, **kwargs):

LOG.debug('DHCP port deletion for %s d request from %s', network_id,
host)
context = augment_context(context)
plugin = manager.QuantumManager.get_plugin()
filters = dict(network_id=[network_id], device_id=[device_id])
ports = plugin.get_ports(context, filters=filters)
Expand All @@ -154,8 +142,6 @@ def release_port_fixed_ip(self, context, **kwargs):
LOG.debug('DHCP port remove fixed_ip for %s d request from %s',
subnet_id,
host)

context = augment_context(context)
plugin = manager.QuantumManager.get_plugin()
filters = dict(network_id=[network_id], device_id=[device_id])
ports = plugin.get_ports(context, filters=filters)
Expand All @@ -179,8 +165,6 @@ def update_lease_expiration(self, context, **kwargs):

LOG.debug('Updating lease expiration for %s on network %s from %s.',
ip_address, network_id, host)

context = augment_context(context)
plugin = manager.QuantumManager.get_plugin()

plugin.update_fixed_ip_lease_expiration(context, network_id,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,11 @@
from quantum.agent.linux import utils
from quantum.agent import rpc as agent_rpc
from quantum.common import config as logging_config
from quantum.common import constants
from quantum.common import topics
from quantum.common import utils as q_utils
from quantum import context
from quantum.openstack.common import cfg
from quantum.openstack.common import context
from quantum.openstack.common import log as logging
from quantum.openstack.common import rpc
from quantum.openstack.common.rpc import dispatcher
from quantum.plugins.linuxbridge.common import config
from quantum.plugins.linuxbridge.common import constants as lconst
Expand Down Expand Up @@ -454,8 +452,7 @@ def setup_rpc(self, physical_interfaces):
self.plugin_rpc = agent_rpc.PluginApi(topics.PLUGIN)

# RPC network init
self.context = context.RequestContext('quantum', 'quantum',
is_admin=False)
self.context = context.get_admin_context_without_session()
# Handle updates from service
self.callbacks = LinuxBridgeRpcCallbacks(self.context,
self.linux_br)
Expand Down
17 changes: 5 additions & 12 deletions quantum/plugins/linuxbridge/lb_quantum_plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,16 @@
from quantum.api.v2 import attributes
from quantum.common import constants as q_const
from quantum.common import exceptions as q_exc
from quantum.common import rpc as q_rpc
from quantum.common import topics
from quantum.db import api as db_api
from quantum.db import db_base_plugin_v2
from quantum.db import dhcp_rpc_base
from quantum.db import l3_db
from quantum.db import models_v2
from quantum.extensions import providernet as provider
from quantum.openstack.common import cfg
from quantum.openstack.common import context
from quantum.openstack.common import log as logging
from quantum.openstack.common import rpc
from quantum.openstack.common.rpc import dispatcher
from quantum.openstack.common.rpc import proxy
from quantum.plugins.linuxbridge.common import constants
from quantum.plugins.linuxbridge.db import l2network_db_v2 as db
Expand All @@ -46,16 +44,13 @@ class LinuxBridgeRpcCallbacks(dhcp_rpc_base.DhcpRpcCallbackMixin):
# Device names start with "tap"
TAP_PREFIX_LEN = 3

def __init__(self, rpc_context):
self.rpc_context = rpc_context

def create_rpc_dispatcher(self):
'''Get the rpc dispatcher for this manager.
If a manager would like to set an rpc API version, or support more than
one class as the target of rpc messages, override this method.
'''
return dispatcher.RpcDispatcher([self])
return q_rpc.PluginRpcDispatcher([self])

def get_device_details(self, rpc_context, **kwargs):
"""Agent requests device details"""
Expand Down Expand Up @@ -173,10 +168,8 @@ def __init__(self):
def _setup_rpc(self):
# RPC support
self.topic = topics.PLUGIN
self.rpc_context = context.RequestContext('quantum', 'quantum',
is_admin=False)
self.conn = rpc.create_connection(new=True)
self.callbacks = LinuxBridgeRpcCallbacks(self.rpc_context)
self.callbacks = LinuxBridgeRpcCallbacks()
self.dispatcher = self.callbacks.create_rpc_dispatcher()
self.conn.create_consumer(self.topic, self.dispatcher,
fanout=False)
Expand Down Expand Up @@ -377,7 +370,7 @@ def delete_network(self, context, id):
binding.vlan_id, self.network_vlan_ranges)
# the network_binding record is deleted via cascade from
# the network record, so explicit removal is not necessary
self.notifier.network_delete(self.rpc_context, id)
self.notifier.network_delete(context, id)

def get_network(self, context, id, fields=None):
net = super(LinuxBridgePluginV2, self).get_network(context, id, None)
Expand All @@ -404,7 +397,7 @@ def update_port(self, context, id, port):
if original_port['admin_state_up'] != port['admin_state_up']:
binding = db.get_network_binding(context.session,
port['network_id'])
self.notifier.port_update(self.rpc_context, port,
self.notifier.port_update(context, port,
binding.physical_network,
binding.vlan_id)
return port
Expand Down
7 changes: 2 additions & 5 deletions quantum/plugins/openvswitch/agent/ovs_quantum_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,11 @@
from quantum.agent.linux import utils
from quantum.agent import rpc as agent_rpc
from quantum.common import config as logging_config
from quantum.common import constants as q_const
from quantum.common import topics
from quantum.common import utils as q_utils
from quantum import context
from quantum.openstack.common import cfg
from quantum.openstack.common import context
from quantum.openstack.common import log as logging
from quantum.openstack.common import rpc
from quantum.openstack.common.rpc import dispatcher
from quantum.plugins.openvswitch.common import config
from quantum.plugins.openvswitch.common import constants
Expand Down Expand Up @@ -171,8 +169,7 @@ def setup_rpc(self, integ_br):
self.plugin_rpc = agent_rpc.PluginApi(topics.PLUGIN)

# RPC network init
self.context = context.RequestContext('quantum', 'quantum',
is_admin=False)
self.context = context.get_admin_context_without_session()
# Handle updates from service
self.dispatcher = self.create_rpc_dispatcher()
# Define the listening consumers for the agent
Expand Down

0 comments on commit 05383d1

Please sign in to comment.