backup revision a8028fd2789e323040de08827a0fe1f7d36fde2b
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa#!/usr/bin/env ruby
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa# You can find more extensive documentation of this script at
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# https://github.com/ontohub/ontohub/blob/staging/doc/backup_and_restore_of_ontohub_data.md
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa# Description
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa# This backup script creates and restores backups of ontohub data. It includes:
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa# * bare git repositories (data/repositories)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# * named symlinks to git repositories (data/git_daemon)
b1fe9054ad7c7192fe4c474363247dad15963e99Eugen Kuksa# * the postgres database
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa#
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa# Usage
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa# First note: Run this as the ontohub user, *not* as root.
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa# To create a backup, run this script with the argument `create`:
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa# $ script/backup create
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa# Then a backup named with the current date and time is created in the
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# backup directory (see below).
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa#
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# To restore a backup, run this script with the argument `restore <backup name>`
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# $ script/backup restore 2015-01-01_00-00
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# Then the selected backup is fully restored
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa#
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# Backup directory
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# For development machines, the backup directory is:
366ce8d807067a97613cb23d49105d8a093c5015Eugen Kuksa# <rails root>/tmp/backup/
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# And for production machines, the backup directory is:
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# /home/ontohub/ontohub_data_backup
366ce8d807067a97613cb23d49105d8a093c5015Eugen Kuksa#
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# Super user privileges
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# To create and restore, we need root privileges. Otherwise file modes are not
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# preserved. This script will call `sudo` when needed and inform you about the
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# reason for calling `sudo`. If you don't allow sudo, a backup will be created
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# or restored anyway, but the file modes and ownership are not preserved.
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# Then, you need to adjust them manually.
366ce8d807067a97613cb23d49105d8a093c5015Eugen Kuksa#
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# Maintenance mode
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# While backing up and restoring the data, the maintenance mode is activated.
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# This way we guarantee data consistency of the backup.
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksarequire 'tmpdir.rb'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksarequire 'fileutils'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksarequire 'pathname'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksarequire 'open3'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksamodule Backup
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa class Backup
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa # Amount of backups that have to be there at least
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa BACKUPS_COUNT = 30
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa # Backups are kept for at least 365 days
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa BACKUPS_VALIDITY_TIME = 365 * 60 * 60 * 24
daf3e28fff47a65b53d6fb65155301763b9f166eEugen 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)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa attr_reader :db_name, :data_root, :backup_root, :backup_instance_dir
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksa attr_reader :dry_run, :verbose, :sql_dump_as_postgres_user
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa def initialize(db_name, data_root, backup_root,
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa verbose: false, dry_run: true, sql_dump_as_postgres_user: false)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa @db_name = db_name
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa @backup_root = Pathname.new(backup_root)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa @data_root = Pathname.new(data_root)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa @data_root_basename = @data_root.basename.to_s
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa @data_dirs = DATA_DIRS.map { |dir| File.join(@data_root_basename, dir) }
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa @dry_run = dry_run
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa @verbose = verbose
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa @sql_dump_as_postgres_user = sql_dump_as_postgres_user
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def create
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts 'Creating backup...'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa enable_maintenance_mode
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa initialize_backup
daf3e28fff47a65b53d6fb65155301763b9f166eEugen 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
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa def restore(backup_name)
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa enable_maintenance_mode
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa initialize_restore(backup_name)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa restore_sql_dump
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa restore_repository_archive
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa disable_maintenance_mode
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts "Restored backup from #{backup_instance_dir}"
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
284432981d641cf3d679841f75acbcf039d83062Eugen Kuksa
284432981d641cf3d679841f75acbcf039d83062Eugen Kuksa def self.prune(backup_root)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa if !Dir.exists?(backup_root)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa $stderr.puts "Nothing to prune: There is no backup directory."
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa return
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa now = Time.now
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa backup_dirs_allowed_to_delete(Dir.new(backup_root).entries).each do |dir|
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksa backup = backup_root.join(dir)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen 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
28001d576e67ba46ed481c5695f1e0827ff26007Eugen 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
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
2dbc668d1e44c95db1857d3968bcde7517852beaEugen Kuksa def initialize_backup
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa @backup_instance_dir = backup_root.join(new_backup_name)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts "FileUtils.mkdir_p #{backup_instance_dir}" if verbose
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa # Create directory even in dry run to let the script continue.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa FileUtils.mkdir_p(backup_instance_dir)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa def create_sql_dump
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts 'Creating SQL dump...'
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa Dir.chdir(backup_instance_dir) do
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa exec('pg_dump', *pg_user_switch, '-Fc', db_name, '-f', SQL_DUMP_FILE)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def create_repository_archive
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts 'Creating repository archive...'
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa Dir.chdir(data_root.join('..')) do
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa archive_file = backup_instance_dir.join(REPOSITORY_FILE)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa exec('tar', verbose ? '-v' : '', '-cf', archive_file.to_s, *@data_dirs)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa def initialize_restore(backup_name)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa @backup_instance_dir = backup_root.join(backup_name)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa unless Dir.exists?(backup_instance_dir)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa $stderr.puts (
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa "Error: Backup '#{backup_name}' does not exist in #{backup_root}.")
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa exit
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa def restore_sql_dump
284432981d641cf3d679841f75acbcf039d83062Eugen Kuksa 'Restoring SQL dump...'
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa Dir.chdir(backup_instance_dir) do
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa exec('pg_restore', '-c', *pg_user_switch, '-d', db_name, SQL_DUMP_FILE)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
284432981d641cf3d679841f75acbcf039d83062Eugen Kuksa def restore_repository_archive
284432981d641cf3d679841f75acbcf039d83062Eugen 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
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa remove_tmpdir(tmpdir)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa rescue => e
b51057b860560bf3ee454c03a121af3d5d34f482Eugen 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.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa MSG
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa raise e
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa end
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def move_data_dirs_to_tmpdir(tmpdir)
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa puts "FileUtils.mv(#{@data_dirs}, #{tmpdir})" if verbose
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa FileUtils.mv(@data_dirs, tmpdir) unless dry_run
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa rescue Errno::EACCES
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts <<-MSG
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen KuksaAs the current user I have no access to move the repository data
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksadirectories #{@data_dirs.join(' ')} to a temporary directory #{tmpdir}.
28001d576e67ba46ed481c5695f1e0827ff26007Eugen KuksaThis is used as a backup for the case of an error while restoring.
28001d576e67ba46ed481c5695f1e0827ff26007Eugen KuksaTo continue, I try the command again using sudo.
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa MSG
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa exec('sudo', 'mv', *@data_dirs, tmpdir)
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa end
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa def extract_archive
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa archive_file = backup_instance_dir.join(REPOSITORY_FILE)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts <<-MSG
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
28001d576e67ba46ed481c5695f1e0827ff26007Eugen KuksaSuper user privileges are needed to reset the file permissions as
28001d576e67ba46ed481c5695f1e0827ff26007Eugen 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
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksarestored and all restored files will belong to the current user/group.
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa MSG
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa try_as_sudo_with_fallback('tar', verbose ? '-v' : '', '-xf',
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa archive_file.to_s, *@data_dirs)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa def remove_tmpdir(tmpdir)
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa puts "FileUtils.remove_entry(#{tmpdir})" if verbose
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa FileUtils.remove_entry(tmpdir) # even do this in dry run
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa rescue Errno::EACCES
6d055d16c7620b7804b6a46cb481d00b3dbb5007Eugen Kuksa puts <<-MSG
6d055d16c7620b7804b6a46cb481d00b3dbb5007Eugen Kuksa
6d055d16c7620b7804b6a46cb481d00b3dbb5007Eugen KuksaAs the current user I have no access to remove the temporary
6d055d16c7620b7804b6a46cb481d00b3dbb5007Eugen Kuksadirectory #{tmpdir}.
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen KuksaTo continue, I try the command again using sudo.
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa MSG
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa exec('sudo', 'rm', '-r', tmpdir)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa def enable_maintenance_mode
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa puts 'Enabling maintenance mode...'
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa if File.exist?(maintenance_file)
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa $stderr.puts 'Maintenance mode was already enabled.'
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa $stderr.puts "Please check the file #{maintenance_file}"
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa $stderr.puts 'Aborting.'
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa exit
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa end
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa puts "FileUtils.touch #{maintenance_file}" if verbose
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa FileUtils.touch maintenance_file unless dry_run
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa end
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa def disable_maintenance_mode
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa puts 'Disabling maintenance mode...'
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa puts "FileUtils.rm #{maintenance_file}" if verbose
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa FileUtils.rm maintenance_file unless dry_run
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa end
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa def exec(*args)
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa puts "[executing next command in #{Dir.getwd}]" if verbose
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa out = args.join(' ')
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts out if verbose
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa system(*args) unless dry_run
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def try_as_sudo_with_fallback(*args)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa _out, _err, exit_code = exec('sudo', *args)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa unless exit_code.success?
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa sudo_not_given_fallback(*args) # Wrong sudo password
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa rescue Exception => e
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa raise e unless e.is_a?(Interrupt) # Ctrl-C when asked for password
0b99be5ced371cca00283694e1bd53a8ac0d7b5dEugen Kuksa sudo_not_given_fallback(*args)
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa end
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa def sudo_not_given_fallback(*args)
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa puts 'Super user privileges not granted. Trying as normal user.'
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa exec(*args)
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa end
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa def maintenance_file
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa data_root.join(MAINTENANCE_FILE)
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
b1fe9054ad7c7192fe4c474363247dad15963e99Eugen Kuksa def pg_user_switch
366ce8d807067a97613cb23d49105d8a093c5015Eugen Kuksa sql_dump_as_postgres_user ? %w(-U postgres) : []
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def self.backup_dirs_allowed_to_delete(entries)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa entries.reject{ |entry| %w(. ..).include?(entry) }[0..-(BACKUPS_COUNT+1)]
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksaend
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksa
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksadef data_root(rails_root)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa if on_development_system?(rails_root)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa File.realpath(rails_root.join('data'))
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa else
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa ENV['DATA_ROOT'] ||'/data/git'
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa end
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksaend
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksadef on_development_system?(rails_root)
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksa data_path = rails_root.join('data')
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa File.exist?(data_path) && !File.symlink?(data_path)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksaend
# Don't allow this to be run as the root user.
if ENV['USER'] == 'root'
puts 'Running this script as the root user is disabled.'
puts 'Please run it as a normal user that has sudo privileges, e.g. ontohub.'
exit
end
# We assume, this script runs in "RAILS_ROOT/script/".
RAILS_ROOT = Pathname.new(__FILE__).dirname.join('..')
BACKUP_ROOT_PRODUCTION = '/local/home/ontohub/ontohub_data_backup'
DATABASE =
if on_development_system?(RAILS_ROOT)
'ontohub_development'
else
'ontohub'
end
BACKUP_ROOT =
if on_development_system?(RAILS_ROOT)
RAILS_ROOT.join('tmp', 'backup')
else
File.realpath(BACKUP_ROOT_PRODUCTION)
end
backup = Backup::Backup.new(DATABASE, data_root(RAILS_ROOT), BACKUP_ROOT,
sql_dump_as_postgres_user: on_development_system?(RAILS_ROOT),
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