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 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,6 @@
1
+ config_file = "#{RAILS_ROOT}/config/assets_backup_config.yml"
2
+ if FileTest.exists?(config_file)
3
+ APP_CONFIG = YAML.load_file(config_file)
4
+ else
5
+ raise "Can't find assets_backup_config.yml"
6
+ 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
@@ -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
+