xaviershay-db2s3 0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
+