← Back to team overview

launchpad-reviewers team mailing list archive

[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())