mongo-db-utils 0.0.9 → 0.0.9.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.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/Gemfile +0 -5
- data/README.md +18 -3
- data/integration-test-env/.gitignore +4 -0
- data/integration-test-env/README.md +29 -0
- data/integration-test-env/create_two_replica_sets +76 -0
- data/integration-test-env/create_two_standalone_dbs +27 -0
- data/integration-test-env/helper.rb +50 -0
- data/integration-test-env/kill_processes +19 -0
- data/integration-test-env/replica_sets/config.yml +21 -0
- data/integration-test-env/seed_replica_sets +15 -0
- data/integration-test-env/standalone/config.yml +19 -0
- data/lib/mongo-db-utils/cli.rb +27 -10
- data/lib/mongo-db-utils/cmd.rb +8 -24
- data/lib/mongo-db-utils/config-loader.rb +33 -24
- data/lib/mongo-db-utils/console.rb +68 -5
- data/lib/mongo-db-utils/models/bucket.rb +17 -0
- data/lib/mongo-db-utils/models/config.rb +82 -0
- data/lib/mongo-db-utils/models/db.rb +81 -0
- data/lib/mongo-db-utils/tools/commands.rb +80 -0
- data/lib/mongo-db-utils/version.rb +1 -1
- data/mongo-db-utils.gemspec +4 -4
- data/spec/config_loader_spec.rb +30 -0
- data/spec/config_proxy_spec.rb +33 -0
- data/spec/models/config_spec.rb +52 -0
- data/spec/models/db_spec.rb +36 -0
- data/spec/mongo_tools_cmd_spec.rb +38 -0
- metadata +42 -45
- data/lib/mongo-db-utils/cmd/mongotools.rb +0 -68
- data/lib/mongo-db-utils/models.rb +0 -161
- data/spec/config-loader-spec.rb +0 -21
- data/spec/mongo_db_utils_spec.rb +0 -65
@@ -1,59 +1,68 @@
|
|
1
|
-
|
1
|
+
project_root = File.dirname(File.absolute_path(__FILE__))
|
2
|
+
|
3
|
+
Dir.glob(project_root + '/lib/mongo-db-utils/models/*', &method(:require))
|
4
|
+
|
2
5
|
require 'yaml'
|
3
6
|
|
4
7
|
module MongoDbUtils
|
5
8
|
|
6
9
|
class ConfigLoader
|
7
|
-
|
10
|
+
|
8
11
|
ROOT_FOLDER = "~/.mongo-db-utils"
|
9
12
|
CONFIG_LOCATION = "#{ROOT_FOLDER}/config.yml"
|
10
13
|
|
11
|
-
|
12
|
-
full_path = File.expand_path(load_path)
|
13
|
-
puts "loading config from #{full_path}"
|
14
|
+
attr_reader :config
|
14
15
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
config
|
19
|
-
else
|
20
|
-
self.create_fresh_install_config(full_path)
|
21
|
-
end
|
16
|
+
def initialize(config_path)
|
17
|
+
@config_path = config_path
|
18
|
+
load
|
22
19
|
end
|
23
20
|
|
24
|
-
def
|
25
|
-
path = File.expand_path(
|
21
|
+
def flush
|
22
|
+
path = File.expand_path(@config_path)
|
26
23
|
puts "removing: #{path}"
|
27
24
|
FileUtils.rm(path) if File.exist?(path)
|
28
|
-
|
25
|
+
initialize_files(path)
|
29
26
|
end
|
30
27
|
|
31
|
-
def
|
28
|
+
def save(config)
|
32
29
|
raise "config is nil" if config.nil?
|
33
|
-
|
34
|
-
File.open( File.expand_path(path), 'w' ) do |out|
|
30
|
+
File.open( File.expand_path(@config_path), 'w' ) do |out|
|
35
31
|
YAML.dump( config, out )
|
36
32
|
end
|
37
33
|
end
|
38
34
|
|
39
|
-
private
|
40
|
-
def
|
35
|
+
private
|
36
|
+
def load
|
37
|
+
full_path = File.expand_path(@config_path)
|
38
|
+
puts "loading config from #{full_path}"
|
39
|
+
|
40
|
+
if File.exist?(full_path) && YAML.load(File.open(full_path))
|
41
|
+
config = YAML.load(File.open(full_path))
|
42
|
+
config.writer = self
|
43
|
+
@config = config
|
44
|
+
else
|
45
|
+
@config = create_fresh_install_config(full_path)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_fresh_install_config(full_path)
|
41
50
|
config = Model::Config.new
|
42
51
|
config.writer = self
|
43
52
|
config.backup_folder = "#{ROOT_FOLDER}/backups"
|
44
|
-
|
53
|
+
initialize_files(full_path)
|
45
54
|
File.open( full_path, 'w' ) do |out|
|
46
55
|
YAML.dump( config, out )
|
47
56
|
end
|
48
57
|
config
|
49
58
|
end
|
50
59
|
|
51
|
-
def
|
60
|
+
def get_folder_name(path)
|
52
61
|
/(.*)\/.*.yml/.match(path)[1]
|
53
62
|
end
|
54
63
|
|
55
|
-
def
|
56
|
-
folder =
|
64
|
+
def initialize_files(path)
|
65
|
+
folder = get_folder_name(path)
|
57
66
|
FileUtils.mkdir_p(folder) unless File.exist?(folder)
|
58
67
|
FileUtils.touch(path)
|
59
68
|
end
|
@@ -1,8 +1,45 @@
|
|
1
1
|
require 'highline/import'
|
2
2
|
require 'mongo-db-utils/version'
|
3
|
-
|
3
|
+
Dir['lib/mongo-db-utils/models/*.rb'].each {|file| require file.gsub("lib/", "") }
|
4
|
+
|
4
5
|
|
5
6
|
module MongoDbUtils
|
7
|
+
|
8
|
+
# This is a workaround for this issue:
|
9
|
+
# https://github.com/JEG2/highline/issues/69
|
10
|
+
# In ruby 2 + highline the yaml strings don't get serialized correctly.
|
11
|
+
# The workaround is for any argument that is of type HighLine::String to call to_s on it
|
12
|
+
class ConfigProxy
|
13
|
+
|
14
|
+
def initialize(config)
|
15
|
+
@config = config
|
16
|
+
end
|
17
|
+
|
18
|
+
protected
|
19
|
+
def method_missing(name, *args, &block)
|
20
|
+
cleaned_args = args.map{ |a| trim(clean(a)) }
|
21
|
+
cleaned_args.each{ |a| puts "#{a} -> #{a.class}"}
|
22
|
+
@config.send(name, *cleaned_args, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def clean(a)
|
26
|
+
if a.class.to_s == "HighLine::String"
|
27
|
+
a.to_s
|
28
|
+
else
|
29
|
+
a
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def trim(s)
|
34
|
+
if(s.class.to_s == "String")
|
35
|
+
s.strip
|
36
|
+
else
|
37
|
+
s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
|
6
43
|
class Console
|
7
44
|
|
8
45
|
HEADER = <<-eos
|
@@ -13,7 +50,7 @@ eos
|
|
13
50
|
|
14
51
|
|
15
52
|
def initialize(config, cmd)
|
16
|
-
@config = config
|
53
|
+
@config = ConfigProxy.new(config)
|
17
54
|
@cmd = cmd
|
18
55
|
end
|
19
56
|
|
@@ -128,9 +165,15 @@ eos
|
|
128
165
|
end
|
129
166
|
|
130
167
|
def add_config
|
131
|
-
|
132
|
-
|
133
|
-
|
168
|
+
my_menu("Single db or replica set?") do |menu|
|
169
|
+
menu.choice "single db" do add_single_db end
|
170
|
+
menu.choice "replica set db" do add_replica_set end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
def add_single_db
|
175
|
+
mongo_uri = ask("Mongo uri (eg: 'mongodb://user:pass@locahost:27017/db')")
|
176
|
+
new_uri = mongo_uri.to_s.strip
|
134
177
|
successful = @config.add_db_from_uri(new_uri)
|
135
178
|
|
136
179
|
say("bad uri!") unless successful
|
@@ -142,6 +185,21 @@ eos
|
|
142
185
|
end
|
143
186
|
end
|
144
187
|
|
188
|
+
def add_replica_set
|
189
|
+
mongo_uri = ask("Replica Set uri: (eg: mongodb://user:pass@host1:port,host2:port,.../db)1
|
190
|
+
")
|
191
|
+
replica_set_name = ask("Replica Set name: ")
|
192
|
+
|
193
|
+
successful = @config.add_replica_set(mongo_uri, replica_set_name)
|
194
|
+
|
195
|
+
say("bad replica set uri") unless successful
|
196
|
+
|
197
|
+
my_menu("") do |menu|
|
198
|
+
menu.choice (successful ? "add another" : "try again?") do add_config end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
|
145
203
|
def remove_server_from_config
|
146
204
|
db_list_menu("Remove server from config:") do |db|
|
147
205
|
@config.remove_db(db)
|
@@ -209,5 +267,10 @@ eos
|
|
209
267
|
end
|
210
268
|
end
|
211
269
|
|
270
|
+
private
|
271
|
+
def clean(s)
|
272
|
+
s.to_s.strip
|
273
|
+
end
|
274
|
+
|
212
275
|
end
|
213
276
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'mongo-db-utils/models/db'
|
2
|
+
module MongoDbUtils
|
3
|
+
|
4
|
+
module Model
|
5
|
+
class Config
|
6
|
+
attr_reader :dbs, :buckets
|
7
|
+
attr_writer :writer
|
8
|
+
attr_accessor :backup_folder
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@dbs = []
|
12
|
+
@buckets = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def empty?
|
16
|
+
@dbs.nil? || @dbs.empty?
|
17
|
+
end
|
18
|
+
|
19
|
+
def has_buckets?
|
20
|
+
!@buckets.nil? && !@buckets.empty?
|
21
|
+
end
|
22
|
+
|
23
|
+
def flush
|
24
|
+
@dbs = []
|
25
|
+
@writer.flush
|
26
|
+
end
|
27
|
+
|
28
|
+
def remove_db(db)
|
29
|
+
@dbs = @dbs - [db]
|
30
|
+
save
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_replica_set(uri, name)
|
34
|
+
add_db ReplicaSetDb.new(uri,name)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def add_db_from_uri(uri)
|
39
|
+
add_db Db.new(uri)
|
40
|
+
end
|
41
|
+
|
42
|
+
def already_contains(db)
|
43
|
+
!@dbs.find{|current| current.uri == db.uri }.nil?
|
44
|
+
end
|
45
|
+
|
46
|
+
# because we are serializing the config - the bucket may be nil
|
47
|
+
# at this point
|
48
|
+
def add_bucket(bucket)
|
49
|
+
@buckets = [] if @buckets.nil?
|
50
|
+
unless already_contains_bucket?(bucket)
|
51
|
+
@buckets << bucket
|
52
|
+
save
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def already_contains_bucket?(bucket)
|
57
|
+
!@buckets.find{ |b| b.to_s == bucket.to_s}.nil?
|
58
|
+
end
|
59
|
+
|
60
|
+
def to_s
|
61
|
+
"Config"
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
def save
|
66
|
+
@writer.save(self) unless @writer.nil?
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_db(db)
|
70
|
+
@dbs = [] if @dbs.nil?
|
71
|
+
unless db.nil? || already_contains(db)
|
72
|
+
@dbs << db
|
73
|
+
@dbs.sort!
|
74
|
+
save
|
75
|
+
end
|
76
|
+
@dbs.include?(db) && !db.nil?
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
module MongoDbUtils
|
2
|
+
module Model
|
3
|
+
|
4
|
+
# A Db stored in the config
|
5
|
+
class Db
|
6
|
+
|
7
|
+
URI_NO_USER = /mongodb:\/\/(.*)\/(.*$)/
|
8
|
+
URI_USER = /mongodb:\/\/(.*):(.*)@(.*)\/(.*$)/
|
9
|
+
|
10
|
+
attr_accessor :username, :password, :name, :uri
|
11
|
+
|
12
|
+
def initialize(uri)
|
13
|
+
user,pwd,host_port,db = nil
|
14
|
+
|
15
|
+
if( uri.match(URI_USER))
|
16
|
+
match, user, pwd, host_port, name = *uri.match(URI_USER)
|
17
|
+
elsif(uri.match(URI_NO_USER))
|
18
|
+
match, host_port, name = *uri.match(URI_NO_USER)
|
19
|
+
user = ""
|
20
|
+
pwd = ""
|
21
|
+
end
|
22
|
+
|
23
|
+
raise "can't parse uri" if( host_port.nil? || name.nil? )
|
24
|
+
|
25
|
+
@host_port = host_port
|
26
|
+
@name = name
|
27
|
+
@username = user
|
28
|
+
@password = pwd
|
29
|
+
@uri = uri
|
30
|
+
end
|
31
|
+
|
32
|
+
def authentication_required?
|
33
|
+
has?(self.username) && has?(self.password)
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return the host string in a format that is compatable with mongo binary tools
|
37
|
+
# See: http://docs.mongodb.org/manual/reference/program/mongodump/#cmdoption-mongodump--host
|
38
|
+
def to_host_s
|
39
|
+
"#{@host_port}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_s_simple
|
43
|
+
"#{@name} on #{@host_port} - (#{@username}:#{@password})"
|
44
|
+
end
|
45
|
+
|
46
|
+
def to_s
|
47
|
+
"[SingleDb-(#{to_host_s}/#{name})]"
|
48
|
+
end
|
49
|
+
|
50
|
+
def <=>(other)
|
51
|
+
self.to_s <=> other.to_s
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
def has?(s)
|
56
|
+
!s.nil? && !s.empty?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
class ReplicaSetDb < Db
|
62
|
+
|
63
|
+
attr_reader :set_name
|
64
|
+
def initialize(uri, name)
|
65
|
+
super(uri)
|
66
|
+
@set_name = name
|
67
|
+
end
|
68
|
+
|
69
|
+
# Note: we override this to provide a replica set format
|
70
|
+
def to_host_s
|
71
|
+
"#{@set_name}/#{@host_port}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def to_s
|
75
|
+
"[ReplicaSetDb-(#{to_host_s}/#{@name})]"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'aws/s3'
|
2
|
+
|
3
|
+
module MongoDbUtils
|
4
|
+
|
5
|
+
module Tools
|
6
|
+
|
7
|
+
class BaseCmd
|
8
|
+
private
|
9
|
+
def self.o(key,value)
|
10
|
+
Option.new(key,value)
|
11
|
+
end
|
12
|
+
|
13
|
+
# options common to all commands
|
14
|
+
def self.build_base_options(host_and_port,db,username="",password="")
|
15
|
+
options = []
|
16
|
+
options << o("-h", host_and_port)
|
17
|
+
options << o("-db", db)
|
18
|
+
options << o("-u", username)
|
19
|
+
options << o("-p", password)
|
20
|
+
options
|
21
|
+
end
|
22
|
+
|
23
|
+
# given an array of options build a string of those options unless the option is empty
|
24
|
+
def self.options_string(opts)
|
25
|
+
out = ""
|
26
|
+
opts.each do |o|
|
27
|
+
out << "#{o.key} #{o.value} " unless o.empty?
|
28
|
+
end
|
29
|
+
out.strip
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class Dump < BaseCmd
|
34
|
+
|
35
|
+
# create the cmd string that will be executed by the system
|
36
|
+
def self.cmd(host_and_port,db,output,username = "", password = "")
|
37
|
+
options = build_base_options(host_and_port,db,username,password)
|
38
|
+
options << o("-o", output)
|
39
|
+
"mongodump #{options_string(options)}"
|
40
|
+
end
|
41
|
+
|
42
|
+
# run the command
|
43
|
+
def self.run(host_and_port,db,output,username="", password ="")
|
44
|
+
cmd_string = self.cmd(host_and_port,db,output,username,password)
|
45
|
+
puts "[Dump] run: #{cmd_string}"
|
46
|
+
`#{cmd_string}`
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
class Restore < BaseCmd
|
52
|
+
def self.cmd(host_and_port,db,source_folder,username = "", password = "")
|
53
|
+
options = build_base_options(host_and_port,db,username,password)
|
54
|
+
params = options_string(options) << " --drop #{source_folder}"
|
55
|
+
"mongorestore #{params}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.run(host_and_port,db,source_folder,username="", password ="")
|
59
|
+
cmd_string = self.cmd(host_and_port,db,source_folder,username,password)
|
60
|
+
puts "[Restore] run: #{cmd_string}"
|
61
|
+
`#{cmd_string}`
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
class Option
|
67
|
+
attr_accessor :key, :value
|
68
|
+
|
69
|
+
def initialize(key,value)
|
70
|
+
@key = key
|
71
|
+
@value = value
|
72
|
+
end
|
73
|
+
|
74
|
+
def empty?
|
75
|
+
@value.nil? || @value.empty?
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|