backup revision 57c81a32dff6182f040b4f852892144641a62fe5
2834197ede0bfaec5b57cb1666e0c21f76408570David Lawrence#!/usr/bin/env ruby
0ba23b0a24e0c17ee50073789704edaeeae2c360Andreas Gustafsson
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# You can find more extensive documentation of this script at
76c42915b4b54a486d68a9020d7fceaed42f7c1eAndreas Gustafsson# https://github.com/ontohub/ontohub/blob/staging/doc/backup_and_restore_of_ontohub_data.md
9c3531d72aeaad6c5f01efe6a1c82023e1379e4dDavid Lawrence
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# Description
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# This backup script creates and restores backups of ontohub data. It includes:
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# * bare git repositories (data/repositories)
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# * named symlinks to git repositories (data/git_daemon)
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# * the postgres database
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson#
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# Usage
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson# First note: Run this as the ontohub user, *not* as root.
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# To create a backup, run this script with the argument `create`:
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence# $ script/backup create
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson# Then a backup named with the current date and time is created in the
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# backup directory (see below).
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson#
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# To restore a backup, run this script with the argument `restore <backup name>`
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson# $ script/backup restore 2015-01-01_00-00
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# Then the selected backup is fully restored
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson#
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# Backup directory
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson# For development machines, the backup directory is:
dbeb32261081835bb9ba44db68df5dfed0fda411Andreas Gustafsson# <rails root>/tmp/backup/
717e2cf05b12506b40eb03f42ea963c30c7e9f97Brian Wellington# And for production machines, the backup directory is:
717e2cf05b12506b40eb03f42ea963c30c7e9f97Brian Wellington# /home/ontohub/ontohub_data_backup
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson#
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence# Super user privileges
a1747570262ed336c213aaf6bd31bc91993a46deAndreas Gustafsson# To create and restore, we need root privileges. Otherwise file modes are not
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence# preserved. This script will call `sudo` when needed and inform you about the
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson# reason for calling `sudo`. If you don't allow sudo, a backup will be created
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# or restored anyway, but the file modes and ownership are not preserved.
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson# Then, you need to adjust them manually.
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson#
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# Maintenance mode
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# While backing up and restoring the data, the maintenance mode is activated.
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson# This way we guarantee data consistency of the backup.
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
76c42915b4b54a486d68a9020d7fceaed42f7c1eAndreas Gustafssonrequire 'tmpdir.rb'
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafssonrequire 'fileutils'
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafssonrequire 'pathname'
2e711b60024d1ba41e7bc8010949e91aa404b244Andreas Gustafssonrequire 'open3'
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafssonmodule Backup
e0c769c3ecb8b251fac07ffeeef8a82c1689a949Mark Andrews class Backup
e0c769c3ecb8b251fac07ffeeef8a82c1689a949Mark Andrews # Amount of backups that have to be there at least
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson BACKUPS_COUNT = 30
1bc9afc3313249d656abae2d298c8d84308891d0Andreas Gustafsson # Backups are kept for at least 365 days
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson BACKUPS_VALIDITY_TIME = 365 * 60 * 60 * 24
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson MAINTENANCE_FILE = 'maintenance.txt'
717e2cf05b12506b40eb03f42ea963c30c7e9f97Brian Wellington
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson SQL_DUMP_FILE = 'ontohub_sql_dump.postgresql'
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson REPOSITORY_FILE = 'ontohub_repositories.tar.gz'
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
f83520a3d87dfd32cd0b8cecc5fd2c3ae71767b6Andreas Gustafsson DATA_DIRS = %w(repositories git_daemon)
dbeb32261081835bb9ba44db68df5dfed0fda411Andreas Gustafsson
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson attr_reader :db_name, :data_root, :backup_root, :backup_instance_dir
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson attr_reader :dry_run, :verbose, :sql_dump_as_db_user
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
876a69ba28028df41d8783369338f29501a917d3Andreas Gustafsson def initialize(db_name, data_root, backup_root,
10e6498d6d7b2cfd8d822788d817fc9a3e0b0c3aDavid Lawrence verbose: false, dry_run: true, sql_dump_as_db_user: nil)
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson @db_name = db_name
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson @backup_root = Pathname.new(backup_root)
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson @data_root = Pathname.new(data_root)
e21d199dca95aff5d50f133d6b064309e209af00Brian Wellington @data_root_basename = @data_root.basename.to_s
ef45c94e927e97ad0c804780a1eca59240088f60Andreas Gustafsson @data_dirs = DATA_DIRS.map { |dir| File.join(@data_root_basename, dir) }
ef45c94e927e97ad0c804780a1eca59240088f60Andreas Gustafsson
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson @dry_run = dry_run
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson @verbose = verbose
bfcdcde570be11e3d210cfdd262fae8b8e6c62ceMark Andrews @sql_dump_as_db_user = sql_dump_as_db_user
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson end
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson def create
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson puts 'Creating backup...'
7cd4c3ddd1baf5f2b204562fdba3da37c716cc78Andreas Gustafsson enable_maintenance_mode
7cd4c3ddd1baf5f2b204562fdba3da37c716cc78Andreas Gustafsson initialize_backup
19ab334c3f47db2550ff6ad13bbab67ff4090139Andreas Gustafsson create_sql_dump
51b951ab2a5e45e6a3994d033fec9b68e1f07985Mark Andrews create_repository_archive
51b951ab2a5e45e6a3994d033fec9b68e1f07985Mark Andrews # We needed to create the directory for the script to continue later on.
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson Dir.rmdir(backup_instance_dir) if dry_run
cfab2f4e039052fd5c71f8de93a9510bec0581f9Andreas Gustafsson disable_maintenance_mode
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson puts "Created backup in #{backup_instance_dir}"
e01ecff4b1562a24e6de7e9396c60e9dffdb78ceAndreas Gustafsson self.class.prune(backup_root)
cbe5f076ba5595c3d63daa223ea373bef55561b2Andreas Gustafsson end
cbe5f076ba5595c3d63daa223ea373bef55561b2Andreas Gustafsson
4bc5101166ec97bf88448efb9a65da600e82040eAndreas Gustafsson def restore(backup_name)
e240e36503adf4d2073adfee98fb17b5b9d10fddAndreas Gustafsson enable_maintenance_mode
e240e36503adf4d2073adfee98fb17b5b9d10fddAndreas Gustafsson initialize_restore(backup_name)
51b951ab2a5e45e6a3994d033fec9b68e1f07985Mark Andrews restore_sql_dump
54f6b2cfa87871782549a859ed9fc275b4b620bcAndreas Gustafsson restore_repository_archive
54f6b2cfa87871782549a859ed9fc275b4b620bcAndreas Gustafsson disable_maintenance_mode
54f6b2cfa87871782549a859ed9fc275b4b620bcAndreas Gustafsson puts "Restored backup from #{backup_instance_dir}"
54f6b2cfa87871782549a859ed9fc275b4b620bcAndreas Gustafsson end
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
51b951ab2a5e45e6a3994d033fec9b68e1f07985Mark Andrews def self.prune(backup_root)
9fdf20d0dea288572033095995547789059d4d6bAndreas Gustafsson if !Dir.exists?(backup_root)
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson $stderr.puts "Nothing to prune: There is no backup directory."
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson return
2e711b60024d1ba41e7bc8010949e91aa404b244Andreas Gustafsson end
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson now = Time.now
2cc3f128610eb9e42d7c386160665583b63882bfAndreas Gustafsson backup_dirs_allowed_to_delete(Dir.new(backup_root).entries).each do |dir|
2cc3f128610eb9e42d7c386160665583b63882bfAndreas Gustafsson backup = backup_root.join(dir)
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson if now - File.new(backup).ctime > BACKUPS_VALIDITY_TIME
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson puts "removing old backup: #{dir}"
50baab1389a4aa811ecd6e363e310904485d969fAndreas Gustafsson FileUtils.rm_r(backup)
50baab1389a4aa811ecd6e363e310904485d969fAndreas Gustafsson end
50baab1389a4aa811ecd6e363e310904485d969fAndreas Gustafsson end
50baab1389a4aa811ecd6e363e310904485d969fAndreas Gustafsson end
88eee65d8dd3e6051d855ec9f7b375207ed40a87Andreas Gustafsson
d2148c21700b9739ef125a49897288ad2636f706Andreas Gustafsson protected
50baab1389a4aa811ecd6e363e310904485d969fAndreas Gustafsson
2e711b60024d1ba41e7bc8010949e91aa404b244Andreas Gustafsson def new_backup_name
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson Time.now.strftime("%Y-%m-%d_%H-%M-%S")
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson end
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson def initialize_backup
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson @backup_instance_dir = backup_root.join(new_backup_name)
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson puts "FileUtils.mkdir_p #{backup_instance_dir}" if verbose
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson # Create directory even in dry run to let the script continue.
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson FileUtils.mkdir_p(backup_instance_dir)
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson end
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
4034406393893f4d07ab07b56da3541155493855Andreas Gustafsson def create_sql_dump
4034406393893f4d07ab07b56da3541155493855Andreas Gustafsson puts 'Creating SQL dump...'
4034406393893f4d07ab07b56da3541155493855Andreas Gustafsson Dir.chdir(backup_instance_dir) do
4034406393893f4d07ab07b56da3541155493855Andreas Gustafsson exec('pg_dump', *pg_user_switch, '-Fc', db_name, '-f', SQL_DUMP_FILE)
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson end
c011a692803976aa5100f7a4e6a1fa8a1ea2c3f3Andreas Gustafsson end
fa3cbea8bfba19d1c11f9a6ad20f40a2c15377f0Brian Wellington
4bc5101166ec97bf88448efb9a65da600e82040eAndreas Gustafsson def create_repository_archive
e240e36503adf4d2073adfee98fb17b5b9d10fddAndreas Gustafsson puts 'Creating repository archive...'
4bc5101166ec97bf88448efb9a65da600e82040eAndreas Gustafsson Dir.chdir(data_root.join('..')) do
e01ecff4b1562a24e6de7e9396c60e9dffdb78ceAndreas Gustafsson archive_file = backup_instance_dir.join(REPOSITORY_FILE)
2bc0dee981fd5d9c7d7d6fe67278dfafbe614bc3Andreas Gustafsson exec('tar', verbose ? '-v' : '', '-cf', archive_file.to_s, *@data_dirs)
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson end
c011a692803976aa5100f7a4e6a1fa8a1ea2c3f3Andreas Gustafsson end
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson def initialize_restore(backup_name)
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson @backup_instance_dir = backup_root.join(backup_name)
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence unless Dir.exists?(backup_instance_dir)
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson $stderr.puts (
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson "Error: Backup '#{backup_name}' does not exist in #{backup_root}.")
4334d2e8a16c4e154e8eb6fb7c7c8e8862771c8cBrian Wellington exit
4334d2e8a16c4e154e8eb6fb7c7c8e8862771c8cBrian Wellington end
876a69ba28028df41d8783369338f29501a917d3Andreas Gustafsson end
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
d2148c21700b9739ef125a49897288ad2636f706Andreas Gustafsson def restore_sql_dump
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson 'Restoring SQL dump...'
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson Dir.chdir(backup_instance_dir) do
e0c769c3ecb8b251fac07ffeeef8a82c1689a949Mark Andrews exec('pg_restore', '-n', 'public',
38e62f7bfbe301b4718bc9e8525bf141cc080e71Andreas Gustafsson '-c', *pg_user_switch,
38e62f7bfbe301b4718bc9e8525bf141cc080e71Andreas Gustafsson '-d', db_name,
717e2cf05b12506b40eb03f42ea963c30c7e9f97Brian Wellington SQL_DUMP_FILE)
717e2cf05b12506b40eb03f42ea963c30c7e9f97Brian Wellington end
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson end
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
d2148c21700b9739ef125a49897288ad2636f706Andreas Gustafsson def restore_repository_archive
e54683130c25e85ab63dde3e8d14578a59479825Brian Wellington puts 'Restoring repository archive...'
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson Dir.chdir(data_root.join('..')) do
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson tmpdir = Dir.mktmpdir
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson move_data_dirs_to_tmpdir(tmpdir)
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson begin
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson extract_archive
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson remove_tmpdir(tmpdir)
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence rescue => e
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson puts <<-MSG
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas GustafssonAn error occured while restoring the repositories:
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson#{e.message}
4334d2e8a16c4e154e8eb6fb7c7c8e8862771c8cBrian WellingtonYou can find the pre-restore repositories at #{tmpdir}
4334d2e8a16c4e154e8eb6fb7c7c8e8862771c8cBrian WellingtonDo something about it.
876a69ba28028df41d8783369338f29501a917d3Andreas Gustafsson MSG
10e6498d6d7b2cfd8d822788d817fc9a3e0b0c3aDavid Lawrence raise e
02da394e0c3220ca2f37c5c6258994bd3ba07993Andreas Gustafsson end
7eabdeaeeebf4be93de87af803d020d380eb7273Andreas Gustafsson end
38e62f7bfbe301b4718bc9e8525bf141cc080e71Andreas Gustafsson end
38e62f7bfbe301b4718bc9e8525bf141cc080e71Andreas Gustafsson
cbe5f076ba5595c3d63daa223ea373bef55561b2Andreas Gustafsson def move_data_dirs_to_tmpdir(tmpdir)
cbe5f076ba5595c3d63daa223ea373bef55561b2Andreas Gustafsson puts "FileUtils.mv(#{@data_dirs}, #{tmpdir})" if verbose
e0c769c3ecb8b251fac07ffeeef8a82c1689a949Mark Andrews FileUtils.mv(@data_dirs, tmpdir) unless dry_run
50baab1389a4aa811ecd6e363e310904485d969fAndreas Gustafsson rescue Errno::EACCES
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson puts <<-MSG
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas GustafssonAs the current user I have no access to move the repository data
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafssondirectories #{@data_dirs.join(' ')} to a temporary directory #{tmpdir}.
717e2cf05b12506b40eb03f42ea963c30c7e9f97Brian WellingtonThis is used as a backup for the case of an error while restoring.
717e2cf05b12506b40eb03f42ea963c30c7e9f97Brian WellingtonTo continue, I try the command again using sudo.
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson MSG
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson exec('sudo', 'mv', *@data_dirs, tmpdir)
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson end
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson def extract_archive
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson archive_file = backup_instance_dir.join(REPOSITORY_FILE)
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson puts <<-MSG
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafsson
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas GustafssonSuper user privileges are needed to reset the file permissions as
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafssonthey were before the backup. If you refuse to enter the password
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafsson(Ctl-C) or enter a wrong password, only the permissions will not be
4334d2e8a16c4e154e8eb6fb7c7c8e8862771c8cBrian Wellingtonrestored and all restored files will belong to the current user/group.
4334d2e8a16c4e154e8eb6fb7c7c8e8862771c8cBrian Wellington MSG
876a69ba28028df41d8783369338f29501a917d3Andreas Gustafsson try_as_sudo_with_fallback('tar', verbose ? '-v' : '', '-xf',
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafsson archive_file.to_s, *@data_dirs)
51b951ab2a5e45e6a3994d033fec9b68e1f07985Mark Andrews end
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafsson
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafsson def remove_tmpdir(tmpdir)
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafsson puts "FileUtils.remove_entry(#{tmpdir})" if verbose
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafsson FileUtils.remove_entry(tmpdir) # even do this in dry run
e0c769c3ecb8b251fac07ffeeef8a82c1689a949Mark Andrews rescue Errno::EACCES
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafsson puts <<-MSG
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafsson
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas GustafssonAs the current user I have no access to remove the temporary
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafssondirectory #{tmpdir}.
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas GustafssonTo continue, I try the command again using sudo.
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson MSG
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson exec('sudo', 'rm', '-r', tmpdir)
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson end
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafsson def enable_maintenance_mode
335a4599898f181f18b618a5ac4fe4e083ecd308Andreas Gustafsson puts 'Enabling maintenance mode...'
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence if File.exist?(maintenance_file)
4334d2e8a16c4e154e8eb6fb7c7c8e8862771c8cBrian Wellington $stderr.puts 'Maintenance mode was already enabled.'
4334d2e8a16c4e154e8eb6fb7c7c8e8862771c8cBrian Wellington $stderr.puts "Please check the file #{maintenance_file}"
4334d2e8a16c4e154e8eb6fb7c7c8e8862771c8cBrian Wellington $stderr.puts 'Aborting.'
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson exit
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson end
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence puts "FileUtils.touch #{maintenance_file}" if verbose
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson FileUtils.touch maintenance_file unless dry_run
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson end
876a69ba28028df41d8783369338f29501a917d3Andreas Gustafsson
250ed9e230b3903b1b264dd1ed2f691fc7cd2f8fAndreas Gustafsson def disable_maintenance_mode
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson puts 'Disabling maintenance mode...'
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson puts "FileUtils.rm #{maintenance_file}" if verbose
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson FileUtils.rm maintenance_file unless dry_run
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson end
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson
1bc9afc3313249d656abae2d298c8d84308891d0Andreas Gustafsson def exec(*args)
717e2cf05b12506b40eb03f42ea963c30c7e9f97Brian Wellington puts "[executing next command in #{Dir.getwd}]" if verbose
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson out = args.join(' ')
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson puts out if verbose
fea398993b583058fb8167902eed3eedd26f464cAndreas Gustafsson system(*args) unless dry_run
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson end
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson
876a69ba28028df41d8783369338f29501a917d3Andreas Gustafsson def try_as_sudo_with_fallback(*args)
10e6498d6d7b2cfd8d822788d817fc9a3e0b0c3aDavid Lawrence unless exec('sudo', *args)
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson sudo_not_given_fallback(*args) # Wrong sudo password
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson end
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson rescue Exception => e
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson raise e unless e.is_a?(Interrupt) # Ctrl-C when asked for password
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson sudo_not_given_fallback(*args)
51b951ab2a5e45e6a3994d033fec9b68e1f07985Mark Andrews end
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson def sudo_not_given_fallback(*args)
7cd4c3ddd1baf5f2b204562fdba3da37c716cc78Andreas Gustafsson puts 'Super user privileges not granted. Trying as normal user.'
7cd4c3ddd1baf5f2b204562fdba3da37c716cc78Andreas Gustafsson exec(*args)
19ab334c3f47db2550ff6ad13bbab67ff4090139Andreas Gustafsson end
51b951ab2a5e45e6a3994d033fec9b68e1f07985Mark Andrews
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson def maintenance_file
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson data_root.join(MAINTENANCE_FILE)
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson end
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson def pg_user_switch
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson sql_dump_as_db_user ? %W(-U #{sql_dump_as_db_user}) : []
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson end
53f483103b02669ea339c1011709038e4a578604Andreas Gustafsson
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson def self.backup_dirs_allowed_to_delete(entries)
98c7e0d8ba881f06f56716d6f7098d54643f4f2fAndreas Gustafsson entries.reject{ |entry| %w(. ..).include?(entry) }[0..-(BACKUPS_COUNT+1)]
98c7e0d8ba881f06f56716d6f7098d54643f4f2fAndreas Gustafsson end
fea398993b583058fb8167902eed3eedd26f464cAndreas Gustafsson end
d2148c21700b9739ef125a49897288ad2636f706Andreas Gustafssonend
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafssondef data_root(rails_root)
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson if on_development_system?(rails_root)
a057b6e5e2d8a890184854728b26f4c86a9bdcb3Andreas Gustafsson File.realpath(rails_root.join('data'))
113251976d99be74da788bdb78300957b77a1381Andreas Gustafsson else
ENV['DATA_ROOT'] ||'/data/git'
end
end
def on_development_system?(rails_root)
data_path = rails_root.join('data')
File.exist?(data_path) && !File.symlink?(data_path)
end
# 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_db_user: on_development_system?(RAILS_ROOT) ? 'postgres' : 'ontohub',
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