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