backup revision f9e467b8fe6fef705eec2989b20e92eaa9d917e1
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 ontohub user, *not* as root.
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
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen Kuksa DATA_DIRS = %w(repositories git_daemon)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa attr_reader :db_name, :data_root, :backup_root, :backup_instance_dir
67daeb8066e4460cb820db60c45138dd48309bb9Eugen Kuksa attr_reader :dry_run, :verbose, :sql_dump_as_db_user
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def initialize(db_name, data_root, backup_root,
67daeb8066e4460cb820db60c45138dd48309bb9Eugen Kuksa verbose: false, dry_run: true, sql_dump_as_db_user: false)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @db_name = db_name
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @backup_root = Pathname.new(backup_root)
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen Kuksa @data_root = Pathname.new(data_root)
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen Kuksa @data_root_basename = @data_root.basename.to_s
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen Kuksa @data_dirs = DATA_DIRS.map { |dir| File.join(@data_root_basename, dir) }
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @dry_run = dry_run
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa @verbose = verbose
67daeb8066e4460cb820db60c45138dd48309bb9Eugen Kuksa @sql_dump_as_db_user = sql_dump_as_db_user
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def create
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen 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
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa puts "Created backup in #{backup_instance_dir}"
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa self.class.prune(backup_root)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def restore(backup_name)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen 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
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa puts "Restored backup from #{backup_instance_dir}"
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa def self.prune(backup_root)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa if !Dir.exists?(backup_root)
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen 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
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa puts "removing old backup: #{dir}"
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa FileUtils.rm_r(backup)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa end
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa end
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa end
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen 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)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts "FileUtils.mkdir_p #{backup_instance_dir}" if verbose
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa # Create directory even in dry run to let the script continue.
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa FileUtils.mkdir_p(backup_instance_dir)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def create_sql_dump
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa puts 'Creating SQL dump...'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa Dir.chdir(backup_instance_dir) do
96c47a92d836bca1aca373db8664c5ec84cfc8afEugen Kuksa exec('pg_dump', *pg_user_switch, '-Fc', db_name, '-f', SQL_DUMP_FILE)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def create_repository_archive
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa puts 'Creating repository archive...'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa Dir.chdir(data_root.join('..')) do
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa archive_file = backup_instance_dir.join(REPOSITORY_FILE)
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen Kuksa exec('tar', verbose ? '-v' : '', '-cf', archive_file.to_s, *@data_dirs)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen 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)
4634cde5d3428bd5ab34b8212ac2f4637cdfff6fEugen Kuksa $stderr.puts (
4634cde5d3428bd5ab34b8212ac2f4637cdfff6fEugen Kuksa "Error: Backup '#{backup_name}' does not exist in #{backup_root}.")
daf3e28fff47a65b53d6fb65155301763b9f166eEugen 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
f9e467b8fe6fef705eec2989b20e92eaa9d917e1Eugen Kuksa exec('pg_restore', '-n', 'public',
f9e467b8fe6fef705eec2989b20e92eaa9d917e1Eugen Kuksa '-c', *pg_user_switch,
f9e467b8fe6fef705eec2989b20e92eaa9d917e1Eugen Kuksa '-d', db_name,
f9e467b8fe6fef705eec2989b20e92eaa9d917e1Eugen Kuksa SQL_DUMP_FILE)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def restore_repository_archive
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa puts 'Restoring repository archive...'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa Dir.chdir(data_root.join('..')) do
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa tmpdir = Dir.mktmpdir
2dbc668d1e44c95db1857d3968bcde7517852beaEugen 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
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen 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
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa raise e
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa def move_data_dirs_to_tmpdir(tmpdir)
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen Kuksa puts "FileUtils.mv(#{@data_dirs}, #{tmpdir})" if verbose
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen Kuksa FileUtils.mv(@data_dirs, tmpdir) unless dry_run
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa rescue Errno::EACCES
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts <<-MSG
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen KuksaAs the current user I have no access to move the repository data
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen Kuksadirectories #{@data_dirs.join(' ')} to a temporary directory #{tmpdir}.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen KuksaThis is used as a backup for the case of an error while restoring.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen KuksaTo continue, I try the command again using sudo.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa MSG
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen Kuksa exec('sudo', 'mv', *@data_dirs, tmpdir)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa def extract_archive
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa archive_file = backup_instance_dir.join(REPOSITORY_FILE)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts <<-MSG
284432981d641cf3d679841f75acbcf039d83062Eugen 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
6cdc461aada609d57d50ff675d29b15378717ff2Eugen 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.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa MSG
76f98a73426869ab54073075345686d98b6a8cafEugen Kuksa try_as_sudo_with_fallback('tar', verbose ? '-v' : '', '-xf',
a8028fd2789e323040de08827a0fe1f7d36fde2bEugen 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
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa FileUtils.remove_entry(tmpdir) # even do this in dry run
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa rescue Errno::EACCES
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts <<-MSG
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa
b51057b860560bf3ee454c03a121af3d5d34f482Eugen KuksaAs the current user I have no access to remove the temporary
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksadirectory #{tmpdir}.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen KuksaTo continue, I try the command again using sudo.
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa MSG
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa exec('sudo', 'rm', '-r', tmpdir)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def enable_maintenance_mode
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa puts 'Enabling maintenance mode...'
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksa if File.exist?(maintenance_file)
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksa $stderr.puts 'Maintenance mode was already enabled.'
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksa $stderr.puts "Please check the file #{maintenance_file}"
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksa $stderr.puts 'Aborting.'
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksa exit
bacf95fddc53ab3107f380c4c816fa8072358bd9Eugen Kuksa end
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa puts "FileUtils.touch #{maintenance_file}" if verbose
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa FileUtils.touch maintenance_file unless dry_run
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa def disable_maintenance_mode
4ec9d8b62c3c1a001548eb0883b6f81e00c391a0Eugen Kuksa puts 'Disabling maintenance mode...'
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa puts "FileUtils.rm #{maintenance_file}" if verbose
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa FileUtils.rm maintenance_file unless dry_run
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
96c47a92d836bca1aca373db8664c5ec84cfc8afEugen Kuksa def exec(*args)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa puts "[executing next command in #{Dir.getwd}]" if verbose
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa out = args.join(' ')
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa puts out if verbose
96c47a92d836bca1aca373db8664c5ec84cfc8afEugen Kuksa system(*args) unless dry_run
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa def try_as_sudo_with_fallback(*args)
dd553f2f8b8abb774ba64a4fb9ebe3abea9f7f17Eugen Kuksa _out, _err, exit_code = exec('sudo', *args)
dd553f2f8b8abb774ba64a4fb9ebe3abea9f7f17Eugen Kuksa unless exit_code.success?
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa sudo_not_given_fallback(*args) # Wrong sudo password
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa rescue Exception => e
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa raise e unless e.is_a?(Interrupt) # Ctrl-C when asked for password
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa sudo_not_given_fallback(*args)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa def sudo_not_given_fallback(*args)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa puts 'Super user privileges not granted. Trying as normal user.'
28001d576e67ba46ed481c5695f1e0827ff26007Eugen Kuksa exec(*args)
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa end
b51057b860560bf3ee454c03a121af3d5d34f482Eugen Kuksa
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa def maintenance_file
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa data_root.join(MAINTENANCE_FILE)
486df98bbf3348cfb96e93c3e499d12435880bb5Eugen Kuksa end
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa
6d055d16c7620b7804b6a46cb481d00b3dbb5007Eugen Kuksa def pg_user_switch
67daeb8066e4460cb820db60c45138dd48309bb9Eugen Kuksa sql_dump_as_db_user ? %w(-U ontohub) : []
6d055d16c7620b7804b6a46cb481d00b3dbb5007Eugen Kuksa end
6d055d16c7620b7804b6a46cb481d00b3dbb5007Eugen Kuksa
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa def self.backup_dirs_allowed_to_delete(entries)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa entries.reject{ |entry| %w(. ..).include?(entry) }[0..-(BACKUPS_COUNT+1)]
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksaend
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksadef data_root(rails_root)
26e23083feb1577ee4bd102bc09ca440d20548b9Eugen Kuksa if on_development_system?(rails_root)
26e23083feb1577ee4bd102bc09ca440d20548b9Eugen Kuksa File.realpath(rails_root.join('data'))
26e23083feb1577ee4bd102bc09ca440d20548b9Eugen Kuksa else
26e23083feb1577ee4bd102bc09ca440d20548b9Eugen Kuksa ENV['DATA_ROOT'] ||'/data/git'
26e23083feb1577ee4bd102bc09ca440d20548b9Eugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksaend
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksadef on_development_system?(rails_root)
2da9df454152009d7a5e0d83d519aa2bc9844233Eugen Kuksa data_path = rails_root.join('data')
2da9df454152009d7a5e0d83d519aa2bc9844233Eugen Kuksa File.exist?(data_path) && !File.symlink?(data_path)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksaend
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa# Don't allow this to be run as the root user.
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksaif ENV['USER'] == 'root'
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa puts 'Running this script as the root user is disabled.'
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa puts 'Please run it as a normal user that has sudo privileges, e.g. ontohub.'
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa exit
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksaend
0978722f6ca27f5d5f5ed4ec8400703dfe211184Eugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa# We assume, this script runs in "RAILS_ROOT/script/".
daf3e28fff47a65b53d6fb65155301763b9f166eEugen KuksaRAILS_ROOT = Pathname.new(__FILE__).dirname.join('..')
e6edf613be834fd6ab5ea816077d4263609db07eEugen KuksaBACKUP_ROOT_PRODUCTION = '/local/home/ontohub/ontohub_data_backup'
0b99be5ced371cca00283694e1bd53a8ac0d7b5dEugen Kuksa
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen KuksaDATABASE =
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksa if on_development_system?(RAILS_ROOT)
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa 'ontohub_development'
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa else
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa 'ontohub'
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa end
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksa
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen KuksaBACKUP_ROOT =
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksa if on_development_system?(RAILS_ROOT)
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa RAILS_ROOT.join('tmp', 'backup')
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa else
1724834ae596f84e8237a3bba5a8af15916a8ee9Eugen Kuksa File.realpath(BACKUP_ROOT_PRODUCTION)
df4ff7ec6be98e7ae5830731becc1a3d55105378Eugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
b1fe9054ad7c7192fe4c474363247dad15963e99Eugen Kuksabackup = Backup::Backup.new(DATABASE, data_root(RAILS_ROOT), BACKUP_ROOT,
67daeb8066e4460cb820db60c45138dd48309bb9Eugen Kuksa sql_dump_as_db_user: true,
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa dry_run: false, verbose: true)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksacase ARGV.first
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksawhen 'create'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa backup.create
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksawhen 'restore'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa if ARGV.length == 1
4634cde5d3428bd5ab34b8212ac2f4637cdfff6fEugen Kuksa $stderr.puts(
4634cde5d3428bd5ab34b8212ac2f4637cdfff6fEugen Kuksa 'To restore a backup, you need to specify one with the arguments')
4634cde5d3428bd5ab34b8212ac2f4637cdfff6fEugen Kuksa $stderr.puts('"restore backup_name"')
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa exit
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa end
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa backup_name = ARGV[1]
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa backup.restore(backup_name)
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksawhen 'prune'
5efadb4662f2a63d5f5f1a5b303ab7c3371069a8Eugen Kuksa Backup::Backup.prune(BACKUP_ROOT)
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksaelse
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksa $stderr.puts 'unknown or missing parameter'
923d69139038e74c0936e826bbfdc8717fbbc7b3Eugen Kuksa $stderr.puts 'use parameter "create" or "restore <backup_name>" or "prune"'
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksa exit
daf3e28fff47a65b53d6fb65155301763b9f166eEugen Kuksaend