1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.zope2;
8
9 zope2Opts = { name, ... }: {
10 options = {
11
12 name = mkOption {
13 default = "${name}";
14 type = types.str;
15 description = lib.mdDoc "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 = lib.mdDoc "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.str;
27 description = lib.mdDoc "Give a port and address for the HTTP server.";
28 };
29
30 user = mkOption {
31 default = "zope2";
32 type = types.str;
33 description = lib.mdDoc "The name of the effective user for the Zope process.";
34 };
35
36 clientHome = mkOption {
37 default = "/var/lib/zope2/${name}";
38 type = types.path;
39 description = lib.mdDoc "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.lines;
56 description = lib.mdDoc "Extra zope.conf";
57 };
58
59 packages = mkOption {
60 type = types.listOf types.package;
61 description = lib.mdDoc "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 = with types; attrsOf (submodule zope2Opts);
78 example = literalExpression ''
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 = lib.mdDoc "zope2 instances to be created automatically by the system.";
99 };
100 };
101
102 ###### implementation
103
104 config = mkIf (cfg.instances != {}) {
105
106 users.users.zope2 = {
107 isSystemUser = true;
108 group = "zope2";
109 };
110 users.groups.zope2 = {};
111
112 systemd.services =
113 let
114
115 createZope2Instance = opts: name:
116 let
117 interpreter = pkgs.writeScript "interpreter"
118 ''
119 import sys
120
121 _interactive = True
122 if len(sys.argv) > 1:
123 _options, _args = __import__("getopt").getopt(sys.argv[1:], 'ic:m:')
124 _interactive = False
125 for (_opt, _val) in _options:
126 if _opt == '-i':
127 _interactive = True
128 elif _opt == '-c':
129 exec _val
130 elif _opt == '-m':
131 sys.argv[1:] = _args
132 _args = []
133 __import__("runpy").run_module(
134 _val, {}, "__main__", alter_sys=True)
135
136 if _args:
137 sys.argv[:] = _args
138 __file__ = _args[0]
139 del _options, _args
140 execfile(__file__)
141
142 if _interactive:
143 del _interactive
144 __import__("code").interact(banner="", local=globals())
145 '';
146 env = pkgs.buildEnv {
147 name = "zope2-${name}-env";
148 paths = [
149 pkgs.python27
150 pkgs.python27Packages.recursivePthLoader
151 pkgs.python27Packages."plone.recipe.zope2instance"
152 ] ++ attrValues pkgs.python27.modules
153 ++ opts.packages;
154 postBuild =
155 ''
156 echo "#!$out/bin/python" > $out/bin/interpreter
157 cat ${interpreter} >> $out/bin/interpreter
158 '';
159 };
160 conf = pkgs.writeText "zope2-${name}-conf"
161 ''
162 %define INSTANCEHOME ${env}
163 instancehome $INSTANCEHOME
164 %define CLIENTHOME ${opts.clientHome}/${opts.name}
165 clienthome $CLIENTHOME
166
167 debug-mode off
168 security-policy-implementation C
169 verbose-security off
170 default-zpublisher-encoding utf-8
171 zserver-threads ${toString opts.threads}
172 effective-user ${opts.user}
173
174 pid-filename ${opts.clientHome}/${opts.name}/pid
175 lock-filename ${opts.clientHome}/${opts.name}/lock
176 python-check-interval 1000
177 enable-product-installation off
178
179 <environment>
180 zope_i18n_compile_mo_files false
181 </environment>
182
183 <eventlog>
184 level INFO
185 <logfile>
186 path /var/log/zope2/${name}.log
187 level INFO
188 </logfile>
189 </eventlog>
190
191 <logger access>
192 level WARN
193 <logfile>
194 path /var/log/zope2/${name}-Z2.log
195 format %(message)s
196 </logfile>
197 </logger>
198
199 <http-server>
200 address ${opts.http_address}
201 </http-server>
202
203 <zodb_db temporary>
204 <temporarystorage>
205 name temporary storage for sessioning
206 </temporarystorage>
207 mount-point /temp_folder
208 container-class Products.TemporaryFolder.TemporaryContainer
209 </zodb_db>
210
211 ${opts.extra}
212 '';
213 ctlScript = pkgs.writeScript "zope2-${name}-ctl-script"
214 ''
215 #!${env}/bin/python
216
217 import sys
218 import plone.recipe.zope2instance.ctl
219
220 if __name__ == '__main__':
221 sys.exit(plone.recipe.zope2instance.ctl.main(
222 ["-C", "${conf}"]
223 + sys.argv[1:]))
224 '';
225
226 ctl = pkgs.writeScript "zope2-${name}-ctl"
227 ''
228 #!${pkgs.bash}/bin/bash -e
229 export PYTHONHOME=${env}
230 exec ${ctlScript} "$@"
231 '';
232 in {
233 #description = "${name} instance";
234 after = [ "network.target" ]; # with RelStorage also add "postgresql.service"
235 wantedBy = [ "multi-user.target" ];
236 path = opts.packages;
237 preStart =
238 ''
239 mkdir -p /var/log/zope2/
240 touch /var/log/zope2/${name}.log
241 touch /var/log/zope2/${name}-Z2.log
242 chown ${opts.user} /var/log/zope2/${name}.log
243 chown ${opts.user} /var/log/zope2/${name}-Z2.log
244
245 mkdir -p ${opts.clientHome}/filestorage ${opts.clientHome}/blobstorage
246 mkdir -p ${opts.clientHome}/${opts.name}
247 chown ${opts.user} ${opts.clientHome} -R
248
249 ${ctl} adduser admin admin
250 '';
251
252 serviceConfig.Type = "forking";
253 serviceConfig.ExecStart = "${ctl} start";
254 serviceConfig.ExecStop = "${ctl} stop";
255 serviceConfig.ExecReload = "${ctl} restart";
256 };
257
258 in listToAttrs (map (name: { name = "zope2-${name}"; value = createZope2Instance (builtins.getAttr name cfg.instances) name; }) (builtins.attrNames cfg.instances));
259
260 };
261
262}