s3_db_assets_backup 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +59 -0
- data/Rakefile +49 -0
- data/generators/assets_backup/USAGE +11 -0
- data/generators/assets_backup/assets_backup_generator.rb +10 -0
- data/generators/assets_backup/templates/assets_backup.rake +30 -0
- data/generators/assets_backup/templates/assets_backup_config.yml +11 -0
- data/generators/assets_backup/templates/db_backup.rake +31 -0
- data/generators/assets_backup/templates/load_assets_backup_config.rb +6 -0
- data/test/s3_db_assets_backup_test.rb +67 -0
- data/test/test_helper.rb +34 -0
- metadata +65 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 Chris Barnes
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
= S3DbAssetsBackup
|
2
|
+
|
3
|
+
Generates rake tasks for backing up your database and public folder (which should also contain any uploaded assets) to an existing bucket in your Amazon S3 account. The rake tasks compresses and uploads each backup with a time stamp and the config file allows you to set how many of each backup to keep. This script is "very largly based on" the following (http://www.magnionlabs.com/2009/7/7/db-backups)
|
4
|
+
|
5
|
+
== Install
|
6
|
+
|
7
|
+
script/plugin install git://github.com/randomutterings/s3_db_assets_backup.git
|
8
|
+
|
9
|
+
Edit config/assets_backup_config.yml with your aws credentials.
|
10
|
+
|
11
|
+
Install aws-s3 library
|
12
|
+
|
13
|
+
gem install aws-s3
|
14
|
+
|
15
|
+
Create the backup rake tasks, config file, and initializer.
|
16
|
+
|
17
|
+
script/generate assets_backup
|
18
|
+
|
19
|
+
Backup the production database.
|
20
|
+
|
21
|
+
rake db:backup RAILS_ENV=production
|
22
|
+
|
23
|
+
Backup the public folder
|
24
|
+
|
25
|
+
rake assets:backup
|
26
|
+
|
27
|
+
Optionally setup cron to do your backups with the following crontab
|
28
|
+
|
29
|
+
# Full backup every Wednesday at 11:01
|
30
|
+
1 23 * * 3 cd /path/to/your/project && /var/lib/gems/1.8/bin/rake db:backup RAILS_ENV=production
|
31
|
+
1 23 * * 3 cd /path/to/your/project && /var/lib/gems/1.8/bin/rake assets:backup
|
32
|
+
|
33
|
+
If you ever need to restore the production database, use the tool of your choice to download the backup from S3 and run.
|
34
|
+
|
35
|
+
gzip -dc production_dump-YYYY-MM-DD_HH-MM-SS.sql.gz | mysql -u root -p <production database>
|
36
|
+
|
37
|
+
== Troubleshooting and FAQs
|
38
|
+
|
39
|
+
<b>I get "cannot create ./tmp/production_dump-YYYY-MM-DD_HH-MM-SS.sql.gz: Directory nonexistent" when running the database backup to S3</b>
|
40
|
+
|
41
|
+
You need to create a tmp directory in the root.
|
42
|
+
|
43
|
+
mkdir tmp
|
44
|
+
|
45
|
+
<b>Another problem?</b>
|
46
|
+
|
47
|
+
Make sure you're using Rails 2.3.5.
|
48
|
+
|
49
|
+
|
50
|
+
== Found a bug?
|
51
|
+
|
52
|
+
If you are having a problem with the site, first look at the FAQs above. If you still cannot resolve it, please submit an issue here.
|
53
|
+
|
54
|
+
http://github.com/randomutterings/s3_db_assets_backup/issues
|
55
|
+
|
56
|
+
|
57
|
+
== Rails 3
|
58
|
+
|
59
|
+
This project does not yet officially work with Rails 3.
|
data/Rakefile
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
require 'rake/gempackagetask'
|
5
|
+
|
6
|
+
desc 'Default: run unit tests.'
|
7
|
+
task :default => :test
|
8
|
+
|
9
|
+
desc 'Test the s3_db_assets_backup plugin.'
|
10
|
+
Rake::TestTask.new(:test) do |t|
|
11
|
+
t.libs << 'lib'
|
12
|
+
t.libs << 'test'
|
13
|
+
t.pattern = 'test/**/*_test.rb'
|
14
|
+
t.verbose = true
|
15
|
+
end
|
16
|
+
|
17
|
+
desc 'Generate documentation for the s3_db_assets_backup plugin.'
|
18
|
+
Rake::RDocTask.new(:rdoc) do |rdoc|
|
19
|
+
rdoc.rdoc_dir = 'rdoc'
|
20
|
+
rdoc.title = 'S3DbAssetsBackup'
|
21
|
+
rdoc.options << '--line-numbers' << '--inline-source'
|
22
|
+
rdoc.rdoc_files.include('README')
|
23
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
24
|
+
end
|
25
|
+
|
26
|
+
PKG_FILES = FileList[
|
27
|
+
'[a-zA-Z]*',
|
28
|
+
'generators/**/*',
|
29
|
+
'test/**/*'
|
30
|
+
]
|
31
|
+
|
32
|
+
spec = Gem::Specification.new do |s|
|
33
|
+
s.name = "s3_db_assets_backup"
|
34
|
+
s.version = "0.0.1"
|
35
|
+
s.author = "Chris Barnes"
|
36
|
+
s.email = "randomutterings@gmail.com"
|
37
|
+
s.homepage = "http://www.randomutterings.com/projects/s3_db_assets_backup"
|
38
|
+
s.platform = Gem::Platform::RUBY
|
39
|
+
s.summary = "Generates rake tasks for backing up db and public folder to S3 bucket"
|
40
|
+
s.files = PKG_FILES.to_a
|
41
|
+
s.require_path = "lib"
|
42
|
+
s.has_rdoc = false
|
43
|
+
s.extra_rdoc_files = ["README.rdoc"]
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'Turn this plugin into a gem.'
|
47
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
48
|
+
pkg.gem_spec = spec
|
49
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
Description:
|
2
|
+
generates backup rake tasks, config yaml file, and initializer
|
3
|
+
|
4
|
+
Example:
|
5
|
+
./script/generate assets_backup
|
6
|
+
|
7
|
+
This will create:
|
8
|
+
lib/tasks/assets_backup.rake
|
9
|
+
lib/tasks/db_backup.rake
|
10
|
+
config/assets_backup_config.yml
|
11
|
+
config/initializers/load_assets_backup_config.rb
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class AssetsBackupGenerator < Rails::Generator::Base
|
2
|
+
def manifest
|
3
|
+
record do |m|
|
4
|
+
m.file "assets_backup_config.yml", "config/assets_backup_config.yml"
|
5
|
+
m.file "load_assets_backup_config.rb", "config/initializers/load_assets_backup_config.rb"
|
6
|
+
m.file "assets_backup.rake", "lib/tasks/assets_backup.rake"
|
7
|
+
m.file "db_backup.rake", "lib/tasks/db_backup.rake"
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'find'
|
2
|
+
require 'ftools'
|
3
|
+
require 'aws/s3'
|
4
|
+
|
5
|
+
namespace :assets do
|
6
|
+
desc "Backup everything in the public folder."
|
7
|
+
task :backup => [:environment] do
|
8
|
+
AWS::S3::Base.establish_connection!(:access_key_id => APP_CONFIG['access_key_id'], :secret_access_key => APP_CONFIG['secret_access_key'])
|
9
|
+
BUCKET = APP_CONFIG['bucket']
|
10
|
+
|
11
|
+
datestamp = Time.now.strftime("%Y-%m-%d_%H-%M-%S")
|
12
|
+
base_path = ENV["RAILS_ROOT"] || "."
|
13
|
+
file_name = "#{RAILS_ENV}_assets-#{datestamp}.tgz"
|
14
|
+
backup_file = File.join(base_path, "tmp", file_name)
|
15
|
+
sh "tar -cvzpf #{backup_file} public"
|
16
|
+
AWS::S3::S3Object.store(file_name, open(backup_file), BUCKET)
|
17
|
+
puts "Created backup: #{file_name}"
|
18
|
+
FileUtils.rm_rf(backup_file)
|
19
|
+
|
20
|
+
bucket = AWS::S3::Bucket.find(BUCKET)
|
21
|
+
all_backups = bucket.objects.select { |f| f.key.match(/assets/) }.sort { |a,b| a.key <=> b.key }.reverse
|
22
|
+
max_backups = APP_CONFIG['assets_backups_to_keep'].to_i || 28
|
23
|
+
unwanted_backups = all_backups[max_backups..-1] || []
|
24
|
+
for unwanted_backup in unwanted_backups
|
25
|
+
unwanted_backup.delete
|
26
|
+
puts "deleted #{unwanted_backup.key}"
|
27
|
+
end
|
28
|
+
puts "Deleted #{unwanted_backups.length} backups, #{all_backups.length - unwanted_backups.length} backups available"
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# amazon aws credentials
|
2
|
+
access_key_id: your-aws-access-key-id
|
3
|
+
secret_access_key: your-aws-secret-access-key
|
4
|
+
|
5
|
+
# bucket you would like to use for backups
|
6
|
+
bucket: your_existing_s3_bucket
|
7
|
+
|
8
|
+
# how many backups would you like to keep for
|
9
|
+
# the database and public folder
|
10
|
+
database_backups_to_keep: 8
|
11
|
+
assets_backups_to_keep: 3
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'find'
|
2
|
+
require 'ftools'
|
3
|
+
require 'aws/s3'
|
4
|
+
|
5
|
+
namespace :db do
|
6
|
+
desc "Backup the database to a file. Options: RAILS_ENV=production"
|
7
|
+
task :backup => [:environment] do
|
8
|
+
AWS::S3::Base.establish_connection!(:access_key_id => APP_CONFIG['access_key_id'], :secret_access_key => APP_CONFIG['secret_access_key'])
|
9
|
+
BUCKET = APP_CONFIG['bucket']
|
10
|
+
|
11
|
+
datestamp = Time.now.strftime("%Y-%m-%d_%H-%M-%S")
|
12
|
+
base_path = ENV["RAILS_ROOT"] || "."
|
13
|
+
file_name = "#{RAILS_ENV}_dump-#{datestamp}.sql.gz"
|
14
|
+
backup_file = File.join(base_path, "tmp", file_name)
|
15
|
+
db_config = ActiveRecord::Base.configurations[RAILS_ENV]
|
16
|
+
sh "mysqldump -u #{db_config['username']} -p#{db_config['password']} -Q --add-drop-table -O add-locks=FALSE -O lock-tables=FALSE #{db_config['database']} | gzip -c > #{backup_file}"
|
17
|
+
AWS::S3::S3Object.store(file_name, open(backup_file), BUCKET)
|
18
|
+
puts "Created backup: #{file_name}"
|
19
|
+
FileUtils.rm_rf(backup_file)
|
20
|
+
|
21
|
+
bucket = AWS::S3::Bucket.find(BUCKET)
|
22
|
+
all_backups = bucket.objects.select { |f| f.key.match(/dump/) }.sort { |a,b| a.key <=> b.key }.reverse
|
23
|
+
max_backups = APP_CONFIG['database_backups_to_keep'].to_i || 28
|
24
|
+
unwanted_backups = all_backups[max_backups..-1] || []
|
25
|
+
for unwanted_backup in unwanted_backups
|
26
|
+
unwanted_backup.delete
|
27
|
+
puts "deleted #{unwanted_backup.key}"
|
28
|
+
end
|
29
|
+
puts "Deleted #{unwanted_backups.length} backups, #{all_backups.length - unwanted_backups.length} backups available"
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
|
+
require 'rails_generator'
|
3
|
+
require 'rails_generator/scripts/generate'
|
4
|
+
|
5
|
+
class S3DbAssetsBackupTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
# creates all dirs down to initializers and tasks
|
9
|
+
FileUtils.mkdir_p(initializers_dir)
|
10
|
+
FileUtils.mkdir_p(tasks_dir)
|
11
|
+
Rails::Generator::Scripts::Generate.new.run(["assets_backup"], :destination => fake_rails_root)
|
12
|
+
end
|
13
|
+
|
14
|
+
def teardown
|
15
|
+
FileUtils.rm_r(fake_rails_root)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_generates_backup_config_yaml_file
|
19
|
+
assert_generated_file("config/assets_backup_config.yml")
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_generates_backup_config_initializer
|
23
|
+
assert_generated_file("config/initializers/load_assets_backup_config.rb")
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_generates_assets_backup_rake_task
|
27
|
+
assert_generated_file("lib/tasks/assets_backup.rake")
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_generates_db_backup_rake_task
|
31
|
+
assert_generated_file("lib/tasks/db_backup.rake")
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def fake_rails_root
|
37
|
+
File.join(File.dirname(__FILE__), 'rails_root')
|
38
|
+
end
|
39
|
+
|
40
|
+
def config_dir
|
41
|
+
File.join(File.dirname(__FILE__), 'rails_root/config')
|
42
|
+
end
|
43
|
+
|
44
|
+
def initializers_dir
|
45
|
+
File.join(File.dirname(__FILE__), 'rails_root/config/initializers')
|
46
|
+
end
|
47
|
+
|
48
|
+
def tasks_dir
|
49
|
+
File.join(File.dirname(__FILE__), 'rails_root/lib/tasks')
|
50
|
+
end
|
51
|
+
|
52
|
+
# Asserts that the given file was generated.
|
53
|
+
# The contents of the file is passed to a block.
|
54
|
+
def assert_generated_file(path)
|
55
|
+
assert_file_exists(path)
|
56
|
+
File.open("#{fake_rails_root}/#{path}") do |f|
|
57
|
+
yield f.read if block_given?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# asserts that the given file exists
|
62
|
+
def assert_file_exists(path)
|
63
|
+
assert File.exist?("#{fake_rails_root}/#{path}"),
|
64
|
+
"The file '#{fake_rails_root}/#{path}' should exist"
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
ENV['RAILS_ENV'] = 'test'
|
2
|
+
ENV['RAILS_ROOT'] ||= File.dirname(__FILE__) + '/../../../..'
|
3
|
+
|
4
|
+
require 'test/unit'
|
5
|
+
require File.expand_path(File.join(ENV['RAILS_ROOT'], 'config/environment.rb'))
|
6
|
+
|
7
|
+
def load_schema
|
8
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
9
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
|
10
|
+
|
11
|
+
db_adapter = ENV['DB']
|
12
|
+
|
13
|
+
# no db passed, try one of these fine config-free DBs before bombing.
|
14
|
+
db_adapter ||=
|
15
|
+
begin
|
16
|
+
require 'rubygems'
|
17
|
+
require 'sqlite'
|
18
|
+
'sqlite'
|
19
|
+
rescue MissingSourceFile
|
20
|
+
begin
|
21
|
+
require 'sqlite3'
|
22
|
+
'sqlite3'
|
23
|
+
rescue MissingSourceFile
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
if db_adapter.nil?
|
28
|
+
raise "No DB Adapter selected. Pass the DB= option to pick one, or install Sqlite or Sqlite3."
|
29
|
+
end
|
30
|
+
|
31
|
+
ActiveRecord::Base.establish_connection(config[db_adapter])
|
32
|
+
load(File.dirname(__FILE__) + "/schema.rb")
|
33
|
+
require File.dirname(__FILE__) + '/../rails/init.rb'
|
34
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: s3_db_assets_backup
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Barnes
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-03-22 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: randomutterings@gmail.com
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files:
|
23
|
+
- README.rdoc
|
24
|
+
files:
|
25
|
+
- MIT-LICENSE
|
26
|
+
- Rakefile
|
27
|
+
- README.rdoc
|
28
|
+
- generators/assets_backup/assets_backup_generator.rb
|
29
|
+
- generators/assets_backup/templates/assets_backup.rake
|
30
|
+
- generators/assets_backup/templates/assets_backup_config.yml
|
31
|
+
- generators/assets_backup/templates/db_backup.rake
|
32
|
+
- generators/assets_backup/templates/load_assets_backup_config.rb
|
33
|
+
- generators/assets_backup/USAGE
|
34
|
+
- test/s3_db_assets_backup_test.rb
|
35
|
+
- test/test_helper.rb
|
36
|
+
has_rdoc: true
|
37
|
+
homepage: http://www.randomutterings.com/projects/s3_db_assets_backup
|
38
|
+
licenses: []
|
39
|
+
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: "0"
|
50
|
+
version:
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project:
|
60
|
+
rubygems_version: 1.3.5
|
61
|
+
signing_key:
|
62
|
+
specification_version: 3
|
63
|
+
summary: Generates rake tasks for backing up db and public folder to S3 bucket
|
64
|
+
test_files: []
|
65
|
+
|