server-scripts/backup-container

104 lines
2.8 KiB
Plaintext
Raw Normal View History

2014-10-19 15:27:33 +00:00
#!/usr/bin/env ruby
require 'json'
require 'pathname'
require 'fileutils'
2014-10-21 17:36:41 +00:00
require 'open3'
2014-10-19 15:27:33 +00:00
LXC_PATH = Pathname.new("/data/containers")
2014-10-19 15:27:33 +00:00
BACKUP_LOCATIONS = %w{home srv etc usr/local}
CONFIG_PATH = "/etc/lxc/container.json"
BACKUP_PATH = "/mnt/backup/attic"
ATTIC_PATH = Pathname.new("/data/attic")
PASSWORD_FILE = ATTIC_PATH.join("passwordfile").to_s
KEEP_DAILY = 7
KEEP_WEEKLY = 4
KEEP_MONTHLY = 0
2014-10-19 15:27:33 +00:00
def load_config
2014-10-21 17:36:41 +00:00
return JSON.load(File.open(CONFIG_PATH))
2014-10-19 15:27:33 +00:00
rescue SystemCallError => e
abort "failed to open configuration '#{CONFIG_PATH}', #{e}"
rescue JSON::ParserError => e
abort "failed to parse configuration '#{CONFIG_PATH}', #{e}"
end
2014-10-21 17:36:41 +00:00
def sh(cmd, env={}, *args)
pretty_args = args.map {|arg| "'#{arg}'"}
puts ([cmd] + pretty_args).join(" ")
system(env, cmd, *args)
2014-10-19 15:27:33 +00:00
end
class Container
def initialize(name, backup_paths, backup_scripts)
@name = name
@backup_paths = backup_paths
@backup_scripts = backup_scripts
@path = LXC_PATH.join(name, "rootfs")
end
2014-10-21 17:36:41 +00:00
def backup_paths
paths = BACKUP_LOCATIONS
2014-10-19 15:27:33 +00:00
if @backup_paths.is_a?(Array)
2014-10-21 17:36:41 +00:00
paths += @backup_paths
2014-10-19 15:27:33 +00:00
end
2014-10-21 17:36:41 +00:00
paths.map do |relative_path|
@path.join(relative_path)
2014-10-19 15:27:33 +00:00
end
end
def run_backup_scripts
if @backup_scripts.is_a?(Array)
2014-10-21 17:36:41 +00:00
@backup_scripts.map do |script|
2014-10-19 15:27:33 +00:00
backup_script(script)
end
2014-10-21 17:36:41 +00:00
else
[]
2014-10-19 15:27:33 +00:00
end
end
private
def backup_script(script)
unless script.is_a?(Hash)
abort("backup-scripts: Expected an Object, got #{script.class}")
end
command = script["command"]
if command.nil?
abort("command not set for backup-scripts for container '#{@name}'")
end
backupname = script["backupname"]
if backupname.nil?
abort("backupname not set for backup-scripts for container '#{@name}'")
end
backupname = ATTIC_PATH.join(backupname.gsub("/", ""))
2014-10-19 15:27:33 +00:00
FileUtils.mkdir_p(backupname)
puts "cd #{backupname}"
Dir.chdir(backupname) do
2014-10-21 17:36:41 +00:00
sh(command)
2014-10-19 15:27:33 +00:00
end
2014-10-21 17:36:41 +00:00
backupname
2014-10-19 15:27:33 +00:00
end
def empty_directory?(path)
return false unless Dir.exists?(path)
return Dir.entries(path).size <= 2 # - [".", ".."]
end
end
config = load_config
backup_paths = BACKUP_LOCATIONS.map do |location|
"/#{location}"
end
config["network"].each do |container, data|
2014-10-21 17:36:41 +00:00
next if data["lxc"] == false
container = Container.new(container, data["backup-paths"], data["backup-scripts"])
backup_paths += container.backup_paths
backup_paths += container.run_backup_scripts
2014-10-19 15:27:33 +00:00
end
env = { "ATTIC_PASSPHRASE" => File.read(PASSWORD_FILE).chomp }
now = Time.now.strftime("%Y-%m-%d-%H:%M:%S")
paths = backup_paths.map {|path| path.to_s }
sh("attic", env, "create", "--stats", "#{BACKUP_PATH}::eve-#{now}", *paths)
sh("attic", env, "prune", "-v", BACKUP_PATH,
"--keep-daily", KEEP_DAILY.to_s,
"--keep-weekly", KEEP_WEEKLY.to_s,
"--keep-monthly", KEEP_MONTHLY.to_s)