├── files └── empty ├── tests ├── inventory ├── tasks │ ├── post.yml │ └── pre.yml ├── vars │ └── main.yml ├── test.yml └── vagrant.yml ├── requirements.yml ├── .ansible-lint ├── vars └── main.yml ├── handlers └── main.yml ├── molecule └── default │ ├── collections.yml │ ├── prepare.yml │ ├── verify.yml │ ├── converge.yml │ └── molecule.yml ├── defaults └── main.yml ├── templates └── etc │ └── duply │ ├── exclude.j2 │ └── conf.j2 ├── .yamllint ├── .github └── workflows │ ├── release.yml │ └── ci.yml ├── .gitignore ├── tasks ├── main.yml ├── jobs.yml ├── gpg.yml └── configuration.yml ├── meta └── main.yml ├── Dockerfile ├── LICENSE.txt ├── Vagrantfile └── README.md /files/empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/inventory: -------------------------------------------------------------------------------- 1 | localhost 2 | -------------------------------------------------------------------------------- /requirements.yml: -------------------------------------------------------------------------------- 1 | # requirements file 2 | --- 3 | collections: [] 4 | -------------------------------------------------------------------------------- /.ansible-lint: -------------------------------------------------------------------------------- 1 | --- 2 | warn_list: 3 | - role-name 4 | - name[play] 5 | - name[casing] 6 | - risky-shell-pipe 7 | -------------------------------------------------------------------------------- /vars/main.yml: -------------------------------------------------------------------------------- 1 | # vars file 2 | --- 3 | duply_backup_profile_directory: /etc/duply 4 | duply_backup_lock_directory: "/var/lib/ansible/duply-backup/lock" 5 | -------------------------------------------------------------------------------- /handlers/main.yml: -------------------------------------------------------------------------------- 1 | # handlers file 2 | --- 3 | - name: update trustdb 4 | ansible.builtin.command: > 5 | gpg --update-trustdb 6 | changed_when: true 7 | -------------------------------------------------------------------------------- /molecule/default/collections.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collections: 3 | - name: community.docker 4 | version: '>=1.2.0,<2' 5 | - name: community.general 6 | version: '>=2,<3' 7 | -------------------------------------------------------------------------------- /molecule/default/prepare.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Prepare 3 | hosts: all 4 | become: true 5 | tasks: 6 | - name: include tasks 7 | ansible.builtin.import_tasks: "{{ playbook_dir }}/../../tests/tasks/pre.yml" 8 | -------------------------------------------------------------------------------- /molecule/default/verify.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Verify 3 | hosts: all 4 | become: true 5 | tasks: 6 | - name: include tasks 7 | ansible.builtin.import_tasks: "{{ playbook_dir }}/../../tests/tasks/post.yml" 8 | -------------------------------------------------------------------------------- /defaults/main.yml: -------------------------------------------------------------------------------- 1 | # defaults file 2 | --- 3 | duply_backup_profiles: {} 4 | 5 | duply_backup_gpg_pub_keys: [] 6 | duply_backup_gpg_ownertrusts: [] 7 | duply_backup_gpg_sec_keys: [] 8 | 9 | duply_backup_jobs: [] 10 | -------------------------------------------------------------------------------- /templates/etc/duply/exclude.j2: -------------------------------------------------------------------------------- 1 | {{ ansible_managed | comment }} 2 | 3 | {% if item.value.excludes is defined and item.value.excludes %} 4 | {% for exclude in item.value.excludes %} 5 | {{ exclude }} 6 | {% endfor %} 7 | {% endif %} 8 | -------------------------------------------------------------------------------- /molecule/default/converge.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | become: true 5 | pre_tasks: 6 | - name: include vars 7 | ansible.builtin.include_vars: "{{ playbook_dir }}/../../tests/vars/main.yml" 8 | roles: 9 | - ../../../ 10 | -------------------------------------------------------------------------------- /.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | 4 | rules: 5 | braces: 6 | max-spaces-inside: 1 7 | level: error 8 | brackets: 9 | max-spaces-inside: 1 10 | level: error 11 | line-length: disable 12 | truthy: disable 13 | 14 | ignore: | 15 | .tox/ 16 | -------------------------------------------------------------------------------- /tests/tasks/post.yml: -------------------------------------------------------------------------------- 1 | # post test file 2 | --- 3 | - name: run test 4 | ansible.builtin.shell: > 5 | # Test duply backup 6 | duply etc backup; 7 | # Test duply restore 8 | duply etc restore /tmp/duply-backup/restore && test -d /tmp/duply-backup/restore/skel; 9 | changed_when: false 10 | -------------------------------------------------------------------------------- /tests/vars/main.yml: -------------------------------------------------------------------------------- 1 | # vars file 2 | --- 3 | duply_backup_profiles: 4 | etc: 5 | conf: 6 | target: 'file:///tmp/duply-backup/target' 7 | source: '/etc' 8 | excludes: 9 | - '+ /etc/skel' 10 | - '- **' 11 | duply_backup_jobs: 12 | - name: "duply-backup-etc" 13 | job: "/usr/local/bin/duply etc status" 14 | minute: '*/5' 15 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Release 3 | 'on': 4 | push: 5 | tags: 6 | - '*' 7 | 8 | jobs: 9 | 10 | release: 11 | name: Release 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Check out the codebase 15 | uses: actions/checkout@v3 16 | 17 | - name: Publish to Galaxy 18 | uses: robertdebock/galaxy-action@1.2.0 19 | with: 20 | galaxy_api_key: ${{ secrets.GALAXY_API_KEY }} 21 | -------------------------------------------------------------------------------- /tests/test.yml: -------------------------------------------------------------------------------- 1 | # test file 2 | --- 3 | - hosts: localhost 4 | connection: local 5 | become: true 6 | pre_tasks: 7 | - name: include vars 8 | ansible.builtin.include_vars: "{{ playbook_dir }}/vars/main.yml" 9 | - name: include tasks 10 | ansible.builtin.import_tasks: "{{ playbook_dir }}/tasks/pre.yml" 11 | roles: 12 | - ../../ 13 | post_tasks: 14 | - name: include tasks 15 | ansible.builtin.import_tasks: "{{ playbook_dir }}/tasks/post.yml" 16 | -------------------------------------------------------------------------------- /tests/vagrant.yml: -------------------------------------------------------------------------------- 1 | # test file 2 | --- 3 | - hosts: all 4 | remote_user: vagrant 5 | become: true 6 | pre_tasks: 7 | - name: include vars 8 | ansible.builtin.include_vars: "{{ playbook_dir }}/vars/main.yml" 9 | - name: include tasks 10 | ansible.builtin.import_tasks: "{{ playbook_dir }}/tasks/pre.yml" 11 | roles: 12 | - ../../ 13 | post_tasks: 14 | - name: include tasks 15 | ansible.builtin.import_tasks: "{{ playbook_dir }}/tasks/post.yml" 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS generated files # 2 | ###################### 3 | .DS_Store 4 | .DS_Store? 5 | ._* 6 | .Spotlight-V100 7 | .Trashes 8 | Icon? 9 | ehthumbs.db 10 | Thumbs.db 11 | 12 | # IDE files # 13 | ################# 14 | /.settings 15 | /.buildpath 16 | /.project 17 | /nbproject 18 | *.komodoproject 19 | *.kpf 20 | /.idea 21 | 22 | # Vagrant files # 23 | .virtualbox/ 24 | .vagrant/ 25 | vagrant_ansible_inventory_* 26 | ansible.cfg 27 | 28 | # Other files # 29 | ############### 30 | !empty 31 | -------------------------------------------------------------------------------- /tasks/main.yml: -------------------------------------------------------------------------------- 1 | # tasks file 2 | --- 3 | - name: configuration 4 | ansible.builtin.import_tasks: configuration.yml 5 | tags: 6 | - configuration 7 | - duply-backup 8 | - duply-backup-configuration 9 | 10 | - name: gpg 11 | ansible.builtin.import_tasks: gpg.yml 12 | tags: 13 | - configuration 14 | - duply-backup 15 | - duply-backup-gpg 16 | 17 | - name: jobs 18 | ansible.builtin.import_tasks: jobs.yml 19 | tags: 20 | - configuration 21 | - duply-backup 22 | - duply-backup-jobs 23 | -------------------------------------------------------------------------------- /meta/main.yml: -------------------------------------------------------------------------------- 1 | # meta file 2 | --- 3 | galaxy_info: 4 | author: oefenweb 5 | role_name: duply_backup 6 | company: Oefenweb.nl B.V. 7 | description: Set up duplicity backups using duply in Debian-like systems 8 | license: MIT 9 | min_ansible_version: 2.10.0 10 | platforms: 11 | - name: Ubuntu 12 | versions: 13 | - xenial 14 | - bionic 15 | - focal 16 | - name: Debian 17 | versions: 18 | - buster 19 | - bullseye 20 | - bookworm 21 | galaxy_tags: 22 | - system 23 | dependencies: [] 24 | -------------------------------------------------------------------------------- /molecule/default/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | driver: 5 | name: docker 6 | platforms: 7 | - name: instance 8 | image: "geerlingguy/docker-${MOLECULE_DISTRO:-ubuntu1604}-ansible:latest" 9 | command: ${MOLECULE_DOCKER_COMMAND:-""} 10 | volumes: 11 | - /sys/fs/cgroup:/sys/fs/cgroup:rw 12 | - /var/lib/containerd 13 | cgroupns_mode: host 14 | privileged: true 15 | pre_build_image: true 16 | provisioner: 17 | name: ansible 18 | playbooks: 19 | prepare: prepare.yml 20 | converge: converge.yml 21 | verify: verify.yml 22 | -------------------------------------------------------------------------------- /tasks/jobs.yml: -------------------------------------------------------------------------------- 1 | # tasks file 2 | --- 3 | - name: configure (cron) jobs 4 | ansible.builtin.cron: 5 | name: "{{ item.name }}" 6 | job: "{{ item.job }}" 7 | state: "{{ item.state | default('present') }}" 8 | day: "{{ item.day | default('*') }}" 9 | hour: "{{ item.hour | default('*') }}" 10 | minute: "{{ item.minute | default('*') }}" 11 | month: "{{ item.month | default('*') }}" 12 | weekday: "{{ item.weekday | default('*') }}" 13 | cron_file: duply-backup 14 | user: root 15 | with_items: "{{ duply_backup_jobs }}" 16 | tags: 17 | - duply-backup-jobs-configure-cron 18 | -------------------------------------------------------------------------------- /tests/tasks/pre.yml: -------------------------------------------------------------------------------- 1 | # pre test file 2 | --- 3 | - name: install test dependencies 4 | ansible.builtin.apt: 5 | name: 6 | - wget 7 | - duplicity 8 | - cron 9 | update_cache: true 10 | cache_valid_time: "{{ apt_update_cache_valid_time | default(3600) }}" 11 | state: "{{ apt_install_state | default('latest') }}" 12 | 13 | - name: setup test 14 | ansible.builtin.get_url: 15 | url: 'http://duply.net/tmp/duply.sh' 16 | dest: /usr/local/bin/duply 17 | owner: root 18 | group: root 19 | mode: 0755 20 | 21 | - name: setup test 22 | ansible.builtin.file: 23 | path: /tmp/duply-backup/target 24 | state: directory 25 | owner: root 26 | group: root 27 | mode: 0755 28 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:18.04 2 | MAINTAINER Mischa ter Smitten 3 | 4 | ENV LANG C.UTF-8 5 | ENV LC_ALL C.UTF-8 6 | 7 | # python 8 | RUN apt-get update && \ 9 | DEBIAN_FRONTEND=noninteractive apt-get install -y python3-minimal python3-dev curl && \ 10 | apt-get clean 11 | RUN curl -sL https://bootstrap.pypa.io/pip/3.6/get-pip.py | python3 - 12 | RUN rm -rf $HOME/.cache 13 | 14 | # ansible 15 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -y python3-apt && \ 16 | apt-get clean 17 | RUN pip3 install ansible==2.10.7 18 | RUN rm -rf $HOME/.cache 19 | 20 | # provision 21 | COPY . /etc/ansible/roles/ansible-role 22 | WORKDIR /etc/ansible/roles/ansible-role 23 | RUN ansible-playbook -i tests/inventory tests/test.yml --connection=local 24 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Oefenweb.nl 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /tasks/gpg.yml: -------------------------------------------------------------------------------- 1 | # tasks file 2 | --- 3 | - name: create (lock) directory 4 | ansible.builtin.file: 5 | path: "{{ duply_backup_lock_directory }}" 6 | state: directory 7 | owner: root 8 | group: root 9 | mode: 0755 10 | tags: 11 | - duply-backup-gpg-directory 12 | 13 | - name: import public keys 14 | ansible.builtin.shell: > 15 | echo '{{ lookup('file', item) }}' | gpg --import && touch {{ duply_backup_lock_directory }}/{{ item | basename }} 16 | args: 17 | creates: "{{ duply_backup_lock_directory }}/{{ item | basename }}" 18 | with_items: "{{ duply_backup_gpg_pub_keys }}" 19 | tags: 20 | - duply-backup-gpg-pub-import 21 | 22 | - name: import ownertrusts 23 | ansible.builtin.shell: > 24 | echo '{{ lookup('file', item) }}' | gpg --import-ownertrust && touch {{ duply_backup_lock_directory }}/{{ item | basename }} 25 | args: 26 | creates: "{{ duply_backup_lock_directory }}/{{ item | basename }}" 27 | notify: update trustdb 28 | with_items: "{{ duply_backup_gpg_ownertrusts }}" 29 | tags: 30 | - duply-backup-gpg-ownertrust-import 31 | 32 | - name: import private keys 33 | ansible.builtin.shell: > 34 | echo '{{ lookup('file', item) }}' | gpg --allow-secret-key-import --batch --import && touch {{ duply_backup_lock_directory }}/{{ item | basename }} 35 | args: 36 | creates: "{{ duply_backup_lock_directory }}/{{ item | basename }}" 37 | with_items: "{{ duply_backup_gpg_sec_keys }}" 38 | tags: 39 | - duply-backup-gpg-sec-import 40 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby ts=2 sw=2 tw=0 et : 3 | 4 | role = File.basename(File.expand_path(File.dirname(__FILE__))) 5 | 6 | boxes = [ 7 | { 8 | :name => "ubuntu-1604", 9 | :box => "bento/ubuntu-16.04", 10 | :ip => '10.0.0.12', 11 | :cpu => "50", 12 | :ram => "256" 13 | }, 14 | { 15 | :name => "ubuntu-1804", 16 | :box => "bento/ubuntu-18.04", 17 | :ip => '10.0.0.13', 18 | :cpu => "50", 19 | :ram => "384" 20 | }, 21 | { 22 | :name => "ubuntu-2004", 23 | :box => "bento/ubuntu-20.04", 24 | :ip => '10.0.0.14', 25 | :cpu => "50", 26 | :ram => "384" 27 | }, 28 | { 29 | :name => "debian-10", 30 | :box => "bento/debian-10", 31 | :ip => '10.0.0.18', 32 | :cpu => "50", 33 | :ram => "256" 34 | }, 35 | { 36 | :name => "debian-11", 37 | :box => "bento/debian-11", 38 | :ip => '10.0.0.19', 39 | :cpu => "50", 40 | :ram => "256" 41 | }, 42 | { 43 | :name => "debian-12", 44 | :box => "bento/debian-12", 45 | :ip => '10.0.0.20', 46 | :cpu => "50", 47 | :ram => "256" 48 | }, 49 | ] 50 | 51 | Vagrant.configure("2") do |config| 52 | boxes.each do |box| 53 | config.vm.define box[:name] do |vms| 54 | vms.vm.box = box[:box] 55 | vms.vm.hostname = "ansible-#{role}-#{box[:name]}" 56 | 57 | vms.vm.provider "virtualbox" do |v| 58 | v.customize ["modifyvm", :id, "--cpuexecutioncap", box[:cpu]] 59 | v.customize ["modifyvm", :id, "--memory", box[:ram]] 60 | end 61 | 62 | vms.vm.network :private_network, ip: box[:ip] 63 | 64 | vms.vm.provision :ansible do |ansible| 65 | ansible.playbook = "tests/vagrant.yml" 66 | ansible.verbose = "vv" 67 | end 68 | end 69 | end 70 | end 71 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: CI 3 | 'on': 4 | pull_request: 5 | push: 6 | branches: 7 | - master 8 | schedule: 9 | - cron: '30 1 * * 3' 10 | 11 | jobs: 12 | 13 | lint: 14 | name: Lint 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Check out the codebase 18 | uses: actions/checkout@v3 19 | 20 | - name: Set up Python 3 21 | uses: actions/setup-python@v4 22 | with: 23 | python-version: '3.x' 24 | 25 | - name: Install test dependencies 26 | run: | 27 | pip install ansible-lint 28 | ansible-galaxy install -r requirements.yml 29 | 30 | - name: Lint code 31 | run: | 32 | yamllint . 33 | ansible-lint 34 | 35 | molecule: 36 | name: Molecule 37 | runs-on: ubuntu-latest 38 | defaults: 39 | run: 40 | working-directory: "${{ github.repository }}" 41 | needs: 42 | - lint 43 | strategy: 44 | fail-fast: false 45 | matrix: 46 | include: 47 | - distro: debian10 48 | - distro: debian11 49 | - distro: debian12 50 | - distro: ubuntu1604 51 | ansible-version: '>=2.10, <2.11' 52 | - distro: ubuntu1604 53 | - distro: ubuntu1804 54 | - distro: ubuntu2004 55 | 56 | steps: 57 | - name: Check out the codebase 58 | uses: actions/checkout@v3 59 | with: 60 | path: "${{ github.repository }}" 61 | 62 | - name: Set up Python 3 63 | uses: actions/setup-python@v4 64 | with: 65 | python-version: '3.x' 66 | 67 | - name: Install test dependencies 68 | run: pip install 'ansible${{ matrix.ansible-version }}' molecule[docker] docker 69 | 70 | - name: Run Molecule tests 71 | run: | 72 | molecule test 73 | env: 74 | ANSIBLE_FORCE_COLOR: '1' 75 | ANSIBLE_VERBOSITY: '2' 76 | MOLECULE_DEBUG: '1' 77 | MOLECULE_DISTRO: "${{ matrix.distro }}" 78 | PY_COLORS: '1' 79 | -------------------------------------------------------------------------------- /tasks/configuration.yml: -------------------------------------------------------------------------------- 1 | # tasks file 2 | --- 3 | - name: create (profile) directories 4 | ansible.builtin.file: 5 | path: "{{ duply_backup_profile_directory }}/{{ item.key }}" 6 | state: directory 7 | owner: root 8 | group: root 9 | mode: 0700 10 | with_dict: "{{ duply_backup_profiles }}" 11 | tags: 12 | - duply-backup-configuration-profile-directories 13 | 14 | - name: configure configuration files 15 | ansible.builtin.template: 16 | src: etc/duply/conf.j2 17 | dest: "{{ duply_backup_profile_directory }}/{{ item.key }}/conf" 18 | owner: root 19 | group: root 20 | mode: 0600 21 | with_dict: "{{ duply_backup_profiles }}" 22 | tags: 23 | - duply-backup-configuration-profile-conf 24 | 25 | - name: remove obsolete pre scripts 26 | ansible.builtin.file: 27 | path: "{{ duply_backup_profile_directory }}/{{ item.key }}/pre" 28 | state: absent 29 | with_dict: "{{ duply_backup_profiles }}" 30 | when: item.value.pre is not defined or not item.value.pre 31 | tags: 32 | - duply-backup-configuration-profile-pre 33 | 34 | - name: copy pre scripts 35 | ansible.builtin.copy: 36 | src: "{{ item.value.pre }}" 37 | dest: "{{ duply_backup_profile_directory }}/{{ item.key }}/pre" 38 | owner: root 39 | group: root 40 | mode: 0700 41 | with_dict: "{{ duply_backup_profiles }}" 42 | when: 43 | - item.value.pre is defined 44 | - item.value.pre 45 | tags: 46 | - duply-backup-configuration-profile-pre 47 | 48 | - name: remove obsolete post scripts 49 | ansible.builtin.file: 50 | path: "{{ duply_backup_profile_directory }}/{{ item.key }}/post" 51 | state: absent 52 | with_dict: "{{ duply_backup_profiles }}" 53 | when: item.value.post is not defined or not item.value.post 54 | tags: 55 | - duply-backup-configuration-profile-post 56 | 57 | - name: copy post scripts 58 | ansible.builtin.copy: 59 | src: "{{ item.value.post }}" 60 | dest: "{{ duply_backup_profile_directory }}/{{ item.key }}/post" 61 | owner: root 62 | group: root 63 | mode: 0700 64 | with_dict: "{{ duply_backup_profiles }}" 65 | when: 66 | - item.value.post is defined 67 | - item.value.post 68 | tags: 69 | - duply-backup-configuration-profile-post 70 | 71 | - name: configure exclude files 72 | ansible.builtin.template: 73 | src: etc/duply/exclude.j2 74 | dest: "{{ duply_backup_profile_directory }}/{{ item.key }}/exclude" 75 | owner: root 76 | group: root 77 | mode: 0600 78 | with_dict: "{{ duply_backup_profiles }}" 79 | tags: 80 | - duply-backup-configuration-profile-exclude 81 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## duply-backup 2 | 3 | [![CI](https://github.com/Oefenweb/ansible-duply-backup/workflows/CI/badge.svg)](https://github.com/Oefenweb/ansible-duply-backup/actions?query=workflow%3ACI) 4 | [![Ansible Galaxy](http://img.shields.io/badge/ansible--galaxy-duply--backup-blue.svg)](https://galaxy.ansible.com/Oefenweb/duply_backup) 5 | 6 | Set up [duplicity](http://duplicity.nongnu.org/) backups using [duply](http://duply.net/) in Debian-like systems. 7 | 8 | #### Requirements 9 | 10 | None 11 | 12 | #### Variables 13 | 14 | * `duply_backup_profiles`: [default: `{}`]: Duply backup profiles 15 | * `duply_backup_profiles.key`: The name of the profile (e.g. `etc`) 16 | * `duply_backup_profiles.key.conf`: Conf declarations 17 | * `duply_backup_profiles.key.conf.gpg_key`: Encrypt with key (**optional**, omitting will disable encryption) 18 | * `duply_backup_profiles.key.conf.gpg_pw`: Symmetric encryption using passphrase only (**optional**) 19 | * `duply_backup_profiles.key.conf.gpg_keys_enc`: Public key to encrypt to (**optional**) 20 | * `duply_backup_profiles.key.conf.gpg_key_sign`: A secret key for signing (**optional**) 21 | * `duply_backup_profiles.key.conf.gpg_pw_sign`: Signing key passphrase (**optional**) 22 | * `duply_backup_profiles.key.conf.gpg`: Override the used gpg executable, defaults to `gpg` (**optional**) 23 | * `duply_backup_profiles.key.conf.gpg_opts`: GPG options passed from duplicity to gpg process (**optional**) 24 | * `duply_backup_profiles.key.conf.gpg_test`: Disable preliminary tests (**optional**, set to `false` to disable) 25 | * `duply_backup_profiles.key.conf.gpg_import`: Disable automatic gpg key importing altogether 26 | * `duply_backup_profiles.key.conf.gpg_export`: Disable automatic gpg key exporting to profile folder 27 | * `duply_backup_profiles.key.conf.target`: Location of the backup target, [see duplicity manpage](http://duplicity.nongnu.org/duplicity.1.html#sect7) 28 | * `duply_backup_profiles.key.conf.target_user`: Username of the backup target (**optional**) 29 | * `duply_backup_profiles.key.conf.target_pass`: Password of the backup target (**optional**) 30 | * `duply_backup_profiles.key.conf.export`: Environment variables to set (**optional**) 31 | * `duply_backup_profiles.key.conf.export.{n}.name`: Name of the variable (e.g. `AWS_ACCESS_KEY_ID`) 32 | * `duply_backup_profiles.key.conf.export.{n}.value`: Value of the variable (e.g. `26E1A49CFE81D46C83C2`) 33 | * `duply_backup_profiles.key.conf.source`: Base directory to back up 34 | * `duply_backup_profiles.key.conf.dupl_precmd`: A command that runs duplicity (**optional**) 35 | * `duply_backup_profiles.key.conf.python`: Override the used python interpreter, defaults to `python` (**optional**) 36 | * `duply_backup_profiles.key.conf.exclude_if_present`: Exclude if present file name (**optional**) 37 | * `duply_backup_profiles.key.conf.max_age`: Time frame for old backups to keep (**optional**) 38 | * `duply_backup_profiles.key.conf.max_full_backups`: Number of full backups to keep (**optional**) 39 | * `duply_backup_profiles.key.conf.max_fulls_with_incrs`: Number of full backups for which incrementals will be kept for (**optional**) 40 | * `duply_backup_profiles.key.conf.max_fullbkp_age`: Forces a full backup if last full backup reaches a specified age (**optional**) 41 | * `duply_backup_profiles.key.conf.volsize`: Sets the size of backup chunks (**optional**, in MB's) 42 | * `duply_backup_profiles.key.conf.verbosity`: Verbosity of output (**optional**) 43 | * `duply_backup_profiles.key.conf.temp_dir`: Temporary file space. At least the size of the biggest file in backup for a successful restoration process (**optional**) 44 | * `duply_backup_profiles.key.conf.arch_dir`: Defines a folder that holds unencrypted metadata of the backup, enabling new incrementals without the need to decrypt backend metadata first (**optional**) 45 | * `duply_backup_profiles.key.conf.time_separator`: Enables duplicity `--time-separator` option (**optional**, **deprecated**, set to `true` to enable) 46 | * `duply_backup_profiles.key.conf.short_filenames`: Enables duplicity `--short-filenames` option (**optional**, **deprecated**, set to `true` to enable) 47 | * `duply_backup_profiles.key.conf.dupl_params`: Additional duplicity command line options. Don't forget to leave a separating space char at the end (**optional**) 48 | * `duply_backup_profiles.key.pre`: Pre script (**optional**) 49 | * `duply_backup_profiles.key.post`: Post script (**optional**) 50 | * `duply_backup_profiles.key.excludes`: A list of glob patterns of included or excluded files / folders (**optional**) 51 | 52 | * `duply_backup_gpg_pub_keys`: [default: `[]`]: Public keys to import 53 | * `duply_backup_gpg_ownertrusts`: [default: `[]`]: Owner trusts to import 54 | * `duply_backup_gpg_sec_keys`: [default: `[]`]: Private keys to import 55 | 56 | * `duply_backup_jobs`: [default: `[]`]: Duply backup jobs (scheduled by `cron.d`) 57 | * `duply_backup_jobs.{n}.name`: [required]: Description of a crontab entry, should be unique, and changing the value will result in a new cron task being created (e.g. `duply-backup-etc`) 58 | * `duply_backup_jobs.{n}.job`: [required]: The command to execute (e.g. `/usr/local/bin/duply etc backup`) 59 | * `duply_backup_jobs.{n}.state`: [default: `present`]: Whether to ensure the job is present or absent 60 | * `duply_backup_jobs.{n}.day`: [default: `*`]: Day of the month the job should run (`1-31`, `*`, `*/2`) 61 | * `duply_backup_jobs.{n}.hour`: [default: `*`]: Hour when the job should run (e.g. `0-23`, `*`, `*/2`) 62 | * `duply_backup_jobs.{n}.minute`: [default: `*`]: Minute when the job should run (e.g. `0-59`, `*`, `*/2`) 63 | * `duply_backup_jobs.{n}.month`: [default: `*`]: Month of the year the job should run (e.g `1-12`, `*`, `*/2`) 64 | * `duply_backup_jobs.{n}.weekday`: [default: `*`]: Day of the week that the job should run (e.g. `0-6` for Sunday-Saturday, `*`) 65 | 66 | ## Dependencies 67 | 68 | None 69 | 70 | ## Recommended 71 | 72 | * `ansible-duplicity` ([see](https://github.com/Oefenweb/ansible-duplicity), to get the latest version of `duplicity`) 73 | * `ansible-duply` ([see](https://github.com/Oefenweb/ansible-duply), to get the latest version of `duply`) 74 | 75 | #### Example(s) 76 | 77 | ##### Simple configuration (GPG disabled) 78 | 79 | ```yaml 80 | --- 81 | - hosts: all 82 | roles: 83 | - oefenweb.duply-backup 84 | vars: 85 | duply_backup_profiles: 86 | etc: 87 | conf: 88 | target: 'file:///tmp/duply-backup/target' 89 | source: '/etc' 90 | excludes: 91 | - '+ /etc/skel' 92 | - '- **' 93 | ``` 94 | 95 | ##### Advance configuration (GPG enabled) 96 | 97 | On your Ansible control machine machine in `../../../files/duply-backup/`. 98 | 99 | ###### Generate a GPG key pair 100 | ```sh 101 | gpg --batch --gen-key < %echo Generating a GPG key 103 | > Key-Type: RSA 104 | > Key-Length: 4096 105 | > Subkey-Type: RSA 106 | > Subkey-Length: 4096 107 | > Name-Real: Duplicity Backup 108 | > Name-Comment: localhost.localdomain 109 | > Name-Email: root@localhost.localdomain 110 | > Expire-Date: 0 111 | > Passphrase: QUsNMnD6GHUTFSBruSwbJpZBhto= 112 | > %commit 113 | > %echo Done 114 | > EOF 115 | gpg: Generating a GPG key 116 | .....+++++ 117 | ........+++++ 118 | .....+++++ 119 | .........................+++++ 120 | gpg: key E6564C6E marked as ultimately trusted 121 | gpg: Done 122 | ``` 123 | 124 | ###### Export the public key 125 | ```sh 126 | gpg --output E6564C6E.pub.asc --armor --export E6564C6E; 127 | ``` 128 | 129 | ###### Export the ownertrust (value 6, ultimately trusted) 130 | ```sh 131 | echo "$(gpg --with-fingerprint E6564C6E.pub.asc | grep fingerprint | tr -d '[:space:]' | awk 'BEGIN { FS = "=" } ; { print $2 }'):6:" 1> E6564C6E.ownertrust.txt; 132 | ``` 133 | 134 | ###### Export the private key 135 | ```sh 136 | gpg --output E6564C6E.sec.asc --armor --export-secret-key E6564C6E; 137 | ``` 138 | 139 | ```yaml 140 | --- 141 | - hosts: all 142 | roles: 143 | - oefenweb.duply-backup 144 | vars: 145 | duply_backup_profiles: 146 | etc: 147 | conf: 148 | gpg_key: 'E6564C6E' 149 | gpg_pw: 'QUsNMnD6GHUTFSBruSwbJpZBhto=' 150 | gpg_key_sign: 'E6564C6E' 151 | gpg_pw_sign: 'QUsNMnD6GHUTFSBruSwbJpZBhto=' 152 | gpg_opts: '--pinentry-mode loopback' 153 | 154 | target: 'file:///data/backup/etc' 155 | source: '/etc' 156 | 157 | max_age: 1W 158 | max_fullbkp_age: 1M 159 | 160 | verbosity: 5 161 | 162 | arch_dir: '/data/backup/.duply-cache' 163 | pre: ../../../files/duply-backup/pre 164 | post: ../../../files/duply-backup/post 165 | excludes: 166 | - '+ /etc/skel' 167 | - '- **' 168 | 169 | duply_backup_gpg_pub_keys: 170 | - ../../../files/duply-backup/E6564C6E.pub.asc 171 | duply_backup_gpg_ownertrusts: 172 | - ../../../files/duply-backup/E6564C6E.ownertrust.txt 173 | duply_backup_gpg_sec_keys: 174 | - ../../../files/duply-backup/E6564C6E.sec.asc 175 | duply_backup_jobs: 176 | - name: duply-backup-etc 177 | job: /usr/local/bin/duply etc backup 178 | minute: "0" 179 | ``` 180 | 181 | #### License 182 | 183 | MIT 184 | 185 | #### Author Information 186 | 187 | Mischa ter Smitten 188 | 189 | #### Feedback, bug-reports, requests, ... 190 | 191 | Are [welcome](https://github.com/Oefenweb/ansible-duply-backup/issues)! 192 | -------------------------------------------------------------------------------- /templates/etc/duply/conf.j2: -------------------------------------------------------------------------------- 1 | {{ ansible_managed | comment }} 2 | 3 | # gpg encryption settings, simple settings: 4 | # GPG_KEY='disabled' - disables encryption alltogether 5 | # GPG_KEY='[,]'; GPG_PW='pass' - encrypt with keys, 6 | # sign if secret key of key1 is available use GPG_PW for sign & decrypt 7 | # Note: you can specify keys via all methods described in gpg manpage, 8 | # section "How to specify a user ID", escape commas (,) via backslash (\) 9 | # e.g. 'Mueller, Horst', 'Bernd' -> 'Mueller\, Horst, Bernd' 10 | # as they are used to separate the entries 11 | # GPG_PW='passphrase' - symmetric encryption using passphrase only 12 | {% if item.value.conf.gpg_key is defined %} 13 | GPG_KEY='{{ item.value.conf.gpg_key }}' 14 | {% else %} 15 | GPG_KEY='disabled' 16 | {% endif %} 17 | {% if item.value.conf.gpg_pw is defined %} 18 | GPG_PW='{{ item.value.conf.gpg_pw }}' 19 | {% else %} 20 | #GPG_PW='_GPG_PASSWORD_' 21 | {% endif %} 22 | # gpg encryption settings in detail (extended settings) 23 | # the above settings translate to the following more specific settings 24 | # GPG_KEYS_ENC='[,,...]' - list of pubkeys to encrypt to 25 | # GPG_KEY_SIGN='|disabled' - a secret key for signing 26 | # GPG_PW='' - needed for signing, decryption and symmetric 27 | # encryption. If you want to deliver different passphrases for e.g. 28 | # several keys or symmetric encryption plus key signing you can use 29 | # gpg-agent. Simply make sure that GPG_AGENT_INFO is set in environment. 30 | # also see "A NOTE ON SYMMETRIC ENCRYPTION AND SIGNING" in duplicity manpage 31 | # notes on en/decryption 32 | # private key and passphrase will only be needed for decryption or signing. 33 | # decryption happens on restore and incrementals (compare archdir contents). 34 | # for security reasons it makes sense to separate the signing key from the 35 | # encryption keys. https://answers.launchpad.net/duplicity/+question/107216 36 | {% if item.value.conf.gpg_keys_enc is defined %} 37 | GPG_KEYS_ENC='{{ item.value.conf.gpg_keys_enc }}' 38 | {% else %} 39 | #GPG_KEYS_ENC=',,...' 40 | {% endif %} 41 | {% if item.value.conf.gpg_key_sign is defined %} 42 | GPG_KEY_SIGN='{{ item.value.conf.gpg_key_sign }}' 43 | {% else %} 44 | #GPG_KEY_SIGN='' 45 | {% endif %} 46 | # set if signing key passphrase differs from encryption (key) passphrase 47 | # NOTE: available since duplicity 0.6.14, translates to SIGN_PASSPHRASE 48 | {% if item.value.conf.gpg_pw_sign is defined %} 49 | GPG_PW_SIGN='{{ item.value.conf.gpg_pw_sign }}' 50 | {% else %} 51 | #GPG_PW_SIGN='' 52 | {% endif %} 53 | 54 | # uncomment and set a file path or name force duply to use this gpg executable 55 | # available in duplicity 0.7.04 and above (currently unreleased 06/2015) 56 | {% if item.value.conf.gpg is defined %} 57 | GPG='{{ item.value.conf.gpg }}' 58 | {% else %} 59 | #GPG='/usr/local/gpg-2.1/bin/gpg' 60 | {% endif %} 61 | 62 | # gpg options passed from duplicity to gpg process (default='') 63 | # e.g. "--trust-model pgp|classic|direct|always" 64 | # or "--compress-algo=bzip2 --bzip2-compress-level=9" 65 | # or "--personal-cipher-preferences AES256,AES192,AES..." 66 | # or "--homedir ~/.duply" - keep keyring and gpg settings duply specific 67 | # or "--pinentry-mode loopback" - needed for GPG 2.1+ _and_ 68 | # also enable allow-loopback-pinentry in your .gnupg/gpg-agent.conf 69 | {% if item.value.conf.gpg_opts is defined %} 70 | GPG_OPTS='{{ item.value.conf.gpg_opts }}' 71 | {% else %} 72 | #GPG_OPTS='' 73 | {% endif %} 74 | 75 | # disable preliminary tests with the following setting 76 | {% if item.value.conf.gpg_test is defined and item.value.conf.gpg_test | bool == False %} 77 | GPG_TEST='disabled' 78 | {% else %} 79 | #GPG_TEST='disabled' 80 | {% endif %} 81 | # disable automatic gpg key importing altogether 82 | {% if item.value.conf.gpg_import is defined and item.value.conf.gpg_import | bool == False %} 83 | GPG_IMPORT='disabled' 84 | {% else %} 85 | #GPG_IMPORT='disabled' 86 | {% endif %} 87 | # disable automatic gpg key exporting to profile folder 88 | {% if item.value.conf.gpg_export is defined and item.value.conf.gpg_export | bool == False %} 89 | GPG_EXPORT='disabled' 90 | {% else %} 91 | #GPG_EXPORT='disabled' 92 | {% endif %} 93 | 94 | # backend, credentials & location of the backup target (URL-Format) 95 | # generic syntax is 96 | # scheme://[user[:password]@]host[:port]/[/]path 97 | # e.g. 98 | # sftp://bob:secret@backupserver.com//home/bob/dupbkp 99 | # for details and available backends see duplicity manpage, section URL Format 100 | # http://duplicity.us/vers8/duplicity.1.html#url-format 101 | # BE AWARE: 102 | # some backends (cloudfiles, S3 etc.) need additional env vars to be set to 103 | # work properly, read after the TARGET definition for more details. 104 | # ATTENTION: 105 | # characters other than A-Za-z0-9.-_.~ in the URL have to be 106 | # replaced by their url encoded pendants, see 107 | # http://en.wikipedia.org/wiki/Url_encoding 108 | # if you define the credentials as TARGET_USER, TARGET_PASS below duply 109 | # will try to url_encode them for you if the need arises. 110 | TARGET='{{ item.value.conf.target }}' 111 | 112 | # optionally the username/password can be defined as extra variables 113 | # setting them here _and_ in TARGET results in an error 114 | # ATTENTION: 115 | # there are backends that do not support the user/pass auth scheme. 116 | # prominent examples are S3, Azure, Cloudfiles. when in doubt consult the 117 | # duplicity manpage. usually there is a NOTE section explaining if and which 118 | # env vars should be set. 119 | {% if item.value.conf.target_user is defined %} 120 | TARGET_USER='{{ item.value.conf.target_user }}' 121 | {% else %} 122 | #TARGET_USER='_backend_username_' 123 | {% endif %} 124 | {% if item.value.conf.target_pass is defined %} 125 | TARGET_PASS='{{ item.value.conf.target_pass }}' 126 | {% else %} 127 | #TARGET_PASS='_backend_password_' 128 | {% endif %} 129 | # eg. for cloud files backend it might look like this (uncomment for use!) 130 | {% if item.value.conf.export is defined %} 131 | {% for export in item.value.conf.export %} 132 | export {{ export.name }}='{{ export.value }}' 133 | {% endfor %} 134 | {% else %} 135 | # e.g. for cloud files backend it might look like this (uncomment for use!) 136 | #export CLOUDFILES_USERNAME='someuser' 137 | #export CLOUDFILES_APIKEY='somekey' 138 | #export CLOUDFILES_AUTHURL ='someurl' 139 | {% endif %} 140 | # the following is an incomplete list (: comma separated env vars list) 141 | # Azure: AZURE_ACCOUNT_NAME, AZURE_ACCOUNT_KEY 142 | # Cloudfiles: CLOUDFILES_USERNAME, CLOUDFILES_APIKEY, CLOUDFILES_AUTHURL 143 | # Google Cloud Storage: GS_ACCESS_KEY_ID, GS_SECRET_ACCESS_KEY 144 | # Pydrive: GOOGLE_DRIVE_ACCOUNT_KEY, GOOGLE_DRIVE_SETTINGS 145 | # S3: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY 146 | # Swift: SWIFT_USERNAME, SWIFT_PASSWORD, SWIFT_AUTHURL, 147 | # SWIFT_TENANTNAME OR SWIFT_PREAUTHURL, SWIFT_PREAUTHTOKEN 148 | 149 | # base directory to backup 150 | SOURCE='{{ item.value.conf.source }}' 151 | 152 | # a command that runs duplicity e.g. 153 | # shape bandwidth use via trickle 154 | # "trickle -s -u 640 -d 5120" # 5Mb up, 40Mb down" 155 | {% if item.value.conf.dupl_precmd is defined %} 156 | DUPL_PRECMD="{{ item.value.conf.dupl_precmd }}" 157 | {% else %} 158 | #DUPL_PRECMD="" 159 | {% endif %} 160 | 161 | # override the python interpreter to execute duplicity, unset by default 162 | # e.g. "python3" or "/usr/bin/python3.8" 163 | {% if item.value.conf.python is defined %} 164 | PYTHON="{{ item.value.conf.python }}" 165 | {% else %} 166 | #PYTHON="python" 167 | {% endif %} 168 | 169 | # exclude folders containing exclusion file (since duplicity 0.5.14) 170 | # Uncomment the following two lines to enable this setting. 171 | {% if item.value.conf.exclude_if_present is defined %} 172 | FILENAME='{{ item.value.conf.exclude_if_present }}' 173 | DUPL_PARAMS="$DUPL_PARAMS --exclude-if-present '$FILENAME'" 174 | {% else %} 175 | #FILENAME='.duplicity-ignore' 176 | #DUPL_PARAMS="$DUPL_PARAMS --exclude-if-present '$FILENAME'" 177 | {% endif %} 178 | 179 | # Time frame for old backups to keep, Used for the "purge" command. 180 | # see duplicity man page, chapter TIME_FORMATS) 181 | {% if item.value.conf.max_age is defined %} 182 | MAX_AGE={{ item.value.conf.max_age }} 183 | {% else %} 184 | #MAX_AGE=1M 185 | {% endif %} 186 | 187 | # Number of full backups to keep. Used for the "purgeFull" command. 188 | # See duplicity man page, action "remove-all-but-n-full". 189 | {% if item.value.conf.max_full_backups is defined %} 190 | MAX_FULL_BACKUPS={{ item.value.conf.max_full_backups }} 191 | {% else %} 192 | #MAX_FULL_BACKUPS=1 193 | {% endif %} 194 | 195 | # Number of full backups for which incrementals will be kept for. 196 | # Used for the "purgeIncr" command. 197 | # See duplicity man page, action "remove-all-inc-of-but-n-full". 198 | {% if item.value.conf.max_fulls_with_incrs is defined %} 199 | MAX_FULLS_WITH_INCRS={{ item.value.conf.max_fulls_with_incrs }} 200 | {% else %} 201 | #MAX_FULLS_WITH_INCRS=1 202 | {% endif %} 203 | 204 | # activates duplicity --full-if-older-than option (since duplicity v0.4.4.RC3) 205 | # forces a full backup if last full backup reaches a specified age, for the 206 | # format of MAX_FULLBKP_AGE see duplicity man page, chapter TIME_FORMATS 207 | # Uncomment the following two lines to enable this setting. 208 | {% if item.value.conf.max_fullbkp_age is defined %} 209 | MAX_FULLBKP_AGE={{ item.value.conf.max_fullbkp_age }} 210 | DUPL_PARAMS="$DUPL_PARAMS --full-if-older-than $MAX_FULLBKP_AGE " 211 | {% else %} 212 | #MAX_FULLBKP_AGE=1M 213 | #DUPL_PARAMS="$DUPL_PARAMS --full-if-older-than $MAX_FULLBKP_AGE " 214 | {% endif %} 215 | 216 | # sets duplicity --volsize option (available since v0.4.3.RC7) 217 | # set the size of backup chunks to VOLSIZE MB instead of the default 25MB. 218 | # VOLSIZE must be number of MB's to set the volume size to. 219 | # Uncomment the following two lines to enable this setting. 220 | {% if item.value.conf.volsize is defined %} 221 | VOLSIZE={{ item.value.conf.volsize }} 222 | DUPL_PARAMS="$DUPL_PARAMS --volsize $VOLSIZE " 223 | {% else %} 224 | #VOLSIZE=50 225 | #DUPL_PARAMS="$DUPL_PARAMS --volsize $VOLSIZE " 226 | {% endif %} 227 | 228 | # verbosity of output (error 0, warning 1-2, notice 3-4, info 5-8, debug 9) 229 | # default is 4, if not set 230 | {% if item.value.conf.verbosity is defined %} 231 | VERBOSITY={{ item.value.conf.verbosity }} 232 | {% else %} 233 | #VERBOSITY=5 234 | {% endif %} 235 | 236 | # temporary file space. at least the size of the biggest file in backup 237 | # for a successful restoration process. (default is '/tmp', if not set) 238 | {% if item.value.conf.temp_dir is defined %} 239 | TEMP_DIR={{ item.value.conf.temp_dir }} 240 | {% else %} 241 | #TEMP_DIR=/tmp 242 | {% endif %} 243 | 244 | # Modifies archive-dir option (since 0.6.0) Defines a folder that holds 245 | # unencrypted meta data of the backup, enabling new incrementals without the 246 | # need to decrypt backend metadata first. If empty or deleted somehow, the 247 | # private key and it's password are needed. 248 | # NOTE: This is confidential data. Put it somewhere safe. It can grow quite 249 | # big over time so you might want to put it not in the home dir. 250 | # default '~/.cache/duplicity/duply_/' 251 | # if set '${ARCH_DIR}/' 252 | {% if item.value.conf.arch_dir is defined %} 253 | ARCH_DIR={{ item.value.conf.arch_dir }} 254 | {% else %} 255 | #ARCH_DIR=/some/space/safe/.duply-cache 256 | {% endif %} 257 | 258 | # DEPRECATED setting 259 | # sets duplicity --time-separator option (since v0.4.4.RC2) to allow users 260 | # to change the time separator from ':' to another character that will work 261 | # on their system. HINT: For Windows SMB shares, use --time-separator='_'. 262 | # NOTE: '-' is not valid as it conflicts with date separator. 263 | # ATTENTION: only use this with duplicity < 0.5.10, since then default file 264 | # naming is compatible and this option is pending depreciation 265 | {% if item.value.conf.time_separator is defined and item.value.conf.time_separator | bool == True %} 266 | DUPL_PARAMS="$DUPL_PARAMS --time-separator _ " 267 | {% else %} 268 | #DUPL_PARAMS="$DUPL_PARAMS --time-separator _ " 269 | {% endif %} 270 | 271 | # DEPRECATED setting 272 | # activates duplicity --short-filenames option, when uploading to a file 273 | # system that can't have filenames longer than 30 characters (e.g. Mac OS 8) 274 | # or have problems with ':' as part of the filename (e.g. Microsoft Windows) 275 | # ATTENTION: only use this with duplicity < 0.5.10, later versions default file 276 | # naming is compatible and this option is pending depreciation 277 | {% if item.value.conf.short_filenames is defined and item.value.conf.short_filenames | bool == True %} 278 | DUPL_PARAMS="$DUPL_PARAMS --short-filenames " 279 | {% else %} 280 | #DUPL_PARAMS="$DUPL_PARAMS --short-filenames " 281 | {% endif %} 282 | 283 | # more duplicity command line options can be added in the following way 284 | # don't forget to leave a separating space char at the end 285 | {% if item.value.conf.dupl_params is defined %} 286 | DUPL_PARAMS="$DUPL_PARAMS {{ item.value.conf.dupl_params }} " 287 | {% else %} 288 | #DUPL_PARAMS="$DUPL_PARAMS --put_your_options_here " 289 | {% endif %} 290 | --------------------------------------------------------------------------------