ref: master
lib/tasks/backup.rake
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 |
task :load_backup_config do db_file = Rails.root.join('config', 'database.yml') $config = YAML.load(ERB.new(File.read(db_file)).result) end task :check_backup_support => :load_backup_config do if $config['production']['adapter'] != 'postgresql' fail("Only PostgreSQL is supported for backups at the moment") end end backup_dirs = [ 'public/image_uploads', 'public/articles', 'public/thumbnails', 'public/user_themes', ] desc "Creates a backup of the database and uploaded files" task :backup => :check_backup_support do dirs = backup_dirs.select { |d| File.exists?(d) } rails_env = ENV["RAILS_ENV"] || 'production' backup_name = Time.now.strftime('%Y-%m-%d-%R') backup_file = File.join('tmp/backup', backup_name) + '.tar.gz' mkdir_p 'tmp/backup' dump = File.join('tmp/backup', backup_name) + '.sql' database = $config[rails_env]['database'] host = $config[rails_env]['host'] host = host && "-h #{host}" || "" sh "pg_dump #{host} #{database} > #{dump}" sh 'tar', 'chaf', backup_file, dump, *dirs rm_f dump puts "****************************************************" puts "Backup in #{backup_file} !" puts puts "To restore, use:" puts "$ rake restore BACKUP=#{backup_file}" puts "****************************************************" end def invalid_backup!(message, items=[]) puts "E: #{message}" items.each do |i| puts "E: - #{i}" end puts "E: Is this a backup archive created by Noosfero with \`rake backup\`?" exit 1 end desc "Restores a backup created previousy with \`rake backup\`" task :restore => :check_backup_support do backup = ENV["BACKUP"] rails_env = ENV["RAILS_ENV"] || 'production' unless backup puts "usage: rake restore BACKUP=/path/to/backup" exit 1 end files = `tar taf #{backup}`.split # validate files in the backup invalid_files = [] files.each do |f| if f !~ /tmp\/backup\// && (backup_dirs.none? { |d| f =~ /^#{d}\// }) invalid_files << f end end if invalid_files.size > 0 invalid_backup!("Invalid files found in the backup archive", invalid_files) end # find database dump in the archive dumps = files.select do |f| File.dirname(f) == 'tmp/backup' && f =~ /\.sql$/ end if dumps.size == 0 invalid_backup!("Could not find a database dump in the archive.") elsif dumps.size > 1 invalid_backup!("Multiple database dumps found in the archive:", dumps) end dump = dumps.first database = $config[rails_env]['database'] username = $config[rails_env]['username'] host = $config[rails_env]['host'] host = host && "-h #{host}" || "" puts "WARNING: backups should be restored to an empty database, otherwise" puts "data from the backup may not be loaded properly." puts puts 'You can remove the existing database and create a new one with:' puts puts "$ sudo -u postgres dropdb #{host} #{database}" puts "$ sudo -u postgres createdb #{host} #{database} --owner #{username}" puts print "Are you sure you want to continue (y/N)? " response = $stdin.gets.strip unless ['y', 'yes'].include?(response.downcase) puts "*** ABORTED." exit 1 end sh 'tar', 'xaf', backup sh "rails dbconsole #{rails_env} < #{dump}" rm_f dump puts "****************************************************" puts "Backup restored!" puts "****************************************************" end desc 'Removes emails from database' task 'restore:remove_emails' => :environment do connection = ActiveRecord::Base.connection [ "UPDATE users SET email = concat('user', id, '@localhost.localdomain')", "UPDATE environments SET contact_email = concat('environment', id, '@localhost.localdomain')", ].each do |update| puts update connection.execute(update) end profiles = connection.execute("select id, data from profiles") profiles.each do |profile| if profile['data'] data = YAML.load(profile['data']) if data[:contact_email] && data[:contact_email] !~ /@localhost.localdomain$/ data[:contact_email] = ['profile', profile['id'], '@localhost.localdomain'].join sql = Environment.send(:sanitize_sql, [ "UPDATE profiles SET data = ? WHERE id = ?", YAML.dump(data), profile['id'], ]) puts sql connection.execute(sql) end end end end |