launchpad-reviewers team mailing list archive
-
launchpad-reviewers team
-
Mailing list archive
-
Message #27278
[Merge] ~cjwatson/launchpad:simplify-webapp-wsgi into launchpad:master
Colin Watson has proposed merging ~cjwatson/launchpad:simplify-webapp-wsgi into launchpad:master.
Commit message:
Simplify webapp WSGI startup
Requested reviews:
Launchpad code reviewers (launchpad-reviewers)
For more details, see:
https://code.launchpad.net/~cjwatson/launchpad/+git/launchpad/+merge/405874
Inline a few small bits of zope.app.wsgi.getWSGIApplication. This allows us to entirely ignore launchpad.conf when running under gunicorn.
--
Your team Launchpad code reviewers is requested to review the proposed merge of ~cjwatson/launchpad:simplify-webapp-wsgi into launchpad:master.
diff --git a/lib/lp/scripts/runlaunchpad.py b/lib/lp/scripts/runlaunchpad.py
index 2c8b232..0557ee8 100644
--- a/lib/lp/scripts/runlaunchpad.py
+++ b/lib/lp/scripts/runlaunchpad.py
@@ -10,9 +10,7 @@ try:
from contextlib import ExitStack
except ImportError:
from contextlib2 import ExitStack
-from io import StringIO
import os
-import re
import signal
import subprocess
import sys
@@ -334,35 +332,7 @@ def start_testapp(argv=list(sys.argv)):
pass
-def gunicornify_zope_config_file():
- """Creates a new launchpad.config file removing directives related to
- Zope Server that shouldn't be used when running on gunicorn.
- """
- original_filename = config.zope_config_file
- with open(original_filename) as fd:
- content = fd.read()
-
- # Remove unwanted tags.
- for tag in ['server', 'accesslog', 'logger']:
- content = re.sub(
- r"<%s>.*?</%s>" % (tag, tag), "", content, flags=re.S)
-
- # Remove unwanted contents of required tags.
- for tag in ['eventlog']:
- content = re.sub(
- r"<%s>.*?</%s>" % (tag, tag), "<%s>\n</%s>" % (tag, tag), content,
- flags=re.S)
-
- # Remove unwanted single-line directives.
- for directive in ['interrupt-check-interval']:
- content = re.sub(r"%s .*" % directive, "", content)
-
- new_file = StringIO(content)
- config.zope_config_file = new_file
-
-
def gunicorn_main():
- gunicornify_zope_config_file()
orig_argv = sys.argv
try:
sys.argv = [
diff --git a/lib/lp/scripts/tests/test_runlaunchpad.py b/lib/lp/scripts/tests/test_runlaunchpad.py
index 15dbc5d..3a5d998 100644
--- a/lib/lp/scripts/tests/test_runlaunchpad.py
+++ b/lib/lp/scripts/tests/test_runlaunchpad.py
@@ -15,11 +15,9 @@ __all__ = [
import os
import shutil
import tempfile
-from textwrap import dedent
from lp.scripts.runlaunchpad import (
get_services_to_run,
- gunicornify_zope_config_file,
process_config_arguments,
SERVICES,
split_out_runlaunchpad_arguments,
@@ -190,77 +188,3 @@ class TestAppServerStart(lp.testing.TestCase):
start_launchpad([])
self.assertEqual(0, gmain.call_count)
self.assertEqual(1, zmain.call_count)
-
- def test_gunicornify_config(self):
- content = dedent("""
- site-definition zcml/webapp.zcml
- # With some comment
- devmode off
- interrupt-check-interval 200
- <server>
- type HTTP
- address 8085
- </server>
- <server>
- type XXX
- address 123
- </server>
-
- <zodb>
- <mappingstorage/>
- </zodb>
-
- <accesslog>
- <logfile>
- path logs/test-appserver-layer.log
- </logfile>
- </accesslog>
-
- <eventlog>
- <logfile>
- path logs/test-appserver-layer.log
- </logfile>
- </eventlog>
-
- <logger>
- name zc.tracelog
- propagate false
-
- <logfile>
- format %(message)s
- path logs/test-appserver-layer-trace.log
- </logfile>
- </logger>
- """)
- config_filename = tempfile.mktemp()
- with open(config_filename, "w") as fd:
- fd.write(content)
-
- patched_cfg = mock.patch(
- 'lp.services.config.LaunchpadConfig.zope_config_file',
- new_callable=mock.PropertyMock)
- with patched_cfg as mock_zope_config_file:
- mock_zope_config_file.return_value = config_filename
-
- gunicornify_zope_config_file()
- self.assertEqual(2, mock_zope_config_file.call_count)
- new_file = mock_zope_config_file.call_args[0][0]
- self.assertEqual(dedent("""
- site-definition zcml/webapp.zcml
- # With some comment
- devmode off
-
-
-
-
- <zodb>
- <mappingstorage/>
- </zodb>
-
-
-
- <eventlog>
- </eventlog>
-
-
- """), new_file.read())
diff --git a/lib/lp/services/webapp/wsgi.py b/lib/lp/services/webapp/wsgi.py
new file mode 100644
index 0000000..4a68591
--- /dev/null
+++ b/lib/lp/services/webapp/wsgi.py
@@ -0,0 +1,37 @@
+# Copyright 2021 Canonical Ltd. This software is licensed under the
+# GNU Affero General Public License version 3 (see the file LICENSE).
+
+"""Main Launchpad WSGI application."""
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+__metaclass__ = type
+__all__ = [
+ "get_wsgi_application",
+ ]
+
+import logging
+
+from zope.app.appsetup import appsetup
+from zope.app.wsgi import WSGIPublisherApplication
+from zope.event import notify
+from zope.processlifetime import DatabaseOpened
+
+from lp.services.config import config
+
+
+def get_wsgi_application():
+ features = []
+ if config.launchpad.devmode:
+ features.append("devmode")
+ logging.warning(
+ "Developer mode is enabled: this is a security risk and should "
+ "NOT be enabled on production servers. Developer mode can be "
+ "turned off in launchpad-lazr.conf.")
+ appsetup.config("zcml/webapp.zcml", features=features)
+
+ # We don't use ZODB, but the webapp subscribes to IDatabaseOpened to
+ # perform some post-configuration tasks, so emit that event manually.
+ notify(DatabaseOpened(None))
+
+ return WSGIPublisherApplication()
diff --git a/lib/lp/startwsgi.py b/lib/lp/startwsgi.py
index 785a08c..eedb7b0 100644
--- a/lib/lp/startwsgi.py
+++ b/lib/lp/startwsgi.py
@@ -8,17 +8,12 @@ from __future__ import absolute_import, print_function, unicode_literals
__metaclass__ = type
__all__ = []
-from zope.app.publication.httpfactory import HTTPPublicationRequestFactory
-from zope.app.wsgi import getWSGIApplication
from zope.event import notify
import zope.processlifetime
-from lp.services.config import config
+from lp.services.webapp.wsgi import get_wsgi_application
-application = getWSGIApplication(
- config.zope_config_file,
- requestFactory=HTTPPublicationRequestFactory
-)
+application = get_wsgi_application()
notify(zope.processlifetime.ProcessStarting())