backup.rake
4.18 KB
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
task :load_backup_config do
$config = YAML.load_file('config/database.yml')
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