Port zfs snapshot backups
This commit is contained in:
parent
a620a2a2f4
commit
d0708f520d
@ -73,7 +73,8 @@ services_host_services:
|
|||||||
# --------------------------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------------------------
|
||||||
# services:backups
|
# services:backups
|
||||||
# --------------------------------------------------------------------------------------------------
|
# --------------------------------------------------------------------------------------------------
|
||||||
services_backups_datasets_root: "rpool/var/lib/yggdrasil/data"
|
services_backups_syncoid_data_dataset: "{{ services_data_dataset |
|
||||||
|
replace('rpool/var/lib', 'hpool/backup') }}"
|
||||||
services_backups_datasets: "\
|
services_backups_datasets: "\
|
||||||
{% set datasets = {} %}\
|
{% set datasets = {} %}\
|
||||||
{% for service in services_host_services.keys() %}\
|
{% for service in services_host_services.keys() %}\
|
||||||
|
1
main.yml
1
main.yml
@ -1,4 +1,5 @@
|
|||||||
---
|
---
|
||||||
- ansible.builtin.import_playbook: "plays/system/main.yml"
|
- ansible.builtin.import_playbook: "plays/system/main.yml"
|
||||||
- ansible.builtin.import_playbook: "plays/vpn/main.yml"
|
- ansible.builtin.import_playbook: "plays/vpn/main.yml"
|
||||||
|
- ansible.builtin.import_playbook: "plays/backups/main.yml"
|
||||||
- ansible.builtin.import_playbook: "plays/services/main.yml"
|
- ansible.builtin.import_playbook: "plays/services/main.yml"
|
||||||
|
@ -3,6 +3,5 @@
|
|||||||
hosts: yggdrasil
|
hosts: yggdrasil
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
- import_tasks: tasks/backups/00-zfs-snapshots.yml
|
|
||||||
- import_tasks: tasks/backups/01-restic-setup.yml
|
- import_tasks: tasks/backups/01-restic-setup.yml
|
||||||
- import_tasks: tasks/backups/02-restic-enable.yml
|
- import_tasks: tasks/backups/02-restic-enable.yml
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
---
|
|
||||||
- name: Configure yggdrasil backups
|
|
||||||
hosts: yggdrasil
|
|
||||||
|
|
||||||
tasks:
|
|
||||||
- import_tasks: tasks/backups/01-restic-setup.yml
|
|
@ -1,49 +0,0 @@
|
|||||||
- name: Configure sanoid system snapshots
|
|
||||||
blockinfile:
|
|
||||||
path: /etc/sanoid/sanoid.conf
|
|
||||||
create: yes
|
|
||||||
mode: 0644
|
|
||||||
insertbefore: "BOF"
|
|
||||||
marker: "# {mark} ANSIBLE MANAGED BLOCK SYSTEM #"
|
|
||||||
block: |
|
|
||||||
[bpool/BOOT]
|
|
||||||
use_template = system
|
|
||||||
recursive = yes
|
|
||||||
process_children_only = yes
|
|
||||||
|
|
||||||
[rpool/ROOT]
|
|
||||||
use_template = system
|
|
||||||
recursive = yes
|
|
||||||
process_children_only = yes
|
|
||||||
|
|
||||||
[rpool/home]
|
|
||||||
use_template = system,home
|
|
||||||
recursive = yes
|
|
||||||
process_children_only = yes
|
|
||||||
|
|
||||||
- name: Configure sanoid service snapshots
|
|
||||||
blockinfile:
|
|
||||||
path: /etc/sanoid/sanoid.conf
|
|
||||||
insertbefore: "# BEGIN ANSIBLE MANAGED BLOCK TEMPLATES #"
|
|
||||||
marker: "# {mark} ANSIBLE MANAGED BLOCK SERVICE {{ service_name }} #"
|
|
||||||
block: |
|
|
||||||
[rpool/var/lib/{{ ansible_hostname }}/data/pod-{{ service_name }}]
|
|
||||||
use_template = production
|
|
||||||
recursive = yes
|
|
||||||
process_children_only = yes
|
|
||||||
|
|
||||||
[hpool/backup/{{ ansible_hostname }}/data/pod-{{ service_name }}]
|
|
||||||
use_template = backup
|
|
||||||
recursive = yes
|
|
||||||
process_children_only = yes
|
|
||||||
|
|
||||||
with_items: "{{ host_services }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: service_name
|
|
||||||
|
|
||||||
- name: Configure sanoid templates
|
|
||||||
blockinfile:
|
|
||||||
path: /etc/sanoid/sanoid.conf
|
|
||||||
insertafter: "EOF"
|
|
||||||
marker: "# {mark} ANSIBLE MANAGED BLOCK TEMPLATES #"
|
|
||||||
block: "{{ lookup('file', './filesystem/{{ ansible_hostname }}/etc/sanoid/sanoid-templates.conf') }}"
|
|
@ -1,58 +0,0 @@
|
|||||||
- name: Configure syncoid unit
|
|
||||||
blockinfile:
|
|
||||||
path: /etc/systemd/system/syncoid-volume-data.service
|
|
||||||
create: yes
|
|
||||||
mode: 0644
|
|
||||||
insertbefore: "BOF"
|
|
||||||
marker: "# {mark} ANSIBLE MANAGED BLOCK UNIT"
|
|
||||||
block: |
|
|
||||||
[Unit]
|
|
||||||
Description=Replicate volume data snapshots
|
|
||||||
Documentation=man:syncoid(8)
|
|
||||||
After=sanoid.service
|
|
||||||
Before=sanoid-prune.service
|
|
||||||
OnFailure=status-mail@%n.service
|
|
||||||
register: systemd_syncoid_volume_data_unit_service_file
|
|
||||||
|
|
||||||
- name: Configure syncoid service
|
|
||||||
blockinfile:
|
|
||||||
path: /etc/systemd/system/syncoid-volume-data.service
|
|
||||||
insertafter: "# END ANSIBLE MANAGED BLOCK UNIT"
|
|
||||||
marker: "# {mark} ANSIBLE MANAGED BLOCK SERVICE"
|
|
||||||
block: |
|
|
||||||
[Service]
|
|
||||||
Type=oneshot
|
|
||||||
register: systemd_syncoid_volume_data_service_service_file
|
|
||||||
|
|
||||||
- name: Configure syncoid commands
|
|
||||||
blockinfile:
|
|
||||||
path: /etc/systemd/system/syncoid-volume-data.service
|
|
||||||
insertbefore: "# BEGIN ANSIBLE MANAGED BLOCK INSTALL"
|
|
||||||
marker: "# {mark} ANSIBLE MANAGED BLOCK SYNCOID {{ service_name }} #"
|
|
||||||
block: >
|
|
||||||
ExecStart=/usr/sbin/syncoid --recursive --skip-parent --no-sync-snap
|
|
||||||
rpool/var/lib/{{ ansible_hostname }}/data/pod-{{ service_name }}
|
|
||||||
hpool/backup/{{ ansible_hostname }}/data/pod-{{ service_name }}
|
|
||||||
with_items: "{{ host_services }}"
|
|
||||||
loop_control:
|
|
||||||
loop_var: service_name
|
|
||||||
register: systemd_syncoid_volume_data_syncoid_service_file
|
|
||||||
|
|
||||||
- name: Configure syncoid install
|
|
||||||
blockinfile:
|
|
||||||
path: /etc/systemd/system/syncoid-volume-data.service
|
|
||||||
insertafter: "EOF"
|
|
||||||
marker: "# {mark} ANSIBLE MANAGED BLOCK INSTALL"
|
|
||||||
block: |
|
|
||||||
[Install]
|
|
||||||
WantedBy=sanoid.service
|
|
||||||
register: systemd_syncoid_volume_data_install_service_file
|
|
||||||
|
|
||||||
- name: SystemD daemon reload
|
|
||||||
systemd:
|
|
||||||
daemon_reload: true
|
|
||||||
when:
|
|
||||||
systemd_syncoid_volume_data_unit_service_file is changed or
|
|
||||||
systemd_syncoid_volume_data_service_service_file is changed or
|
|
||||||
systemd_syncoid_volume_data_install_service_file is changed or
|
|
||||||
systemd_syncoid_volume_data_syncoid_service_file is changed
|
|
@ -1,24 +0,0 @@
|
|||||||
- name: Install sanoid
|
|
||||||
apt:
|
|
||||||
name: sanoid
|
|
||||||
|
|
||||||
- name: Create sanoid directory
|
|
||||||
file:
|
|
||||||
path: /etc/sanoid
|
|
||||||
state: directory
|
|
||||||
mode: 0755
|
|
||||||
|
|
||||||
- import_tasks: 00-zfs-snapshots.d/sanoid.yml
|
|
||||||
|
|
||||||
- import_tasks: 00-zfs-snapshots.d/syncoid.yml
|
|
||||||
|
|
||||||
- name: Enable syncoid service
|
|
||||||
systemd:
|
|
||||||
name: syncoid-volume-data.service
|
|
||||||
enabled: yes
|
|
||||||
|
|
||||||
- name: Enable sanoid service
|
|
||||||
systemd:
|
|
||||||
name: sanoid.timer
|
|
||||||
enabled: yes
|
|
||||||
state: started
|
|
10
plays/backups/main.yml
Normal file
10
plays/backups/main.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
---
|
||||||
|
- name: "backups : yggdrasil"
|
||||||
|
hosts: "yggdrasil"
|
||||||
|
roles:
|
||||||
|
- role: "snapshots"
|
||||||
|
tags: "backups:snapshots"
|
||||||
|
when: the_nine_worlds_production | bool
|
||||||
|
# - role: "backups"
|
||||||
|
# tags: "backups:restic"
|
||||||
|
# when: the_nine_worlds_production | bool
|
50
plays/backups/roles/snapshots/files/syncoid-batch
Normal file
50
plays/backups/roles/snapshots/files/syncoid-batch
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
def load_and_validate_config_dir(config_dir):
|
||||||
|
if not os.path.isdir(config_dir):
|
||||||
|
raise ValueError(f"{config_dir} is not a directory")
|
||||||
|
|
||||||
|
return [
|
||||||
|
load_and_validate_config_file(os.path.join(config_dir, file))
|
||||||
|
for file in os.listdir(config_dir)
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def load_and_validate_config_file(config_file_path):
|
||||||
|
if not os.path.isfile(config_file_path):
|
||||||
|
raise ValueError(f"{config_file_path} is not a file")
|
||||||
|
|
||||||
|
with open(config_file_path, encoding="utf-8") as config_file:
|
||||||
|
config = yaml.safe_load(config_file)
|
||||||
|
|
||||||
|
for key in ["dataset", "syncoid_dataset"]:
|
||||||
|
if key not in config:
|
||||||
|
raise KeyError(f"{key} must be present in {config_file_path}")
|
||||||
|
|
||||||
|
return config
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = argparse.ArgumentParser(description="Backup service data using syncoid")
|
||||||
|
parser.add_argument("--config-dir", type=str, default="/etc/syncoid-batch.d",
|
||||||
|
help="Path to directory with YAML config files")
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
config_list = load_and_validate_config_dir(args.config_dir)
|
||||||
|
|
||||||
|
for config in config_list:
|
||||||
|
syncoid_cmd = ["/usr/sbin/syncoid", "--no-sync-snap"]
|
||||||
|
if config.get("recursive", False):
|
||||||
|
syncoid_cmd.append("--recursive")
|
||||||
|
if config.get("skip_parent", False):
|
||||||
|
syncoid_cmd.append("--skip-parent")
|
||||||
|
syncoid_cmd.append(config["dataset"])
|
||||||
|
syncoid_cmd.append(config["syncoid_dataset"])
|
||||||
|
|
||||||
|
subprocess.run(syncoid_cmd, check=True)
|
13
plays/backups/roles/snapshots/files/syncoid-batch.service
Normal file
13
plays/backups/roles/snapshots/files/syncoid-batch.service
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Replicate volume data snapshots
|
||||||
|
Documentation=man:syncoid(8)
|
||||||
|
After=sanoid.service
|
||||||
|
Before=sanoid-prune.service
|
||||||
|
OnFailure=status-mail@%n.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
ExecStart=/usr/local/sbin/syncoid-batch --config-dir /etc/syncoid-batch.d
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=sanoid.service
|
69
plays/backups/roles/snapshots/tasks/main.yml
Normal file
69
plays/backups/roles/snapshots/tasks/main.yml
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
- name: "install sanoid and syncoid"
|
||||||
|
ansible.builtin.apt:
|
||||||
|
name:
|
||||||
|
- "sanoid"
|
||||||
|
- "python3-yaml"
|
||||||
|
|
||||||
|
- name: "create sanoid configuration directory"
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/etc/sanoid"
|
||||||
|
state: "directory"
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: "configure sanoid templates"
|
||||||
|
ansible.builtin.blockinfile:
|
||||||
|
path: "/etc/sanoid/sanoid.conf"
|
||||||
|
create: true
|
||||||
|
mode: 0644
|
||||||
|
insertafter: "EOF"
|
||||||
|
marker: "# {mark} ANSIBLE MANAGED BLOCK TEMPLATES #"
|
||||||
|
block: "{{ lookup('file', './sanoid-templates.conf') }}"
|
||||||
|
|
||||||
|
- name: "configure sanoid system snapshots"
|
||||||
|
ansible.builtin.blockinfile:
|
||||||
|
path: "/etc/sanoid/sanoid.conf"
|
||||||
|
insertbefore: "BOF"
|
||||||
|
marker: "# {mark} ANSIBLE MANAGED BLOCK SYSTEM {{ item.name }} #"
|
||||||
|
# Note that the {{ '' }} is required to force a newline.
|
||||||
|
block: |
|
||||||
|
[{{ item.name }}]
|
||||||
|
use_template = {{ item.templates | join(',') }}
|
||||||
|
recursive = {% if item.recursive %}yes{% else %}no{% endif %}{{ '' }}
|
||||||
|
process_children_only = {% if item.children_only %}yes{% else %}no{% endif %}{{ '' }}
|
||||||
|
loop: "{{ backups_snapshots_sanoid_system_datasets | reverse }}"
|
||||||
|
|
||||||
|
- name: "create syncoid-batch config directory"
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "/etc/syncoid-batch.d"
|
||||||
|
state: "directory"
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: "install syncoid script"
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "./syncoid-batch"
|
||||||
|
dest: "/usr/local/sbin/syncoid-batch"
|
||||||
|
mode: 0755
|
||||||
|
|
||||||
|
- name: "install syncoid-batch service"
|
||||||
|
ansible.builtin.copy:
|
||||||
|
src: "./syncoid-batch.service"
|
||||||
|
dest: "/etc/systemd/system/syncoid-batch.service"
|
||||||
|
mode: 0644
|
||||||
|
register: services_backups_snapshots_syncoid_volume_data_service_file
|
||||||
|
|
||||||
|
- name: "snapshots : systemd daemon reload"
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
daemon_reload: true
|
||||||
|
when:
|
||||||
|
services_backups_snapshots_syncoid_volume_data_service_file.changed
|
||||||
|
|
||||||
|
- name: "enable syncoid-batch service"
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "syncoid-batch.service"
|
||||||
|
enabled: true
|
||||||
|
|
||||||
|
- name: "enable sanoid service"
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: "sanoid.timer"
|
||||||
|
enabled: true
|
||||||
|
state: "started"
|
@ -56,3 +56,22 @@
|
|||||||
loop_control:
|
loop_control:
|
||||||
loop_var: "services_service_name"
|
loop_var: "services_service_name"
|
||||||
tags: "always"
|
tags: "always"
|
||||||
|
|
||||||
|
- name: "services : yggdrasil"
|
||||||
|
hosts: "yggdrasil"
|
||||||
|
|
||||||
|
tasks:
|
||||||
|
- name: "backups"
|
||||||
|
ansible.builtin.include_role:
|
||||||
|
name: "backups"
|
||||||
|
apply:
|
||||||
|
tags:
|
||||||
|
- "services:{{ services_service_name }}"
|
||||||
|
- "services:backups"
|
||||||
|
- "services:backups:{{ services_service_name }}"
|
||||||
|
- "services:{{ services_service_name }}:backups"
|
||||||
|
loop: "{{ services_host_services | dict2items | map(attribute='key') }}"
|
||||||
|
loop_control:
|
||||||
|
loop_var: "services_service_name"
|
||||||
|
tags: "always"
|
||||||
|
when: the_nine_worlds_production | bool
|
||||||
|
21
plays/services/roles/backups/tasks/include/snapshots.yml
Normal file
21
plays/services/roles/backups/tasks/include/snapshots.yml
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
- name: "{{ services_service_name }} : snapshots : configure service sanoid snapshots"
|
||||||
|
ansible.builtin.blockinfile:
|
||||||
|
path: "/etc/sanoid/sanoid.conf"
|
||||||
|
insertbefore: "# BEGIN ANSIBLE MANAGED BLOCK TEMPLATES #"
|
||||||
|
marker: "# {mark} ANSIBLE MANAGED BLOCK SERVICE {{ services_service_name }} #"
|
||||||
|
block: |
|
||||||
|
[{{ services_backups_user_dataset }}]
|
||||||
|
use_template = production
|
||||||
|
recursive = yes
|
||||||
|
process_children_only = yes
|
||||||
|
|
||||||
|
[{{ services_backups_user_syncoid_dataset }}]
|
||||||
|
use_template = backup
|
||||||
|
recursive = yes
|
||||||
|
process_children_only = yes
|
||||||
|
|
||||||
|
- name: "{{ services_service_name }} : snapshots : configure service syncoid snapshots"
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: "./snapshots/syncoid-volumes-service.yml.j2"
|
||||||
|
dest: "/etc/syncoid-batch.d/syncoid-volumes-{{ services_service_name }}.yml"
|
||||||
|
mode: 0644
|
15
plays/services/roles/backups/tasks/main.yml
Normal file
15
plays/services/roles/backups/tasks/main.yml
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
- name: "play:services : role:backups:{{ services_service_name }} : tasks:vars"
|
||||||
|
ansible.builtin.import_role:
|
||||||
|
name: "include"
|
||||||
|
vars_from: "user"
|
||||||
|
tags:
|
||||||
|
- "services:backups:user"
|
||||||
|
- "services:backups:{{ services_service_name }}:snapshots"
|
||||||
|
- "services:{{ services_service_name }}:backups:snapshots"
|
||||||
|
|
||||||
|
- name: "play:services : role:backups : tasks:snapshots"
|
||||||
|
ansible.builtin.import_tasks: "include/snapshots.yml"
|
||||||
|
tags:
|
||||||
|
- "services:backups:snapshots"
|
||||||
|
- "services:backups:{{ services_service_name }}:snapshots"
|
||||||
|
- "services:{{ services_service_name }}:backups:snapshots"
|
@ -0,0 +1,4 @@
|
|||||||
|
dataset: {{ services_backups_user_dataset }}
|
||||||
|
syncoid_dataset: {{ services_backups_user_syncoid_dataset }}
|
||||||
|
recursive: true
|
||||||
|
skip_parent: true
|
3
plays/services/roles/backups/vars/main.yml
Normal file
3
plays/services/roles/backups/vars/main.yml
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
services_backups_user_dataset: "{{ services_data_dataset }}/{{ services_service_user_name }}"
|
||||||
|
services_backups_user_syncoid_dataset: "\
|
||||||
|
{{ services_backups_syncoid_data_dataset }}/{{ services_service_user_name }}"
|
Loading…
Reference in New Issue
Block a user