mys3ql 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in mys3ql.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,70 @@
1
+ # mys3ql = mysql + s3
2
+
3
+ Simple backup of your MySql database onto Amazon S3.
4
+
5
+
6
+ ## Quick start
7
+
8
+ Install and configure as below.
9
+
10
+ To perform a full backup:
11
+
12
+ $ mys3ql full
13
+
14
+ If you are using MySql's binary logging (see below), back up the binary logs like this:
15
+
16
+ $ mys3ql incremental
17
+
18
+
19
+ ## Installation
20
+
21
+ First install the gem:
22
+
23
+ $ gem install mys3ql
24
+
25
+ Second, create your `~/.mys3ql` config file:
26
+
27
+ mysql:
28
+ # Database to back up
29
+ database: aircms_production
30
+ # MySql credentials
31
+ user: root
32
+ password:
33
+ # Path (with trailing slash) to mysql commands e.g. mysqldump
34
+ bin_path: /usr/local/mysql/bin/
35
+ # If you are using MySql binary logging:
36
+ # Path to the binary logs, should match the bin_log option in your my.cnf.
37
+ # Comment out if you are not using mysql binary logging
38
+ bin_log: /Users/andy/Desktop/mysql-bin
39
+
40
+ s3:
41
+ # S3 credentials
42
+ access_key_id: XXXXXXXXXXXXXXXXXXXX
43
+ secret_access_key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
44
+ # Bucket in which to store your backups
45
+ bucket: db_backups
46
+
47
+
48
+ ## Binary logging
49
+
50
+ To use incremental backups you need to enable binary logging by making sure that the MySQL config file (my.cnf) has the following line in it:
51
+
52
+ log_bin = /var/db/mysql/binlog/mysql-bin
53
+
54
+ The MySQL user needs to have the RELOAD and the SUPER privileges, these can be granted with the following SQL commands (which need to be executed as the MySQL root user):
55
+
56
+ GRANT RELOAD ON *.* TO 'user_name'@'%' IDENTIFIED BY 'password';
57
+ GRANT SUPER ON *.* TO 'user_name'@'%' IDENTIFIED BY 'password';
58
+
59
+
60
+ ## Inspiration
61
+
62
+ Marc-André Cournoyer's [mysql_s3_backup](https://github.com/macournoyer/mysql_s3_backup).
63
+
64
+
65
+ ## To Do
66
+
67
+ - tests ;)
68
+ - restore (pull latest dump, pull bin files, pipe dump into mysql, pipe binfiles into mysql)
69
+ - remove old dump files (s3)
70
+ - fix verbosity/debugging flag
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/bin/mys3ql ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby-local-exec
2
+
3
+ lib_dir = File.join(File.dirname(__FILE__), '..', 'lib')
4
+ $LOAD_PATH.unshift lib_dir if File.directory?(lib_dir)
5
+
6
+ require 'mys3ql'
7
+
8
+ Mys3ql::Conductor.run ARGV
data/lib/mys3ql.rb ADDED
@@ -0,0 +1,2 @@
1
+ require 'mys3ql/conductor'
2
+ require 'mys3ql/version'
@@ -0,0 +1,46 @@
1
+ require 'mys3ql/config'
2
+ require 'mys3ql/mysql'
3
+ require 'mys3ql/s3'
4
+
5
+ module Mys3ql
6
+ class Conductor
7
+
8
+ def self.run(args)
9
+ abort usage unless args.length == 1 && %w[ full inc ].include?(args.first)
10
+ conductor = Conductor.new
11
+
12
+ command = args.first
13
+ if command == 'full'
14
+ conductor.full
15
+ else
16
+ conductor.incremental
17
+ end
18
+ end
19
+
20
+ def initialize
21
+ @config = Config.new
22
+ @mysql = Mysql.new @config
23
+ @s3 = S3.new @config
24
+ end
25
+
26
+ def full
27
+ @mysql.dump
28
+ @s3.push_dump_to_s3 @mysql.dump_file
29
+ @mysql.clean_up_dump
30
+ @s3.delete_bin_logs_on_s3
31
+ end
32
+
33
+ def incremental
34
+ @s3.push_bin_logs_to_s3
35
+ end
36
+
37
+ def self.usage
38
+ <<END
39
+ usage:
40
+ mys3ql full - full backup, push to S3
41
+ mys3ql incremental - push bin logs to S3
42
+ END
43
+ end
44
+
45
+ end
46
+ end
@@ -0,0 +1,67 @@
1
+ require 'yaml'
2
+
3
+ module Mys3ql
4
+ class Config
5
+
6
+ def initialize
7
+ @config = YAML.load_file config_file
8
+ rescue Errno::ENOENT
9
+ $stderr.puts "missing ~/.mys3ql config file"
10
+ exit 1
11
+ end
12
+
13
+ #
14
+ # MySQL
15
+ #
16
+
17
+ def user
18
+ mysql['user']
19
+ end
20
+
21
+ def password
22
+ mysql['password']
23
+ end
24
+
25
+ def database
26
+ mysql['database']
27
+ end
28
+
29
+ def bin_path
30
+ mysql['bin_path']
31
+ end
32
+
33
+ def bin_log
34
+ mysql['bin_log']
35
+ end
36
+
37
+ #
38
+ # S3
39
+ #
40
+
41
+ def access_key_id
42
+ s3['access_key_id']
43
+ end
44
+
45
+ def secret_access_key
46
+ s3['secret_access_key']
47
+ end
48
+
49
+ def bucket
50
+ s3['bucket']
51
+ end
52
+
53
+ private
54
+
55
+ def mysql
56
+ @config['mysql']
57
+ end
58
+
59
+ def s3
60
+ @config['s3']
61
+ end
62
+
63
+ def config_file
64
+ File.join "#{ENV['HOME']}", '.mys3ql'
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,40 @@
1
+ require 'mys3ql/shell'
2
+
3
+ module Mys3ql
4
+ class Mysql
5
+ include Shell
6
+
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ def dump
12
+ cmd = "#{@config.bin_path}mysqldump -u'#{@config.user}'"
13
+ cmd += " -p'#{@config.password}'" if @config.password
14
+ cmd += " --quick --single-transaction --create-options"
15
+ cmd += ' --flush-logs --master-data=2 --delete-master-logs' if binary_logging?
16
+ cmd += " #{@config.database} | gzip > #{dump_file}"
17
+ execute cmd
18
+ end
19
+
20
+ def clean_up_dump
21
+ File.delete dump_file
22
+ debug "deleted #{dump_file}"
23
+ end
24
+
25
+ def dump_file
26
+ @dump_file ||= "#{timestamp}.sql.gz"
27
+ end
28
+
29
+ private
30
+
31
+ def timestamp
32
+ Time.now.utc.strftime "%Y%m%d%H%M"
33
+ end
34
+
35
+ def binary_logging?
36
+ @config.bin_log && @config.bin_log.length > 0
37
+ end
38
+
39
+ end
40
+ end
data/lib/mys3ql/s3.rb ADDED
@@ -0,0 +1,87 @@
1
+ require 'mys3ql/shell'
2
+ require 'fog'
3
+
4
+ module Mys3ql
5
+ class S3
6
+ include Shell
7
+
8
+ def initialize(config)
9
+ @config = config
10
+ end
11
+
12
+ def push_dump_to_s3(dump_file)
13
+ key = "#{dumps_prefix}/#{dump_file}"
14
+ copy_key = "#{dumps_prefix}/latest.sql.gz"
15
+ s3_file = push_to_s3 dump_file, key
16
+ if s3_file
17
+ s3_file.copy @config.bucket, copy_key
18
+ debug "copied #{key} to #{copy_key}"
19
+ end
20
+ end
21
+
22
+ def push_bin_logs_to_s3
23
+ if bin_logs_exist?
24
+ Dir["#{@config.bin_log}/*"].each do |file|
25
+ name = File.basename file
26
+ key = "#{bin_logs_prefix}/#{name}"
27
+ push_to_s3 file, key
28
+ end
29
+ end
30
+ end
31
+
32
+ def delete_bin_logs_on_s3
33
+ bucket.files.all(:prefix => "#{bin_logs_prefix}").each do |file|
34
+ file.destroy
35
+ debug "destroyed #{file.key}"
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def s3
42
+ @s3 ||= begin
43
+ s = Fog::Storage.new(
44
+ :provider => 'AWS',
45
+ :aws_secret_access_key => @config.secret_access_key,
46
+ :aws_access_key_id => @config.access_key_id
47
+ )
48
+ debug 'connected to s3'
49
+ s
50
+ end
51
+ end
52
+
53
+ def bucket
54
+ @directory ||= begin
55
+ d = s3.directories.get @config.bucket # assume bucket exists
56
+ debug "opened bucket #{@config.bucket}"
57
+ d
58
+ end
59
+ end
60
+
61
+ # returns Fog::Storage::AWS::File if we pushed, nil otherwise.
62
+ def push_to_s3(local_file_name, s3_key)
63
+ unless bucket.files.head(s3_key)
64
+ s3_file = bucket.files.create(
65
+ :key => s3_key,
66
+ :body => File.open(local_file_name),
67
+ :public => false
68
+ )
69
+ debug "pushed #{local_file_name} to #{s3_key}"
70
+ s3_file
71
+ end
72
+ end
73
+
74
+ def dumps_prefix
75
+ "#{@config.database}/dumps"
76
+ end
77
+
78
+ def bin_logs_prefix
79
+ "#{@config.database}/bin_logs"
80
+ end
81
+
82
+ def bin_logs_exist?
83
+ @config.bin_log && @config.bin_log.length > 0 && File.exist?(@config.bin_log)
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,22 @@
1
+ module Mys3ql
2
+ class ShellCommandError < RuntimeError ; end
3
+
4
+ module Shell
5
+ def execute(command)
6
+ log command
7
+ result = `#{command}`
8
+ log "==> #{result}"
9
+ raise ShellCommandError, "error (exit status #{$?.exitstatus}): #{command} ==> #{result}: #{$?}" unless $?.success?
10
+ result
11
+ end
12
+
13
+ def log(message)
14
+ puts message if debugging?
15
+ end
16
+
17
+ def debugging?
18
+ true
19
+ end
20
+
21
+ end
22
+ end
@@ -0,0 +1,3 @@
1
+ module Mys3ql
2
+ VERSION = "0.0.1"
3
+ end
data/mys3ql.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "mys3ql/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "mys3ql"
7
+ s.version = Mys3ql::VERSION
8
+ s.authors = ["Andy Stewart"]
9
+ s.email = ["boss@airbladesoftware.com"]
10
+ s.homepage = 'https://github.com/airblade/mys3ql'
11
+ s.summary = 'Simple backup of your MySql database onto Amazon S3.'
12
+ s.description = s.summary
13
+
14
+ s.rubyforge_project = "mys3ql"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'fog', '~> 1.0.0'
22
+ s.add_development_dependency 'rake'
23
+ end
metadata ADDED
@@ -0,0 +1,109 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: mys3ql
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Andy Stewart
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-10-26 00:00:00 +02:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: fog
23
+ prerelease: false
24
+ version_requirements: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 1
32
+ - 0
33
+ - 0
34
+ version: 1.0.0
35
+ type: :runtime
36
+ requirement: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: rake
39
+ prerelease: false
40
+ version_requirements: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 3
46
+ segments:
47
+ - 0
48
+ version: "0"
49
+ type: :development
50
+ requirement: *id002
51
+ description: Simple backup of your MySql database onto Amazon S3.
52
+ email:
53
+ - boss@airbladesoftware.com
54
+ executables:
55
+ - mys3ql
56
+ extensions: []
57
+
58
+ extra_rdoc_files: []
59
+
60
+ files:
61
+ - .gitignore
62
+ - Gemfile
63
+ - README.md
64
+ - Rakefile
65
+ - bin/mys3ql
66
+ - lib/mys3ql.rb
67
+ - lib/mys3ql/conductor.rb
68
+ - lib/mys3ql/config.rb
69
+ - lib/mys3ql/mysql.rb
70
+ - lib/mys3ql/s3.rb
71
+ - lib/mys3ql/shell.rb
72
+ - lib/mys3ql/version.rb
73
+ - mys3ql.gemspec
74
+ has_rdoc: true
75
+ homepage: https://github.com/airblade/mys3ql
76
+ licenses: []
77
+
78
+ post_install_message:
79
+ rdoc_options: []
80
+
81
+ require_paths:
82
+ - lib
83
+ required_ruby_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ hash: 3
89
+ segments:
90
+ - 0
91
+ version: "0"
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ hash: 3
98
+ segments:
99
+ - 0
100
+ version: "0"
101
+ requirements: []
102
+
103
+ rubyforge_project: mys3ql
104
+ rubygems_version: 1.6.2
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Simple backup of your MySql database onto Amazon S3.
108
+ test_files: []
109
+