xaviershay-db2s3 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
@@ -0,0 +1,31 @@
1
+ DB2S3 - A rails plugin to backup Mysql to Amazon S3
2
+ ---------------------------------------------------
3
+
4
+ Dependencies:
5
+ gem install aws-s3
6
+
7
+ Usage:
8
+ ./script/plugin install git://github.com/xaviershay/db2s3.git
9
+ # In config/initializers/db2s3.rb
10
+ DB2S3::Config.instance_eval do
11
+ S3 = {
12
+ :access_key_id => 'yourkey',
13
+ :secret_access_key => 'yoursecretkey',
14
+ :bucket => 'yourapp-db-backup'
15
+ }
16
+ end
17
+ # DB credentials are read from your rails environment
18
+
19
+ # Add to your crontab or whatever
20
+ rake db2s3:backup:full
21
+ rake db2s3:backup:incremental # Unimplemented
22
+
23
+ # Handy tasks
24
+ rake db2s3:metrics # Estimated costs
25
+ rake db2s3:backup:restore # You should be testing this regularly
26
+
27
+ Caveats:
28
+ Currently only stores the latest backup
29
+
30
+ Kudos:
31
+ http://github.com/pauldowman/blog_code_examples/tree/master/mysql_s3_backup
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ desc "Create test database"
2
+ task :create_test_db do
3
+ `mysqladmin -u root create db2s3_unittest`
4
+ end
data/db2s3.gemspec ADDED
@@ -0,0 +1,46 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{db2s3}
5
+ s.version = "0.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Xavier Shay"]
9
+ s.date = %q{2009-03-08}
10
+ s.description = %q{db2s3 provides rake tasks for backing up and restoring your DB to S3}
11
+ s.email = %q{contact@rhnh.net}
12
+ s.files = %w(
13
+ README
14
+ Rakefile
15
+ db2s3.gemspec
16
+ init.rb
17
+ lib
18
+ lib/db2s3.rb
19
+ rails
20
+ rails/init.rb
21
+ spec
22
+ spec/db2s3_spec.rb
23
+ spec/mysql_drop_schema.sql
24
+ spec/mysql_schema.sql
25
+ spec/s3_config.example.rb
26
+ spec/s3_config.rb
27
+ spec/spec_helper.rb
28
+ tasks
29
+ tasks/tasks.rake
30
+ )
31
+ s.has_rdoc = false
32
+ s.homepage = %q{http://github.com/xaviershay/db2s3}
33
+ #s.rdoc_options = ["--inline-source", "--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ #s.rubyforge_project = %q{grit}
36
+ s.rubygems_version = %q{1.3.0}
37
+ s.summary = %q{db2s3 provides rake tasks for backing up and restoring your DB to S3}
38
+
39
+ # TODO: WTF does this do
40
+ if s.respond_to? :specification_version then
41
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
42
+ s.specification_version = 2
43
+ end
44
+
45
+ s.add_dependency(%q<aws-s3>, [">= 0.5.1"])
46
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init"
data/lib/db2s3.rb ADDED
@@ -0,0 +1,107 @@
1
+ require 'aws/s3'
2
+
3
+ class DB2S3
4
+ class Config
5
+ end
6
+
7
+ def initialize
8
+ end
9
+
10
+ def full_backup
11
+ store.store("dump-#{db_credentials[:database]}.sql.gz", open(dump_db.path))
12
+ end
13
+
14
+ def restore
15
+ file = store.fetch("dump-#{db_credentials[:database]}.sql.gz")
16
+ run "gunzip -c #{file.path} | mysql #{mysql_options}"
17
+ end
18
+
19
+ def metrics
20
+ dump_file = dump_db
21
+
22
+ storage_dollars_per_byte_per_month = 0.15 / 1024.0 / 1024.0 / 1024.0
23
+ transfer_dollars_per_byte_per_month = 0.10 / 1024.0 / 1024.0 / 1024.0
24
+ full_dumps_per_month = 30
25
+
26
+ storage_cost = dump_file.size * storage_dollars_per_byte_per_month
27
+ transfer_cost = dump_file.size * full_dumps_per_month * transfer_dollars_per_byte_per_month
28
+
29
+ {
30
+ :db_size => dump_file.size,
31
+ :storage_cost => storage_cost,
32
+ :transfer_cost => transfer_cost,
33
+ :total_cost => storage_cost + transfer_cost,
34
+ :full_backups_per_month => full_dumps_per_month
35
+ }
36
+ end
37
+
38
+ private
39
+
40
+ def dump_db
41
+ dump_file = Tempfile.new("dump")
42
+
43
+ #cmd = "mysqldump --quick --single-transaction --create-options -u#{db_credentials[:user]} --flush-logs --master-data=2 --delete-master-logs"
44
+ cmd = "mysqldump --quick --single-transaction --create-options #{mysql_options}"
45
+ cmd += " | gzip > #{dump_file.path}"
46
+ run(cmd)
47
+
48
+ dump_file
49
+ end
50
+
51
+ def mysql_options
52
+ cmd = " -u#{db_credentials[:user]} "
53
+ cmd += " -p'#{db_credentials[:password]}'" unless db_credentials[:password].nil?
54
+ cmd += " #{db_credentials[:database]}"
55
+ end
56
+
57
+ def store
58
+ @store ||= S3Store.new
59
+ end
60
+
61
+ def run(command)
62
+ result = system(command)
63
+ raise("error, process exited with status #{$?.exitstatus}") unless result
64
+ end
65
+
66
+ def db_credentials
67
+ ActiveRecord::Base.connection.instance_eval { @config } # Dodgy!
68
+ end
69
+
70
+ class S3Store
71
+ def initialize
72
+ @connected = false
73
+ end
74
+
75
+ def ensure_connected
76
+ return if @connected
77
+ AWS::S3::Base.establish_connection!(DB2S3::Config::S3.slice(:access_key_id, :secret_access_key).merge(:use_ssl => true))
78
+ AWS::S3::Bucket.create(bucket)
79
+ @connected = true
80
+ end
81
+
82
+ def store(file_name, file)
83
+ ensure_connected
84
+ AWS::S3::S3Object.store(file_name, file, bucket)
85
+ end
86
+
87
+ def fetch(file_name)
88
+ ensure_connected
89
+ AWS::S3::S3Object.find(file_name, bucket)
90
+
91
+ file = Tempfile.new("dump")
92
+ open(file.path, 'w') do |f|
93
+ AWS::S3::S3Object.stream(file_name, bucket) do |chunk|
94
+ f.write chunk
95
+ end
96
+ end
97
+ file
98
+ end
99
+
100
+ private
101
+
102
+ def bucket
103
+ DB2S3::Config::S3[:bucket]
104
+ end
105
+ end
106
+
107
+ end
data/rails/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/lib/db2s3')
@@ -0,0 +1,38 @@
1
+ require File.dirname(__FILE__) + '/spec_helper'
2
+
3
+ describe 'db2s3' do
4
+ def load_schema
5
+ `cat '#{File.dirname(__FILE__) + '/mysql_schema.sql'}' | mysql -u #{DBConfig[:user]} #{DBConfig[:database]}`
6
+ end
7
+
8
+ def drop_schema
9
+ `cat '#{File.dirname(__FILE__) + '/mysql_drop_schema.sql'}' | mysql -u #{DBConfig[:user]} #{DBConfig[:database]}`
10
+ end
11
+
12
+ class Person < ActiveRecord::Base
13
+ end
14
+
15
+ it 'can save and restore a backup to S3' do
16
+ db2s3 = DB2S3.new
17
+ load_schema
18
+ Person.create!(:name => "Baxter")
19
+ db2s3.full_backup
20
+ drop_schema
21
+ db2s3.restore
22
+ Person.find_by_name("Baxter").should_not be_nil
23
+ end
24
+
25
+ it 'provides estimated metrics' do
26
+ db2s3 = DB2S3.new
27
+ # 1 GB DB
28
+ db2s3.stub!(:dump_db).and_return(stub("dump file", :size => 1024 * 1024 * 1024))
29
+ metrics = db2s3.metrics
30
+ metrics.should == {
31
+ :storage_cost => 0.15, # 15c/GB-Month, we're only storing one backup
32
+ :transfer_cost => 3.0, # 10c/GB-Month * 30 backups
33
+ :db_size => 1024 * 1024 * 1024, # 1 GB
34
+ :total_cost => 3.15,
35
+ :full_backups_per_month => 30 # Default 1 backup/day
36
+ }
37
+ end
38
+ end
@@ -0,0 +1 @@
1
+ DROP TABLE IF EXISTS people;
@@ -0,0 +1,4 @@
1
+ DROP TABLE IF EXISTS people;
2
+ CREATE TABLE people (
3
+ name VARCHAR(255) NULL
4
+ );
@@ -0,0 +1,7 @@
1
+ DB2S3::Config.instance_eval do
2
+ S3 = {
3
+ :access_key_id => 'yourkey',
4
+ :secret_access_key => 'yoursecretkey',
5
+ :bucket => 'db2s3_test'
6
+ }
7
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec'
2
+ require 'activerecord'
3
+ require File.dirname(__FILE__) + '/../lib/db2s3'
4
+ require File.dirname(__FILE__) + '/s3_config.rb'
5
+
6
+ DBConfig = {
7
+ :adapter => "mysql",
8
+ :encoding => "utf8",
9
+ :database => 'db2s3_unittest',
10
+ :user => "root"
11
+ }
12
+
13
+ ActiveRecord::Base.configurations = { 'production' => DBConfig }
14
+ ActiveRecord::Base.establish_connection(:production)
data/tasks/tasks.rake ADDED
@@ -0,0 +1,29 @@
1
+ namespace :db2s3 do
2
+ namespace :backup do
3
+ desc "Save a full back to S3"
4
+ task :full => :environment do
5
+ DB2S3.new.full_backup
6
+ end
7
+ end
8
+
9
+ desc "Provide estimated costs for backing up your DB to S3"
10
+ task :metrics => :environment do
11
+ def format_size(size)
12
+ units = %w{B KB MB GB TB}
13
+ e = (Math.log(size)/Math.log(1024)).floor
14
+ s = "%.3f" % (size.to_f / 1024**e)
15
+ s.sub(/\.?0*$/, units[e])
16
+ end
17
+
18
+ metrics = DB2S3.new.metrics
19
+ puts <<-EOS
20
+ Estimates only, does not take into account metadata overhead
21
+
22
+ DB Size: #{format_size(metrics[:db_size])}
23
+ Full backups/month: #{metrics[:full_backups_per_month]}
24
+ Storage Cost $US: #{metrics[:storage_cost]}
25
+ Transfer Cost $US: #{metrics[:transfer_cost]}
26
+ Total Cost $US: #{metrics[:total_cost]}
27
+ EOS
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,78 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: xaviershay-db2s3
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.2"
5
+ platform: ruby
6
+ authors:
7
+ - Xavier Shay
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-08 00:00:00 -08:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: aws-s3
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.5.1
24
+ version:
25
+ description: db2s3 provides rake tasks for backing up and restoring your DB to S3
26
+ email: contact@rhnh.net
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - README
35
+ - Rakefile
36
+ - db2s3.gemspec
37
+ - init.rb
38
+ - lib
39
+ - lib/db2s3.rb
40
+ - rails
41
+ - rails/init.rb
42
+ - spec
43
+ - spec/db2s3_spec.rb
44
+ - spec/mysql_drop_schema.sql
45
+ - spec/mysql_schema.sql
46
+ - spec/s3_config.example.rb
47
+ - spec/s3_config.rb
48
+ - spec/spec_helper.rb
49
+ - tasks
50
+ - tasks/tasks.rake
51
+ has_rdoc: false
52
+ homepage: http://github.com/xaviershay/db2s3
53
+ post_install_message:
54
+ rdoc_options: []
55
+
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.2.0
74
+ signing_key:
75
+ specification_version: 2
76
+ summary: db2s3 provides rake tasks for backing up and restoring your DB to S3
77
+ test_files: []
78
+