commit 3ca3916515274c3b6c32a5995551ea81f28d7154 Author: Martin Puppe Date: Wed Mar 25 10:26:10 2020 +0100 Initial commit diff --git a/mpbackup b/mpbackup new file mode 100644 index 0000000..0f99ac2 --- /dev/null +++ b/mpbackup @@ -0,0 +1,90 @@ +#!/usr/bin/env ruby +require 'io/console' +require 'optparse' +require 'pathname' +require 'yaml' + +ENV.delete('RESTIC_REPOSITORY') +ENV.delete('RESTIC_PASSWORD') + +DEFAULT_CONFIG_FILE = Pathname.new('/etc/mpbackup.yaml') + +options = {} + +OptionParser.new do |parser| + parser.on("-f CONFIG_FILE", "--config-file CONFIG_FILE", "Path to config file") do |v| + options[:config_file] = v + end + + parser.on("-h", "--help", "Prints this help") do + puts parser + exit + end +end.parse! + +if options[:config_file] + config_file = Pathname.new(options[:config_file]) +else + config_file = DEFAULT_CONFIG_FILE +end + +if !Pathname.new(config_file).exist? then + STDERR.puts "Config file #{config_file} has not been found!" + exit 1 +end + +def do_backup(config) + ENV['RESTIC_REPOSITORY'] = config['repository'] + ENV['RESTIC_PASSWORD'] = STDIN.getpass('Please put in your restic password: ') + + puts "Backing up with restic…" + # https://restic.readthedocs.io/en/latest/040_backup.html#including-and-excluding-files + exclude = config.dig('backup', 'exclude')&.flat_map{|e| ['--exclude', e]} || [] + paths = config.dig('backup', 'paths') || [] + backup_command = ['restic', 'backup', *exclude, *paths] + puts("Command: #{backup_command.join(' ')}") + system(*backup_command) + if $?.exitstatus > 0 + STDERR.puts 'Failed to do backup.' + exit 1 + end + + puts 'Checking restic repo…' + check_command = ['restic', 'check'] + puts("Command: #{check_command.join(' ')}") + system(*check_command) + if $?.exitstatus > 0 + STDERR.puts "Checking restic repository #{ENV['RESTIC_REPOSITORY']} failed." + exit 1 + end + + puts "Deleting unnecessary snapshots…" + flags = config['forget'].filter{|k,v| k != 'enable'} + flags = flags.flat_map{|k,v| ['--' + k, v.to_s]} + forget_command = ['restic', 'forget'] + flags + puts("Command: #{forget_command.join(' ')}") + system(*forget_command) + # Data will only be deleted when `restic prune` is executed or when + # `restic forget` is called with `--prune`. + if $?.exitstatus > 0 + STDERR.puts "Forgetting snapshots failed." + exit 1 + end + + ENV.delete('RESTIC_REPOSITORY') + ENV.delete('RESTIC_PASSWORD') +end + +configs = YAML.load_stream(File.open(config_file)) +if ARGV.empty? + puts "No configuration name has been given. Using the first configuration." + do_backup(configs[0]) +else + ARGV.each do |config_name| + configs.each do |config| + if config_name == config['name'] + do_backup(config) + end + end + end +end