Merge branch 'erp5-component' into erp5
[slapos.git] / software / slaprunner / instance-runner.cfg
1 [buildout]
2 parts =
3   nginx_conf
4   nginx-launcher
5   certificate-authority
6   ca-nginx
7   ca-shellinabox
8   gunicorn-launcher
9   gunicorn-graceful
10   sshkeys-dropbear-runner
11   dropbear-server-add-authorized-key
12   sshkeys-authority
13   publish-connection-informations
14   slaprunner-promise
15   slaprunner-frontend-promise
16   dropbear-promise
17   runtestsuite
18   shellinabox-promise
19   symlinks
20   shellinabox
21   slapos-cfg
22   slapos-repo-config
23   cron-entry-prepare-software
24   deploy-instance-parameters
25   instance-software-type
26 {% if slapparameter_dict.get('custom-frontend-backend-url') %}
27   custom-frontend-promise
28 {% endif %}
29 ## Monitoring part
30 ###Parts to add for monitoring
31   cron
32   certificate-authority
33   cron-entry-monitor
34   cron-entry-rss
35   deploy-index
36   deploy-settings-cgi
37   deploy-status-cgi
38   deploy-status-history-cgi
39   setup-static-files
40   certificate-authority
41   zero-parameters
42   public-symlink
43   cgi-httpd-wrapper
44   cgi-httpd-graceful-wrapper
45   monitor-promise
46   monitor-instance-log-access
47 ## Monitor for runner
48   monitor-current-log-access
49
50 extends = ${monitor-template:output}
51
52 eggs-directory = ${buildout:eggs-directory}
53 develop-eggs-directory = ${buildout:develop-eggs-directory}
54 offline = true
55
56 {% if slapparameter_dict.get('custom-frontend-backend-url') -%}
57 # Requests, if defined, a frontend to allow access to a server
58 # located inside of the virtual machine listening to port X
59 # to LAN IPv4.
60 # Internaly, the frontend will be asked to listen on the IPv6
61 # with port X + 10000, to match NAT rules of Qemu.
62 [request-custom-frontend]
63 recipe = slapos.cookbook:requestoptional
64 software-url = {{ slapparameter_dict.get('custom-frontend-software-url', 'http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg') }}
65 software-type = {{ slapparameter_dict.get('custom-frontend-software-type', 'RootSoftwareInstance') }}
66 slave = true
67 name = Custom Web Frontend
68
69 server-url = $${slap-connection:server-url}
70 key-file = $${slap-connection:key-file}
71 cert-file = $${slap-connection:cert-file}
72 computer-id = $${slap-connection:computer-id}
73 partition-id = $${slap-connection:partition-id}
74
75 {%- if slapparameter_dict.get('custom-frontend-instance-guid') -%}
76 sla = instance_guid
77 sla-instance_guid = $${slap-parameter:frontend-instance-guid}
78 {% endif -%}
79
80 {% set custom_frontend_backend_type = slapparameter_dict.get('custom-frontend-backend-type')%}
81 {% if custom_frontend_backend_type %}
82 config = url type
83 config-type = {{ custom_frontend_backend_type }}
84 {% else %}
85 config = url
86 {% endif -%}
87 config-url = {{ slapparameter_dict.get('custom-frontend-backend-url') }}
88 return = site_url domain
89
90 [custom-frontend-promise]
91 recipe = slapos.cookbook:check_url_available
92 path = $${directory:promises}/custom_frontend_promise
93 url = https://$${request-custom-frontend:connection-domain}
94 {% if slapparameter_dict.get('custom-frontend-basic-auth') -%}
95 check-secure = 1
96 {% endif -%}
97 dash_path = {{ dash_executable_location }}
98 curl_path = {{ curl_executable_location }}
99
100 [publish-connection-informations]
101 custom-frontend-url = https://$${request-custom-frontend:connection-domain}
102 {% endif %}
103
104 # Create all needed directories
105 [directory]
106 recipe = slapos.cookbook:mkdirectory
107 etc = $${buildout:directory}/etc/
108 var = $${buildout:directory}/var/
109 srv = $${buildout:directory}/srv/
110 bin = $${buildout:directory}/bin/
111 tmp = $${buildout:directory}/tmp/
112
113 sshkeys = $${:srv}/sshkeys
114 services = $${:etc}/service/
115 scripts = $${:etc}/run/
116 ssh = $${:etc}/ssh/
117 log = $${:var}/log/
118 run = $${:var}/run/
119 backup = $${:srv}/backup/
120 promises = $${:etc}/promise/
121 test = $${:etc}/test/
122 nginx-data = $${directory:srv}/nginx
123 ca-dir = $${:srv}/ssl
124 project = $${:srv}/runner/project
125
126 [runnerdirectory]
127 recipe = slapos.cookbook:mkdirectory
128 home = $${directory:srv}/runner/
129 test = $${directory:srv}/test/
130 project = $${:home}/project
131 public = $${:home}/public
132 software-root = $${:home}/software
133 instance-root = $${:home}/instance
134 project-test = $${:test}/project
135 software-test = $${:test}/software
136 instance-test = $${:test}/instance
137 sessions = $${buildout:directory}/.sessions
138
139 #Create password recovery code for slaprunner
140 [recovery-code]
141 recipe = slapos.cookbook:generate.password
142 storage-path = $${directory:etc}/.rcode
143 bytes = 8
144
145 [slaprunner]
146 slaprunner = ${buildout:directory}/bin/slaprunner
147 slapos = ${buildout:directory}/bin/slapos
148 slapproxy = ${buildout:directory}/bin/slapproxy
149 supervisor = ${buildout:directory}/bin/slapgrid-supervisorctl
150 git-binary = ${git:location}/bin/git
151 root_check = false
152 slapos.cfg = $${directory:etc}/slapos.cfg
153 working-directory = $${runnerdirectory:home}
154 project-directory = $${runnerdirectory:project}
155 instance_root = $${runnerdirectory:instance-root}
156 software_root = $${runnerdirectory:software-root}
157 #XXX-Nico hardcoded default port because overridden by this buildout config
158 instance-monitor-url = https://[$${:ipv6}]:9685
159 etc_dir = $${directory:etc}
160 log_dir =  $${directory:log}
161 run_dir = $${directory:run}
162 ssh_client = $${sshkeys-dropbear-runner:wrapper}
163 public_key = $${sshkeys-dropbear-runner:public-key}
164 private_key = $${sshkeys-dropbear-runner:private-key}
165 ipv4 = $${slap-network-information:local-ipv4}
166 ipv6 = $${slap-network-information:global-ipv6}
167 instance_root = $${runnerdirectory:instance-root}
168 proxy_port = 50000
169 runner_port = 50005
170 partition-amount = $${slap-parameter:instance-amount}
171 wrapper = $${directory:services}/slaprunner
172 debug = $${slap-parameter:debug}
173 access-url = https://[$${:ipv6}]:$${:runner_port}
174 supervisord_config = $${directory:etc}/supervisord.conf
175 proxy_database = $${slaprunner:working-directory}/proxy.db
176 console = False
177 verbose = False
178 debug = False
179 auto_deploy = $${slap-parameter:auto-deploy}
180 auto_deploy_instance = $${slap-parameter:auto-deploy-instance}
181 autorun = $${slap-parameter:autorun}
182 knowledge0_file = $${buildout:directory}/$${public:filename}
183
184 [test-runner]
185 <= slaprunner
186 slapos.cfg = $${directory:etc}/slapos-test.cfg
187 working-directory = $${runnerdirectory:test}
188 project-directory = $${runnerdirectory:project-test}
189 software-directory = $${runnerdirectory:software-test}
190 instance-directory = $${runnerdirectory:instance-test}
191 proxy_port = 8602
192 etc_dir = $${directory:test}
193
194 [runtestsuite]
195 recipe = slapos.cookbook:wrapper
196 command-line = ${buildout:directory}/bin/slaprunnertest
197 wrapper-path = $${directory:bin}/runTestSuite
198 environment = RUNNER_CONFIG=$${slapos-test-cfg:rendered}
199
200 # Deploy dropbear (minimalist SSH server)
201 [sshkeys-directory]
202 recipe = slapos.cookbook:mkdirectory
203 requests = $${directory:sshkeys}/requests/
204 keys = $${directory:sshkeys}/keys/
205
206 [sshkeys-authority]
207 recipe = slapos.cookbook:sshkeys_authority
208 request-directory = $${sshkeys-directory:requests}
209 keys-directory = $${sshkeys-directory:keys}
210 wrapper = $${directory:services}/sshkeys_authority
211 keygen-binary = ${dropbear:location}/bin/dropbearkey
212
213 [dropbear-runner-server]
214 recipe = slapos.cookbook:dropbear
215 host = $${slap-network-information:global-ipv6}
216 port = 22222
217 home = $${directory:ssh}
218 wrapper = $${directory:bin}/runner_sshd
219 shell = ${bash:location}/bin/bash
220 rsa-keyfile = $${directory:ssh}/server_key.rsa
221 dropbear-binary = ${dropbear:location}/sbin/dropbear
222
223 [sshkeys-dropbear-runner]
224 <= sshkeys-authority
225 recipe = slapos.cookbook:sshkeys_authority.request
226 name = dropbear
227 type = rsa
228 executable = $${dropbear-runner-server:wrapper}
229 public-key = $${dropbear-runner-server:rsa-keyfile}.pub
230 private-key = $${dropbear-runner-server:rsa-keyfile}
231 wrapper = $${directory:services}/runner_sshd
232
233 [dropbear-server-add-authorized-key]
234 <= dropbear-runner-server
235 recipe = slapos.cookbook:dropbear.add_authorized_key
236 key = $${slap-parameter:user-authorized-key}
237
238 #---------------------------
239 #--
240 #-- Set nginx frontend
241
242 [tempdirectory]
243 recipe = slapos.cookbook:mkdirectory
244 client_body_temp_path = $${directory:tmp}/client_body_temp_path
245 proxy_temp_path = $${directory:tmp}/proxy_temp_path
246 fastcgi_temp_path = $${directory:tmp}/fastcgi_temp_path
247 uwsgi_temp_path = $${directory:tmp}/uwsgi_temp_path
248 scgi_temp_path = $${directory:tmp}/scgi_temp_path
249
250 [nginx-frontend]
251 # Options
252 nb_workers = 2
253 # Network
254 local-ip = $${slap-network-information:local-ipv4}
255 port = 30001
256 global-ip = $${slap-network-information:global-ipv6}
257 global-port = $${slaprunner:runner_port}
258 # Backend
259 runner-ip = $${slaprunner:ipv4}
260 runner-port = $${slaprunner:runner_port}
261 # SSL
262 ssl-certificate = $${ca-nginx:cert-file}
263 ssl-key = $${ca-nginx:key-file}
264 # Log
265 path_pid = $${directory:run}/nginx.pid
266 path_log = $${directory:log}/nginx.log
267 path_access_log = $${directory:log}/nginx.access.log
268 path_error_log = $${directory:log}/nginx.error.log
269 path_tmp = $${directory:tmp}/
270 # Config files
271 path_nginx_conf = $${directory:etc}/nginx.conf
272 # Executables
273 bin_nginx = ${nginx-webdav:location}/sbin/nginx
274 bin_launcher = $${directory:bin}/launcher
275 # Utils
276 path_shell = ${dash:location}/bin/dash
277 # Misc.
278 etc_dir = $${directory:etc}
279 work_dir = $${slaprunner:working-directory}
280
281 [nginx_conf]
282 recipe = slapos.recipe.template:jinja2
283 template = ${template_nginx_conf:location}/${template_nginx_conf:filename}
284 rendered = $${nginx-frontend:path_nginx_conf}
285 context =
286     key shellinabox_port shellinabox:port
287     key socket gunicorn:socket
288     section param_nginx_frontend nginx-frontend
289     section param_tempdir tempdirectory
290
291 [nginx-launcher]
292 recipe = slapos.recipe.template:jinja2
293 template = ${template_launcher:location}/${template_launcher:filename}
294 rendered = $${nginx-frontend:bin_launcher}
295 mode = 700
296 context =
297     section param_nginx_frontend nginx-frontend
298
299 [httpd-parameters]
300 path_pid = $${directory:run}/httpd.pid
301 path_error_log = $${directory:log}/httpd-error.log
302 path_access_log = $${directory:log}/httpd-access.log
303 key_file = $${ca-httpd:key-file}
304 cert_file = $${ca-httpd:cert-file}
305 global_ip = $${slap-network-information:global-ipv6}
306 global_port = $${slaprunner:runner_port}
307 monitor_port = $${monitor-parameters:port}
308 monitor_index = $${deploy-index:rendered}
309 working_directory = $${slaprunner:working-directory}
310 dav_lock = $${directory:var}/DavLock
311 etc_dir = $${directory:etc}
312 var_dir = $${directory:var}
313 project_folder = $${directory:project}
314 runner_home = $${runnerdirectory:home}
315 git_http_backend = ${git:location}/libexec/git-core/git-http-backend
316 cgi_httpd_conf = $${cgi-httpd-configuration-file:output}
317
318 [httpd-conf]
319 recipe = slapos.recipe.template:jinja2
320 template = ${template_httpd_conf:location}/${template_httpd_conf:filename}
321 rendered = $${directory:etc}/httpd.conf
322 context =
323     section parameters httpd-parameters
324
325 [cgi-httpd-wrapper]
326 recipe = slapos.cookbook:wrapper
327 apache-executable = ${apache:location}/bin/httpd
328 wrapper-path = $${ca-httpd:executable}
329 command-line = $${:apache-executable} -f $${httpd-conf:rendered} -DFOREGROUND
330
331 #--------------------
332 #--
333 #-- WSGI
334
335 [gunicorn]
336 bin_gunicorn = $${directory:bin}/gunicorn
337 bin_launcher = $${directory:services}/gunicorn
338 path_shell = ${dash:location}/bin/dash
339 socket = $${directory:tmp}/flaskserver.sock
340 path_pid = $${directory:run}/gunicorn.pid
341
342 [gunicorn-launcher]
343 recipe = slapos.cookbook:wrapper
344 command-line = $${gunicorn:bin_gunicorn} slapos.runner:app -p $${gunicorn:path_pid} -b unix:$${gunicorn:socket} -e RUNNER_CONFIG=$${slaprunner:slapos.cfg} --preload
345 wrapper-path = $${gunicorn:bin_launcher}
346 environment = PATH=$${environ:PATH}:${git:location}/bin/
347   RUNNER_CONFIG=$${slaprunner:slapos.cfg}
348
349 [gunicorn-graceful]
350 recipe = slapos.cookbook:wrapper
351 command-line = $${directory:bin}/killpidfromfile $${gunicorn:path_pid} SIGHUP
352 wrapper-path = $${directory:scripts}/gunicorn-graceful
353
354 #--------------------
355 #--
356 #-- ssl certificates
357
358 [certificate-authority]
359 recipe = slapos.cookbook:certificate_authority
360 openssl-binary = ${openssl:location}/bin/openssl
361 ca-dir = $${directory:ca-dir}
362 requests-directory = $${cadirectory:requests}
363 wrapper = $${directory:services}/certificate_authority
364 ca-private = $${cadirectory:private}
365 ca-certs = $${cadirectory:certs}
366 ca-newcerts = $${cadirectory:newcerts}
367 ca-crl = $${cadirectory:crl}
368
369 [cadirectory]
370 recipe = slapos.cookbook:mkdirectory
371 requests = $${directory:ca-dir}/requests/
372 private = $${directory:ca-dir}/private/
373 certs = $${directory:ca-dir}/certs/
374 newcerts = $${directory:ca-dir}/newcerts/
375 crl = $${directory:ca-dir}/crl/
376
377 [ca-nginx]
378 <= certificate-authority
379 recipe = slapos.cookbook:certificate_authority.request
380 key-file = $${cadirectory:certs}/nginx_frontend.key
381 cert-file = $${cadirectory:certs}/nginx_frontend.crt
382 executable = $${nginx-launcher:rendered}
383 wrapper = $${directory:services}/nginx-frontend
384 # Put domain name
385 name = example.com
386
387 [ca-shellinabox]
388 <= certificate-authority
389 recipe = slapos.cookbook:certificate_authority.request
390 executable = $${shellinabox:wrapper}
391 wrapper = $${directory:services}/shellinaboxd
392 key-file = $${cadirectory:certs}/shellinabox.key
393 cert-file = $${cadirectory:certs}/shellinabox.crt
394 #--------------------
395 #--
396 #-- Request frontend
397
398 [request-frontend]
399 <= slap-connection
400 recipe = slapos.cookbook:requestoptional
401 name = SlapRunner Frontend
402 # XXX We have hardcoded SR URL here.
403 software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
404 slave = true
405 config = url domain
406 config-url = $${slaprunner:access-url}
407 config-domain = $${slap-parameter:frontend-domain}
408 return = site_url domain
409
410 [monitor-frontend]
411 <= slap-connection
412 recipe = slapos.cookbook:requestoptional
413 name = Monitor Frontend
414 # XXX We have hardcoded SR URL here.
415 software-url = http://git.erp5.org/gitweb/slapos.git/blob_plain/HEAD:/software/apache-frontend/software.cfg
416 slave = true
417 config = url domain
418 config-url = https://[$${cgi-httpd-configuration-file:listening-ip}]:$${monitor-parameters:port}
419 config-domain = $${slap-parameter:frontend-domain}
420 return = site_url domain
421
422 #--------------------------------------
423 #--
424 #-- Send informations to SlapOS Master
425
426 [publish-connection-informations]
427 recipe = slapos.cookbook:publish
428 1_info = On your first run, Use "access_url" to setup you account. Then you can use both "url" or "access_url". Or "backend_url" if you want to use ipv6. Set up your account in the webrunner in order to use webdav, and being able to clone your git repositories from the runner.
429 2_info = In order to set up your account, get the recovery-code from the monitoring interface. Before read the notification on monitor_info.
430 backend_url = $${slaprunner:access-url}
431 access_url = $${:url}/login
432 url =  https://$${request-frontend:connection-domain}
433 ssh_command = ssh $${dropbear-runner-server:host} -p $${dropbear-runner-server:port}
434 monitor_url = https://$${monitor-frontend:connection-domain}
435 webdav_url = $${:monitor_url}/share/
436 public_url =  $${:monitor_url}/public/
437 git_public_url =  https://[$${httpd-parameters:global_ip}]:$${httpd-parameters:monitor_port}/git-public/
438 git_private_url = https://[$${httpd-parameters:global_ip}]:$${httpd-parameters:monitor_port}/git/
439
440 #---------------------------
441 #--
442 #-- Deploy promises scripts
443
444 [slaprunner-promise]
445 recipe = slapos.cookbook:check_port_listening
446 path = $${directory:promises}/slaprunner
447 hostname = $${slaprunner:ipv6}
448 port = $${slaprunner:runner_port}
449
450 [slaprunner-frontend-promise]
451 recipe = slapos.cookbook:check_url_available
452 path = $${directory:promises}/slaprunner_frontend
453 url = https://$${request-frontend:connection-domain}/login
454 dash_path = ${dash:location}/bin/dash
455 curl_path = ${curl:location}/bin/curl
456
457 [dropbear-promise]
458 recipe = slapos.cookbook:check_port_listening
459 path = $${directory:promises}/dropbear
460 hostname = $${dropbear-runner-server:host}
461 port = $${dropbear-runner-server:port}
462
463 [shellinabox-promise]
464 recipe = slapos.cookbook:check_port_listening
465 path = $${directory:promises}/shellinabox
466 hostname = $${shellinabox:ipv6}
467 port = $${shellinabox:port}
468
469 [symlinks]
470 recipe = cns.recipe.symlink
471 symlink_target = $${directory:bin}
472 symlink_base = ${buildout:directory}/bin
473
474 [slap-parameter]
475 # Default value if no ssh key is specified
476 user-authorized-key =
477 # Default value of instances number in slaprunner
478 instance-amount = 10
479 debug = false
480 frontend-domain =
481 slapos-repository = http://git.erp5.org/repos/slapos.git
482 slapos-software =
483 slapos-software-type =
484 slapos-reference = master
485 auto-deploy = false
486 auto-deploy-instance = true
487 autorun = false
488 monitor-port = 9684
489
490 [monitor-parameters]
491 port = $${slap-parameter:monitor-port}
492
493 [slapos-cfg]
494 recipe = slapos.recipe.template:jinja2
495 template = ${slapos-cfg-template:location}/${slapos-cfg-template:filename}
496 rendered = $${slaprunner:slapos.cfg}
497 mode = 700
498 context =
499   section slaprunner slaprunner
500
501 [slapos-test-cfg]
502 recipe = slapos.recipe.template:jinja2
503 template = ${slapos-cfg-template:location}/${slapos-cfg-template:filename}
504 rendered = $${test-runner:slapos.cfg}
505 mode = 700
506 context =
507   section slaprunner test-runner
508
509 [shellinabox]
510 recipe = slapos.cookbook:shellinabox
511 ipv6 = $${slap-network-information:global-ipv6}
512 port = 8080
513 shell = $${shell:wrapper}
514 wrapper = $${directory:bin}/shellinaboxd
515 shellinabox-binary = ${shellinabox:location}/bin/shellinaboxd
516 password = $${zero-parameters:shell-password}
517 directory = $${runnerdirectory:home}
518 login-shell = $${directory:bin}/login
519 certificate-directory = $${cadirectory:certs}
520 cert-file = $${ca-shellinabox:cert-file}
521 key-file = $${ca-shellinabox:key-file}
522
523 [shellinabox-code]
524 recipe = slapos.cookbook:generate.password
525 storage-path = $${directory:etc}/.scode
526 bytes = 8
527
528 [shell]
529 recipe = slapos.cookbook:shell
530 wrapper = $${directory:bin}/sh
531 shell = ${bash:location}/bin/bash
532 home = $${runnerdirectory:home}
533 path = $${environ:PATH}:${nano:location}/bin:${vim:location}/bin:${screen:location}/bin:${git:location}/bin
534 ps1 = "\\w> "
535
536 [environ]
537 recipe = collective.recipe.environment
538
539 [slapos-repo]
540 recipe = slapos.recipe.build:gitclone
541 repository = $${slap-parameter:slapos-repository}
542 git-executable = ${git:location}/bin/git
543 develop = true
544 location = $${directory:project}/slapos
545
546 [slapos-repo-config]
547 recipe = plone.recipe.command
548 stop-on-error = true
549 command = cd $${slapos-repo:location} && ${git:location}/bin/git checkout $${slap-parameter:slapos-reference} && SR=$${slap-parameter:slapos-software} && if [ -n "$SR" ] && [ ! -f "$${directory:etc}/.project" ]; then echo workspace/slapos/$${slap-parameter:slapos-software}/ > $${directory:etc}/.project; fi
550 update-command = true
551
552 [prepare-software]
553 recipe = slapos.cookbook:wrapper
554 command-line = ${curl:location}/bin/curl -g https://[$${slaprunner:ipv6}]:$${slaprunner:runner_port}/isSRReady --max-time 1 --insecure
555 wrapper-path = $${directory:scripts}/prepareSoftware
556
557 [cron-entry-prepare-software]
558 <= cron
559 recipe = slapos.cookbook:cron.d
560 name = prepare-software
561 frequency = */2 * * * *
562 command = $${prepare-software:wrapper-path}
563
564 [instance-parameters]
565 recipe = slapos.recipe.template:jinja2
566 extensions = jinja2.ext.do
567 template = ${parameters-template:location}/${parameters-template:filename}
568 rendered = $${directory:etc}/.parameter.xml.default
569 mode = 0644
570 context =
571   key slapparameter_dict slap-configuration:configuration
572
573 [deploy-instance-parameters]
574 recipe = plone.recipe.command
575 stop-on-error = true
576 parameter-xml = $${directory:etc}/.parameter.xml
577 command = if [ ! -f $${:parameter-xml} ]; then cp $${instance-parameters:rendered} $${:parameter-xml}; fi
578
579 [instance-software-type]
580 recipe = plone.recipe.command
581 stop-on-error = true
582 # XXX It should not be named with .xml as it is not xml
583 software-type-path = $${directory:etc}/.software_type.xml
584 command = if [ ! -f $${:software-type-path} -a "$${slap-parameter:slapos-software-type}" != "" ]; then echo "$${slap-parameter:slapos-software-type}" > $${:software-type-path}; fi
585
586 [slap-configuration]
587 recipe = slapos.cookbook:slapconfiguration.serialised
588 computer = $${slap-connection:computer-id}
589 partition = $${slap-connection:partition-id}
590 url = $${slap-connection:server-url}
591 key = $${slap-connection:key-file}
592 cert = $${slap-connection:cert-file}
593
594 [public]
595 shell-password = $${shellinabox-code:passwd}
596 recovery-code = $${recovery-code:passwd}
597
598 [zero-parameters]
599
600
601 [monitor-current-log-access]
602 < = monitor-directory-access
603 source = $${directory:log}