namespace :db do
desc 'PG backup' task backup: [:environment, :load_config] do #stamp the filename dateformat = ENV['date-format'] || '%Y-%m-%d_%H-%M-%S' datestamp = Time.now.strftime(dateformat) #create backups folder mkdir_p(backup_dir) config = ActiveRecord::Base.connection_config database_name = ActiveRecord::Base.connection.current_database backup_file = File.join(backup_dir, "#{database_name}_#{datestamp}.dump") #dump the backup and zip it up sh dump_command(config, database_name, backup_file) latest_file_name = File.join(backup_dir, "#{database_name}_latest.dump") if File.exist? latest_file_name rm latest_file_name end safe_ln backup_file, latest_file_name end desc 'PG restore from the last backup file' task restore: ['db:create', :environment, :load_config] do config = ActiveRecord::Base.connection_config database_name = ActiveRecord::Base.connection.current_database backup_dir = ENV['backup-path'] || Rails.root.join('db', 'backups') backup_file = File.join(backup_dir, "#{database_name}_latest.dump") execute_task!('db:kill_postgres_connections') execute_task!('db:drop') execute_task!('db:create') command = db_restore_command(config, database_name, backup_file) sh "#{command} || echo 'done'" end task :kill_postgres_connections => :environment do config = ActiveRecord::Base.connection_config next if config[:adapter] != "postgresql" db_name = ActiveRecord::Base.connection.current_database pid_column_name = if ActiveRecord::Base.connection.send(:postgresql_version) > 90200 'pid' else 'procpid' end kill_query = <<-QUERY SELECT pg_terminate_backend(#{pid_column_name}) FROM pg_stat_activity WHERE datname = '#{db_name}'; QUERY begin ActiveRecord::Base.connection.exec_query(kill_query) rescue ActiveRecord::StatementInvalid => ex puts "All connections to #{db_name} were killed successfully!" puts "Database message: #{ex.message}" end end desc 'Clean up old dumps' task :cleanup do dumps = FileList.new(File.join(backup_dir, '*.dump')).exclude(/_latest.dump$/) if keep_versions > 0 && dumps.count >= keep_versions puts "Keep #{keep_versions} dumps" files = (dumps - dumps.last(keep_versions)) if files.any? files.each do |f| rm_r f end end end end def backup_dir @_backup_dir ||= ENV['backup-path'] || Rails.root.join('db', 'backups') end def keep_versions @_keep_versions ||= ENV['ROTATE'].to_i end def postgres_dump_command(config, database_name, backup_file) result = "#{postgres_password(config)} pg_dump #{database_name} -w -F c" result += postgres_auth_options(config) result + " > #{backup_file}" end def mysql_dump_command(config, database_name, backup_file) result = "mysqldump #{database_name} " result += mysql_auth_options(config) result + " > #{backup_file}" end def dump_command(config, database_name, backup_file) case config[:adapter] when /mysql/ mysql_dump_command(config, database_name, backup_file) when 'postgresql', 'pg' postgres_dump_command(config, database_name, backup_file) end end def db_restore_command(config, database_name, backup_file) case config[:adapter] when /mysql/ mysql_restore_command(config, database_name, backup_file) when 'postgresql', 'pg' postgres_restore_command(config, database_name, backup_file) end end def postgres_restore_command(config, database_name, backup_file) result = "#{postgres_password(config)} pg_restore -d #{database_name} -F c -w #{backup_file}" result += postgres_auth_options(config) result + ' -O -c' end def mysql_restore_command(config, database_name, backup_file) "mysql #{database_name} #{mysql_auth_options(config)} < #{backup_file}" end def postgres_password(config) "PGPASSWORD='#{config[:password]}'" if config[:password].present? end def postgres_auth_options(config) command_options = '' command_options += " -h #{config[:host]}" if config[:host].present? command_options += " -U #{config[:username]}" if config[:username].present? command_options end def mysql_auth_options(config) command_options = '' command_options += "--password='#{config[:password]}'" if config[:password].present? command_options += " -h #{config[:host]}" if config[:host].present? command_options += " -u #{config[:username]}" if config[:username].present? command_options end
end
TODO: Use setting to get S3 credentials def send_to_amazon(file_path)
bucket = "db-backups" file_name = File.basename(file_path) AWS::S3::Base.establish_connection!(:access_key_id => 'YOUR KEY', :secret_access_key => 'YOUR SECRET') #push the file up AWS::S3::S3Object.store(file_name, File.open(file_path), bucket)
end
def execute_task!(task_name)
Rake::Task[task_name].reenable Rake::Task[task_name].invoke
end