From 030305fc22b16851935de4dc52f912c550bdbd09 Mon Sep 17 00:00:00 2001 From: Trygve Laugstøl Date: Wed, 15 May 2019 13:58:42 +0200 Subject: o New borg. --- ansible/roles/borg-client/defaults/main.yml | 2 + ansible/roles/borg-client/handlers/main.yml | 3 ++ ansible/roles/borg-client/tasks/main.yml | 59 ++++++++++++++++++++ ansible/roles/borg-client/templates/bin/tergum | 24 +++++++++ .../roles/borg-client/templates/bin/tergum-post | 18 +++++++ ansible/roles/borg-job/defaults/main.yml | 6 +++ ansible/roles/borg-job/handlers/main.yml | 8 +++ ansible/roles/borg-job/tasks/main.yml | 60 +++++++++++++++++++++ ansible/roles/borg-target/defaults/main.yml | 6 +++ ansible/roles/borg-target/tasks/borg-init.yml | 47 ++++++++++++++++ ansible/roles/borg-target/tasks/main.yml | 62 ++++++++++++++++++++++ 11 files changed, 295 insertions(+) create mode 100644 ansible/roles/borg-client/defaults/main.yml create mode 100644 ansible/roles/borg-client/handlers/main.yml create mode 100644 ansible/roles/borg-client/tasks/main.yml create mode 100644 ansible/roles/borg-client/templates/bin/tergum create mode 100644 ansible/roles/borg-client/templates/bin/tergum-post create mode 100644 ansible/roles/borg-job/defaults/main.yml create mode 100644 ansible/roles/borg-job/handlers/main.yml create mode 100644 ansible/roles/borg-job/tasks/main.yml create mode 100644 ansible/roles/borg-target/defaults/main.yml create mode 100644 ansible/roles/borg-target/tasks/borg-init.yml create mode 100644 ansible/roles/borg-target/tasks/main.yml (limited to 'ansible/roles') diff --git a/ansible/roles/borg-client/defaults/main.yml b/ansible/roles/borg-client/defaults/main.yml new file mode 100644 index 0000000..ff82ed3 --- /dev/null +++ b/ansible/roles/borg-client/defaults/main.yml @@ -0,0 +1,2 @@ +borg_client__ssh_key: "borg/{{ ansible_hostname }}/ssh-key" + diff --git a/ansible/roles/borg-client/handlers/main.yml b/ansible/roles/borg-client/handlers/main.yml new file mode 100644 index 0000000..970492f --- /dev/null +++ b/ansible/roles/borg-client/handlers/main.yml @@ -0,0 +1,3 @@ +- name: systemctl daemon-reload + systemd: + daemon_reload: true diff --git a/ansible/roles/borg-client/tasks/main.yml b/ansible/roles/borg-client/tasks/main.yml new file mode 100644 index 0000000..d5767cd --- /dev/null +++ b/ansible/roles/borg-client/tasks/main.yml @@ -0,0 +1,59 @@ +- tags: packages + apt: + name: + - borgbackup + install_recommends: no + +- name: "mkdir /etc/tergum" + file: + path: "/etc/tergum" + state: directory + mode: u=rwx,go= + owner: root + group: root + +- copy: + dest: /etc/tergum/ssh-key + src: "{{ borg_client__ssh_key }}" + mode: u=rwx,go= + owner: root + group: root + +- name: "/etc/systemd/system/tergum@.service" + copy: + dest: "/etc/systemd/system/tergum@.service" + content: | + [Unit] + Description=Borg backup + + [Service] + Type=oneshot + WorkingDirectory=/ + ExecStart=-/usr/bin/tergum %i + #ExecStartPost=-/usr/bin/tergum-post foo@example.org + SuccessExitStatus=0 1 + EnvironmentFile=/etc/tergum/jobs/%i/env + notify: + - systemctl daemon-reload + +- name: "/etc/systemd/system/tergum@.timer" + copy: + dest: "/etc/systemd/system/tergum@.timer" + content: | + [Unit] + Description=Borg + + [Install] + WantedBy=timers.target + notify: + - systemctl daemon-reload + +- template: + dest: "/usr/bin/{{ item }}" + src: "bin/{{ item }}" + mode: u=rwx,go=rx + owner: root + group: root + with_items: + - tergum + - tergum-post diff --git a/ansible/roles/borg-client/templates/bin/tergum b/ansible/roles/borg-client/templates/bin/tergum new file mode 100644 index 0000000..eaab95c --- /dev/null +++ b/ansible/roles/borg-client/templates/bin/tergum @@ -0,0 +1,24 @@ +#!/bin/bash + +set -euo pipefail + +cd / + +instance=$1; shift + +echo BORG_RSH="$BORG_RSH" +echo BORG_REPO="$BORG_REPO" + +echo "Doing backup for instance $instance" + +cmd=() +cmd+=(borg create) +cmd+=("--stats") +cmd+=("--exclude-from=/etc/tergum/jobs/$instance/excludes") +cmd+=("--patterns-from=/etc/tergum/jobs/$instance/patterns") +cmd+=("::{hostname}-{now:%Y-%m-%dT%H:%M:%S}") + +set -x +time "${cmd[@]}" + +borg info --last 1 diff --git a/ansible/roles/borg-client/templates/bin/tergum-post b/ansible/roles/borg-client/templates/bin/tergum-post new file mode 100644 index 0000000..647bf5b --- /dev/null +++ b/ansible/roles/borg-client/templates/bin/tergum-post @@ -0,0 +1,18 @@ +#!/bin/bash + +set -euo pipefail + +cd / + +instance=$1; shift + +/usr/sbin/sendmail -t < +Subject: Backup @ $HOSTNAME +Content-Transfer-Encoding: 8bit +Content-Type: text/plain; charset=UTF-8 + +$(systemctl status --full 2>&1) +$(journalctl --since today --unit tergum@$instance 2>&1) +ERRMAIL diff --git a/ansible/roles/borg-job/defaults/main.yml b/ansible/roles/borg-job/defaults/main.yml new file mode 100644 index 0000000..b5f3cbc --- /dev/null +++ b/ansible/roles/borg-job/defaults/main.yml @@ -0,0 +1,6 @@ +borg_job__on_calendar: daily +borg_job__default_excludes: + - /proc + - /dev + - /sys + - /run diff --git a/ansible/roles/borg-job/handlers/main.yml b/ansible/roles/borg-job/handlers/main.yml new file mode 100644 index 0000000..76e08ab --- /dev/null +++ b/ansible/roles/borg-job/handlers/main.yml @@ -0,0 +1,8 @@ +- name: systemctl daemon-reload + systemd: + daemon_reload: true + +- name: "service start tergum@{{ borg_job__name }}.timer" + service: + name: "tergum@{{ borg_job__name }}.timer" + state: restarted diff --git a/ansible/roles/borg-job/tasks/main.yml b/ansible/roles/borg-job/tasks/main.yml new file mode 100644 index 0000000..10076d6 --- /dev/null +++ b/ansible/roles/borg-job/tasks/main.yml @@ -0,0 +1,60 @@ +- name: Install packages + tags: packages + apt: + name: + - borgbackup + install_recommends: no + +- name: "mkdir /etc/tergum/jobs/{{ borg_job__name }}" + file: + path: "/etc/tergum/jobs/{{ borg_job__name }}" + state: directory + +- name: "/etc/tergum/jobs/{{ borg_job__name }}/env" + copy: + dest: "/etc/tergum/jobs/{{ borg_job__name }}/env" + content: | + BORG_REPO={{ borg_job__username }}@{{ borg_job__target }}:{{ ansible_hostname }}/{{ borg_job__name }} + BORG_RSH=ssh -i /etc/tergum/ssh-key + BORG_PASSPHRASE={{ borg__passphrases[ansible_hostname][borg_job__name] }} + +# BORG_KEYS_DIR +# BORG_SECURITY_DIR +# BORG_CACHE_DIR + +- name: "/etc/tergum/jobs/{{ borg_job__name }}/patterns" + copy: + dest: "/etc/tergum/jobs/{{ borg_job__name }}/patterns" + content: "{{ borg_job__settings.patterns }}" + +- name: "/etc/tergum/jobs/{{ borg_job__name }}/excludes" + vars: + excludes: "{{ borg_job__settings.excludes if borg_job__settings.excludes is defined else [] }}" + copy: + dest: "/etc/tergum/jobs/{{ borg_job__name }}/excludes" + content: | + {% for item in excludes %} + {{ item }} + {% endfor %} + {% for item in borg_job__default_excludes %} + {{ item }} + {% endfor %} + +- file: + path: "/etc/systemd/system/tergum@{{ borg_job__name }}.timer.d" + state: directory + +- copy: + dest: "/etc/systemd/system/tergum@{{ borg_job__name }}.timer.d/override.conf" + content: | + [Timer] + OnCalendar={{ borg_job__settings.on_calendar if borg_job__settings.on_calendar is defined else borg_job__on_calendar }} + notify: + - systemctl daemon-reload + +- meta: flush_handlers + +- systemd: + name: "tergum@{{ borg_job__name }}.timer" + enabled: yes + state: started diff --git a/ansible/roles/borg-target/defaults/main.yml b/ansible/roles/borg-target/defaults/main.yml new file mode 100644 index 0000000..734434a --- /dev/null +++ b/ansible/roles/borg-target/defaults/main.yml @@ -0,0 +1,6 @@ +borg_target__user: borg +borg_target__group: borg +borg_target__shell: /bin/bash +borg_target__home: /opt/borg + +borg_target__repos: diff --git a/ansible/roles/borg-target/tasks/borg-init.yml b/ansible/roles/borg-target/tasks/borg-init.yml new file mode 100644 index 0000000..21b86d6 --- /dev/null +++ b/ansible/roles/borg-target/tasks/borg-init.yml @@ -0,0 +1,47 @@ +- with_items: "{{ client.value.repos }}" + assert: + that: + - "item in borg_target__passphrases[client.key]" + fail_msg: "{{ item }} is missing from borg-secrets.yml" + success_msg: "" + +- set_fact: + ssh_key: "{{ client.value.ssh_key_path if client.value.ssh_key_path is defined else ('files/borg/' + client.key + '/ssh-key') }}" +- debug: var=ssh_key + +- with_items: "{{ client.value.repos }}" + name: mkdir client dir + file: + path: "{{ path | dirname }}" + state: directory + owner: "{{ borg_target__user }}" + group: "{{ borg_target__group }}" + vars: + path: "{{ borg_target__home }}/repos/{{ client.key }}/{{ item }}" + +- with_items: "{{ client.value.repos }}" + name: borg init + become_user: "{{ borg_target__user }}" + command: "borg init --encryption repokey {{ path }}" + args: + creates: "{{ path }}" + environment: + BORG_PASSPHRASE: "{{ borg_target__passphrases[client.key][item] }}" + vars: + path: "{{ borg_target__home }}/repos/{{ client.key }}/{{ item }}" + +- local_action: + module: stat + path: "{{ ssh_key }}" + register: ssh_key_stat + +- local_action: + module: file + path: "{{ (playbook_dir + '/' + ssh_key) | dirname }}" + state: directory + become: no + +- name: Generating SSH key + local_action: command ssh-keygen -t ed25519 -N "" -f "{{ ssh_key }}" -C "borg@{{ client.key }}" + when: not ssh_key_stat.stat.exists + become: no diff --git a/ansible/roles/borg-target/tasks/main.yml b/ansible/roles/borg-target/tasks/main.yml new file mode 100644 index 0000000..c3b8693 --- /dev/null +++ b/ansible/roles/borg-target/tasks/main.yml @@ -0,0 +1,62 @@ +- name: Install packages + tags: packages + apt: + name: + - borgbackup + install_recommends: no + +- name: Create unix group + become: yes + group: + name: "{{ borg_target__group }}" + system: yes + +- name: Create unix user + become: yes + user: + name: "{{ borg_target__user }}" + group: "{{ borg_target__group }}" + shell: "{{ borg_target__shell }}" + home: "{{ borg_target__home }}" + system: yes + +- name: mkdir repos + file: + path: "{{ borg_target__home }}/repos" + state: directory + mode: u=rwx,go= + owner: "{{ borg_target__user }}" + group: "{{ borg_target__group }}" + +- with_dict: "{{ borg_target__clients }}" + file: + path: "{{ borg_target__home }}/repos/{{ item.key }}" + state: directory + +- include_tasks: borg-init.yml + with_dict: "{{ borg_target__clients }}" + loop_control: + loop_var: client + +- file: + path: "{{ borg_target__home }}/.ssh" + state: directory + mode: u=rx,go= + owner: "{{ borg_target__user }}" + group: "{{ borg_target__group }}" + +- name: authorized_keys + tags: xxx + copy: + dest: "{{ borg_target__home }}/.ssh/authorized_keys" + content: | + tilde={{ '~borg' | expanduser }} + {% for client, config in borg_target__clients.items() %} + {% set state=config.state | default('present') %} + # Client: {{ client }}, state={{state}} + {% if state == 'present' %} + {% set key=lookup('file', 'borg/' + client + '/ssh-key.pub') %} + command="cd {{ borg_target__home }}/repos && borg serve --append-only{% for r in config.repos %} --restrict-to-repository {{ client }}/{{ r }}{% endfor %}",no-port-forwarding,no-X11-forwarding,no-pty,no-agent-forwarding,no-user-rc {{ key }} + {% endif %} + {% endfor %} +# " -- cgit v1.2.3