backup revision 3edb9eac22c71a937953dd2ad4911d12fb22c6c6
26N/A# The first line is for deployment machines only. For local machines, use: 26N/A# You can find more extensive documentation of this script at 26N/A# This backup script creates and restores backups of ontohub data. It includes: 26N/A# * the postgres database 26N/A# First note: Run this as the root user, e.g. with sudo. 26N/A# To create a backup, run this script with the argument `create`: 26N/A# Then a backup named with the current date and time is created in the 26N/A# backup directory (see below). 26N/A# To restore a backup, run this script with the argument `restore <backup name>` 2466N/A# Then the selected backup is fully restored 26N/A# For production machines, the backup directory is: 1431N/A# To create and restore, we need root privileges. Otherwise file modes are not 1218N/A# preserved. This script will call `sudo` when needed and inform you about the 576N/A# reason for calling `sudo`. If you don't allow sudo, a backup will be created 576N/A# or restored anyway, but the file modes and ownership are not preserved. 1431N/A# Then, you need to adjust them manually. 1431N/A# While backing up and restoring the data, the maintenance mode is activated. 1431N/A# This way we guarantee data consistency of the backup. 2466N/A # Amount of backups that have to be there at least 2466N/A # Backups are kept for at least 365 days 696N/A # Use 'sudo' on most systems 1218N/A # We needed to create the directory for the script to continue later on. 1218N/A puts "Created backup in #{backup_instance_dir}" 1218N/A puts "Restored backup from #{backup_instance_dir}" 1431N/A # Create directory even in dry run to let the script continue. 1431N/A "Error: Backup '#{backup_name}' does not exist in #{backup_root}.") 1431N/A exec('pg_restore', '-n', 'public', 1431N/AAn error occured while restoring the repositories: 1431N/AYou can find the pre-restore repositories at #{tmpdir} 1431N/A def move_data_dirs_to_tmpdir(tmpdir) 1431N/A puts "FileUtils.mv(#{@data_dirs}, #{tmpdir})" if verbose 1431N/A FileUtils.mv(@data_dirs, tmpdir) unless dry_run 1431N/AAs the current user I have no access to move the repository data 1431N/Adirectories #{@data_dirs.join(' ')} to a temporary directory #{tmpdir}. 1431N/AThis is used as a backup for the case of an error while restoring. 1431N/ATo continue, I try the command again using sudo. 1431N/A exec('mv', *@data_dirs, tmpdir, user: 'root') unless dry_run 1431N/A archive_file = backup_instance_dir.join(REPOSITORY_FILE) 1431N/ASuper user privileges are needed to reset the file permissions as 1431N/Athey were before the backup. If you refuse to enter the password 1431N/A(Ctl-C) or enter a wrong password, only the permissions will not be 576N/Arestored and all restored files will belong to the current user/group. 576N/A exec('tar', verbose ? 'vxf' : 'xf', archive_file.to_s, *@data_dirs, def remove_tmpdir(tmpdir) puts "FileUtils.remove_entry(#{tmpdir})" if verbose FileUtils.remove_entry(tmpdir) # even do this in dry run As the current user I have no access to remove the temporary To continue, I try the command again using sudo. exec('rm', '-r', tmpdir, user: 'root') def enable_maintenance_mode puts 'Enabling maintenance mode...' if File.exist?(maintenance_file) $stderr.puts 'Maintenance mode was already enabled.' $stderr.puts "Please check the file #{maintenance_file}" puts "FileUtils.touch #{maintenance_file}" if verbose FileUtils.touch maintenance_file unless dry_run def disable_maintenance_mode puts 'Disabling maintenance mode...' puts "FileUtils.rm #{maintenance_file}" if verbose FileUtils.rm maintenance_file unless dry_run # Execute a command as the given user. def exec(*args, user: nil) print "[executing next command in #{Dir.getwd}" if verbose print " as user #{user}" if verbose && user exec_system(*[sudo, *args]) # This looks strange because of the combination of + and sudo. # It is needed on our deployment machines to get the environment right. # On other machines, remove the call of +. exec_system(*['+', 'sudo', '-u', user, 'bash', '-c', "cd #{Dir.getwd} && #{escape_arguments(args)}"]) # puts args.join(' ') # For debugging def escape_arguments(args) rest = args[1..-1].map do |arg| if arg.to_s.include?(' ') %("#{arg.gsub('"', '\"')}") ([args[0]] + rest).join(' ') data_root.join(MAINTENANCE_FILE) sql_dump_as_db_user ? %W(-U #{sql_dump_as_db_user}) : [] def self.backup_dirs_allowed_to_delete(entries) entries.reject{ |entry| %w(. ..).include?(entry) }[0..-(BACKUPS_COUNT+1)] def data_root(rails_root) ENV['DATA_ROOT'] ||'/data/git' # Don't allow this to be run as the root user. puts 'Running this script as a normal user is disabled.' puts 'Please run it as root.' # We assume, this script runs in "RAILS_ROOT/script/". RAILS_ROOT = Pathname.new(__FILE__).dirname.join('..') BACKUP_ROOT_PRODUCTION = '/data/ontohub_data_backup' unless File.exist?(BACKUP_ROOT_PRODUCTION) FileUtils.mkdir_p(BACKUP_ROOT_PRODUCTION) BACKUP_ROOT = File.realpath(BACKUP_ROOT_PRODUCTION) backup = Backup::Backup.new(DATABASE, data_root(RAILS_ROOT), BACKUP_ROOT, sql_dump_as_db_user: 'ontohub', user: USER, group: GROUP, dry_run: false, verbose: true) 'To restore a backup, you need to specify one with the arguments') $stderr.puts('"restore backup_name"') backup.restore(backup_name) Backup::Backup.prune(BACKUP_ROOT) $stderr.puts 'unknown or missing parameter' $stderr.puts 'use parameter "create" or "restore <backup_name>" or "prune"'