- name: fail if backup parameters are missing fail: msg: backup parameters are missing or incorrect when: (backup is not mapping) or (backup.dirs is not defined) - name: install restic include_tasks: tasks/install_packages.yml vars: package: - restic - name: add restic repo include_role: name: rest-server vars: function: add_repo repo: user: "{{ backup.user | d(host_name) }}" password: "{{ backup.password }}" name: "{{ backup.repo | d(None) }}" retention: "{{ backup.retention | d(restic_default_backup_retention) | d({}) }}" repo_password: "{{ backup.repo_password | d(None) }}" server: "{{ backup.server | d(None) }}" - name: set backup id set_fact: restic_backup_id: "{{ (backup.user | d(host_name)) ~ (('-' ~ backup.repo) if backup.repo is defined else '') }}" - block: - name: ensure work dir exists file: path: "{{ restic_dir.linux }}" state: directory mode: 0700 - name: set exclude file location set_fact: restic_exclude_file_path: "{{ restic_dir.linux ~ '/exclude-file-' ~ restic_backup_id }}" - name: create exclude file copy: content: "{{ backup.filter | join('\n') }}" dest: "{{ restic_exclude_file_path }}" when: ansible_system != 'Win32NT' and (backup.filter | type_debug == 'list') and (backup.filter | length > 0) - block: - name: ensure work dir exists win_file: path: "{{ restic_dir.windows }}" state: directory - name: set exclude file location set_fact: restic_exclude_file_path: "{{ restic_dir.windows ~ '\\exclude-file-' ~ restic_backup_id }}" restic_exclude_file_path_psh: "{{ restic_dir.windows_psh ~ '\\exclude-file-' ~ restic_backup_id }}" - name: create exclude file win_copy: content: "{{ backup.filter | join('\r\n') }}" dest: "{{ restic_exclude_file_path }}" when: ansible_system == 'Win32NT' and (backup.filter | type_debug == 'list') and (backup.filter | length > 0) - name: build restic args set_fact: restic_args: "{{ [ ('--one-file-system' if (backup.fs_single | d(false) == true) else ''), ('--use-fs-snapshot' if (backup.fs_snapshot | d(false) == true) else ''), (('--tag ' ~ (backup.tags | select() | list | join(',') | quote)) if (backup.tags | type_debug == 'list') else ''), (('--tag ' ~ (backup.tags | quote)) if (backup.tags is string and backup.tags | length > 0) else ''), (('--limit-download ' ~ (backup.download_limit | quote)) if (backup.download_limit is defined and backup.download_limit != 0) else ''), (('--limit-upload ' ~ (backup.upload_limit | quote)) if (backup.upload_limit is defined and backup.upload_limit != 0) else ''), (('--exclude-larger-than ' ~ (backup.max_size | quote)) if (backup.max_size is string and backup.max_size | length > 0) else ''), (('--iexclude-file \"' ~ restic_exclude_file_path_psh ~ '\"') if ((backup.filter | type_debug == 'list') and (backup.filter | length > 0) and ansible_system == 'Win32NT') else ''), (('--iexclude-file ' ~ (restic_exclude_file_path | quote)) if ((backup.filter | type_debug == 'list') and (backup.filter | length > 0) and ansible_system != 'Win32NT') else '') ] | select() | list | join(' ') }}" restic_item_list: "{{ (backup.dirs if (backup.dirs | type_debug == 'list') else [backup.dirs]) | map('quote') | join(' ') }}" - name: build env vars set_fact: restic_env_vars: RESTIC_PASSWORD: "{{ backup.repo_password | d(backup.password) }}" RESTIC_REPOSITORY: "{{ ('rest:' ~ (services.backup.protocol | d('https')) ~ '://' ~ (backup.user | d(host_name)) ~ ':' ~ backup.password ~ '@' ~ (backup.server | d(services.backup.hostname)) ~ '.' ~ (services.backup.tld | d(int_tld)) ~ ':' ~ (services.backup.port | d('443')) ~ '/' ~ (backup.user | d(host_name)) ~ (('/' ~ backup.repo) if backup.repo is defined else '')) }}" - name: add backup job to cron cron: name: "{{ 'restic-backup-' ~ restic_backup_id }}" minute: "{{ backup.minute | d(59 | random(seed=restic_backup_id)) }}" hour: "{{ backup.hour | d(4 | random(start=1, seed=restic_backup_id)) }}" day: "{{ backup.day | d('*') }}" weekday: "{{ backup.weekday | d('*') }}" month: "{{ backup.month | d('*') }}" job: "{{ restic_env_vars.keys() | zip(restic_env_vars.values() | map('quote')) | map('join', '=') | list | join(' ') }} restic backup {{ restic_args }} {{ restic_item_list }}" when: (ansible_system != 'Win32NT') and (backup.schedule | d(true) == true) - block: - name: template backup script to remote host win_template: src: win_script.j2 dest: "{{ restic_dir.windows ~ '\\backup-' ~ restic_backup_id ~ '.ps1' }}" lstrip_blocks: yes - name: add scheduled task win_scheduled_task: name: "{{ 'Restic Backup (' ~ restic_backup_id ~ ')' }}" description: Initiate a Restic backup job allow_demand_start: yes allow_hard_terminate: yes compatibility: 3 execution_time_limit: PT18H disallow_start_if_on_batteries: no enabled: yes logon_type: service_account multiple_instances: 2 username: SYSTEM run_level: highest start_when_available: yes stop_if_going_on_batteries: no wake_to_run: no update_password: no actions: - path: powershell.exe arguments: "{{ '-ExecutionPolicy Unrestricted -File \"' ~ restic_dir.windows ~ '\\backup-' ~ restic_backup_id ~ '.ps1\"' }}" triggers: - type: "{{ backup.interval }}" enabled: yes start_boundary: "2020-01-01T{{ '%02d' | format(backup.hour | d(4 | random(start=1, seed=restic_backup_id))) }}\ :{{ '%02d' | format(backup.minute | d(59 | random(seed=restic_backup_id))) }}:00" random_delay: "{{ backup.random_delay | d(omit) }}" days_of_week: "{{ backup.days_of_week | d(omit) }}" days_of_month: "{{ backup.days_of_month | d(omit) }}" weeks_interval: "{{ backup.weeks_interval | d(omit) }}" when: (backup.schedule | d(true) == true) when: ansible_system == 'Win32NT'