summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2021-05-01 20:15:49 +0200
committerChristian Pointner <equinox@spreadspace.org>2021-05-01 20:15:49 +0200
commita64636bdedf842402016b29932862896dd6a6265 (patch)
tree89cdb48408761bdeb64899f1fce3cd41aafcf93b
parentch-epimetheus: rename zfs pool to backup (diff)
add experimental syncoid zfs backup role
-rw-r--r--chaos-at-home/ch-epimetheus.yml1
-rw-r--r--inventory/host_vars/ch-epimetheus.yml27
-rw-r--r--inventory/host_vars/ch-prometheus.yml1
-rw-r--r--roles/storage/zfs/syncoid/defaults/main.yml19
-rw-r--r--roles/storage/zfs/syncoid/filter_plugins/zfs_syncoid.py29
-rw-r--r--roles/storage/zfs/syncoid/tasks/datasets.yml16
-rw-r--r--roles/storage/zfs/syncoid/tasks/main.yml47
-rw-r--r--roles/storage/zfs/syncoid/templates/systemd.service.j216
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