diff options
-rw-r--r-- | chaos-at-home/ch-epimetheus.yml | 1 | ||||
-rw-r--r-- | inventory/host_vars/ch-epimetheus.yml | 27 | ||||
-rw-r--r-- | inventory/host_vars/ch-prometheus.yml | 1 | ||||
-rw-r--r-- | roles/storage/zfs/syncoid/defaults/main.yml | 19 | ||||
-rw-r--r-- | roles/storage/zfs/syncoid/filter_plugins/zfs_syncoid.py | 29 | ||||
-rw-r--r-- | roles/storage/zfs/syncoid/tasks/datasets.yml | 16 | ||||
-rw-r--r-- | roles/storage/zfs/syncoid/tasks/main.yml | 47 | ||||
-rw-r--r-- | roles/storage/zfs/syncoid/templates/systemd.service.j2 | 16 |
8 files changed, 152 insertions, 4 deletions
diff --git a/chaos-at-home/ch-epimetheus.yml b/chaos-at-home/ch-epimetheus.yml index 4e3a3296..8d3bac5a 100644 --- a/chaos-at-home/ch-epimetheus.yml +++ b/chaos-at-home/ch-epimetheus.yml @@ -12,6 +12,7 @@ - role: storage/zfs/pools - role: apt-repo/spreadspace - role: storage/zfs/sanoid + - role: storage/zfs/syncoid post_tasks: - name: install simple suspend script copy: diff --git a/inventory/host_vars/ch-epimetheus.yml b/inventory/host_vars/ch-epimetheus.yml index da8ea719..8b816097 100644 --- a/inventory/host_vars/ch-epimetheus.yml +++ b/inventory/host_vars/ch-epimetheus.yml @@ -22,9 +22,9 @@ apt_repo_components: luks_volumes: - crypto-sata0: - passphrase: "{{ vault_luks_volumes['crypto-sata0'].passphrase }}" - device: /dev/disk/by-id/ata-WDC_WD30EFRX-68AX9N0_WD-WMC1T1674991 + # crypto-sata0: + # passphrase: "{{ vault_luks_volumes['crypto-sata0'].passphrase }}" + # device: /dev/disk/by-id/ata-WDC_WD30EFRX-68AX9N0_WD-WMC1T1674991 crypto-sata1: passphrase: "{{ vault_luks_volumes['crypto-sata1'].passphrase }}" device: /dev/disk/by-id/ata-WDC_WD30EFRX-68AX9N0_WD-WMC1T1357355 @@ -43,10 +43,29 @@ zfs_arc_size: zfs_pools: backup: mountpoint: /srv/backup - create_vdevs: raidz /dev/mapper/crypto-sata0 /dev/mapper/crypto-sata1 /dev/mapper/crypto-sata2 /dev/mapper/crypto-sata3 +# create_vdevs: raidz /dev/mapper/crypto-sata0 /dev/mapper/crypto-sata1 /dev/mapper/crypto-sata2 /dev/mapper/crypto-sata3 + create_vdevs: raidz /dev/mapper/crypto-sata1 /dev/mapper/crypto-sata2 /dev/mapper/crypto-sata3 zfs_sanoid_modules: backup: use_template: backup recursive: yes process_children_only: yes + +zfs_syncoid_target_pool: backup +zfs_syncoid_sources: + 'ch-prometheus': + ssh_hostname: "{{ network_zones.lan.prefix | ipaddr(network_zones.lan.offsets['ch-prometheus']) | ipaddr('address') }}" + ssh_port: "{{ hostvars['ch-prometheus'].ansible_port }}" + paths: + nvme/vm: + recursive: yes + skip_parent: yes + storage/vm: + recursive: yes + skip_parent: yes + storage: + recursive: yes + skip_parent: yes + exclude: + - '^storage/vm' diff --git a/inventory/host_vars/ch-prometheus.yml b/inventory/host_vars/ch-prometheus.yml index f64c7a25..9381f0c2 100644 --- a/inventory/host_vars/ch-prometheus.yml +++ b/inventory/host_vars/ch-prometheus.yml @@ -42,6 +42,7 @@ apt_repo_components: ssh_keys_root_extra: - ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9AkOBxvf1wZ0B3wEyf7O3GbaIGx5o2f6cVuQIrOjeFfgMSAr1LwiB/gmHhMSEq6OSauD37TA5yDIrzk6NPPjVs/wiklsHgYtTqIxSPItTZFPX4gLvNwwGuRvEW9bTEiHd+bVPIiIT7HOje0kgacjan44rdgppX9DgcUp2j7uSZZabsxDCS/ms0slhwBNU1gtR31PoQ56vIya23D2uMauNAbRJzDEOfAjy4pHF8njYcXPas/yrbLi8PUZ1YO1u/AZto96EIYfHaCLWlstqeCX+R2JrTunvfTr8TF3AkFw8lHMzk3neUR+tPAAFQaqeTlqGPiSNq1Oyf+52XR16qwhd equinox@mail + - ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIZK9NBainiE0+A8pT8dbwlNZ0k0AZVhLTzUSo3YtKJt ZFS Backup syncoid@epimetheus installer_storage: type: lvm diff --git a/roles/storage/zfs/syncoid/defaults/main.yml b/roles/storage/zfs/syncoid/defaults/main.yml new file mode 100644 index 00000000..cdc58750 --- /dev/null +++ b/roles/storage/zfs/syncoid/defaults/main.yml @@ -0,0 +1,19 @@ +--- +# zfs_syncoid_target_pool: target + +# zfs_syncoid_sources: +# somehost: +# ssh_hostname: 192.0.2.0 +# ssh_port: 222 +# paths: +# nvme/vm: +# recursive: yes +# skip_parent: yes +# storage/vm: +# recursive: yes +# skip_parent: yes +# storage: +# recursive: yes +# skip_parent: yes +# exclude: +# - storage/vm diff --git a/roles/storage/zfs/syncoid/filter_plugins/zfs_syncoid.py b/roles/storage/zfs/syncoid/filter_plugins/zfs_syncoid.py new file mode 100644 index 00000000..085d7c74 --- /dev/null +++ b/roles/storage/zfs/syncoid/filter_plugins/zfs_syncoid.py @@ -0,0 +1,29 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from functools import partial + +from ansible import errors + + +def zfs_syncoid_explode_paths(data): + try: + result = [] + for path in data: + parts = path.split('/') + for i in range(len(parts)): + result.append('/'.join(parts[:(i+1)])) + return result + except Exception as e: + raise errors.AnsibleFilterError("zfs_syncoid_explode_paths(): %s" % str(e)) + + +class FilterModule(object): + + ''' zfs syncoid filters ''' + filter_map = { + 'zfs_syncoid_explode_paths': zfs_syncoid_explode_paths, + } + + def filters(self): + return self.filter_map diff --git a/roles/storage/zfs/syncoid/tasks/datasets.yml b/roles/storage/zfs/syncoid/tasks/datasets.yml new file mode 100644 index 00000000..91db0f67 --- /dev/null +++ b/roles/storage/zfs/syncoid/tasks/datasets.yml @@ -0,0 +1,16 @@ +--- +- name: create base dataset for host + zfs: + name: "{{ zfs_syncoid_target_pool }}/{{ source.key }}" + state: present + extra_zfs_properties: + compression: lz4 + xattr: sa + +- name: create datasets for path + loop: "{{ source.value.paths | zfs_syncoid_explode_paths | unique }}" + loop_control: + label: "{{ source.key }}/{{ item }}" + zfs: + name: "{{ zfs_syncoid_target_pool }}/{{ source.key }}/{{ item }}" + state: present diff --git a/roles/storage/zfs/syncoid/tasks/main.yml b/roles/storage/zfs/syncoid/tasks/main.yml new file mode 100644 index 00000000..53aa434a --- /dev/null +++ b/roles/storage/zfs/syncoid/tasks/main.yml @@ -0,0 +1,47 @@ +--- +- name: install sanoid package + apt: + name: sanoid + state: present + +- name: create syncoid directory + file: + path: /var/lib/syncoid + state: directory + mode: 0700 + +- name: genarate ssh keypair for syncoid + openssh_keypair: + path: /var/lib/syncoid/id_ssh_ed25519 + type: ed25519 + comment: ZFS Backup syncoid@{{ host_name }} + +- name: generate syncoid ssh config wrapper + copy: + content: | + #!/bin/bash + exec /usr/sbin/syncoid --sshoption "UserKnownHostsFile=/var/lib/syncoid/ssh.knownhosts" --sshoption "HashKnownHosts=no" --sshkey "/var/lib/syncoid/id_ssh_ed25519" --no-sync-snap --compress zstd-fast "$@" + dest: /var/lib/syncoid/syncoid_wrapper + mode: 0755 + +- name: configure lvm to ignore zfs volumes + lineinfile: + path: /etc/lvm/lvm.conf + backrefs: yes + regexp: '^\s*#?\s*global_filter\s*=' + line: ' global_filter = [ "r|/dev/zd[0-9]+|" ]' + +- name: create target datasets + loop: "{{ zfs_syncoid_sources | dict2items }}" + loop_control: + loop_var: source + label: "{{ source.key }}" + include_tasks: datasets.yml + +- name: create systemd units + loop: "{{ zfs_syncoid_sources | dict2items }}" + loop_control: + label: "{{ item.key }}" + template: + src: systemd.service.j2 + dest: "/etc/systemd/system/syncoid-{{ item.key }}.service" diff --git a/roles/storage/zfs/syncoid/templates/systemd.service.j2 b/roles/storage/zfs/syncoid/templates/systemd.service.j2 new file mode 100644 index 00000000..5a6eba97 --- /dev/null +++ b/roles/storage/zfs/syncoid/templates/systemd.service.j2 @@ -0,0 +1,16 @@ +[Unit] +Description=Schlagergarten Stream Stats Collector + +[Service] +Type=oneshot +{% for path,config in item.value.paths.items() %} +ExecStart=/var/lib/syncoid/syncoid_wrapper --dumpsnaps --quiet {{ config.recursive | default(false) | ternary('-r ', '') }}{{ config.skip_parent | default(false) | ternary('--skip-parent ', '') }}{% for re in config.exclude | default([]) %}--exclude='{{ re }}' {% endfor %}{% if 'ssh_port' in item.value %}--sshport {{ item.value.ssh_port }} {% endif %}root@{{ item.value.ssh_hostname }}:{{ path }} {{ zfs_syncoid_target_pool }}/{{ item.key }}/{{ path }} +{% endfor %} +PrivateTmp=yes +ProtectHome=yes +ProtectKernelTunables=yes +ProtectControlGroups=yes +RestrictRealtime=yes + +[Install] +WantedBy=multi-user.target |