summaryrefslogtreecommitdiff
path: root/roles
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 /roles
parentch-epimetheus: rename zfs pool to backup (diff)
add experimental syncoid zfs backup role
Diffstat (limited to 'roles')
-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
5 files changed, 127 insertions, 0 deletions
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