From faa2d4f9485ee8629bfa3e360f32d737d80be40d Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 1 Feb 2012 11:28:38 +0100 Subject: [PATCH 1/6] [ADD] option allowing to run openerp behind a reverse proxy bzr revid: chs@openerp.com-20120201102838-reg50dmbfyzdgoeq --- openerp/tools/config.py | 5 ++++- openerp/wsgi.py | 20 +++++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/openerp/tools/config.py b/openerp/tools/config.py index 4f33c3b79f1..c72af9e1ed5 100644 --- a/openerp/tools/config.py +++ b/openerp/tools/config.py @@ -3,6 +3,7 @@ # # OpenERP, Open Source Management Solution # Copyright (C) 2004-2009 Tiny SPRL (). +# Copyright (C) 2010-2012 OpenERP s.a. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -116,6 +117,8 @@ class configmanager(object): help="specify the TCP port for the XML-RPC protocol", type="int") group.add_option("--no-xmlrpc", dest="xmlrpc", action="store_false", my_default=True, help="disable the XML-RPC protocol") + group.add_option("--proxy-mode", dest="proxy_mode", action="store_true", my_default=False, + help="Enable correct behavior when behind a reverse proxy") parser.add_option_group(group) # XML-RPC / HTTPS @@ -383,7 +386,7 @@ class configmanager(object): 'language', 'translate_out', 'translate_in', 'overwrite_existing_translations', 'debug_mode', 'smtp_ssl', 'load_language', 'stop_after_init', 'logrotate', 'without_demo', 'netrpc', 'xmlrpc', 'syslog', - 'list_db', 'xmlrpcs', + 'list_db', 'xmlrpcs', 'proxy_mode', 'test_file', 'test_disable', 'test_commit', 'test_report_directory', 'osv_memory_count_limit', 'osv_memory_age_limit', 'max_cron_threads', 'virtual_memory_limit', 'virtual_memory_reset', 'cpu_time_limit', 'unaccent', diff --git a/openerp/wsgi.py b/openerp/wsgi.py index 2b721648196..a1048b2cc7c 100644 --- a/openerp/wsgi.py +++ b/openerp/wsgi.py @@ -2,7 +2,7 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2011 OpenERP s.a. (). +# Copyright (C) 2011-2012 OpenERP s.a. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -402,6 +402,17 @@ def application(environ, start_response): start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', str(len(response)))]) return [response] +def init_proxy_mode(): + global application + if config['proxy_mode']: + try: + from werkzeug.contrib.fixers import ProxyFix + except ImportError: + logging.getLogger('wsgi').error('Werkzeug module unavailable. Cannot activate proxy mode') + config['proxy_mode'] = False + else: + application = ProxyFix(application) + # The WSGI server, started by start_server(), stopped by stop_server(). httpd = None @@ -419,15 +430,16 @@ def serve(): # TODO Change the xmlrpc_* options to http_* interface = config['xmlrpc_interface'] or '0.0.0.0' port = config['xmlrpc_port'] + proxy_msg = ' in proxy mode' if config['proxy_mode'] else '' try: import werkzeug.serving httpd = werkzeug.serving.make_server(interface, port, application, threaded=True) - logging.getLogger('wsgi').info('HTTP service (werkzeug) running on %s:%s', interface, port) + logging.getLogger('wsgi').info('HTTP service (werkzeug) running on %s:%s%s', interface, port, proxy_msg) except ImportError: import wsgiref.simple_server logging.getLogger('wsgi').warn('Werkzeug module unavailable, falling back to wsgiref.') httpd = wsgiref.simple_server.make_server(interface, port, application) - logging.getLogger('wsgi').info('HTTP service (wsgiref) running on %s:%s', interface, port) + logging.getLogger('wsgi').info('HTTP service (wsgiref) running on %s:%s%s', interface, port, proxy_msg) httpd.serve_forever() @@ -436,6 +448,7 @@ def start_server(): The WSGI server can be shutdown with stop_server() below. """ + openerp.wsgi.init_proxy_mode() threading.Thread(target=openerp.wsgi.serve).start() def stop_server(): @@ -457,6 +470,7 @@ def on_starting(server): #openerp.tools.cache = kill_workers_cache openerp.netsvc.init_logger() openerp.osv.osv.start_object_proxy() + openerp.wsgi.init_proxy_mode() openerp.service.web_services.start_web_services() openerp.modules.module.initialize_sys_path() openerp.modules.loading.open_openerp_namespace() From c0e9e2970c8c690f95bf93bb93fb24874455b96f Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Thu, 2 Feb 2012 14:18:13 +0100 Subject: [PATCH 2/6] [IMP] proxy mode require werkzeug (let the exception propagate up) bzr revid: chs@openerp.com-20120202131813-lgfy0tzy94entyu8 --- openerp/wsgi.py | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/openerp/wsgi.py b/openerp/wsgi.py index a1048b2cc7c..9211517a407 100644 --- a/openerp/wsgi.py +++ b/openerp/wsgi.py @@ -402,16 +402,11 @@ def application(environ, start_response): start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', str(len(response)))]) return [response] -def init_proxy_mode(): +def activate_proxy_mode(active): global application - if config['proxy_mode']: - try: - from werkzeug.contrib.fixers import ProxyFix - except ImportError: - logging.getLogger('wsgi').error('Werkzeug module unavailable. Cannot activate proxy mode') - config['proxy_mode'] = False - else: - application = ProxyFix(application) + if active: + from werkzeug.contrib.fixers import ProxyFix + application = ProxyFix(application) # The WSGI server, started by start_server(), stopped by stop_server(). httpd = None @@ -448,7 +443,7 @@ def start_server(): The WSGI server can be shutdown with stop_server() below. """ - openerp.wsgi.init_proxy_mode() + openerp.wsgi.activate_proxy_mode(config['proxy_mode']) threading.Thread(target=openerp.wsgi.serve).start() def stop_server(): @@ -470,7 +465,7 @@ def on_starting(server): #openerp.tools.cache = kill_workers_cache openerp.netsvc.init_logger() openerp.osv.osv.start_object_proxy() - openerp.wsgi.init_proxy_mode() + openerp.wsgi.activate_proxy_mode(config['proxy_mode']) openerp.service.web_services.start_web_services() openerp.modules.module.initialize_sys_path() openerp.modules.loading.open_openerp_namespace() From 4f64a7b09d4a7362f05d0e647fa0d795bf5dc3c4 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 10 Feb 2012 15:36:09 +0100 Subject: [PATCH 3/6] [IMP] wsgi: expose both a normal application() and a proxied application() entry points. bzr revid: vmt@openerp.com-20120210143609-auackb5ip7dqvlk2 --- gunicorn.conf.py | 12 ++++++----- openerp/wsgi/__init__.py | 30 +++++++++++++++++++++++++++ openerp/{wsgi.py => wsgi/core.py} | 25 ++++++++++++----------- openerp/wsgi/proxied.py | 34 +++++++++++++++++++++++++++++++ 4 files changed, 84 insertions(+), 17 deletions(-) create mode 100644 openerp/wsgi/__init__.py rename openerp/{wsgi.py => wsgi/core.py} (97%) create mode 100644 openerp/wsgi/proxied.py diff --git a/gunicorn.conf.py b/gunicorn.conf.py index 7f23553a1de..e7c2d6ed566 100644 --- a/gunicorn.conf.py +++ b/gunicorn.conf.py @@ -5,7 +5,9 @@ # settings below, in order to provide the parameters that # would normally be passed in the command-line, # (at least `bind` and `conf['addons_path']`), then execute: -# $ gunicorn openerp:wsgi.application -c gunicorn.conf.py +# $ gunicorn openerp:wsgi.core.application -c gunicorn.conf.py +# or +# $ gunicorn openerp:wsgi.proxied.application -c gunicorn.conf.py import openerp @@ -20,10 +22,10 @@ pidfile = '.gunicorn.pid' workers = 4 # Some application-wide initialization is needed. -on_starting = openerp.wsgi.on_starting -when_ready = openerp.wsgi.when_ready -pre_request = openerp.wsgi.pre_request -post_request = openerp.wsgi.post_request +on_starting = openerp.wsgi.core.on_starting +when_ready = openerp.wsgi.core.when_ready +pre_request = openerp.wsgi.core.pre_request +post_request = openerp.wsgi.core.post_request # openerp request-response cycle can be quite long for # big reports for example diff --git a/openerp/wsgi/__init__.py b/openerp/wsgi/__init__.py new file mode 100644 index 00000000000..309d0c757f2 --- /dev/null +++ b/openerp/wsgi/__init__.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2012-2012 OpenERP s.a. (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +""" WSGI stack + +This module offers a WSGI interface to/from OpenERP. + +""" + +from . import core + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/wsgi.py b/openerp/wsgi/core.py similarity index 97% rename from openerp/wsgi.py rename to openerp/wsgi/core.py index 9211517a407..1dd21265d26 100644 --- a/openerp/wsgi.py +++ b/openerp/wsgi/core.py @@ -19,9 +19,9 @@ # ############################################################################## -""" WSGI stuffs (proof of concept for now) +""" -This module offers a WSGI interface to OpenERP. +WSGI stack, common code. """ @@ -41,7 +41,7 @@ import traceback import openerp import openerp.modules import openerp.tools.config as config -import service.websrv_lib as websrv_lib +from ..service import websrv_lib # XML-RPC fault codes. Some care must be taken when changing these: the # constants are also defined client-side and must remain in sync. @@ -402,12 +402,6 @@ def application(environ, start_response): start_response('404 Not Found', [('Content-Type', 'text/plain'), ('Content-Length', str(len(response)))]) return [response] -def activate_proxy_mode(active): - global application - if active: - from werkzeug.contrib.fixers import ProxyFix - application = ProxyFix(application) - # The WSGI server, started by start_server(), stopped by stop_server(). httpd = None @@ -428,11 +422,20 @@ def serve(): proxy_msg = ' in proxy mode' if config['proxy_mode'] else '' try: import werkzeug.serving + if config['proxy_mode']: + from werkzeug.contrib.fixers import ProxyFix + app = ProxyFix(application) + suffix = ' (in proxy mode)' + else: + app = application + suffix = '' httpd = werkzeug.serving.make_server(interface, port, application, threaded=True) - logging.getLogger('wsgi').info('HTTP service (werkzeug) running on %s:%s%s', interface, port, proxy_msg) + logging.getLogger('wsgi').info('HTTP service (werkzeug) running on %s:%s%s' + suffix, interface, port, proxy_msg) except ImportError: import wsgiref.simple_server logging.getLogger('wsgi').warn('Werkzeug module unavailable, falling back to wsgiref.') + if config['proxy_mode']: + logging.getLogger('wsgi').warn('Werkzeug module unavailable, not using proxy mode.') httpd = wsgiref.simple_server.make_server(interface, port, application) logging.getLogger('wsgi').info('HTTP service (wsgiref) running on %s:%s%s', interface, port, proxy_msg) @@ -443,7 +446,6 @@ def start_server(): The WSGI server can be shutdown with stop_server() below. """ - openerp.wsgi.activate_proxy_mode(config['proxy_mode']) threading.Thread(target=openerp.wsgi.serve).start() def stop_server(): @@ -465,7 +467,6 @@ def on_starting(server): #openerp.tools.cache = kill_workers_cache openerp.netsvc.init_logger() openerp.osv.osv.start_object_proxy() - openerp.wsgi.activate_proxy_mode(config['proxy_mode']) openerp.service.web_services.start_web_services() openerp.modules.module.initialize_sys_path() openerp.modules.loading.open_openerp_namespace() diff --git a/openerp/wsgi/proxied.py b/openerp/wsgi/proxied.py new file mode 100644 index 00000000000..3cde6c7b78a --- /dev/null +++ b/openerp/wsgi/proxied.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# OpenERP, Open Source Management Solution +# Copyright (C) 2012-2012 OpenERP s.a. (). +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as +# published by the Free Software Foundation, either version 3 of the +# License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +# +############################################################################## + +""" + +WSGI entry point with Proxy mode (from Werkzeug). + +""" + +from werkzeug.contrib.fixers import ProxyFix + +from . import core + +application = ProxyFix(core.application) + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: From db7e1f37a5a06229aac52798cf2729c215da9211 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 10 Feb 2012 16:06:15 +0100 Subject: [PATCH 4/6] [IMP] typo. bzr revid: vmt@openerp.com-20120210150615-3ywm0le30niofxy3 --- openerp/wsgi/proxied.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openerp/wsgi/proxied.py b/openerp/wsgi/proxied.py index 3cde6c7b78a..658f6f29c55 100644 --- a/openerp/wsgi/proxied.py +++ b/openerp/wsgi/proxied.py @@ -2,7 +2,7 @@ ############################################################################## # # OpenERP, Open Source Management Solution -# Copyright (C) 2012-2012 OpenERP s.a. (). +# Copyright (C) 2012 OpenERP s.a. (). # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as From 4890c9544751686ed43bc447576887ff6f7fdb28 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 10 Feb 2012 16:17:15 +0100 Subject: [PATCH 5/6] [FIX] wsgi: use wsgi.core instead of wsgi, remove unused variable. bzr revid: vmt@openerp.com-20120210151715-5vei5cbpdlimlqj5 --- openerp/service/__init__.py | 4 ++-- openerp/wsgi/__init__.py | 3 +++ openerp/wsgi/core.py | 3 +-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openerp/service/__init__.py b/openerp/service/__init__.py index 9fa1cf5c4f9..c387d272e26 100644 --- a/openerp/service/__init__.py +++ b/openerp/service/__init__.py @@ -71,7 +71,7 @@ def start_services(): openerp.netsvc.Server.startAll() # Start the WSGI server. - openerp.wsgi.start_server() + openerp.wsgi.core.start_server() def stop_services(): @@ -80,7 +80,7 @@ def stop_services(): openerp.cron.cancel_all() openerp.netsvc.Server.quitAll() - openerp.wsgi.stop_server() + openerp.wsgi.core.stop_server() config = openerp.tools.config _logger.info("Initiating shutdown") _logger.info("Hit CTRL-C again or send a second signal to force the shutdown.") diff --git a/openerp/wsgi/__init__.py b/openerp/wsgi/__init__.py index 309d0c757f2..a536ee57327 100644 --- a/openerp/wsgi/__init__.py +++ b/openerp/wsgi/__init__.py @@ -27,4 +27,7 @@ This module offers a WSGI interface to/from OpenERP. from . import core +# TODO: This is for the web addons, can be removed later. +register_wsgi_handler = core.register_wsgi_handler + # vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/openerp/wsgi/core.py b/openerp/wsgi/core.py index a832a525d9c..986222596e9 100644 --- a/openerp/wsgi/core.py +++ b/openerp/wsgi/core.py @@ -421,7 +421,6 @@ def serve(): # TODO Change the xmlrpc_* options to http_* interface = config['xmlrpc_interface'] or '0.0.0.0' port = config['xmlrpc_port'] - proxy_msg = ' in proxy mode' if config['proxy_mode'] else '' try: import werkzeug.serving if config['proxy_mode']: @@ -448,7 +447,7 @@ def start_server(): The WSGI server can be shutdown with stop_server() below. """ - threading.Thread(target=openerp.wsgi.serve).start() + threading.Thread(target=serve).start() def stop_server(): """ Initiate the shutdown of the WSGI server. From b76a80944f344d4489bd343ac06a79b526fa8152 Mon Sep 17 00:00:00 2001 From: Vo Minh Thu Date: Fri, 10 Feb 2012 16:25:21 +0100 Subject: [PATCH 6/6] [FIX] wsgi: better instruction to use the proxied.application. bzr revid: vmt@openerp.com-20120210152521-638x9bzrvz0enq9k --- gunicorn.conf.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gunicorn.conf.py b/gunicorn.conf.py index e7c2d6ed566..0f1d93a8638 100644 --- a/gunicorn.conf.py +++ b/gunicorn.conf.py @@ -1,12 +1,14 @@ # Gunicorn sample configuration file. # See http://gunicorn.org/configure.html for more details. # -# To run OpenERP via Gunicorn, change the appropriate +# To run the OpenERP server via Gunicorn, change the appropriate # settings below, in order to provide the parameters that # would normally be passed in the command-line, # (at least `bind` and `conf['addons_path']`), then execute: # $ gunicorn openerp:wsgi.core.application -c gunicorn.conf.py -# or +# or if you want to run it behind a reverse proxy, add the line +# import openerp.wsgi.proxied +# in this file and execute: # $ gunicorn openerp:wsgi.proxied.application -c gunicorn.conf.py import openerp