dbget 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README +1 -0
- data/Rakefile +1 -0
- data/bin/dbget-adm +5 -0
- data/bin/dbget-serve +9 -0
- data/config/dbget.yml.sample +28 -0
- data/config/mask.yml +16 -0
- data/dbget.gemspec +26 -0
- data/lib/dbget/admin.rb +30 -0
- data/lib/dbget/binaries.rb +23 -0
- data/lib/dbget/config.rb +17 -0
- data/lib/dbget/constants.rb +7 -0
- data/lib/dbget/controller.rb +61 -0
- data/lib/dbget/dump.rb +150 -0
- data/lib/dbget/loaders/mongo.rb +77 -0
- data/lib/dbget/loaders/mysql.rb +55 -0
- data/lib/dbget/loaders.rb +6 -0
- data/lib/dbget/runner.rb +67 -0
- data/lib/dbget/utils.rb +65 -0
- data/lib/dbget/version.rb +3 -0
- data/lib/dbget.rb +26 -0
- metadata +80 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/README
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
initial commit for dbget
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/dbget-adm
ADDED
data/bin/dbget-serve
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
backups:
|
2
|
+
path: /opt/backups
|
3
|
+
cache: /tmp/dbget_backups
|
4
|
+
|
5
|
+
openssl:
|
6
|
+
passphrase: xxx
|
7
|
+
|
8
|
+
databases:
|
9
|
+
lmedi:
|
10
|
+
mongo: lmedi_production
|
11
|
+
clinic:
|
12
|
+
mysql: clinic_production
|
13
|
+
test:
|
14
|
+
mysql: test
|
15
|
+
|
16
|
+
users: ['poy', 'jan']
|
17
|
+
|
18
|
+
mysql:
|
19
|
+
host: localhost
|
20
|
+
port: 3306
|
21
|
+
username: root
|
22
|
+
password:
|
23
|
+
|
24
|
+
mongo:
|
25
|
+
host: localhost
|
26
|
+
port: 27017
|
27
|
+
username: root
|
28
|
+
password:
|
data/config/mask.yml
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
people:
|
2
|
+
columns:
|
3
|
+
email: 'masked@caresharing.eu'
|
4
|
+
house_number: '01'
|
5
|
+
postal_code: '1234XX'
|
6
|
+
mobile_number: '123-4567'
|
7
|
+
phone_number: '123-4567'
|
8
|
+
firstname:
|
9
|
+
lastname:
|
10
|
+
street_name:
|
11
|
+
region:
|
12
|
+
birthplace:
|
13
|
+
city:
|
14
|
+
patient_list_displays:
|
15
|
+
columns:
|
16
|
+
name:
|
data/dbget.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require 'dbget/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "dbget"
|
7
|
+
s.version = DBGet::VERSION
|
8
|
+
s.authors = ["Jan Mendoza"]
|
9
|
+
s.email = ["poymode@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Get an encrypted and compressed backup of a MySQL or mongoDB}
|
12
|
+
s.description = %q{This serves the backup}
|
13
|
+
|
14
|
+
s.rubyforge_project = "dbget"
|
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 'thor'
|
22
|
+
|
23
|
+
# specify any dependencies here; for example:
|
24
|
+
# s.add_development_dependency "rspec"
|
25
|
+
# s.add_runtime_dependency "rest-client"
|
26
|
+
end
|
data/lib/dbget/admin.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
module DBGet
|
4
|
+
class Admin < Thor
|
5
|
+
desc "generate_authorized_keys", "generate authorized keys for access"
|
6
|
+
def generate_authorized_keys
|
7
|
+
if File.exist? File.join(Dir.pwd, 'keydir')
|
8
|
+
key_dir = File.join(Dir.pwd, 'keydir')
|
9
|
+
elsif ENV.include?('DBGET_KEYDIR_PATH')
|
10
|
+
key_dir = ENV['DBGET_KEYDIR_PATH']
|
11
|
+
else
|
12
|
+
key_dir = ''
|
13
|
+
end
|
14
|
+
|
15
|
+
raise "Key directory 'keydir' not found." unless File.exists?(key_dir) and File.directory?(key_dir)
|
16
|
+
|
17
|
+
puts "### Generated by dbget, DO NOT EDIT"
|
18
|
+
|
19
|
+
keys = Dir["#{key_dir}/*.pub"]
|
20
|
+
keys.each do |pub_key|
|
21
|
+
bin_path = 'dbget-serve'
|
22
|
+
key_name = File.basename(pub_key, '.pub')
|
23
|
+
key_data = File.read(pub_key)
|
24
|
+
|
25
|
+
puts "command=\"#{bin_path} #{key_name}\",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty #{key_data}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module DBGet
|
2
|
+
module Binaries
|
3
|
+
def self.get_binary(bin)
|
4
|
+
`which #{bin}`.chomp
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.mysql_cmd
|
8
|
+
get_binary('mysql')
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.mongorestore_cmd
|
12
|
+
get_binary('mongorestore')
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.find_cmd
|
16
|
+
get_binary('find')
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.tar_cmd
|
20
|
+
get_binary('tar')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/dbget/config.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
|
3
|
+
module DBGet
|
4
|
+
class Config < Hash
|
5
|
+
include Singleton
|
6
|
+
|
7
|
+
def self.load_from_yml(yaml_path)
|
8
|
+
config = self.instance
|
9
|
+
config.clear
|
10
|
+
config.merge!(YAML.load_file(yaml_path))
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.database(name)
|
14
|
+
self.instance['databases'][name]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module DBGet
|
2
|
+
class Controller
|
3
|
+
def self.boot(options)
|
4
|
+
self.new(options).run!
|
5
|
+
end
|
6
|
+
|
7
|
+
def initialize(options)
|
8
|
+
@dump = DBGet::Dump.new(options)
|
9
|
+
@config = DBGet::Config.instance
|
10
|
+
end
|
11
|
+
|
12
|
+
def run!
|
13
|
+
user_allowed?
|
14
|
+
@dump.prepare
|
15
|
+
finalize_dump
|
16
|
+
load_dump
|
17
|
+
status_report
|
18
|
+
end
|
19
|
+
|
20
|
+
def user_allowed?
|
21
|
+
unless @config['users'].include?(@dump.user)
|
22
|
+
raise "User not allowed to dump"
|
23
|
+
exit 1
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def finalize_dump
|
28
|
+
if @dump.in_cache? @dump.cache_file
|
29
|
+
message = "Found cached file, no need to decrypt."
|
30
|
+
else
|
31
|
+
message = "Decrypting #{@dump.encrypted_dump}..."
|
32
|
+
end
|
33
|
+
|
34
|
+
Utils.say_with_time message do
|
35
|
+
@dump.decrypted_dump = @dump.decrypt_dump
|
36
|
+
end
|
37
|
+
|
38
|
+
@dump.set_final_db
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_dump
|
42
|
+
Utils.say_with_time "Dumping, this may take a while" do
|
43
|
+
case @dump.db_type
|
44
|
+
when 'mysql'
|
45
|
+
DBGet::Loaders::MySql.boot(@dump, @config).load!
|
46
|
+
when 'mongo'
|
47
|
+
DBGet::Loaders::Mongo.boot(@dump, @config).load!
|
48
|
+
else
|
49
|
+
raise "Dump is not supported!"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
def status_report
|
56
|
+
Utils.say "Dump for #{@dump.db} done!"
|
57
|
+
Utils.say "Source: #{@dump.decrypted_dump}"
|
58
|
+
Utils.say "Target: #{@dump.target_db}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/lib/dbget/dump.rb
ADDED
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
module DBGet
|
4
|
+
class Dump
|
5
|
+
include Constants
|
6
|
+
include Utils
|
7
|
+
|
8
|
+
attr_reader :db_type, :user, :db
|
9
|
+
attr_reader :encrypted_dump
|
10
|
+
attr_reader :date, :clean, :verbose, :append_date
|
11
|
+
attr_accessor :backup_name, :collections, :target_db, :decrypted_dump
|
12
|
+
|
13
|
+
def initialize(opts)
|
14
|
+
@db = opts['db']
|
15
|
+
@db_type = opts['db_type']
|
16
|
+
@user = opts['user']
|
17
|
+
@server = opts['server']
|
18
|
+
@custom_name = opts['custom_name']
|
19
|
+
|
20
|
+
@collections = opts['collections']
|
21
|
+
@date = opts['date']
|
22
|
+
@clean = opts['clean']
|
23
|
+
@verbose = opts['verbose']
|
24
|
+
@append_date = opts['append_date']
|
25
|
+
|
26
|
+
@storage_path = File.join(DBGet.base_backups_path, @server, @db_type)
|
27
|
+
end
|
28
|
+
|
29
|
+
def prepare
|
30
|
+
@backup_name = get_backup_name
|
31
|
+
@encrypted_dump = get_encrypted_dump
|
32
|
+
end
|
33
|
+
|
34
|
+
def set_final_db
|
35
|
+
@target_db = @custom_name || @backup_name
|
36
|
+
end
|
37
|
+
|
38
|
+
def form_db_name
|
39
|
+
if !date.nil? and append_date
|
40
|
+
self.target_db = "#{self.user}_#{self.target_db}_#{Utils.get_converted_date(self.date)}"
|
41
|
+
else
|
42
|
+
self.target_db = "#{self.user}_#{self.target_db}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def clean?
|
47
|
+
@clean
|
48
|
+
end
|
49
|
+
|
50
|
+
def decrypt_dump
|
51
|
+
unless @encrypted_dump.nil?
|
52
|
+
if in_cache? cache_file
|
53
|
+
file_path = cache_file
|
54
|
+
elsif File.exists? @encrypted_dump
|
55
|
+
file_path = Utils.decompress_file(decrypt_file(copy_to_cache(@encrypted_dump)))
|
56
|
+
end
|
57
|
+
|
58
|
+
file_path
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def in_cache?(file)
|
63
|
+
File.exists? file
|
64
|
+
end
|
65
|
+
|
66
|
+
def cache_file
|
67
|
+
file = File.join(DBGet.cache_path, decrypted_file_name)
|
68
|
+
file.concat('.tar') if @db_type.eql? 'mongo'
|
69
|
+
|
70
|
+
file
|
71
|
+
end
|
72
|
+
|
73
|
+
protected
|
74
|
+
|
75
|
+
def latest?
|
76
|
+
@date.nil?
|
77
|
+
end
|
78
|
+
|
79
|
+
def decrypted_file_name
|
80
|
+
File.basename(@encrypted_dump.split('.').first)
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_backup_name
|
84
|
+
if !@db.nil? and !@db_type.nil?
|
85
|
+
db = DBGet::Config.database(@db)
|
86
|
+
|
87
|
+
if db.nil?
|
88
|
+
raise "Database \'#{@db}\' not found in config!"
|
89
|
+
end
|
90
|
+
|
91
|
+
db[@db_type]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_encrypted_dump
|
96
|
+
monthly_dir_path = File.join(@storage_path, @backup_name)
|
97
|
+
|
98
|
+
unless File.exist?(monthly_dir_path)
|
99
|
+
raise "Database \'#{@backup_name}\' can't be found in #{@storage_path}!"
|
100
|
+
end
|
101
|
+
|
102
|
+
monthly_dirs = Utils.get_files(monthly_dir_path).sort
|
103
|
+
|
104
|
+
if !monthly_dirs.empty?
|
105
|
+
db_month = get_db_month(monthly_dirs)
|
106
|
+
db_dumps_path = File.join(monthly_dir_path.to_s, db_month.to_s)
|
107
|
+
db_dumps = Utils.get_files(db_dumps_path)
|
108
|
+
|
109
|
+
@encrypted_dump = File.join(db_dumps_path, get_db_file(db_dumps))
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def get_db_month(monthly_dirs)
|
114
|
+
if latest?
|
115
|
+
File.basename(monthly_dirs.last)
|
116
|
+
else
|
117
|
+
@date.strftime("%Y%m")
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
def get_db_file(db_dumps)
|
122
|
+
if latest?
|
123
|
+
db_file = db_dumps.last
|
124
|
+
else
|
125
|
+
db_dumps.each do |filename|
|
126
|
+
if filename.include? "-#{@date.strftime("%Y%m%d")}"
|
127
|
+
db_file = filename
|
128
|
+
break
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
db_file
|
134
|
+
end
|
135
|
+
|
136
|
+
def copy_to_cache(file_path)
|
137
|
+
FileUtils.mkdir_p(DBGet.cache_path)
|
138
|
+
FileUtils.cp(file_path, DBGet.cache_path)
|
139
|
+
|
140
|
+
File.join(DBGet.cache_path, File.basename(file_path))
|
141
|
+
end
|
142
|
+
|
143
|
+
def decrypt_file(file_path)
|
144
|
+
if File.extname(file_path) == ".enc"
|
145
|
+
Utils.decode_file(file_path)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module DBGet
|
2
|
+
module Loaders
|
3
|
+
class Mongo
|
4
|
+
include Constants
|
5
|
+
|
6
|
+
def self.boot(dump, config)
|
7
|
+
self.new(dump, config)
|
8
|
+
end
|
9
|
+
|
10
|
+
def initialize(dump, config)
|
11
|
+
@dump = dump
|
12
|
+
@config = config
|
13
|
+
end
|
14
|
+
|
15
|
+
def load!
|
16
|
+
temp_path = get_temp_path
|
17
|
+
|
18
|
+
FileUtils.mkdir(temp_path) if !File.exists?(temp_path)
|
19
|
+
|
20
|
+
@dump.form_db_name
|
21
|
+
extract_mongo_dump(temp_path)
|
22
|
+
prepare_bson_files(temp_path)
|
23
|
+
|
24
|
+
dump_files = Dir["#{temp_path}/*#{MONGO_FILE_EXT}"]
|
25
|
+
dump_files = specify_collections(dump_files, temp_path)
|
26
|
+
mongo_restore(dump_files)
|
27
|
+
remove_temp_path(temp_path)
|
28
|
+
end
|
29
|
+
|
30
|
+
def mongo_restore(dump_files)
|
31
|
+
dump_files.each do |file|
|
32
|
+
unless index?(file)
|
33
|
+
mongo_restore = Binaries.mongorestore_cmd
|
34
|
+
|
35
|
+
system "#{mongo_restore} -d #{@dump.target_db} #{file} --drop"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_temp_path
|
41
|
+
random = Utils.randomize(16)
|
42
|
+
decrypted_basename = File.basename(@dump.decrypted_dump, '.tar')
|
43
|
+
temp_path = File.join(DBGet.cache_path, "#{decrypted_basename}_#{random}")
|
44
|
+
end
|
45
|
+
|
46
|
+
def remove_temp_path(path)
|
47
|
+
FileUtils.rm_rf(path)
|
48
|
+
end
|
49
|
+
|
50
|
+
def index?(file)
|
51
|
+
File.basename(file) == "#{MONGO_INDEX_FILE}#{MONGO_FILE_EXT}"
|
52
|
+
end
|
53
|
+
|
54
|
+
def specify_collections(dump_files, temp_path)
|
55
|
+
if !@dump.collections.empty?
|
56
|
+
@dump.collections = @dump.collections.collect do |c|
|
57
|
+
File.join(temp_path, c.concat(MONGO_FILE_EXT))
|
58
|
+
end
|
59
|
+
|
60
|
+
dump_files &= @dump.collections
|
61
|
+
end
|
62
|
+
|
63
|
+
dump_files
|
64
|
+
end
|
65
|
+
|
66
|
+
def extract_mongo_dump(temp_path)
|
67
|
+
`#{Binaries.tar_cmd} -C #{temp_path} -xf #{@dump.decrypted_dump} 2> /dev/null`
|
68
|
+
end
|
69
|
+
|
70
|
+
def prepare_bson_files(temp_path)
|
71
|
+
`#{Binaries.find_cmd} #{temp_path} -name '*#{MONGO_FILE_EXT}'`.each_line do |l|
|
72
|
+
FileUtils.mv(l.chomp!, File.join(temp_path, File.basename(l)))
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module DBGet
|
2
|
+
module Loaders
|
3
|
+
class MySql
|
4
|
+
include Constants
|
5
|
+
include Binaries
|
6
|
+
|
7
|
+
def self.boot(dump, config)
|
8
|
+
self.new(dump, config)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(dump, config)
|
12
|
+
@dump = dump
|
13
|
+
@config = config
|
14
|
+
@date = @dump.date
|
15
|
+
@dump_command = form_dump_command
|
16
|
+
end
|
17
|
+
|
18
|
+
def load!
|
19
|
+
@dump.form_db_name
|
20
|
+
clean_dump if @dump.clean?
|
21
|
+
create_db_if_not_exist
|
22
|
+
dump_mysql
|
23
|
+
end
|
24
|
+
|
25
|
+
def form_dump_command
|
26
|
+
@dump_command = "#{Binaries.mysql_cmd} "
|
27
|
+
@dump_command += "-h#{@config['mysql']['host']} "
|
28
|
+
@dump_command += "-P#{@config['mysql']['port']} "
|
29
|
+
@dump_command += "-u#{@config['mysql']['username']} "
|
30
|
+
@dump_command += "-p#{@config['mysql']['password']} " if @config['mysql']['password']
|
31
|
+
@dump_command
|
32
|
+
end
|
33
|
+
|
34
|
+
def get_converted_date
|
35
|
+
@dump.date.to_s.delete('-')
|
36
|
+
end
|
37
|
+
|
38
|
+
def clean_dump
|
39
|
+
puts "Dropping database..."
|
40
|
+
system "echo \"DROP DATABASE IF EXISTS #{@dump.target_db}\" | #{@dump_command}"
|
41
|
+
end
|
42
|
+
|
43
|
+
def create_db_if_not_exist
|
44
|
+
system "echo \"CREATE DATABASE IF NOT EXISTS #{@dump.target_db}\" | #{@dump_command}"
|
45
|
+
end
|
46
|
+
|
47
|
+
def dump_mysql
|
48
|
+
@dump_command += " #{@dump.target_db} "
|
49
|
+
|
50
|
+
out = system("#{@dump_command}< #{@dump.decrypted_dump}")
|
51
|
+
exit 1 unless out
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/dbget/runner.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
module DBGet
|
2
|
+
class Runner
|
3
|
+
def self.boot(user, options)
|
4
|
+
self.new(parse_options(user, options)).run!
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.parse_options(user, options)
|
8
|
+
opts = {}
|
9
|
+
opts['user'] = user
|
10
|
+
|
11
|
+
options.each do |o|
|
12
|
+
k, v = o.split('=')
|
13
|
+
opts[k] = v
|
14
|
+
end
|
15
|
+
|
16
|
+
opts
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(options)
|
20
|
+
@options = options
|
21
|
+
end
|
22
|
+
|
23
|
+
def run!
|
24
|
+
init_config(get_dbget_path)
|
25
|
+
prepare_dump_options
|
26
|
+
dump
|
27
|
+
end
|
28
|
+
|
29
|
+
def prepare_dump_options
|
30
|
+
@options['collections'] = get_final_collection(@options['collections'])
|
31
|
+
@options['date'] = format_date(@options['date'])
|
32
|
+
@options['clean'] = Utils.to_bool(@options['clean'])
|
33
|
+
@options['verbose'] = Utils.to_bool(@options['verbose'])
|
34
|
+
@options['append_date'] = Utils.to_bool(@options['append_date'])
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_final_collection(collection)
|
38
|
+
unless collection == 'EMPTY'
|
39
|
+
collection.split(',')
|
40
|
+
else
|
41
|
+
[]
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def format_date(date)
|
46
|
+
unless date == 'xxxx-xx-xx'
|
47
|
+
Date.strptime(date, "%Y-%m-%d")
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def dump
|
52
|
+
Controller.boot(@options)
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_dbget_path
|
56
|
+
if ENV.include?('DBGET_PATH')
|
57
|
+
ENV['DBGET_PATH']
|
58
|
+
else
|
59
|
+
raise "DBGET_PATH not defined"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def init_config(dbget_path)
|
64
|
+
DBGet.read_config(dbget_path)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/dbget/utils.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'csv'
|
2
|
+
require 'benchmark'
|
3
|
+
|
4
|
+
module DBGet
|
5
|
+
module Utils
|
6
|
+
|
7
|
+
def self.get_files(path)
|
8
|
+
Dir.new(path).entries - %w{ . .. }
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.decode_file(input_file)
|
12
|
+
output_file = input_file.sub(/\.enc$/, "")
|
13
|
+
pass_phrase = DBGet::Config.instance['openssl']['passphrase']
|
14
|
+
|
15
|
+
command = "openssl enc -d -aes-256-cbc -in #{input_file}"
|
16
|
+
command += " -pass pass:#{pass_phrase}"
|
17
|
+
command += " -out #{output_file}; rm #{input_file}"
|
18
|
+
system command
|
19
|
+
|
20
|
+
output_file
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.decompress_file(input_file)
|
24
|
+
command = "gzip -df #{input_file}"
|
25
|
+
system command
|
26
|
+
|
27
|
+
input_file.sub(/\.gz$/, "")
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.compress_file(input_file)
|
31
|
+
command = "gzip #{input_file}"
|
32
|
+
system command
|
33
|
+
|
34
|
+
input_file.concat('.gz')
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.say(message, subitem = false)
|
38
|
+
puts "#{subitem ? " ->" : "--"} #{message}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.say_with_time(message)
|
42
|
+
say(message)
|
43
|
+
result = nil
|
44
|
+
time = Benchmark.measure { result = yield }
|
45
|
+
say "%.4fs" % time.real, :subitem
|
46
|
+
say("#{result} rows", :subitem) if result.is_a?(Integer)
|
47
|
+
result
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.randomize(size)
|
51
|
+
chars = ('a'..'z').to_a + ('A'..'Z').to_a
|
52
|
+
(0...size).collect { chars[Kernel.rand(chars.length)] }.join
|
53
|
+
end
|
54
|
+
|
55
|
+
def self.to_bool(string)
|
56
|
+
return true if string == true || string =~ (/(true|t|yes|y|1)$/i)
|
57
|
+
return false if string == false || string.empty? || string =~ (/(false|f|no|n|0)$/i)
|
58
|
+
raise ArgumentError.new("invalid value for Boolean: \"#{string}\"")
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.get_converted_date(date)
|
62
|
+
date.to_s.delete('-')
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/dbget.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module DBGet
|
4
|
+
autoload :Admin, File.join(File.dirname(__FILE__), 'dbget/admin')
|
5
|
+
autoload :Binaries, File.join(File.dirname(__FILE__), 'dbget/binaries')
|
6
|
+
autoload :Config, File.join(File.dirname(__FILE__), 'dbget/config')
|
7
|
+
autoload :Constants, File.join(File.dirname(__FILE__), 'dbget/constants')
|
8
|
+
autoload :Dump, File.join(File.dirname(__FILE__), 'dbget/dump')
|
9
|
+
autoload :Controller, File.join(File.dirname(__FILE__), 'dbget/controller')
|
10
|
+
autoload :Loaders, File.join(File.dirname(__FILE__), 'dbget/loaders')
|
11
|
+
autoload :Runner, File.join(File.dirname(__FILE__), 'dbget/runner')
|
12
|
+
autoload :Utils, File.join(File.dirname(__FILE__), 'dbget/utils')
|
13
|
+
|
14
|
+
def self.read_config(dbget_path)
|
15
|
+
config_file = File.join(dbget_path, Constants::CONFIG_PATH)
|
16
|
+
DBGet::Config.load_from_yml(config_file)
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.base_backups_path
|
20
|
+
DBGet::Config.instance['backups']['path']
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.cache_path
|
24
|
+
DBGet::Config.instance['backups']['cache']
|
25
|
+
end
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dbget
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.2.2
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Jan Mendoza
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-27 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: thor
|
16
|
+
requirement: &15915760 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *15915760
|
25
|
+
description: This serves the backup
|
26
|
+
email:
|
27
|
+
- poymode@gmail.com
|
28
|
+
executables:
|
29
|
+
- dbget-adm
|
30
|
+
- dbget-serve
|
31
|
+
extensions: []
|
32
|
+
extra_rdoc_files: []
|
33
|
+
files:
|
34
|
+
- .gitignore
|
35
|
+
- Gemfile
|
36
|
+
- README
|
37
|
+
- Rakefile
|
38
|
+
- bin/dbget-adm
|
39
|
+
- bin/dbget-serve
|
40
|
+
- config/dbget.yml.sample
|
41
|
+
- config/mask.yml
|
42
|
+
- dbget.gemspec
|
43
|
+
- lib/dbget.rb
|
44
|
+
- lib/dbget/admin.rb
|
45
|
+
- lib/dbget/binaries.rb
|
46
|
+
- lib/dbget/config.rb
|
47
|
+
- lib/dbget/constants.rb
|
48
|
+
- lib/dbget/controller.rb
|
49
|
+
- lib/dbget/dump.rb
|
50
|
+
- lib/dbget/loaders.rb
|
51
|
+
- lib/dbget/loaders/mongo.rb
|
52
|
+
- lib/dbget/loaders/mysql.rb
|
53
|
+
- lib/dbget/runner.rb
|
54
|
+
- lib/dbget/utils.rb
|
55
|
+
- lib/dbget/version.rb
|
56
|
+
homepage: ''
|
57
|
+
licenses: []
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ! '>='
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
version: '0'
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ! '>='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project: dbget
|
76
|
+
rubygems_version: 1.8.10
|
77
|
+
signing_key:
|
78
|
+
specification_version: 3
|
79
|
+
summary: Get an encrypted and compressed backup of a MySQL or mongoDB
|
80
|
+
test_files: []
|