Revert "Revert "Pecan WSGI: prevent plugins from opening AMQP connections""

This reverts commit 4f1fb05959b211c0edc52021af8774a163aa518c.
Merge of master went in so this can be re-applied and have the
conflict resovled.

Conflicts:
	neutron/server/__init__.py

Change-Id: I917e89b2191b3d4646e66a7a313783a56cf0ace5
This commit is contained in:
Kevin Benton 2015-09-16 03:33:05 -07:00
parent fdc3431ccd
commit 40151be9b3
6 changed files with 150 additions and 33 deletions

View File

@ -10,8 +10,14 @@
# License for the specific language governing permissions and limitations
# under the License.
from neutron import server
from neutron.server import wsgi_eventlet
from neutron.server import wsgi_pecan
def main():
server.main()
def main_wsgi_eventlet():
# This also starts the RPC server
wsgi_eventlet.main()
def main_wsgi_pecan():
wsgi_pecan.main()

View File

@ -47,6 +47,12 @@ TRANSPORT_ALIASES = {
'neutron.rpc.impl_zmq': 'zmq',
}
# NOTE(salv-orlando): I am afraid this is a global variable. While not ideal,
# they're however widely used throughout the code base. It should be set to
# true if the RPC server is not running in the current process space. This
# will prevent get_connection from creating connections to the AMQP server
RPC_DISABLED = False
def init(conf):
global TRANSPORT, NOTIFIER
@ -201,6 +207,25 @@ class Connection(object):
server.wait()
class VoidConnection(object):
def create_consumer(self, topic, endpoints, fanout=False):
pass
def consume_in_threads(self):
pass
def close(self):
pass
# functions
def create_connection(new=True):
# NOTE(salv-orlando): This is a clever interpreation of the factory design
# patter aimed at preventing plugins from initializing RPC servers upon
# initialization when they are running in the REST over HTTP API server.
# The educated reader will perfectly be able that this a fairly dirty hack
# to avoid having to change the initialization process of every plugin.
if RPC_DISABLED:
return VoidConnection()
return Connection()

View File

@ -18,47 +18,21 @@
import sys
import eventlet
from oslo_config import cfg
from oslo_log import log as logging
from neutron.common import config
from neutron.i18n import _LI
from neutron import service
LOG = logging.getLogger(__name__)
def main():
def boot_server(server_func):
# the configuration will be read into the cfg.CONF global data structure
config.init(sys.argv[1:])
config.setup_logging()
if not cfg.CONF.config_file:
sys.exit(_("ERROR: Unable to find configuration file via the default"
" search paths (~/.neutron/, ~/, /etc/neutron/, /etc/) and"
" the '--config-file' option!"))
try:
pool = eventlet.GreenPool()
neutron_api = service.serve_wsgi(service.NeutronApiService)
api_thread = pool.spawn(neutron_api.wait)
try:
neutron_rpc = service.serve_rpc()
except NotImplementedError:
LOG.info(_LI("RPC was already started in parent process by "
"plugin."))
else:
rpc_thread = pool.spawn(neutron_rpc.wait)
plugin_workers = service.start_plugin_workers()
for worker in plugin_workers:
pool.spawn(worker.wait)
# api and rpc should die together. When one dies, kill the other.
rpc_thread.link(lambda gt: api_thread.kill())
api_thread.link(lambda gt: rpc_thread.kill())
pool.waitall()
server_func()
except KeyboardInterrupt:
pass
except RuntimeError as e:

View File

@ -0,0 +1,51 @@
#!/usr/bin/env python
# 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.
import eventlet
from oslo_log import log
from neutron.i18n import _LI
from neutron import server
from neutron import service
LOG = log.getLogger(__name__)
def _eventlet_wsgi_server():
pool = eventlet.GreenPool()
neutron_api = service.serve_wsgi(service.NeutronApiService)
api_thread = pool.spawn(neutron_api.wait)
try:
neutron_rpc = service.serve_rpc()
except NotImplementedError:
LOG.info(_LI("RPC was already started in parent process by "
"plugin."))
else:
rpc_thread = pool.spawn(neutron_rpc.wait)
plugin_workers = service.start_plugin_workers()
for worker in plugin_workers:
pool.spawn(worker.wait)
# api and rpc should die together. When one dies, kill the other.
rpc_thread.link(lambda gt: api_thread.kill())
api_thread.link(lambda gt: rpc_thread.kill())
pool.waitall()
def main():
server.boot_server(_eventlet_wsgi_server)

60
neutron/server/wsgi_pecan.py Executable file
View File

@ -0,0 +1,60 @@
#!/usr/bin/env python
# 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.
import logging as std_logging
from wsgiref import simple_server
from oslo_config import cfg
from oslo_log import log
from six.moves import socketserver
from neutron.common import rpc as n_rpc
from neutron.i18n import _LI, _LW
from neutron.pecan_wsgi import app as pecan_app
from neutron import server
LOG = log.getLogger(__name__)
class ThreadedSimpleServer(socketserver.ThreadingMixIn,
simple_server.WSGIServer):
pass
def _pecan_wsgi_server():
LOG.info(_LI("Pecan WSGI server starting..."))
# No AMQP connection should be created within this process
n_rpc.RPC_DISABLED = True
application = pecan_app.setup_app()
host = cfg.CONF.bind_host
port = cfg.CONF.bind_port
wsgi = simple_server.make_server(
host,
port,
application,
server_class=ThreadedSimpleServer
)
# Log option values
cfg.CONF.log_opt_values(LOG, std_logging.DEBUG)
LOG.warning(
_LW("Development Server Serving on http://%(host)s:%(port)s"),
{'host': host, 'port': port}
)
wsgi.serve_forever()
def main():
server.boot_server(_pecan_wsgi_server)

View File

@ -93,7 +93,8 @@ console_scripts =
neutron-ovs-cleanup = neutron.cmd.ovs_cleanup:main
neutron-pd-notify = neutron.cmd.pd_notify:main
neutron-restproxy-agent = neutron.plugins.bigswitch.agent.restproxy_agent:main
neutron-server = neutron.cmd.eventlet.server:main
neutron-server = neutron.cmd.eventlet.server:main_wsgi_eventlet
neutron-dev-server = neutron.cmd.eventlet.server:main_wsgi_pecan
neutron-rootwrap = oslo_rootwrap.cmd:main
neutron-rootwrap-daemon = oslo_rootwrap.cmd:daemon
neutron-usage-audit = neutron.cmd.usage_audit:main