Add LongRequestLogger product support.
[slapos.git] / slapos / recipe / generic_zope_zeo_client / __init__.py
1 ##############################################################################
2 #
3 # Copyright (c) 2011 Vifib SARL and Contributors. All Rights Reserved.
4 #
5 # WARNING: This program as such is intended to be used by professional
6 # programmers who take the whole responsibility of assessing all potential
7 # consequences resulting from its eventual inadequacies and bugs
8 # End users who are looking for a ready-to-use solution with commercial
9 # guarantees and support are strongly adviced to contract a Free Software
10 # Service Company
11 #
12 # This program is Free Software; you can redistribute it and/or
13 # modify it under the terms of the GNU General Public License
14 # as published by the Free Software Foundation; either version 3
15 # of the License, or (at your option) any later version.
16 #
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
21 #
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #
26 ##############################################################################
27 from slapos.recipe.librecipe import GenericBaseRecipe
28 import binascii
29 import hashlib
30 import os
31 import re
32 import zc.buildout
33
34 _isurl = re.compile('([a-zA-Z0-9+.-]+)://').match
35
36 # based on Zope2.utilities.mkzopeinstance.write_inituser
37 def Zope2InitUser(path, username, password):
38 open(path, 'w').write('')
39 os.chmod(path, 0600)
40 open(path, "w").write('%s:{SHA}%s\n' % (
41 username,binascii.b2a_base64(hashlib.sha1(password).digest())[:-1]))
42
43 class Recipe(GenericBaseRecipe):
44 def _options(self, options):
45 options['password'] = self.generatePassword()
46 options['deadlock-password'] = self.generatePassword()
47
48 def install(self):
49 """
50 All zope have to share file created by portal_classes
51 (until everything is integrated into the ZODB).
52 So, do not request zope instance and create multiple in the same partition.
53 """
54 path_list = []
55 Zope2InitUser(self.options['inituser'], self.options['user'],
56 self.options['password'])
57
58 # Symlink to BT5 repositories defined in instance config.
59 # Those paths will eventually end up in the ZODB, and having symlinks
60 # inside the XXX makes it possible to reuse such ZODB with another software
61 # release[ version].
62 # Note: this path cannot be used for development, it's really just a
63 # read-only repository.
64 repository_path = self.options['bt5-repository']
65
66 self.bt5_repository_list = []
67 append = self.bt5_repository_list.append
68 for repository in self.options.get('bt5-repository-list', '').split():
69 repository = repository.strip()
70 if not repository:
71 continue
72
73 if _isurl(repository) and not repository.startswith("file://"):
74 # XXX: assume it's a valid URL
75 append(repository)
76 continue
77
78 if repository.startswith('file://'):
79 repository = repository.replace('file://', '', '')
80
81 if os.path.isabs(repository):
82 repo_id = hashlib.sha1(repository).hexdigest()
83 link = os.path.join(repository_path, repo_id)
84 if os.path.lexists(link):
85 if not os.path.islink(link):
86 raise zc.buildout.UserError(
87 'Target link already %r exists but it is not link' % link)
88 os.unlink(link)
89 os.symlink(repository, link)
90 self.logger.debug('Created link %r -> %r' % (link, repository_path))
91 # Always provide a URL-Type
92 append("file://" + link)
93
94 # Generate Zeo connections
95 zeo_snippet_template = open(self.getTemplateFilename('zope.zeo.entry.conf.in'
96 )).read()
97 zeo_snippet_list = []
98 for zeo_line in self.options['zeo-connection-string'].splitlines():
99 zeo_line.strip()
100 if not zeo_line:
101 continue
102 d = dict()
103 for param in zeo_line.split():
104 k, v = param.split('=')
105 d[k.strip()] = v.strip()
106 zeo_snippet_list.append(zeo_snippet_template % d)
107 # Create zope configuration file
108 zope_config = dict(
109 products=self.options['products'],
110 thread_amount=self.options['thread-amount'],
111 zodb_configuration='\n'.join(zeo_snippet_list)
112 )
113 zope_environment = dict(
114 TMP=self.options['tmp-path'],
115 TMPDIR=self.options['tmp-path'],
116 HOME=self.options['tmp-path'],
117 PATH=self.options['bin-path'],
118 TIMEZONE=self.options['timezone'],
119 )
120
121 # longrequestlogger product which requires environment settings
122 longrequest_logger_file = self.options.get('longrequest-logger-file', None)
123 longrequest_logger_timeout = \
124 self.options.get('longrequest-logger-timeout', None)
125 longrequest_logger_interval= \
126 self.options.get('longrequest-logger-interval', None)
127 if longrequest_logger_file:
128 # add needed zope configuration
129 zope_environment.update(
130 **dict(longrequestlogger_file = longrequest_logger_file,
131 longrequestlogger_timeout = longrequest_logger_timeout,
132 longrequestlogger_interval = longrequest_logger_interval))
133
134 # configure default Zope2 zcml
135 open(self.options['site-zcml'], 'w').write(open(self.getTemplateFilename(
136 'site.zcml')).read())
137 zope_config['instance'] = self.options['instance-path']
138 zope_config['event_log'] = self.options['event-log']
139 zope_config['z2_log'] = self.options['z2-log']
140 zope_config['pid-filename'] = self.options['pid-file']
141 zope_config['lock-filename'] = self.options['lock-file']
142 prefixed_products = []
143 for product in reversed(zope_config['products'].split()):
144 product = product.strip()
145 if product:
146 prefixed_products.append('products %s' % product)
147 prefixed_products.insert(0, 'products %s' % self.options[
148 'instance-products'])
149 zope_config['products'] = '\n'.join(prefixed_products)
150 zope_config['address'] = '%s:%s' % (self.options['ip'], self.options['port'])
151 zope_config.update(dump_url=self.options['deadlock-path'],
152 secret=self.options['deadlock-password'])
153
154 zope_wrapper_template_location = self.getTemplateFilename('zope.conf.in')
155 zope_conf_content = self.substituteTemplate(zope_wrapper_template_location,
156 zope_config)
157 if self.isTrueValue(self.options['timeserver']):
158 zope_conf_content += self.substituteTemplate(self.getTemplateFilename(
159 'zope.conf.timeserver.in'), {})
160
161 zope_conf_path = self.createFile(self.options['configuration-file'], zope_conf_content)
162 path_list.append(zope_conf_path)
163 # Create init script
164 path_list.append(self.createPythonScript(self.options['wrapper'], 'slapos.recipe.librecipe.execute.executee', [[self.options['runzope-binary'].strip(), '-C', zope_conf_path], zope_environment]))
165 return path_list