{% set ports = itertools.count(slapparameter_dict['tcpv4-port']) -%} {% set ipv4 = (ipv4_set | list)[0] -%} {% set backup_periodicity = slapparameter_dict.get('backup-periodicity', 'daily') -%} {% set part_list = [] -%} {% macro section(name) %}{% do part_list.append(name) %}{{ name }}{% endmacro -%} {% set storage_dict = {} -%} {% set default_zodb_path = buildout_directory ~ '/srv/zodb' -%} {% set default_backup_path = buildout_directory ~ '/srv/backup/zodb' -%} {% set bin_directory = parameter_dict['buildout-bin-directory'] -%} [zeo-base] recipe = slapos.cookbook:zeo log-path = ${directory:log}/${:base-name}.log pid-path = ${directory:run}/${:base-name}.pid conf-path = ${directory:etc}/${:base-name}.conf wrapper-path = ${directory:services}/${:base-name} binary-path = {{ bin_directory }}/runzeo ip = {{ ipv4 }} {% set known_tid_storage_identifier_dict = {} -%} {% set zodb_dict = {} -%} {% for name, zodb in six.iteritems(slapparameter_dict['zodb-dict']) -%} {% do zodb_dict.setdefault(zodb.get('family', 'default').lower(), []).append((name, zodb)) -%} {% endfor -%} {% set tidstorage_port = slapparameter_dict['tcpv4-port'] + len(zodb_dict) -%} {% for family, zodb in six.iteritems(zodb_dict) -%} {% set storage_list = [] -%} {% set current_port = next(ports) -%} {% set known_tid_storage_identifier_host = (ipv4, current_port), -%} {% for name, zodb in zodb -%} {% do storage_dict.__setitem__(name, {'server': ipv4 ~ ':' ~ current_port, 'storage': name, 'server-sync': 'true'}) %} {% set path = zodb.get('path', '%(zodb)s/%(name)s.fs') % {'zodb': default_zodb_path, 'name': name} -%} {% do storage_list.append((name, path)) -%} {% set backup_directory = zodb.get('backup', '%(backup)s/%(name)s') % {'backup': default_backup_path, 'name': name} -%} {# BBB: No mount-point specified because they're meaningless for ZEO and TIDStorage. Pass '' for compatibility, and not None because this would disable TIDStorage bootstrapping. -#} {% do known_tid_storage_identifier_dict.__setitem__(json_module.dumps( (known_tid_storage_identifier_host, name)), (path, backup_directory, '')) -%} {% endfor -%} {% set zeo_section_name = 'zeo-' ~ family %} [{{ zeo_section_name }}] < = zeo-base base-name = zeo-{{ family }} port = {{ current_port }} storage = {{ dumps(storage_list) }} [{{ section("logrotate-" ~ zeo_section_name) }}] < = logrotate-entry-base name = {{ "${" ~ zeo_section_name ~ ":base-name}" }} log = {{ "${" ~ zeo_section_name ~ ":log-path}" }} post = test ! -s {{ "${" ~ zeo_section_name ~":pid-path}" }} || {{ bin_directory }}/slapos-kill --pidfile {{ "${" ~ zeo_section_name ~ ":pid-path}" }} -s USR2 [{{ section(zeo_section_name ~ "-promise") }}] <= monitor-promise-base promise = check_socket_listening name = zeo-{{ family }}.py config-host = {{ "${" ~ zeo_section_name ~ ":ip}" }} config-port = {{ "${" ~ zeo_section_name ~ ":port}" }} {% endfor -%} {% if backup_periodicity == 'never' -%} {% set known_tid_storage_identifier_dict = () %} {% set tidstorage_repozo_path = '' -%} {% else -%} [tidstorage] recipe = slapos.cookbook:tidstorage known-tid-storage-identifier-dict = {{ dumps(known_tid_storage_identifier_dict) }} configuration-path = ${directory:etc}/tidstorage.py ip = {{ ipv4 }} port = {{ tidstorage_port }} {% set tidstorage_repozo_path = slapparameter_dict.get('tidstorage-repozo-path', buildout_directory ~ '/srv/backup/tidstorage') -%} timestamp-file-path = {{ tidstorage_repozo_path ~ '/repozo_tidstorage_timestamp.log' }} {# BBB: recipe requires logfile-name for nothing because tidstorage runs in foreground mode -#} logfile-name = pidfile-name = ${directory:run}/tidstorage.pid {# TODO: Add support for backup status file, so that the status file can be close to the ZODB (rather than close to the backup files). And do it efficiently, to not copy the whole status file every time. -#} status-file = {{ tidstorage_repozo_path ~ '/tidstorage.tid' }} tidstorage-repozo-binary = {{ bin_directory }}/tidstorage_repozo tidstoraged-binary = {{ bin_directory }}/tidstoraged repozo-binary = {{ bin_directory }}/repozo repozo-wrapper = ${buildout:bin-directory}/tidstorage-repozo {% if len(known_tid_storage_identifier_dict) > 1 -%} tidstorage-wrapper = ${directory:services}/tidstoraged [{{ section("promise-tidstorage") }}] <= monitor-promise-base promise = check_socket_listening name = tidstorage.py config-host = ${tidstorage:ip} config-port = ${tidstorage:port} {% endif -%} [{{ section("cron-entry-tidstorage-backup") }}] # TODO: # - configurable full/incremental # - configurable retention recipe = slapos.cookbook:cron.d cron-entries = ${cron:cron-entries} name = tidstorage time = {{ dumps(backup_periodicity) }} command = ${tidstorage:repozo-wrapper} # Used for ERP5 resiliency or (more probably) # webrunner resiliency with erp5 inside. [{{ section("resiliency-exclude-file") }}] # Generate rdiff exclude file recipe = slapos.recipe.template:jinja2 inline = {{ '{{ "${directory:zodb}/**\\n${directory:log}/**\\n" }}' }} output = ${directory:srv}/exporter.exclude [{{ section("resiliency-identity-signature-script")}}] # Generate identity script used by webrunner to check data integrity # It excludes repozo files as they already include a hash function # used to check backups when rebuilding the datafs recipe = slapos.cookbook:wrapper command-line = {{ bin_directory }}/backup-identity-script-excluding-path --exclude-path "srv/backup/logrotate/**" --exclude-path "srv/backup/zodb/*/*fsz" wrapper-path = ${directory:srv}/.backup_identity_script mode = 770 [{{ section("resiliency-after-import-script") }}] # Generate after import script used by importer instance of webrunner recipe = collective.recipe.template input = inline: #!/bin/sh # DO NOT RUN THIS SCRIPT ON PRODUCTION INSTANCE # OR ZODB DATA WILL BE ERASED. # This script will restore the repozo backup to the real # zodb location. It is launched by the clone (importer) instance of webrunner # in the end of the import script. # Depending on the output, it will create a file containing # the status of the restoration (success or failure). zodb_directory="${directory:zodb}" zodb_backup_directory="{{ default_backup_path }}" repozo="${tidstorage:repozo-binary}" EXIT_CODE=0 {% for family, zodb in six.iteritems(zodb_dict) -%} {% for name, zodb in zodb -%} {% set zeo_section_name = 'zeo-' ~ family %} storage_name="{{ name }}" zodb_path="$storage_name.fs" pid_file={{ "${" ~ zeo_section_name ~ ":pid-path}" }} if [ -e "$pid_file" ]; then pid=$(cat $pid_file) > /dev/null 2>&1 if kill -0 "$pid"; then echo "Zeo is already running with pid $pid. Aborting." exit 1 fi fi echo "Removing $zodb_path..." echo "Restoring $storage_name into $zodb_path..." $repozo --verify --repository="$zodb_backup_directory/$storage_name" CURRENT_EXIT_CODE=$? if [ ! "$CURRENT_EXIT_CODE"="0" ]; then echo "$storage_name Backup verification failed. Backup data is inconsistent." exit "$CURRENT_EXIT_CODE" fi $repozo --recover --output="$zodb_directory/$zodb_path" --repository="$zodb_backup_directory/$storage_name" CURRENT_EXIT_CODE=$? if [ ! "$CURRENT_EXIT_CODE"="0" ]; then EXIT_CODE="$CURRENT_EXIT_CODE" echo "$storage_name Backup restoration failed." fi {% endfor -%} {% endfor -%} exit $EXIT_CODE output = ${directory:srv}/runner-import-restore mode = 755 {% endif -%} [{{ section('promise-check-computer-memory') }}] <= monitor-promise-base promise = check_command_execute name = check-computer-memory.py config-command = "{{ parameter_dict["check-computer-memory-binary"] }}" -db ${monitor-instance-parameter:collector-db} --threshold "{{ slapparameter_dict["computer-memory-percent-threshold"] }}" --unit percent [publish] recipe = slapos.cookbook:publish.serialised storage-dict = {{ dumps(storage_dict) }} {% if len(known_tid_storage_identifier_dict) > 1 -%} tidstorage-ip = ${tidstorage:ip} tidstorage-port = ${tidstorage:port} {% else -%} tidstorage-ip = tidstorage-port = {% endif -%} monitor-base-url = ${monitor-publish-parameters:monitor-base-url} [directory] recipe = slapos.cookbook:mkdirectory bin = ${buildout:directory}/bin etc = ${buildout:directory}/etc services = ${:etc}/run plugin = ${:etc}/plugin srv = ${buildout:directory}/srv var = ${buildout:directory}/var log = ${:var}/log run = ${:var}/run backup-zodb = {{ default_backup_path }} zodb = {{ default_zodb_path }} tidstorage = {{ tidstorage_repozo_path }} [monitor-instance-parameter] monitor-httpd-ipv6 = {{ (ipv6_set | list)[0] }} monitor-httpd-port = {{ next(ports) }} monitor-title = {{ slapparameter_dict['name'] }} password = {{ slapparameter_dict['monitor-passwd'] }} [buildout] extends = {{ template_monitor }} parts += {{ part_list | join('\n ') }} publish