dbget_client 0.1.4 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
data/bin/dbget CHANGED
@@ -3,4 +3,4 @@
3
3
  DBGET_LIB_PATH = File.join(File.dirname(__FILE__), '../lib')
4
4
  require File.join(DBGET_LIB_PATH, 'dbget')
5
5
 
6
- DBGet::Runner.boot(ARGV, 'mysql')
6
+ DBGet::Runner.new.run!(ARGV, 'mysql')
@@ -3,4 +3,4 @@
3
3
  DBGET_LIB_PATH = File.join(File.dirname(__FILE__), '../lib')
4
4
  require File.join(DBGET_LIB_PATH, 'dbget')
5
5
 
6
- DBGet::Runner.boot(ARGV, 'mongo')
6
+ DBGet::Runner.new.run!(ARGV, 'mongo')
@@ -1,17 +1,15 @@
1
1
  require 'fileutils'
2
2
  require 'yaml'
3
- require 'zlib'
4
3
  require 'optparse'
5
4
 
6
5
  DBGET_LIB_ROOT = File.expand_path('../dbget', __FILE__)
7
6
  require File.join(DBGET_LIB_ROOT, 'version')
8
7
 
9
8
  module DBGet
10
- autoload :Initializer, File.join(DBGET_LIB_ROOT, 'initializer')
11
- autoload :DBDump, File.join(DBGET_LIB_ROOT, 'db_dump')
12
- autoload :Loaders, File.join(DBGET_LIB_ROOT, 'loaders')
9
+ autoload :Config, File.join(DBGET_LIB_ROOT, 'config')
10
+ autoload :Connector, File.join(DBGET_LIB_ROOT, 'connector')
13
11
  autoload :Constants, File.join(DBGET_LIB_ROOT, 'constants')
14
- autoload :ConfigLoader, File.join(DBGET_LIB_ROOT, 'config_loader')
12
+ autoload :Controller, File.join(DBGET_LIB_ROOT, 'controller')
15
13
  autoload :Runner, File.join(DBGET_LIB_ROOT, 'runner')
16
14
  autoload :Utils, File.join(DBGET_LIB_ROOT, 'utils')
17
15
  end
@@ -0,0 +1,14 @@
1
+ require 'singleton'
2
+
3
+ module DBGet
4
+ class Config < Hash
5
+ include Singleton
6
+
7
+ def self.load_from_yaml(yaml_path)
8
+ config = self.instance
9
+ config.clear
10
+ config.merge!(YAML.load_file(yaml_path))
11
+ end
12
+ end
13
+ end
14
+
@@ -0,0 +1,57 @@
1
+ require 'net/ssh'
2
+
3
+ module DBGet
4
+ class Connector
5
+ include Utils
6
+ include Constants
7
+
8
+ attr_accessor :collections
9
+ attr_reader :db, :db_path
10
+ attr_reader :clean, :verbose
11
+
12
+ def initialize(database, config, options)
13
+ @db = database
14
+ @options = Utils.stringify(options)
15
+ @config = config.merge!(@options)
16
+ @login = @config['login']
17
+ @db_type = @options['db_type']
18
+ @server = @config['server']
19
+ @date = @config['date']
20
+ @clean = @config['clean']
21
+ @verbose = @config['verbose']
22
+ @collections = @config['collections']
23
+ @custom_name = @config['name']
24
+ @append_date = @config['append_date']
25
+ @ssh_params = init_ssh_params
26
+ end
27
+
28
+ def send_data!
29
+ user, host = @config['login'].split('@')
30
+
31
+ Net::SSH.start(host, user) do |ssh|
32
+
33
+ channel = ssh.open_channel do |ch|
34
+ ch.exec(@ssh_params) do |ch, success|
35
+ raise "SSH connection failure." unless success
36
+
37
+ ch.on_data do |c,data|
38
+ $stdout.puts data
39
+ end
40
+
41
+ ch.on_extended_data do |c, type, data|
42
+ $stderr.print data
43
+ end
44
+
45
+ end
46
+ channel.wait
47
+
48
+ end
49
+ end
50
+ end
51
+
52
+ def init_ssh_params
53
+ "%s db=%s db_type=%s server=%s date=%s clean=%s verbose=%s collections=%s custom_name=%s append_date=%s" %
54
+ [@login, @db, @db_type, @server, @date, @clean, @verbose, @collections, @custom_name, @append_date]
55
+ end
56
+ end
57
+ end
@@ -1,6 +1,5 @@
1
1
  module DBGet
2
2
  module Constants
3
3
  DBGET_CONFIG_FILE = 'dbget.yml'
4
- MONGO_FILE_EXT = '.bson'
5
4
  end
6
5
  end
@@ -0,0 +1,43 @@
1
+ module DBGet
2
+ class Controller
3
+ include Constants
4
+
5
+ attr_reader :connector, :config, :databases, :options
6
+
7
+ def initialize(databases, options)
8
+ @databases = databases
9
+ @options = options
10
+ @connections = []
11
+ end
12
+
13
+ def boot
14
+ load_dbget_config
15
+ @config = DBGet::Config.instance
16
+ store_connections
17
+ end
18
+
19
+ def store_connections
20
+ @databases.each do |database|
21
+ @connections << Connector.new(database, @config, @options)
22
+ end
23
+ end
24
+
25
+ def send_data!
26
+ @connections.each do |connection|
27
+ connection.send_data!
28
+ end
29
+ end
30
+
31
+ protected
32
+
33
+ def load_dbget_config
34
+ config_path = File.join(@options[:dbget_path], DBGET_CONFIG_FILE)
35
+
36
+ if File.exists?(config_path)
37
+ DBGet::Config.load_from_yaml(config_path)
38
+ else
39
+ raise "Cannot find #{config_path}!"
40
+ end
41
+ end
42
+ end
43
+ end
@@ -1,58 +1,47 @@
1
1
  module DBGet
2
2
  class Runner
3
- def self.boot(args, dbtype)
4
- DBGet::Constants.const_set("MYSQL_CMD", `which mysql 2>/dev/null`.strip)
5
- DBGet::Constants.const_set("SSH_CMD", `which ssh 2>/dev/null`.strip)
6
- DBGet::Constants.const_set("MONGORESTORE_CMD", `which mongorestore 2>/dev/null`.strip)
7
- DBGet::Constants.const_set("FIND_CMD", `which find 2>/dev/null`.strip)
8
- DBGet::Constants.const_set("TAR_CMD", `which tar 2>/dev/null`.strip)
9
-
10
- self.new(args, dbtype)
3
+ def initialize
4
+ @options = {}
5
+ set_default_options
6
+ @optparse = init_option_parser
7
+ @args = nil
11
8
  end
12
9
 
13
- def initialize(args, dbtype)
14
- options = {}
15
- options[:append_date] = false
16
- options[:verbose] = false
17
-
10
+ def init_option_parser
18
11
  optparse = OptionParser.new do |opts|
19
12
  opts.banner = "Usage: dbget [options] db1 db2 ...\n"
20
13
  opts.separator "Options:"
21
14
 
22
15
  opts.on('-d', '--date DATE', 'Date of database dump (yyyy-mm-dd).') do |date|
23
- options[:date] = date
16
+ @options[:date] = date
24
17
  end
25
18
 
26
19
  opts.on('-c', '--clean', 'Drops the database before dumping') do
27
- options[:clean] = true
28
- end
29
-
30
- opts.on('-f', '--force', 'Force the use of dbget in production.') do
31
- options[:force] = true
20
+ @options[:clean] = true
32
21
  end
33
22
 
34
- opts.on('-n', '--name NAME', 'Explicitly declare a database name for dumping.') do |name|
35
- options[:opt_db_name] = name
36
- end
37
-
38
- opts.on('-i', '--key KEY', 'Specify ssh connection key') do |key|
39
- options[:key] = key
23
+ opts.on('-k', '--key KEY', 'Specify ssh connection key') do |key|
24
+ @options[:key] = key
40
25
  end
41
26
 
42
27
  opts.on('-s', '--server SERVER', 'Specify the server that contained the database.') do |server|
43
- options[:server] = server
28
+ @options[:server] = server
44
29
  end
45
30
 
46
31
  opts.on('-a', '--append-date', 'Append the given date as suffix') do
47
- options[:append_date] = true
32
+ @options[:append_date] = true
48
33
  end
49
34
 
50
- opts.on('--collections COLLECTION', Array, 'Only dump specific mongodb collections separated by comma') do |collection|
51
- options[:collections] = collection
35
+ opts.on('--collections COLLECTION', 'Only dump specific mongodb collections separated by comma') do |collection|
36
+ @options[:collections] = collection
37
+ end
38
+
39
+ opts.on('--n', '--name NAME', 'Specify a custom name/key for databases') do |name|
40
+ @options[:name] = name
52
41
  end
53
42
 
54
43
  opts.on('-v', '--verbose', 'Execute NERD mode!') do
55
- options[:verbose] = true
44
+ @options[:verbose] = true
56
45
  end
57
46
 
58
47
  opts.on('-V', '--version', 'Version') do
@@ -66,37 +55,47 @@ module DBGet
66
55
  end
67
56
  end
68
57
 
69
- optparse.parse!
58
+ optparse
59
+ end
70
60
 
71
- if args.length == 0
72
- puts optparse.help
73
- else
74
- options[:dbtype] = dbtype
75
- options[:databases] = args.dup
61
+ def set_default_options
62
+ @options[:append_date] = false
63
+ @options[:verbose] = false
64
+ @options[:clean] = false
65
+ @options[:date] = 'xxxx-xx-xx'
66
+ @options[:collections] = 'EMPTY'
67
+ end
68
+
69
+ def run!(args, type)
70
+ check_path
71
+ @args = args
72
+ has_arguments?
76
73
 
77
- run(options)
74
+ @optparse.parse!
75
+ @options[:db_type] = type
76
+
77
+ controller
78
+ end
79
+
80
+ def controller
81
+ controller = DBGet::Controller.new(@args, @options)
82
+ controller.boot
83
+ controller.send_data!
84
+ end
85
+
86
+ def has_arguments?
87
+ if @args.length == 0
88
+ puts @optparse.help
89
+ exit
78
90
  end
79
91
  end
80
92
 
81
- def run(opts)
93
+ def check_path
82
94
  if ENV.include?('DBGET_PATH')
83
- opts[:dbget_path] = ENV['DBGET_PATH']
95
+ @options[:dbget_path] = ENV['DBGET_PATH']
84
96
  else
85
97
  raise "Cannot find DBGET_PATH!"
86
98
  end
87
-
88
- # lets turn off opt_db_name if we have more arguments
89
- # this feature is not supported at the moment
90
- if opts[:databases].count > 1 and opts.include?(:opt_db_name)
91
- raise "You cannot use -n with multiple databases!"
92
- end
93
-
94
- # check if -a switch is give but no -d
95
- if opts[:append_date] and !opts.include?(:date)
96
- raise "You cannnot use -a without -d!"
97
- end
98
-
99
- DBGet::Initializer.boot(opts)
100
99
  end
101
100
  end
102
101
  end
@@ -19,5 +19,12 @@ module DBGet
19
19
  chars = ('a'..'z').to_a + ('A'..'Z').to_a
20
20
  (0...size).collect { chars[Kernel.rand(chars.length)] }.join
21
21
  end
22
+
23
+ def self.stringify(hash)
24
+ hash.inject({}) do |options, (key, value)|
25
+ options[key.to_s] = value.to_s
26
+ options
27
+ end
28
+ end
22
29
  end
23
30
  end
@@ -1,3 +1,3 @@
1
1
  module DBGet
2
- VERSION = "0.1.4"
2
+ VERSION = "0.2.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dbget_client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.4
4
+ version: 0.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-02-20 00:00:00.000000000Z
12
+ date: 2012-08-27 00:00:00.000000000Z
13
13
  dependencies: []
14
14
  description: Decrypts and uncompress MySQL and MongoDB backups from dbget server
15
15
  email:
@@ -28,13 +28,10 @@ files:
28
28
  - bin/mongoget
29
29
  - dbget_client.gemspec
30
30
  - lib/dbget.rb
31
- - lib/dbget/config_loader.rb
31
+ - lib/dbget/config.rb
32
+ - lib/dbget/connector.rb
32
33
  - lib/dbget/constants.rb
33
- - lib/dbget/db_dump.rb
34
- - lib/dbget/initializer.rb
35
- - lib/dbget/loaders.rb
36
- - lib/dbget/loaders/mongodb.rb
37
- - lib/dbget/loaders/mysql.rb
34
+ - lib/dbget/controller.rb
38
35
  - lib/dbget/runner.rb
39
36
  - lib/dbget/utils.rb
40
37
  - lib/dbget/version.rb
@@ -1,19 +0,0 @@
1
- module DBGet
2
- class ConfigLoader
3
-
4
- def initialize(dbget_config, options = {})
5
- @dbget_config = dbget_config
6
- @options = options
7
- end
8
-
9
- def get_config(db_dump)
10
- @db_dump = db_dump
11
-
12
- if @dbget_config['mapping'].include?(db_dump.db)
13
- @dbget_config
14
- else
15
- raise "#{db_dump.db} is not found in your dbget.yml!"
16
- end
17
- end
18
- end
19
- end
@@ -1,124 +0,0 @@
1
- module DBGet
2
- class DBDump
3
- include Utils
4
- include Constants
5
-
6
- attr_accessor :dump_path, :collections
7
- attr_reader :db, :database, :db_path
8
- attr_reader :host, :port, :username, :password
9
- attr_reader :clean, :verbose
10
-
11
- def initialize(options)
12
- @db = options[:db]
13
- @date = options[:date]
14
- @key = options[:key]
15
- @dbtype = options[:dbtype]
16
- @server = options[:server]
17
- @opt_db_name = options[:opt_db_name]
18
- @verbose = options[:verbose]
19
- @append_date = options[:append_date]
20
- @clean = options[:clean]
21
- @collections = options[:collections] || []
22
- @header = {}
23
- end
24
-
25
- def load!(db_config)
26
- @server ||= db_config['source']['server']
27
- @key ||= db_config['key']
28
- @database = @opt_db_name || db_config['mapping'][@db][@dbtype]
29
- @host = db_config['target'][@dbtype]['host']
30
- @port = db_config['target'][@dbtype]['port']
31
- @username = db_config['target'][@dbtype]['username']
32
- @password = db_config['target'][@dbtype]['password']
33
- @dump_path = db_config['source']['dump_path']
34
- @db_path = File.join(@dump_path, "#{@db}")
35
-
36
- if @append_date
37
- @database = @database.concat("_#{@date.delete('-')}")
38
- end
39
-
40
- get_dump(db_config)
41
-
42
- if @header[:status] == 'SUCCESS'
43
- if !@database.nil?
44
- Utils.say "Dump info of #{@db} to #{@dbtype} using connection: \n" +
45
- " host: #{@host}\n" +
46
- " port: #{@port}\n" +
47
- " user: #{@username}\n" +
48
- " database: #{@database}\n"
49
-
50
- if @dbtype == 'mysql'
51
- Loaders::MySQL.new(self).load!
52
- else
53
- Loaders::MongoDB.new(self).load!
54
- end
55
- else
56
- raise "Database #{@db} for #{@dbtype} is not found on #{DBGET_CONFIG_FILE}!"
57
- end
58
- else
59
- raise "There was a problem fetching the database from the server!"
60
- end
61
- end
62
-
63
- protected
64
-
65
- def get_dump(db_config)
66
- user = db_config['source']['user']
67
- host = db_config['source']['host']
68
-
69
- unless File.exist? @dump_path
70
- FileUtils.mkdir_p(@dump_path)
71
- end
72
-
73
- ssh_params = "#{user}@#{host} db=#{@db} date=#{@date} " +
74
- "dbtype=#{@dbtype} server=#{@server}"
75
-
76
- if !@key.nil?
77
- ssh_cmd = "#{SSH_CMD} -i #{@key} #{ssh_params}"
78
- else
79
- ssh_cmd = "#{SSH_CMD} #{ssh_params}"
80
- end
81
-
82
- Utils.say "Fetching..."
83
-
84
- io_handle = IO.popen(ssh_cmd)
85
-
86
- parse_header(io_handle)
87
-
88
- if !io_handle.eof?
89
- File.open(@db_path, "w+") do |f|
90
- gz = Zlib::GzipReader.new(io_handle)
91
-
92
- while !io_handle.eof?
93
- g = gz.read(16*1024)
94
- f.write(g)
95
- end
96
-
97
- f.write(gz.read)
98
-
99
- gz.close
100
- f.close
101
- end
102
- end
103
- end
104
-
105
- def parse_header(io_handle)
106
- while (s = io_handle.readline) != "\r\n"
107
- s = s.split(': ')
108
- @header[s.first.to_sym] = s.last.chomp
109
- end
110
-
111
- print_header if @verbose
112
-
113
- if @header[:status] != "SUCCESS"
114
- raise "Server returned #{@header[:status]}!"
115
- end
116
- end
117
-
118
- def print_header
119
- @header.each do |k, v|
120
- puts ">> #{k.capitalize}: #{v}"
121
- end
122
- end
123
- end
124
- end
@@ -1,53 +0,0 @@
1
- module DBGet
2
- class Initializer
3
- include Constants
4
-
5
- def self.boot(options)
6
- self.new(options).init
7
- end
8
-
9
- def initialize(options)
10
- @options = options
11
- end
12
-
13
- def init
14
- load_dbget_config
15
-
16
- @options[:databases].each do |d|
17
- @options[:db] = d
18
-
19
- db_dump = DBGet::DBDump.new(@options)
20
-
21
- load_db_dumps(db_dump)
22
- end
23
- end
24
-
25
- protected
26
-
27
- def load_dbget_config
28
- config_path = File.join(@options[:dbget_path], DBGET_CONFIG_FILE)
29
-
30
- if File.exists?(config_path)
31
- @dbget_config = YAML.load_file(config_path)
32
- else
33
- raise "Cannot find #{config_path}!"
34
- end
35
- end
36
-
37
- def load_db_dumps(db_dump)
38
- if !@dbget_config.empty?
39
- config_loader = DBGet::ConfigLoader.new(@dbget_config, @options)
40
- else
41
- raise "Your dbget.yml is empty!"
42
- end
43
-
44
- db_dump.load!(config_loader.get_config(db_dump))
45
- end
46
-
47
- def cleanup_db_dumps(db_dumps)
48
- db_dumps.each do |db_dump|
49
- db_dump.clean_up!
50
- end
51
- end
52
- end
53
- end
@@ -1,6 +0,0 @@
1
- module DBGet
2
- module Loaders
3
- autoload :MongoDB, File.join(DBGET_LIB_ROOT, 'loaders/mongodb')
4
- autoload :MySQL, File.join(DBGET_LIB_ROOT, 'loaders/mysql')
5
- end
6
- end
@@ -1,69 +0,0 @@
1
- module DBGet
2
- module Loaders
3
- class MongoDB
4
- include Utils
5
- include Constants
6
-
7
- def self.boot(dump)
8
- # some boot here
9
-
10
- self.new(dump)
11
- end
12
-
13
- def initialize(dump)
14
- @dump = dump
15
- end
16
-
17
- def load!
18
- temp_path = File.join(@dump.dump_path, "#{@dump.db}_#{Utils.randomize(16)}")
19
-
20
- if !File.exists?(temp_path)
21
- FileUtils.mkdir(temp_path)
22
-
23
- Utils.say_with_time "Extracting archive..." do
24
- `#{TAR_CMD} -C #{temp_path} -xf #{File.join(@dump.dump_path, @dump.db)} 2> /dev/null`
25
- end
26
-
27
- Utils.say_with_time "Moving mongo files..." do
28
- `#{FIND_CMD} #{temp_path} -name '*.#{MONGO_FILE_EXT}'`.each_line do |l|
29
- FileUtils.mv(l.chomp!, File.join(temp_path, File.basename(l)))
30
- end
31
- end
32
- end
33
-
34
- dump_files = Dir["#{temp_path}/*#{MONGO_FILE_EXT}"]
35
-
36
- if !@dump.collections.empty?
37
- @dump.collections = @dump.collections.collect do |c|
38
- File.join(temp_path, c.concat(MONGO_FILE_EXT))
39
- end
40
-
41
- dump_files &= @dump.collections
42
- end
43
-
44
- dump_files.each do |d|
45
- # do not include indexes
46
- if File.basename(d) != "system.indexes#{MONGO_FILE_EXT}"
47
- Utils.say_with_time "Dumping #{d}..." do
48
- if !@dump.verbose
49
- `#{MONGORESTORE_CMD} -d #{@dump.database} #{d} --drop`
50
- else
51
- system "#{MONGORESTORE_CMD} -d #{@dump.database} #{d} --drop"
52
- end
53
- end
54
- end
55
- end
56
-
57
- Utils.say "Hooray! Dump for #{@dump.db} done!"
58
-
59
- if FileUtils.rm_rf(File.join(@dump.dump_path, @dump.db))
60
- Utils.say "Dump file removed!"
61
- end
62
-
63
- if FileUtils.rm_rf(temp_path)
64
- Utils.say "Temp directory removed!"
65
- end
66
- end
67
- end
68
- end
69
- end
@@ -1,50 +0,0 @@
1
- module DBGet
2
- module Loaders
3
- class MySQL
4
- include Utils
5
- include Constants
6
-
7
- def self.boot(dump)
8
- # some boot here
9
-
10
- self.new(dump)
11
- end
12
-
13
- def initialize(dump)
14
- @dump = dump
15
- end
16
-
17
- def load!
18
- command = "#{MYSQL_CMD} "
19
- command += "-h#{@dump.host} "
20
- command += "-P#{@dump.port} "
21
- command += "-u#{@dump.username} "
22
- command += "-p#{@dump.password} " if @dump.password
23
-
24
- if @dump.clean
25
- Utils.say_with_time "Dropping database..." do
26
- system "echo \"DROP DATABASE IF EXISTS #{@dump.database}\" | #{command}"
27
- end
28
- end
29
-
30
- system "echo \"CREATE DATABASE IF NOT EXISTS #{@dump.database}\" | #{command}"
31
-
32
- if File.exist?(@dump.db_path) and !File.size?(@dump.db_path).nil?
33
- command += " #{@dump.database} "
34
-
35
- Utils.say_with_time "Dumping #{@dump.db}..." do
36
- system "#{command}< #{File.join(@dump.dump_path, @dump.db)}"
37
- end
38
-
39
- if FileUtils.rm_rf(File.join(@dump.dump_path, @dump.db))
40
- Utils.say "Cleaned temporary file!"
41
- end
42
- else
43
- raise "Dump for #{@dump.db} not found!"
44
- end
45
-
46
- Utils.say "Hooray! Dump for #{@dump.db} done!"
47
- end
48
- end
49
- end
50
- end