backup revision 4fbbf628eda08ffdeb98cb41fb7e9001050eec3a
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa#!/usr/bin/env ruby
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
abc834c020080fe44a1ea4e34278327e99e3e12eEugen Kuksa# You can find more extensive documentation of this script at
abc834c020080fe44a1ea4e34278327e99e3e12eEugen Kuksa# https://github.com/ontohub/ontohub/blob/staging/doc/backup_and_restore_of_ontohub_data.md
abc834c020080fe44a1ea4e34278327e99e3e12eEugen Kuksa
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# Description
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# This backup script creates and restores backups of ontohub data. It includes:
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# * bare git repositories (data/repositories)
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# * named symlinks to git repositories (data/git_daemon)
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# * the postgres database
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa#
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# Usage
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa# First note: Run this as the root user, e.g. with sudo.
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# To create a backup, run this script with the argument `create`:
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# # script/backup create
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# Then a backup named with the current date and time is created in the
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# backup directory (see below).
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa#
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# To restore a backup, run this script with the argument `restore <backup name>`
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# # script/backup restore 2015-01-01_00-00
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# Then the selected backup is fully restored
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa#
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# Backup directory
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# For development machines, the backup directory is:
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# <rails root>/tmp/backup/
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# And for production machines, the backup directory is:
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# /home/ontohub/ontohub_data_backup
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa#
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# Super user privileges
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# To create and restore, we need root privileges. Otherwise file modes are not
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# preserved. This script will call `sudo` when needed and inform you about the
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# reason for calling `sudo`. If you don't allow sudo, a backup will be created
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# or restored anyway, but the file modes and ownership are not preserved.
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# Then, you need to adjust them manually.
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa#
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# Maintenance mode
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# While backing up and restoring the data, the maintenance mode is activated.
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa# This way we guarantee data consistency of the backup.
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa
f0264afd33a980b6584747fc8159ee950805d9e3Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksarequire 'tmpdir.rb'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksarequire 'fileutils'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksarequire 'pathname'
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksarequire 'open3'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
b1fe9054ad7c7192fe4c474363247dad15963e99Eugen Kuksamodule Backup
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa class Backup
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa # Amount of backups that have to be there at least
d89f470f7da0b9f8295d0ac0defff09884894b8bEugen Kuksa BACKUPS_COUNT = 30
d89f470f7da0b9f8295d0ac0defff09884894b8bEugen Kuksa # Backups are kept for at least 365 days
d89f470f7da0b9f8295d0ac0defff09884894b8bEugen Kuksa BACKUPS_VALIDITY_TIME = 365 * 60 * 60 * 24
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa MAINTENANCE_FILE = 'maintenance.txt'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa SQL_DUMP_FILE = 'ontohub_sql_dump.postgresql'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa REPOSITORY_FILE = 'ontohub_repositories.tar.gz'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa DATA_DIRS = %w(repositories git_daemon)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa # Use 'sudo' on most systems
366ce8d807067a97613cb23d49105d8a093c5015Eugen Kuksa SUDO_BINARY = '+'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa attr_reader :db_name, :data_root, :backup_root, :backup_instance_dir
366ce8d807067a97613cb23d49105d8a093c5015Eugen Kuksa attr_reader :dry_run, :verbose, :sql_dump_as_db_user
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def initialize(db_name, data_root, backup_root,
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa verbose: false, dry_run: true, sql_dump_as_db_user: nil, user: nil)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @db_name = db_name
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @backup_root = Pathname.new(backup_root)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @data_root = Pathname.new(data_root)
366ce8d807067a97613cb23d49105d8a093c5015Eugen Kuksa @data_root_basename = @data_root.basename.to_s
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @data_dirs = DATA_DIRS.map { |dir| File.join(@data_root_basename, dir) }
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @user = user
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa @dry_run = dry_run
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @verbose = verbose
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @sql_dump_as_db_user = sql_dump_as_db_user
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def create
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts 'Creating backup...'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa enable_maintenance_mode
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa initialize_backup
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa create_sql_dump
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa create_repository_archive
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa # We needed to create the directory for the script to continue later on.
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa Dir.rmdir(backup_instance_dir) if dry_run
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa disable_maintenance_mode
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts "Created backup in #{backup_instance_dir}"
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa self.class.prune(backup_root)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa def restore(backup_name)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa enable_maintenance_mode
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa initialize_restore(backup_name)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa restore_sql_dump
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa restore_repository_archive
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksa disable_maintenance_mode
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa puts "Restored backup from #{backup_instance_dir}"
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa end
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa def self.prune(backup_root)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa if !Dir.exists?(backup_root)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa $stderr.puts "Nothing to prune: There is no backup directory."
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa return
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa end
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa now = Time.now
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa backup_dirs_allowed_to_delete(Dir.new(backup_root).entries).each do |dir|
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa backup = backup_root.join(dir)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa if now - File.new(backup).ctime > BACKUPS_VALIDITY_TIME
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts "removing old backup: #{dir}"
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa FileUtils.rm_r(backup)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa protected
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def new_backup_name
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa Time.now.strftime("%Y-%m-%d_%H-%M-%S")
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def initialize_backup
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @backup_instance_dir = backup_root.join(new_backup_name)
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa puts "FileUtils.mkdir_p #{backup_instance_dir}" if verbose
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa # Create directory even in dry run to let the script continue.
96c47a92d836bca1aca373db8664c5ec84cfc8afEugen Kuksa FileUtils.mkdir_p(backup_instance_dir)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def create_sql_dump
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts 'Creating SQL dump...'
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa Dir.chdir(backup_instance_dir) do
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa exec('pg_dump', *pg_user_switch, '-Fc', db_name, '-f', SQL_DUMP_FILE,
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa user: @user)
76f98a73426869ab54073075345686d98b6a8cafEugen Kuksa end
284432981d641cf3d679841f75acbcf039d83062Eugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def create_repository_archive
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts 'Creating repository archive...'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa Dir.chdir(data_root.join('..')) do
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa archive_file = backup_instance_dir.join(REPOSITORY_FILE)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa exec('tar', verbose ? '-v' : '', '-cf', archive_file.to_s, *@data_dirs,
4634cde5d3428bd5ab34b8212ac2f4637cdfff6fEugen Kuksa user: @user)
4634cde5d3428bd5ab34b8212ac2f4637cdfff6fEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def initialize_restore(backup_name)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @backup_instance_dir = backup_root.join(backup_name)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa unless Dir.exists?(backup_instance_dir)
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa $stderr.puts (
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa "Error: Backup '#{backup_name}' does not exist in #{backup_root}.")
b4ac7fd47818fbcba8d344e3de41ca62e1473b94Eugen Kuksa exit
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def restore_sql_dump
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa 'Restoring SQL dump...'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa Dir.chdir(backup_instance_dir) do
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa exec('pg_restore', '-n', 'public',
2dbc668d1e44c95db1857d3968bcde7517852beaEugen Kuksa '-c', *pg_user_switch,
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa '-d', db_name,
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa SQL_DUMP_FILE,
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa user: @user)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa def restore_repository_archive
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts 'Restoring repository archive...'
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa Dir.chdir(data_root.join('..')) do
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa tmpdir = Dir.mktmpdir
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa move_data_dirs_to_tmpdir(tmpdir)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa begin
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa extract_archive
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa remove_tmpdir(tmpdir)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa rescue => e
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts <<-MSG
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen KuksaAn error occured while restoring the repositories:
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa#{e.message}
b51057b860560bf3ee454c03a121af3d5d34f482Eugen KuksaYou can find the pre-restore repositories at #{tmpdir}
b51057b860560bf3ee454c03a121af3d5d34f482Eugen KuksaDo something about it.
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa MSG
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa raise e
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa def move_data_dirs_to_tmpdir(tmpdir)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts "FileUtils.mv(#{@data_dirs}, #{tmpdir})" if verbose
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa FileUtils.mv(@data_dirs, tmpdir) unless dry_run
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa rescue Errno::EACCES
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts <<-MSG
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
284432981d641cf3d679841f75acbcf039d83062Eugen KuksaAs the current user I have no access to move the repository data
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksadirectories #{@data_dirs.join(' ')} to a temporary directory #{tmpdir}.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen KuksaThis is used as a backup for the case of an error while restoring.
6cdc461aada609d57d50ff675d29b15378717ff2Eugen KuksaTo continue, I try the command again using sudo.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa MSG
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa exec('mv', *@data_dirs, tmpdir, user: 'root')
76f98a73426869ab54073075345686d98b6a8cafEugen Kuksa end
284432981d641cf3d679841f75acbcf039d83062Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa def extract_archive
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa archive_file = backup_instance_dir.join(REPOSITORY_FILE)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts <<-MSG
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen KuksaSuper user privileges are needed to reset the file permissions as
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksathey were before the backup. If you refuse to enter the password
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa(Ctl-C) or enter a wrong password, only the permissions will not be
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksarestored and all restored files will belong to the current user/group.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa MSG
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa try_as_sudo_with_fallback('tar', verbose ? '-v' : '', '-xf',
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa archive_file.to_s, *@data_dirs)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa def remove_tmpdir(tmpdir)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts "FileUtils.remove_entry(#{tmpdir})" if verbose
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa FileUtils.remove_entry(tmpdir) # even do this in dry run
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa rescue Errno::EACCES
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksa puts <<-MSG
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksa
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen KuksaAs the current user I have no access to remove the temporary
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksadirectory #{tmpdir}.
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen KuksaTo continue, I try the command again using sudo.
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksa MSG
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa exec('rm', '-r', tmpdir, user: 'root')
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def enable_maintenance_mode
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts 'Enabling maintenance mode...'
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa if File.exist?(maintenance_file)
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa $stderr.puts 'Maintenance mode was already enabled.'
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa $stderr.puts "Please check the file #{maintenance_file}"
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa $stderr.puts 'Aborting.'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa exit
96c47a92d836bca1aca373db8664c5ec84cfc8afEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts "FileUtils.touch #{maintenance_file}" if verbose
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa FileUtils.touch maintenance_file unless dry_run
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa end
96c47a92d836bca1aca373db8664c5ec84cfc8afEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def disable_maintenance_mode
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa puts 'Disabling maintenance mode...'
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa puts "FileUtils.rm #{maintenance_file}" if verbose
dd553f2f8b8abb774ba64a4fb9ebe3abea9f7f17Eugen Kuksa FileUtils.rm maintenance_file unless dry_run
dd553f2f8b8abb774ba64a4fb9ebe3abea9f7f17Eugen Kuksa end
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa # Execute a command as the given user.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa def exec(*args, user: nil)
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa puts "[executing next command in #{Dir.getwd}]" if verbose
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa out = args.join(' ')
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts out if verbose
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa if !dry_run
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa if user == 'root'
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa system([sudo, *args])
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa elsif user
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa system([sudo, 'su', '-', user, '-c', escape_arguments(args)])
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa else
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa system(*args)
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa end
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa end
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa end
6d055d16c7620b7804b6a46cb481d00b3dbb5007Eugen Kuksa
b4ac7fd47818fbcba8d344e3de41ca62e1473b94Eugen Kuksa def sudo
6d055d16c7620b7804b6a46cb481d00b3dbb5007Eugen Kuksa SUDO_BINARY
6d055d16c7620b7804b6a46cb481d00b3dbb5007Eugen Kuksa end
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa def escape_arguments(args)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa ([args[0]] + *args[1..-1].map { |a| %("#{a}")}).join(' ')
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def maintenance_file
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa data_root.join(MAINTENANCE_FILE)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def pg_user_switch
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa sql_dump_as_db_user ? %W(-U #{sql_dump_as_db_user}) : []
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def self.backup_dirs_allowed_to_delete(entries)
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa entries.reject{ |entry| %w(. ..).include?(entry) }[0..-(BACKUPS_COUNT+1)]
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa end
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa end
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksaend
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksadef data_root(rails_root)
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa if on_development_system?(rails_root)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa File.realpath(rails_root.join('data'))
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa else
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksa ENV['DATA_ROOT'] ||'/data/git'
0b99be5ced371cca00283694e1bd53a8ac0d7b5dEugen Kuksa end
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksaend
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksa
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksadef on_development_system?(rails_root)
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa data_path = rails_root.join('data')
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa File.exist?(data_path) && !File.symlink?(data_path)
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksaend
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksa
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksa# Don't allow this to be run as the root user.
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksaif ENV['USER'] != 'root'
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa puts 'Running this script as a normal user is disabled.'
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa puts 'Please run it as root.'
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksa exit
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksaend
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
b1fe9054ad7c7192fe4c474363247dad15963e99Eugen Kuksa# We assume, this script runs in "RAILS_ROOT/script/".
366ce8d807067a97613cb23d49105d8a093c5015Eugen KuksaRAILS_ROOT = Pathname.new(__FILE__).dirname.join('..')
daf3e28fff47a65b53d6fb65155301763b9f166eEugen KuksaBACKUP_ROOT_PRODUCTION = '/local/home/ontohub/ontohub_data_backup'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen KuksaUSER = 'ontohub'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen KuksaDATABASE =
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa if on_development_system?(RAILS_ROOT)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa 'ontohub_development'
4634cde5d3428bd5ab34b8212ac2f4637cdfff6fEugen Kuksa else
4634cde5d3428bd5ab34b8212ac2f4637cdfff6fEugen Kuksa 'ontohub'
4634cde5d3428bd5ab34b8212ac2f4637cdfff6fEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen KuksaBACKUP_ROOT =
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa if on_development_system?(RAILS_ROOT)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa RAILS_ROOT.join('tmp', 'backup')
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa else
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa File.realpath(BACKUP_ROOT_PRODUCTION)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksa
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksabackup = Backup::Backup.new(DATABASE, data_root(RAILS_ROOT), BACKUP_ROOT,
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa sql_dump_as_db_user: on_development_system?(RAILS_ROOT) ? 'postgres' : 'ontohub',
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa user: USER,
dry_run: false, verbose: true)
case ARGV.first
when 'create'
backup.create
when 'restore'
if ARGV.length == 1
$stderr.puts(
'To restore a backup, you need to specify one with the arguments')
$stderr.puts('"restore backup_name"')
exit
end
backup_name = ARGV[1]
backup.restore(backup_name)
when 'prune'
Backup::Backup.prune(BACKUP_ROOT)
else
$stderr.puts 'unknown or missing parameter'
$stderr.puts 'use parameter "create" or "restore <backup_name>" or "prune"'
exit
end