Add an rpc API common to all services.

This patch adds an rpc API that is exposed by all services.  The methods
in this API exist in their own namespace and are versioned independently
of the main API for the service.

The first method for this API is a simple ping() method.  This method
exists in the conductor rpc API already, and could be more generally
useful.  Other methods will be added in later patches.

The base rpc API will be exposed from all services automatically unless
they override the create_rpc_dispatcher method in the base manager
class.  All services need to pass a service_name into the base manager
constructor.  Some services already did this, but now it's needed for
all of them.

Implements blueprint base-rpc-api.

Change-Id: I02ab1970578bc53ba26461b533d06d1055c2d88e
This commit is contained in:
Russell Bryant
2013-04-23 13:34:24 -04:00
parent 7c53124cc0
commit 041958cdf7
3 changed files with 77 additions and 4 deletions

68
nova/baserpc.py Normal file
View File

@@ -0,0 +1,68 @@
#
# Copyright 2013 Red Hat, Inc.
#
# 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.
#
"""
Base RPC client and server common to all services.
"""
from nova.openstack.common import jsonutils
import nova.openstack.common.rpc.proxy as rpc_proxy
_NAMESPACE = 'baseapi'
class BaseAPI(rpc_proxy.RpcProxy):
"""Client side of the base rpc API.
API version history:
1.0 - Initial version.
"""
#
# NOTE(russellb): This is the default minimum version that the server
# (manager) side must implement unless otherwise specified using a version
# argument to self.call()/cast()/etc. here. It should be left as X.0 where
# X is the current major API version (1.0, 2.0, ...). For more information
# about rpc API versioning, see the docs in
# openstack/common/rpc/dispatcher.py.
#
BASE_RPC_API_VERSION = '1.0'
def __init__(self, topic):
super(BaseAPI, self).__init__(topic=topic,
default_version=self.BASE_RPC_API_VERSION)
self.namespace = _NAMESPACE
def ping(self, context, arg, timeout=None):
arg_p = jsonutils.to_primitive(arg)
msg = self.make_namespaced_msg('ping', self.namespace, arg=arg_p)
return self.call(context, msg, timeout=timeout)
class BaseRPCAPI(object):
"""Server side of the base RPC API."""
RPC_API_NAMESPACE = _NAMESPACE
RPC_API_VERSION = '1.0'
def __init__(self, service_name):
self.service_name = service_name
def ping(self, context, arg):
resp = {'service': self.service_name, 'arg': arg}
return jsonutils.to_primitive(resp)

View File

@@ -57,6 +57,7 @@ import datetime
import eventlet
from oslo.config import cfg
from nova import baserpc
from nova.db import base
from nova import exception
from nova.openstack.common import log as logging
@@ -195,12 +196,13 @@ class Manager(base.Base):
# Set RPC API version to 1.0 by default.
RPC_API_VERSION = '1.0'
def __init__(self, host=None, db_driver=None):
def __init__(self, host=None, db_driver=None, service_name='undefined'):
if not host:
host = CONF.host
self.host = host
self.load_plugins()
self.backdoor_port = None
self.service_name = service_name
super(Manager, self).__init__(db_driver)
def load_plugins(self):
@@ -213,7 +215,8 @@ class Manager(base.Base):
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 rpc_dispatcher.RpcDispatcher([self])
base_rpc = baserpc.BaseRPCAPI(self.service_name)
return rpc_dispatcher.RpcDispatcher([self, base_rpc])
def periodic_tasks(self, context, raise_on_error=False):
"""Tasks to be run at a periodic interval."""
@@ -292,7 +295,8 @@ class SchedulerDependentManager(Manager):
self.last_capabilities = None
self.service_name = service_name
self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI()
super(SchedulerDependentManager, self).__init__(host, db_driver)
super(SchedulerDependentManager, self).__init__(host, db_driver,
service_name)
def load_plugins(self):
pluginmgr = pluginmanager.PluginManager('nova', self.service_name)

View File

@@ -63,7 +63,8 @@ class SchedulerManager(manager.Manager):
if not scheduler_driver:
scheduler_driver = CONF.scheduler_driver
self.driver = importutils.import_object(scheduler_driver)
super(SchedulerManager, self).__init__(*args, **kwargs)
super(SchedulerManager, self).__init__(service_name='scheduler',
*args, **kwargs)
def post_start_hook(self):
"""After we start up and can receive messages via RPC, tell all