Commit 9be4c8b1 authored by Pietro Albini's avatar Pietro Albini

backup-duplicity: import role

parent e51703af
---
- name: upload backup script
template:
src: automation/backup.py.j2
dest: /usr/local/sbin/backup-duplicity
mode: 0750
owner: root
group: local-backup
- name: upload systemd configuration
template:
src: "automation/{{ item }}.j2"
dest: "/etc/systemd/system/{{ item }}"
with_items:
- backup-duplicity.service
- backup-duplicity.timer
notify:
- common.reload-systemd
- name: enable automation timer
service:
name: backup-duplicity.timer
state: started
enabled: true
notify:
- common.reload-systemd
---
- name: add duplicity stable ppa
apt_repository:
repo: "ppa:duplicity-team/ppa"
filename: duplicity
update_cache: true
- name: install duplicity
apt:
name: "{{ item }}"
state: installed
with_items:
- duplicity
- python-paramiko
- python3-paramiko
---
- name: install
include: install.yml
- name: automation
include: automation.yml
[Unit]
Description=duplicity backup
[Service]
Type=oneshot
ExecStart=/usr/local/sbin/backup-duplicity
WorkingDirectory=/var/local/local-backup-home
User=local-backup
Group=local-backup
[Unit]
Description=automatic duplicity backup
[Timer]
OnCalendar={{ interval }}
Persistent=true
[Install]
WantedBy=timers.target
#!/usr/bin/env python3
from urllib.parse import urlparse
import json
import os
import subprocess
import traceback
import paramiko
PLANS = "/usr/local/share/backup.d"
TARGET_URL = "{{ target }}"
PASSWORD = "{{ password }}"
FULL_AFTER = "{{ full_after }}"
KEEP_SETS = "{{ keep_sets }}"
class BackupPlan:
"""Define a backup plan"""
def __init__(self, path):
with open(path) as f:
self._manifest = json.load(f)
self.name = self._manifest["name"]
self.backup_path = self._manifest["path"]
self.before = self._manifest["before-script"]
self.after = self._manifest["after-script"]
def execute(self):
"""Execute this backup"""
print("[i] Executing before script: %s" % self.name)
subprocess.run(self.before, shell=True)
print("[i] Executing backup: %s" % self.name)
# Execute backup
subprocess.run([
"duplicity", "--full-if-older-than", FULL_AFTER, self.backup_path,
"%s/%s" % (TARGET_URL, self.name), "--no-print-statistics", "-v0",
], env={
"PASSPHRASE": PASSWORD,
})
print("[i] Executing after script: %s" % self.name)
subprocess.run(self.after, shell=True)
print("[i] Removing old backups: %s" % self.name)
# Remove old backups
subprocess.run([
"duplicity", "remove-all-but-n-full", KEEP_SETS, "--force",
TARGET_URL, "--no-print-statistics", "-v0",
])
def trust_ssh_host():
"""Ensure the destination host is trusted"""
parsed = urlparse(TARGET_URL)
if parsed.scheme not in ("sftp", "scp", "rsync"):
return
# Ensure the hosts file exists
path = os.path.expanduser("~/.ssh/known_hosts")
os.makedirs(os.path.dirname(path), exist_ok=True)
if not os.path.exists(path):
open(path, "w").close()
# Check if the host is already trusted
known_hosts = paramiko.hostkeys.HostKeys(path)
if known_hosts.lookup(parsed.hostname) is not None:
return
port = 22
if parsed.port:
port = parsed.port
# Fetch the key from the server
transport = paramiko.transport.Transport('%s:%s' % (parsed.hostname, port))
transport.start_client()
key = transport.get_remote_server_key()
transport.close()
if port != 22:
host = '[%s]:%s' % (parsed.hostname, port)
else:
host = parsed.hostname
# Add the key to the known_hosts file
known_hosts.add(host, key.get_name(), key)
known_hosts.save(path)
def main():
"""Entry point for the script"""
trust_ssh_host()
plans = []
for file in os.listdir(PLANS):
if not file.endswith(".json"):
continue
plans.append(BackupPlan(os.path.join(PLANS, file)))
for plan in plans:
try:
plan.execute()
except:
# Show the traceback and continue doing backups
print(traceback.format_exc())
if __name__ == "__main__":
main()
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment