snatchdb 1.0.0
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/bin/snatch +66 -0
- data/lib/snatch/handler.rb +15 -0
- data/lib/snatch/hash.rb +8 -0
- data/lib/snatch/session.rb +90 -0
- data/lib/snatch/version.rb +3 -0
- data/lib/snatch.rb +14 -0
- metadata +103 -0
data/bin/snatch
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
|
4
|
+
$LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
|
5
|
+
|
6
|
+
require 'rubygems'
|
7
|
+
require 'yaml'
|
8
|
+
require 'optparse'
|
9
|
+
require 'snatch'
|
10
|
+
|
11
|
+
SAMPLE_SCHEMA = <<END
|
12
|
+
---
|
13
|
+
host: YOUR_HOSTNAME
|
14
|
+
user: YOUR_SSH_USER
|
15
|
+
password: YOUR_SSH_PASSWORD
|
16
|
+
db_user: MYSQL_USER
|
17
|
+
db_password: MYSQL_PASSWORD
|
18
|
+
db_list:
|
19
|
+
- database1
|
20
|
+
- database2
|
21
|
+
END
|
22
|
+
|
23
|
+
optparse = OptionParser.new do |opts|
|
24
|
+
opts.banner = "Usage: snatch CONFIG.yml"
|
25
|
+
opts.on('-i', '--info', 'Display this information.') { puts opts ; exit }
|
26
|
+
opts.on('-v', '--version', 'Show version') { puts "Snatch v#{Snatch::VERSION}" ; exit }
|
27
|
+
opts.on('-n', '--new NAME', 'Create a new config file') do |name|
|
28
|
+
unless name =~ /^[a-z\d\_\-]{2,64}$/i
|
29
|
+
puts "Name should be in format: [A-Za-z0-9\-\_]{2,64}"
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
|
33
|
+
file = "#{Dir.pwd}/#{name}.yml"
|
34
|
+
if File.exists?(file)
|
35
|
+
puts "File already exists!" ; exit
|
36
|
+
end
|
37
|
+
|
38
|
+
File.open(file, 'w') { |f| f.write(SAMPLE_SCHEMA) }
|
39
|
+
puts "File #{file} has been created. Edit and snatch!" ; exit
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
begin
|
44
|
+
optparse.parse!
|
45
|
+
|
46
|
+
unless ARGV.empty?
|
47
|
+
file = File.expand_path(ARGV.shift)
|
48
|
+
unless File.exists?(file)
|
49
|
+
puts "File #{file} was not found!"
|
50
|
+
exit
|
51
|
+
end
|
52
|
+
|
53
|
+
config = YAML.load_file(file)
|
54
|
+
config.symbolize!
|
55
|
+
Snatch.run(config)
|
56
|
+
else
|
57
|
+
puts optparse
|
58
|
+
end
|
59
|
+
rescue OptionParser::InvalidOption, OptionParser::MissingArgument
|
60
|
+
puts optparse
|
61
|
+
exit
|
62
|
+
rescue Interrupt
|
63
|
+
puts "Interrupted."
|
64
|
+
rescue StandardError, Snatch::CredentialsError, Snatch::NoDatabaseError => ex
|
65
|
+
puts "ERROR: #{ex.message}"
|
66
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Snatch
|
2
|
+
class TransferHandler
|
3
|
+
def on_open(downloader, file)
|
4
|
+
puts "ftp: downloading: #{file.remote} -> #{file.local}"
|
5
|
+
end
|
6
|
+
|
7
|
+
def on_close(downloader, file)
|
8
|
+
puts "ftp: finished downloading #{File.basename(file.remote)}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def on_finish(downloader)
|
12
|
+
puts "ftp: file saved."
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/snatch/hash.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
module Snatch
|
2
|
+
class CredentialsError < Exception ; end
|
3
|
+
class NoDatabaseError < Exception ; end
|
4
|
+
|
5
|
+
class Session
|
6
|
+
attr_reader :config, :filename
|
7
|
+
|
8
|
+
def initialize(config)
|
9
|
+
@config = config
|
10
|
+
@ssh = nil
|
11
|
+
@filename = "#{@config[:host]}_#{Time.now.strftime("%Y%m%d%H%M%S")}.sql.gz"
|
12
|
+
end
|
13
|
+
|
14
|
+
def run!
|
15
|
+
connect
|
16
|
+
test
|
17
|
+
dump
|
18
|
+
download
|
19
|
+
cleanup
|
20
|
+
disconnect
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Connect to remote server
|
26
|
+
def connect
|
27
|
+
puts "ssh: connecting..."
|
28
|
+
begin
|
29
|
+
@ssh = Net::SSH.start(@config[:host], @config[:user],:password => @config[:password])
|
30
|
+
rescue Net::SSH::AuthenticationFailed
|
31
|
+
raise CredentialsError, 'Invalid SSH user or password'
|
32
|
+
end
|
33
|
+
puts "ssh: connected."
|
34
|
+
end
|
35
|
+
|
36
|
+
# Close ssh connection
|
37
|
+
def disconnect
|
38
|
+
@ssh.close
|
39
|
+
puts "ssh: disconnected."
|
40
|
+
end
|
41
|
+
|
42
|
+
# Check configuration options
|
43
|
+
def test
|
44
|
+
resp = @ssh.exec!("mysql --execute='SHOW DATABASES;' --user=#{@config[:db_user]} --password=#{@config[:db_password]}")
|
45
|
+
if resp =~ /ERROR 1045/
|
46
|
+
raise CredentialsError, 'Invalid MySQL user or password'
|
47
|
+
end
|
48
|
+
|
49
|
+
list = resp.split("\n").map { |s| s.strip }.select { |s| !s.empty? }.drop(1)
|
50
|
+
diff = @config[:db_list] - list
|
51
|
+
|
52
|
+
unless diff.empty?
|
53
|
+
raise NoDatabaseError, "Database(s) not found: #{diff.join(', ')}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Generate MySQL database dump
|
58
|
+
def dump
|
59
|
+
cmd = []
|
60
|
+
cmd << "--user=#{@config[:db_user]}"
|
61
|
+
cmd << "--password=#{@config[:db_password]}" unless @config[:db_password].strip.empty?
|
62
|
+
cmd << "--databases #{@config[:db_list].join(' ')}"
|
63
|
+
cmd << "--add-drop-database"
|
64
|
+
cmd << "--add-drop-table"
|
65
|
+
cmd << "--compact"
|
66
|
+
cmd = "mysqldump #{cmd.join(' ')} | gzip --best > /tmp/#{filename}"
|
67
|
+
|
68
|
+
puts "mysql: creating a dump..."
|
69
|
+
@ssh.exec!(cmd)
|
70
|
+
puts "mysql: done."
|
71
|
+
end
|
72
|
+
|
73
|
+
# Cleanup dump
|
74
|
+
def cleanup
|
75
|
+
@ssh.exec!("rm -f /tmp/#{filename}")
|
76
|
+
end
|
77
|
+
|
78
|
+
# Fetch remote dump to local filesystem
|
79
|
+
def download
|
80
|
+
Net::SFTP.start(@config[:host], @config[:user], :password => @config[:password]) do |sftp|
|
81
|
+
t = sftp.download!(
|
82
|
+
"/tmp/#{filename}", # Remote file
|
83
|
+
"#{Dir.pwd}/#{filename}", # Local file
|
84
|
+
:progress => TransferHandler.new # Handler
|
85
|
+
)
|
86
|
+
t.wait
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
data/lib/snatch.rb
ADDED
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: snatchdb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Dan Sosedoff
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-02-09 00:00:00 -06:00
|
19
|
+
default_executable: snatch
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: net-ssh
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - "="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 63
|
30
|
+
segments:
|
31
|
+
- 2
|
32
|
+
- 0
|
33
|
+
- 24
|
34
|
+
version: 2.0.24
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: net-sftp
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - "="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 5
|
46
|
+
segments:
|
47
|
+
- 2
|
48
|
+
- 0
|
49
|
+
- 5
|
50
|
+
version: 2.0.5
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
description: Remote database downloader
|
54
|
+
email: dan.sosedoff@gmail.com
|
55
|
+
executables:
|
56
|
+
- snatch
|
57
|
+
extensions: []
|
58
|
+
|
59
|
+
extra_rdoc_files: []
|
60
|
+
|
61
|
+
files:
|
62
|
+
- bin/snatch
|
63
|
+
- lib/snatch.rb
|
64
|
+
- lib/snatch/version.rb
|
65
|
+
- lib/snatch/hash.rb
|
66
|
+
- lib/snatch/handler.rb
|
67
|
+
- lib/snatch/session.rb
|
68
|
+
has_rdoc: true
|
69
|
+
homepage: http://github.com/sosedoff/snatch
|
70
|
+
licenses: []
|
71
|
+
|
72
|
+
post_install_message:
|
73
|
+
rdoc_options: []
|
74
|
+
|
75
|
+
require_paths:
|
76
|
+
- lib
|
77
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
hash: 3
|
83
|
+
segments:
|
84
|
+
- 0
|
85
|
+
version: "0"
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
92
|
+
segments:
|
93
|
+
- 0
|
94
|
+
version: "0"
|
95
|
+
requirements: []
|
96
|
+
|
97
|
+
rubyforge_project:
|
98
|
+
rubygems_version: 1.4.1
|
99
|
+
signing_key:
|
100
|
+
specification_version: 3
|
101
|
+
summary: Snatch is a remote database downloader via SSH protocol
|
102
|
+
test_files: []
|
103
|
+
|