1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.zope2;
8
9 zope2Opts = { name, config, ... }: {
10 options = {
11
12 name = mkOption {
13 default = "${name}";
14 type = types.string;
15 description = "The name of the zope2 instance. If undefined, the name of the attribute set will be used.";
16 };
17
18 threads = mkOption {
19 default = 2;
20 type = types.int;
21 description = "Specify the number of threads that Zope's ZServer web server will use to service requests. ";
22 };
23
24 http_address = mkOption {
25 default = "localhost:8080";
26 type = types.string;
27 description = "Give a port and address for the HTTP server.";
28 };
29
30 user = mkOption {
31 default = "zope2";
32 type = types.string;
33 description = "The name of the effective user for the Zope process.";
34 };
35
36 clientHome = mkOption {
37 default = "/var/lib/zope2/${name}";
38 type = types.string;
39 description = "Home directory of zope2 instance.";
40 };
41 extra = mkOption {
42 default =
43 ''
44 <zodb_db main>
45 mount-point /
46 cache-size 30000
47 <blobstorage>
48 blob-dir /var/lib/zope2/${name}/blobstorage
49 <filestorage>
50 path /var/lib/zope2/${name}/filestorage/Data.fs
51 </filestorage>
52 </blobstorage>
53 </zodb_db>
54 '';
55 type = types.string;
56 description = "Extra zope.conf";
57 };
58
59 packages = mkOption {
60 type = types.listOf types.package;
61 description = "The list of packages you want to make available to the zope2 instance.";
62 };
63
64 };
65 };
66
67in
68
69{
70
71 ###### interface
72
73 options = {
74
75 services.zope2.instances = mkOption {
76 default = {};
77 type = types.loaOf types.optionSet;
78 example = literalExample ''
79 {
80 plone01 = {
81 http_address = "127.0.0.1:8080";
82 extra =
83 '''
84 <zodb_db main>
85 mount-point /
86 cache-size 30000
87 <blobstorage>
88 blob-dir /var/lib/zope2/plone01/blobstorage
89 <filestorage>
90 path /var/lib/zope2/plone01/filestorage/Data.fs
91 </filestorage>
92 </blobstorage>
93 </zodb_db>
94 ''';
95 };
96 }
97 '';
98 description = "zope2 instances to be created automaticaly by the system.";
99 options = [ zope2Opts ];
100 };
101 };
102
103 ###### implementation
104
105 config = mkIf (cfg.instances != {}) {
106
107 users.extraUsers.zope2.uid = config.ids.uids.zope2;
108
109 systemd.services =
110 let
111
112 createZope2Instance = opts: name:
113 let
114 interpreter = pkgs.writeScript "interpreter"
115 ''
116 import sys
117
118 _interactive = True
119 if len(sys.argv) > 1:
120 _options, _args = __import__("getopt").getopt(sys.argv[1:], 'ic:m:')
121 _interactive = False
122 for (_opt, _val) in _options:
123 if _opt == '-i':
124 _interactive = True
125 elif _opt == '-c':
126 exec _val
127 elif _opt == '-m':
128 sys.argv[1:] = _args
129 _args = []
130 __import__("runpy").run_module(
131 _val, {}, "__main__", alter_sys=True)
132
133 if _args:
134 sys.argv[:] = _args
135 __file__ = _args[0]
136 del _options, _args
137 execfile(__file__)
138
139 if _interactive:
140 del _interactive
141 __import__("code").interact(banner="", local=globals())
142 '';
143 env = pkgs.buildEnv {
144 name = "zope2-${name}-env";
145 paths = [
146 pkgs.python27
147 pkgs.python27Packages.recursivePthLoader
148 pkgs.python27Packages."plone.recipe.zope2instance"
149 ] ++ attrValues pkgs.python27.modules
150 ++ opts.packages;
151 postBuild =
152 ''
153 echo "#!$out/bin/python" > $out/bin/interpreter
154 cat ${interpreter} >> $out/bin/interpreter
155 '';
156 };
157 conf = pkgs.writeText "zope2-${name}-conf"
158 ''
159 %define INSTANCEHOME ${env}
160 instancehome $INSTANCEHOME
161 %define CLIENTHOME ${opts.clientHome}/${opts.name}
162 clienthome $CLIENTHOME
163
164 debug-mode off
165 security-policy-implementation C
166 verbose-security off
167 default-zpublisher-encoding utf-8
168 zserver-threads ${toString opts.threads}
169 effective-user ${opts.user}
170
171 pid-filename ${opts.clientHome}/${opts.name}/pid
172 lock-filename ${opts.clientHome}/${opts.name}/lock
173 python-check-interval 1000
174 enable-product-installation off
175
176 <environment>
177 zope_i18n_compile_mo_files false
178 </environment>
179
180 <eventlog>
181 level INFO
182 <logfile>
183 path /var/log/zope2/${name}.log
184 level INFO
185 </logfile>
186 </eventlog>
187
188 <logger access>
189 level WARN
190 <logfile>
191 path /var/log/zope2/${name}-Z2.log
192 format %(message)s
193 </logfile>
194 </logger>
195
196 <http-server>
197 address ${opts.http_address}
198 </http-server>
199
200 <zodb_db temporary>
201 <temporarystorage>
202 name temporary storage for sessioning
203 </temporarystorage>
204 mount-point /temp_folder
205 container-class Products.TemporaryFolder.TemporaryContainer
206 </zodb_db>
207
208 ${opts.extra}
209 '';
210 ctlScript = pkgs.writeScript "zope2-${name}-ctl-script"
211 ''
212 #!${env}/bin/python
213
214 import sys
215 import plone.recipe.zope2instance.ctl
216
217 if __name__ == '__main__':
218 sys.exit(plone.recipe.zope2instance.ctl.main(
219 ["-C", "${conf}"]
220 + sys.argv[1:]))
221 '';
222
223 ctl = pkgs.writeScript "zope2-${name}-ctl"
224 ''
225 #!${pkgs.bash}/bin/bash -e
226 export PYTHONHOME=${env}
227 exec ${ctlScript} "$@"
228 '';
229 in {
230 #description = "${name} instance";
231 after = [ "network.target" ]; # with RelStorage also add "postgresql.service"
232 wantedBy = [ "multi-user.target" ];
233 path = opts.packages;
234 preStart =
235 ''
236 mkdir -p /var/log/zope2/
237 touch /var/log/zope2/${name}.log
238 touch /var/log/zope2/${name}-Z2.log
239 chown ${opts.user} /var/log/zope2/${name}.log
240 chown ${opts.user} /var/log/zope2/${name}-Z2.log
241
242 mkdir -p ${opts.clientHome}/filestorage ${opts.clientHome}/blobstorage
243 mkdir -p ${opts.clientHome}/${opts.name}
244 chown ${opts.user} ${opts.clientHome} -R
245
246 ${ctl} adduser admin admin
247 '';
248
249 serviceConfig.Type = "forking";
250 serviceConfig.ExecStart = "${ctl} start";
251 serviceConfig.ExecStop = "${ctl} stop";
252 serviceConfig.ExecReload = "${ctl} restart";
253 };
254
255 in listToAttrs (map (name: { name = "zope2-${name}"; value = createZope2Instance (builtins.getAttr name cfg.instances) name; }) (builtins.attrNames cfg.instances));
256
257 };
258
259}