From efd75ef27955b8a1d3bfecccdf90b8bc767b4f97 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Nowak?= <luke@nexedi.com>
Date: Tue, 18 Oct 2011 11:45:15 +0200
Subject: [PATCH] Add apache backend for zope.

---
 setup.py                                      |  1 +
 slapos/recipe/apache_zope_backend/__init__.py | 68 +++++++++++++++++++
 slapos/recipe/apache_zope_backend/apache.py   | 22 ++++++
 .../template/apache.zope.conf.in              | 63 +++++++++++++++++
 slapos/recipe/erp5/__init__.py                | 30 +-------
 software/erp5/instance-zope.cfg               | 66 +++++++++++++++++-
 software/erp5/software.cfg                    |  2 +-
 7 files changed, 221 insertions(+), 31 deletions(-)
 create mode 100644 slapos/recipe/apache_zope_backend/__init__.py
 create mode 100644 slapos/recipe/apache_zope_backend/apache.py
 create mode 100644 slapos/recipe/apache_zope_backend/template/apache.zope.conf.in

diff --git a/setup.py b/setup.py
index ea975bf5d..9891107e3 100644
--- a/setup.py
+++ b/setup.py
@@ -39,6 +39,7 @@ setup(name=name,
       zip_safe=True,
       entry_points={
         'zc.buildout': [
+          'apache.zope.backend = slapos.recipe.apache_zope_backend:Recipe',
           'certificate_authority = slapos.recipe.certificate_authority:Recipe',
           'certificate_authority.request = slapos.recipe.certificate_authority:Request',
           'cron = slapos.recipe.dcron:Recipe',
diff --git a/slapos/recipe/apache_zope_backend/__init__.py b/slapos/recipe/apache_zope_backend/__init__.py
new file mode 100644
index 000000000..034b30031
--- /dev/null
+++ b/slapos/recipe/apache_zope_backend/__init__.py
@@ -0,0 +1,68 @@
+##############################################################################
+#
+# Copyright (c) 2011 Vifib SARL and Contributors. All Rights Reserved.
+#
+# WARNING: This program as such is intended to be used by professional
+# programmers who take the whole responsibility of assessing all potential
+# consequences resulting from its eventual inadequacies and bugs
+# End users who are looking for a ready-to-use solution with commercial
+# guarantees and support are strongly adviced to contract a Free Software
+# Service Company
+#
+# This program is Free Software; you can redistribute it and/or
+# modify it under the terms of the GNU 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 General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+##############################################################################
+from slapos.recipe.librecipe import GenericBaseRecipe
+
+import pkg_resources
+
+class Recipe(GenericBaseRecipe):
+  def install(self):
+    path_list = []
+    ip = self.options['ip']
+    port = self.options['port']
+    backend = self.options['backend']
+    key = self.options['key-file']
+    certificate = self.options['cert-file']
+    access_control_string = self.options['access-control-string']
+    apache_conf = dict()
+    apache_conf['pid_file'] = self.options['pid-file']
+    apache_conf['lock_file'] = self.options['lock-file']
+    apache_conf['ip'] = ip
+    apache_conf['port'] = port
+    apache_conf['server_admin'] = 'admin@'
+    apache_conf['error_log'] = self.options['error-log']
+    apache_conf['access_log'] = self.options['access-log']
+    apache_conf['server_name'] = '%s' % apache_conf['ip']
+    apache_conf['certificate'] = certificate
+    apache_conf['key'] = key
+    apache_conf['path'] = '/'
+    apache_conf['access_control_string'] = access_control_string
+    apache_conf['rewrite_rule'] = "RewriteRule (.*) http://%s$1 [L,P]" % backend
+    apache_conf_string = pkg_resources.resource_string(__name__,
+          'template/apache.zope.conf.in') % apache_conf
+    apache_config_file = self.createFile(self.options['configuration-file'],
+      apache_conf_string)
+    path_list.append(apache_config_file)
+    wrapper = self.createPythonScript(self.options['wrapper'], __name__ +
+      '.apache.runApache', [
+            dict(
+              required_path_list=[key, certificate],
+              binary=self.options['apache-binary'],
+              config=apache_config_file
+            )
+          ])
+    path_list.append(wrapper)
+    return path_list
diff --git a/slapos/recipe/apache_zope_backend/apache.py b/slapos/recipe/apache_zope_backend/apache.py
new file mode 100644
index 000000000..861f787d0
--- /dev/null
+++ b/slapos/recipe/apache_zope_backend/apache.py
@@ -0,0 +1,22 @@
+import os
+import sys
+import time
+
+
+def runApache(args):
+  sleep = 60
+  conf = args[0]
+  while True:
+    ready = True
+    for f in conf.get('required_path_list', []):
+      if not os.path.exists(f):
+        print 'File %r does not exists, sleeping for %s' % (f, sleep)
+        ready = False
+    if ready:
+      break
+    time.sleep(sleep)
+  apache_wrapper_list = [conf['binary'], '-f', conf['config'], '-DFOREGROUND']
+  apache_wrapper_list.extend(sys.argv[1:])
+  sys.stdout.flush()
+  sys.stderr.flush()
+  os.execl(apache_wrapper_list[0], *apache_wrapper_list)
diff --git a/slapos/recipe/apache_zope_backend/template/apache.zope.conf.in b/slapos/recipe/apache_zope_backend/template/apache.zope.conf.in
new file mode 100644
index 000000000..ac689e15f
--- /dev/null
+++ b/slapos/recipe/apache_zope_backend/template/apache.zope.conf.in
@@ -0,0 +1,63 @@
+# Apache configuration file for Zope
+# Automatically generated
+
+# List of modules
+LoadModule authz_host_module modules/mod_authz_host.so
+LoadModule log_config_module modules/mod_log_config.so
+LoadModule setenvif_module modules/mod_setenvif.so
+LoadModule version_module modules/mod_version.so
+LoadModule proxy_module modules/mod_proxy.so
+LoadModule proxy_http_module modules/mod_proxy_http.so
+LoadModule ssl_module modules/mod_ssl.so
+LoadModule mime_module modules/mod_mime.so
+LoadModule dav_module modules/mod_dav.so
+LoadModule dav_fs_module modules/mod_dav_fs.so
+LoadModule negotiation_module modules/mod_negotiation.so
+LoadModule rewrite_module modules/mod_rewrite.so
+LoadModule headers_module modules/mod_headers.so
+
+# Basic server configuration
+PidFile "%(pid_file)s"
+LockFile "%(lock_file)s"
+Listen %(ip)s:%(port)s
+ServerAdmin %(server_admin)s
+TypesConfig conf/mime.types
+AddType application/x-compress .Z
+AddType application/x-gzip .gz .tgz
+
+# As backend is trusting REMOTE_USER header unset it always
+RequestHeader unset REMOTE_USER
+
+# SSL Configuration
+SSLEngine on
+SSLCertificateFile %(certificate)s
+SSLCertificateKeyFile %(key)s
+SSLRandomSeed startup builtin
+SSLRandomSeed connect builtin
+
+SSLProxyEngine On
+
+# Log configuration
+ErrorLog "%(error_log)s"
+# Default apache log format with request time in microsecond at the end
+LogFormat "%%h %%l %%u %%t \"%%r\" %%>s %%b \"%%{Referer}i\" \"%%{User-Agent}i\" %%D" combined
+CustomLog "%(access_log)s" combined
+
+# Directory protection
+<Directory />
+    Options FollowSymLinks
+    AllowOverride None
+    Order deny,allow
+    Deny from all
+</Directory>
+
+# Path protected
+<Location %(path)s>
+  Order Deny,Allow
+  Deny from all
+  Allow from %(access_control_string)s
+</Location>
+
+# Magic of Zope related rewrite
+RewriteEngine On
+%(rewrite_rule)s
diff --git a/slapos/recipe/erp5/__init__.py b/slapos/recipe/erp5/__init__.py
index 53ac57a02..94790fa6e 100644
--- a/slapos/recipe/erp5/__init__.py
+++ b/slapos/recipe/erp5/__init__.py
@@ -68,9 +68,9 @@ class Recipe(BaseSlapRecipe):
       key_access = None
 
     key, certificate = self.requestCertificate('Login Based Access')
-    apache_conf = dict(
-         apache_login=self.installBackendApache(ip=self.getGlobalIPv6Address(),
-         port=13000, backend=site_access, key=key, certificate=certificate))
+#    apache_conf = dict(
+#         apache_login=self.installBackendApache(ip=self.getGlobalIPv6Address(),
+#         port=13000, backend=site_access, key=key, certificate=certificate))
 
     connection_dict = dict(site_url=apache_conf['apache_login'])
 
@@ -824,27 +824,3 @@ SSLCARevocationPath %(ca_crl)s"""
           ]))
     # Note: IPv6 is assumed always
     return 'https://%(server_name)s:%(port)s%(frontend_path)s' % (apache_conf)
-
-  def installBackendApache(self, ip, port, backend, key, certificate,
-      suffix='', access_control_string=None):
-    apache_conf = self._getApacheConfigurationDict('backend_apache'+suffix, ip,
-        port)
-    apache_conf['server_name'] = '%s' % apache_conf['ip']
-    apache_conf['ssl_snippet'] = pkg_resources.resource_string(__name__,
-        'template/apache.ssl-snippet.conf.in') % dict(
-        login_certificate=certificate, login_key=key)
-    apache_config_file = self._writeApacheConfiguration('backend_apache'+suffix,
-        apache_conf, backend, access_control_string)
-    self.path_list.append(apache_config_file)
-    self.path_list.extend(zc.buildout.easy_install.scripts([(
-      'backend_apache'+suffix,
-        __name__ + '.apache', 'runApache')], self.ws,
-          sys.executable, self.wrapper_directory, arguments=[
-            dict(
-              required_path_list=[key, certificate],
-              binary=self.options['httpd_binary'],
-              config=apache_config_file
-            )
-          ]))
-    # Note: IPv6 is assumed always
-    return 'https://[%(ip)s]:%(port)s' % apache_conf
diff --git a/software/erp5/instance-zope.cfg b/software/erp5/instance-zope.cfg
index 15d2d8eef..6759c24d7 100644
--- a/software/erp5/instance-zope.cfg
+++ b/software/erp5/instance-zope.cfg
@@ -1,7 +1,10 @@
 [buildout]
 parts =
-  publish-zope-connection-string
+  certificate-authority
+  publish-apache-zope-backend-connection-string
   zope-instance
+  apache-zope-backend-instance
+  ca-apache-zope-backend
   logrotate
   logrotate-entry-zope
   cron
@@ -13,11 +16,35 @@ eggs-directory = ${buildout:eggs-directory}
 develop-eggs-directory = ${buildout:develop-eggs-directory}
 offline = true
 
-[publish-zope-connection-string]
+[publish-apache-zope-backend-connection-string]
 recipe = slapos.cookbook:publishurl
-url = http://$${zope-instance:user}:$${zope-instance:password}@$${zope-instance:ip}:$${zope-instance:port}
+url = https://$${zope-instance:user}:$${zope-instance:password}@[$${apache-zope-backend-instance:ip}]:$${apache-zope-backend-instance:port}
 deadlock-url = $${:url}/$${zope-instance:deadlock-path}?$${zope-instance:deadlock-password}
 
+[apache-zope-backend-instance]
+recipe = slapos.cookbook:apache.zope.backend
+backend = http://$${zope-instance:ip}:$${zope-instance:port}/
+ip = $${slap-network-information:global-ipv6}
+port = 16001
+wrapper = $${rootdirectory:bin}/apache
+key-file = $${directory:apache-conf}/apache.key
+cert-file = $${directory:apache-conf}/apache.crt
+configuration-file = $${directory:apache-conf}/apache.conf
+access-control-string = $${slap-parameter:access-control-string}
+pid-file = $${basedirectory:run}/apache.pid
+lock-file = $${basedirectory:run}/apache.lock
+error-log = $${basedirectory:log}/apache-error.log
+access-log = $${basedirectory:log}/apache-access.log
+apache-binary = ${apache:location}/bin/httpd
+
+[ca-apache-zope-backend]
+<= certificate-authority
+recipe = slapos.cookbook:certificate_authority.request
+key-file = $${apache-zope-backend-instance:key-file}
+cert-file = $${apache-zope-backend-instance:cert-file}
+executable = $${apache-zope-backend-instance:wrapper}
+wrapper = $${basedirectory:services}/apache
+
 [zope-instance]
 recipe = slapos.cookbook:generic.zope
 
@@ -79,6 +106,18 @@ sharedscripts = true
 notifempty = true
 create = true
 
+[logrotate-entry-apache-zope-backend]
+<= logrotate
+recipe = slapos.cookbook:logrotate.d
+name = zope
+log = $${apache-zope-backend-instance:error-log} $${apache-zope-backend-instance:access-log}
+frequency = daily
+rotate-num = 30
+post = ${buildout:bin-directory}/killpidfromfile $${apache-zope-backend-instance:pid-file} SIGUSR1
+sharedscripts = true
+notifempty = true
+create = true
+
 [cron]
 recipe = slapos.cookbook:cron
 dcrond-binary = ${dcron:location}/sbin/crond
@@ -100,6 +139,25 @@ name = logrotate
 frequency = 0 0 * * *
 command = $${logrotate:wrapper}
 
+[certificate-authority]
+recipe = slapos.cookbook:certificate_authority
+openssl-binary = ${openssl:location}/bin/openssl
+ca-dir = $${directory:ca-dir}
+requests-directory = $${cadirectory:requests}
+wrapper = $${basedirectory:services}/ca
+ca-private = $${cadirectory:private}
+ca-certs = $${cadirectory:certs}
+ca-newcerts = $${cadirectory:newcerts}
+ca-crl = $${cadirectory:crl}
+
+[cadirectory]
+recipe = slapos.cookbook:mkdirectory
+requests = $${directory:ca-dir}/requests/
+private = $${directory:ca-dir}/private/
+certs = $${directory:ca-dir}/certs/
+newcerts = $${directory:ca-dir}/newcerts/
+crl = $${directory:ca-dir}/crl/
+
 [rootdirectory]
 recipe = slapos.cookbook:mkdirectory
 etc = $${buildout:directory}/etc/
@@ -120,6 +178,7 @@ recipe = slapos.cookbook:mkdirectory
 zodb = $${rootdirectory:srv}/zodb/
 instance = $${rootdirectory:srv}/erp5shared/
 instance-etc = $${:instance}/etc
+apache-conf = $${rootdirectory:etc}/apache
 instance-etc-package-include = $${:instance}/etc/package-include
 # because of bug in slapos.recipe.template keys are lowercased
 instance-document = $${:instance}/Document
@@ -130,6 +189,7 @@ instance-constraint = $${:instance}/Constraint
 instance-import = $${:instance}/import
 instance-lib = $${:instance}/lib
 instance-tests = $${:instance}/tests
+ca-dir = $${rootdirectory:srv}/ssl/
 cron-entries = $${rootdirectory:etc}/cron.d/
 crontabs = $${rootdirectory:etc}/crontabs/
 cronstamps = $${rootdirectory:etc}/cronstamps/
diff --git a/software/erp5/software.cfg b/software/erp5/software.cfg
index 7bd83c551..9f288d619 100644
--- a/software/erp5/software.cfg
+++ b/software/erp5/software.cfg
@@ -32,7 +32,7 @@ mode = 0644
 [template-zope]
 recipe = slapos.recipe.template
 url = ${:_profile_base_location_}/instance-zope.cfg
-md5sum = 1b6613da7980e0dd9f9290d3e30e8eef
+md5sum = 3b5ba87a44f172c8afc14ed57736949f
 output = ${buildout:directory}/template-zope.cfg
 mode = 0644
 
-- 
2.30.9