From: Kevin Benton Date: Wed, 16 Sep 2015 10:33:05 +0000 (-0700) Subject: Revert "Revert "Pecan WSGI: prevent plugins from opening AMQP connections"" X-Git-Url: https://review.fuel-infra.org/gitweb?a=commitdiff_plain;h=40151be9b3d7768de0c231f00d99f05371515c7b;p=openstack-build%2Fneutron-build.git 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 --- diff --git a/neutron/cmd/eventlet/server/__init__.py b/neutron/cmd/eventlet/server/__init__.py index bfa256862..01c3b52c1 100644 --- a/neutron/cmd/eventlet/server/__init__.py +++ b/neutron/cmd/eventlet/server/__init__.py @@ -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() diff --git a/neutron/common/rpc.py b/neutron/common/rpc.py index 6fe39842b..3037f5342 100644 --- a/neutron/common/rpc.py +++ b/neutron/common/rpc.py @@ -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() diff --git a/neutron/server/__init__.py b/neutron/server/__init__.py index 688b75421..3386fcfa6 100644 --- a/neutron/server/__init__.py +++ b/neutron/server/__init__.py @@ -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: diff --git a/neutron/server/wsgi_eventlet.py b/neutron/server/wsgi_eventlet.py new file mode 100644 index 000000000..02c9e1978 --- /dev/null +++ b/neutron/server/wsgi_eventlet.py @@ -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) diff --git a/neutron/server/wsgi_pecan.py b/neutron/server/wsgi_pecan.py new file mode 100755 index 000000000..91677cc29 --- /dev/null +++ b/neutron/server/wsgi_pecan.py @@ -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) diff --git a/setup.cfg b/setup.cfg index 6ab349eb1..87480ad11 100644 --- a/setup.cfg +++ b/setup.cfg @@ -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