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}