diff --git a/slapos/recipe/README.apache.txt b/slapos/recipe/README.apache.txt new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/slapos/recipe/apache/__init__.py b/slapos/recipe/apache/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..506dd97bce7acce465c30eb4a3d048dc4ff265cd --- /dev/null +++ b/slapos/recipe/apache/__init__.py @@ -0,0 +1,201 @@ +############################################################################## +# +# Copyright (c) 2010 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 BaseSlapRecipe +import binascii +import os +import pkg_resources +import hashlib +import sys +import zc.buildout +import zc.recipe.egg +import ConfigParser + + +class Recipe(BaseSlapRecipe): + def getTemplateFilename(self, template_name): + return pkg_resources.resource_filename(__name__, + 'template/%s' % template_name) + + def _install(self): + self.path_list = [] + self.requirements, self.ws = self.egg.working_set() + # self.cron_d is a directory, where cron jobs can be registered + self.logrotate_d, self.logrotate_backup = self.installLogrotate() + self.killpidfromfile = zc.buildout.easy_install.scripts( + [('killpidfromfile', __name__ + '.killpidfromfile', + 'killpidfromfile')], self.ws, sys.executable, self.bin_directory)[0] + self.path_list.append(self.killpidfromfile) + ca_conf = self.installCertificateAuthority() + key, certificate = self.requestCertificate('Login Based Access') + apache_conf = dict( + apache_login=self.installBackendApache(ip=self.getGlobalIPv6Address(), + port=13000, backend=zope_access, key=key, certificate=certificate)) + self.linkBinary() + self.setConnectionDict(dict( + site_url=apache_conf['apache_login'], + )) + return self.path_list + + def installLogrotate(self): + """Installs logortate main configuration file and registers its to cron""" + logrotate_d = os.path.abspath(os.path.join(self.etc_directory, + 'logrotate.d')) + self._createDirectory(logrotate_d) + logrotate_backup = self.createBackupDirectory('logrotate') + logrotate_conf = self.createConfigurationFile("logrotate.conf", + "include %s" % logrotate_d) + logrotate_cron = os.path.join(self.cron_d, 'logrotate') + state_file = os.path.join(self.data_root_directory, 'logrotate.status') + open(logrotate_cron, 'w').write('0 0 * * * %s -s %s %s' % + (self.options['logrotate_binary'], state_file, logrotate_conf)) + self.path_list.extend([logrotate_d, logrotate_conf, logrotate_cron]) + return logrotate_d, logrotate_backup + + def registerLogRotation(self, name, log_file_list, postrotate_script): + """Register new log rotation requirement""" + open(os.path.join(self.logrotate_d, name), 'w').write( + self.substituteTemplate(self.getTemplateFilename( + 'logrotate_entry.in'), + dict(file_list=' '.join(['"'+q+'"' for q in log_file_list]), + postrotate=postrotate_script, olddir=self.logrotate_backup))) + + def linkBinary(self): + """Links binaries to instance's bin directory for easier exposal""" + for linkline in self.options.get('link_binary_list', '').splitlines(): + if not linkline: + continue + target = linkline.split() + if len(target) == 1: + target = target[0] + path, linkname = os.path.split(target) + else: + linkname = target[1] + target = target[0] + link = os.path.join(self.bin_directory, linkname) + if os.path.lexists(link): + if not os.path.islink(link): + raise zc.buildout.UserError( + 'Target link already %r exists but it is not link' % link) + os.unlink(link) + os.symlink(target, link) + self.logger.debug('Created link %r -> %r' % (link, target)) + self.path_list.append(link) + + def requestCertificate(self, name): + hash = hashlib.sha512(name).hexdigest() + key = os.path.join(self.ca_private, hash + self.ca_key_ext) + certificate = os.path.join(self.ca_certs, hash + self.ca_crt_ext) + parser = ConfigParser.RawConfigParser() + parser.add_section('certificate') + parser.set('certificate', 'name', name) + parser.set('certificate', 'key_file', key) + parser.set('certificate', 'certificate_file', certificate) + parser.write(open(os.path.join(self.ca_request_dir, hash), 'w')) + return key, certificate + + def installCertificateAuthority(self, ca_country_code='XX', + ca_email='xx@example.com', ca_state='State', ca_city='City', + ca_company='Company'): + backup_path = self.createBackupDirectory('ca') + self.ca_dir = os.path.join(self.data_root_directory, 'ca') + self._createDirectory(self.ca_dir) + self.ca_request_dir = os.path.join(self.ca_dir, 'requests') + self._createDirectory(self.ca_request_dir) + config = dict(ca_dir=self.ca_dir, request_dir=self.ca_request_dir) + self.ca_private = os.path.join(self.ca_dir, 'private') + self.ca_certs = os.path.join(self.ca_dir, 'certs') + self.ca_crl = os.path.join(self.ca_dir, 'crl') + self.ca_newcerts = os.path.join(self.ca_dir, 'newcerts') + self.ca_key_ext = '.key' + self.ca_crt_ext = '.crt' + for d in [self.ca_private, self.ca_crl, self.ca_newcerts, self.ca_certs]: + self._createDirectory(d) + for f in ['crlnumber', 'serial']: + if not os.path.exists(os.path.join(self.ca_dir, f)): + open(os.path.join(self.ca_dir, f), 'w').write('01') + if not os.path.exists(os.path.join(self.ca_dir, 'index.txt')): + open(os.path.join(self.ca_dir, 'index.txt'), 'w').write('') + openssl_configuration = os.path.join(self.ca_dir, 'openssl.cnf') + config.update( + working_directory=self.ca_dir, + country_code=ca_country_code, + state=ca_state, + city=ca_city, + company=ca_company, + email_address=ca_email, + ) + self._writeFile(openssl_configuration, pkg_resources.resource_string( + __name__, 'template/openssl.cnf.ca.in') % config) + self.path_list.extend(zc.buildout.easy_install.scripts([ + ('certificate_authority', + __name__ + '.certificate_authority', 'runCertificateAuthority')], + self.ws, sys.executable, self.wrapper_directory, arguments=[dict( + openssl_configuration=openssl_configuration, + openssl_binary=self.options['openssl_binary'], + certificate=os.path.join(self.ca_dir, 'cacert.pem'), + key=os.path.join(self.ca_private, 'cakey.pem'), + crl=os.path.join(self.ca_crl), + request_dir=self.ca_request_dir + )])) + # configure backup + backup_cron = os.path.join(self.cron_d, 'ca_rdiff_backup') + open(backup_cron, 'w').write( + '''0 0 * * * %(rdiff_backup)s %(source)s %(destination)s'''%dict( + rdiff_backup=self.options['rdiff_backup_binary'], + source=self.ca_dir, + destination=backup_path)) + self.path_list.append(backup_cron) + + return dict( + ca_certificate=os.path.join(config['ca_dir'], 'cacert.pem'), + ca_crl=os.path.join(config['ca_dir'], 'crl'), + certificate_authority_path=config['ca_dir'] + ) + + def _getApacheConfigurationDict(self, prefix, ip, port): + apache_conf = dict() + apache_conf['pid_file'] = os.path.join(self.run_directory, + prefix + '.pid') + apache_conf['lock_file'] = os.path.join(self.run_directory, + prefix + '.lock') + apache_conf['ip'] = ip + apache_conf['port'] = port + apache_conf['server_admin'] = 'admin@' + apache_conf['error_log'] = os.path.join(self.log_directory, + prefix + '-error.log') + apache_conf['access_log'] = os.path.join(self.log_directory, + prefix + '-access.log') + self.registerLogRotation(prefix, [apache_conf['error_log'], + apache_conf['access_log']], self.killpidfromfile + ' ' + + apache_conf['pid_file'] + ' SIGUSR1') + return apache_conf + + def installFrontendApache(self, ip, port, name, frontend_path, backend_url, + backend_path, key, certificate, access_control_string=None): + """ + """ + pass