mongo 1.8.6 → 1.12.5
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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/LICENSE +1 -1
- data/README.md +114 -282
- data/Rakefile +18 -4
- data/VERSION +1 -1
- data/bin/mongo_console +27 -5
- data/lib/mongo/bulk_write_collection_view.rb +387 -0
- data/lib/mongo/collection.rb +283 -222
- data/lib/mongo/collection_writer.rb +364 -0
- data/lib/mongo/{util → connection}/node.rb +58 -6
- data/lib/mongo/{util → connection}/pool.rb +61 -37
- data/lib/mongo/{util → connection}/pool_manager.rb +72 -22
- data/lib/mongo/{util → connection}/sharding_pool_manager.rb +13 -0
- data/lib/mongo/connection/socket/socket_util.rb +37 -0
- data/lib/mongo/connection/socket/ssl_socket.rb +95 -0
- data/lib/mongo/connection/socket/tcp_socket.rb +87 -0
- data/lib/mongo/connection/socket/unix_socket.rb +39 -0
- data/lib/mongo/connection/socket.rb +18 -0
- data/lib/mongo/connection.rb +19 -0
- data/lib/mongo/cursor.rb +183 -57
- data/lib/mongo/db.rb +302 -138
- data/lib/mongo/exception.rb +145 -0
- data/lib/mongo/functional/authentication.rb +455 -0
- data/lib/mongo/{util → functional}/logging.rb +23 -7
- data/lib/mongo/functional/read_preference.rb +183 -0
- data/lib/mongo/functional/scram.rb +556 -0
- data/lib/mongo/functional/uri_parser.rb +409 -0
- data/lib/mongo/{util → functional}/write_concern.rb +21 -9
- data/lib/mongo/functional.rb +20 -0
- data/lib/mongo/gridfs/grid.rb +19 -8
- data/lib/mongo/gridfs/grid_ext.rb +14 -0
- data/lib/mongo/gridfs/grid_file_system.rb +17 -4
- data/lib/mongo/gridfs/grid_io.rb +21 -9
- data/lib/mongo/gridfs.rb +18 -0
- data/lib/mongo/legacy.rb +76 -7
- data/lib/mongo/mongo_client.rb +246 -206
- data/lib/mongo/mongo_replica_set_client.rb +65 -15
- data/lib/mongo/mongo_sharded_client.rb +18 -3
- data/lib/mongo/networking.rb +47 -18
- data/lib/mongo/{util → utils}/conversions.rb +18 -3
- data/lib/mongo/{util → utils}/core_ext.rb +15 -32
- data/lib/mongo/{util → utils}/server_version.rb +15 -0
- data/lib/mongo/{util → utils}/support.rb +22 -55
- data/lib/mongo/utils/thread_local_variable_manager.rb +25 -0
- data/lib/mongo/utils.rb +19 -0
- data/lib/mongo.rb +44 -26
- data/mongo.gemspec +2 -2
- data/test/functional/authentication_test.rb +31 -10
- data/test/functional/bulk_api_stress_test.rb +133 -0
- data/test/functional/bulk_write_collection_view_test.rb +1198 -0
- data/test/functional/client_test.rb +627 -0
- data/test/functional/collection_test.rb +1419 -654
- data/test/functional/collection_writer_test.rb +83 -0
- data/test/functional/conversions_test.rb +46 -2
- data/test/functional/cursor_fail_test.rb +17 -9
- data/test/functional/cursor_message_test.rb +28 -15
- data/test/functional/cursor_test.rb +300 -165
- data/test/functional/db_api_test.rb +294 -264
- data/test/functional/db_connection_test.rb +15 -3
- data/test/functional/db_test.rb +165 -99
- data/test/functional/grid_file_system_test.rb +124 -112
- data/test/functional/grid_io_test.rb +17 -3
- data/test/functional/grid_test.rb +16 -2
- data/test/functional/pool_test.rb +99 -10
- data/test/functional/safe_test.rb +18 -4
- data/test/functional/ssl_test.rb +29 -0
- data/test/functional/support_test.rb +14 -0
- data/test/functional/timeout_test.rb +27 -27
- data/test/functional/uri_test.rb +268 -22
- data/test/functional/write_concern_test.rb +19 -5
- data/test/helpers/general.rb +50 -0
- data/test/helpers/test_unit.rb +476 -0
- data/test/replica_set/authentication_test.rb +28 -11
- data/test/replica_set/basic_test.rb +79 -23
- data/test/replica_set/client_test.rb +253 -124
- data/test/replica_set/connection_test.rb +59 -37
- data/test/replica_set/count_test.rb +18 -2
- data/test/replica_set/cursor_test.rb +30 -8
- data/test/replica_set/insert_test.rb +109 -2
- data/test/replica_set/max_values_test.rb +85 -10
- data/test/replica_set/pinning_test.rb +66 -2
- data/test/replica_set/query_test.rb +17 -3
- data/test/replica_set/read_preference_test.rb +115 -96
- data/test/replica_set/refresh_test.rb +59 -9
- data/test/replica_set/replication_ack_test.rb +32 -11
- data/test/replica_set/ssl_test.rb +32 -0
- data/test/sharded_cluster/basic_test.rb +73 -25
- data/test/shared/authentication/basic_auth_shared.rb +260 -0
- data/test/shared/authentication/bulk_api_auth_shared.rb +249 -0
- data/test/shared/authentication/gssapi_shared.rb +176 -0
- data/test/shared/authentication/sasl_plain_shared.rb +96 -0
- data/test/shared/authentication/scram_shared.rb +92 -0
- data/test/shared/ssl_shared.rb +235 -0
- data/test/test_helper.rb +47 -196
- data/test/threading/basic_test.rb +42 -2
- data/test/tools/mongo_config.rb +175 -35
- data/test/tools/mongo_config_test.rb +15 -1
- data/test/unit/client_test.rb +186 -57
- data/test/unit/collection_test.rb +44 -54
- data/test/unit/connection_test.rb +160 -71
- data/test/unit/cursor_test.rb +37 -3
- data/test/unit/db_test.rb +38 -14
- data/test/unit/grid_test.rb +15 -1
- data/test/unit/mongo_sharded_client_test.rb +30 -14
- data/test/unit/node_test.rb +16 -1
- data/test/unit/pool_manager_test.rb +21 -4
- data/test/unit/read_pref_test.rb +386 -1
- data/test/unit/read_test.rb +27 -13
- data/test/unit/safe_test.rb +22 -8
- data/test/unit/sharding_pool_manager_test.rb +25 -4
- data/test/unit/write_concern_test.rb +23 -9
- data.tar.gz.sig +0 -0
- metadata +80 -54
- metadata.gz.sig +0 -0
- data/lib/mongo/exceptions.rb +0 -65
- data/lib/mongo/util/read_preference.rb +0 -112
- data/lib/mongo/util/socket_util.rb +0 -20
- data/lib/mongo/util/ssl_socket.rb +0 -51
- data/lib/mongo/util/tcp_socket.rb +0 -62
- data/lib/mongo/util/thread_local_variable_manager.rb +0 -11
- data/lib/mongo/util/unix_socket.rb +0 -23
- data/lib/mongo/util/uri_parser.rb +0 -337
- data/test/functional/connection_test.rb +0 -449
- data/test/functional/threading_test.rb +0 -95
- data/test/replica_set/complex_connect_test.rb +0 -64
- data/test/shared/authentication.rb +0 -66
- data/test/unit/pool_test.rb +0 -9
- data/test/unit/util_test.rb +0 -55
data/test/test_helper.rb
CHANGED
|
@@ -1,210 +1,61 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
# Copyright (C) 2009-2013 MongoDB, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
7
14
|
|
|
8
|
-
#
|
|
9
|
-
if RUBY_VERSION >= '1.9.0' && RUBY_ENGINE == 'ruby'
|
|
10
|
-
if ENV.key?('COVERAGE')
|
|
11
|
-
require 'simplecov'
|
|
12
|
-
SimpleCov.start do
|
|
13
|
-
add_group "Mongo", 'lib/mongo'
|
|
14
|
-
add_group "BSON", 'lib/bson'
|
|
15
|
-
add_filter "/test/"
|
|
16
|
-
merge_timeout 3600
|
|
17
|
-
command_name ENV['SIMPLECOV_COMMAND_NAME'] if ENV.has_key?('SIMPLECOV_COMMAND_NAME')
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
gem 'test-unit' # Do NOT remove this line - gem version is needed for Test::Unit::TestCase.shutdown
|
|
22
|
-
require 'test/unit'
|
|
23
|
-
require 'tools/mongo_config'
|
|
24
|
-
|
|
25
|
-
class Test::Unit::TestCase
|
|
26
|
-
|
|
27
|
-
TEST_DATA = File.join(File.dirname(__FILE__), 'data')
|
|
28
|
-
|
|
29
|
-
def ensure_cluster(kind=nil, opts={})
|
|
30
|
-
@@cluster ||= nil
|
|
15
|
+
# NOTE: on ruby <1.9 you need to run individual tests with 'bundle exec'
|
|
31
16
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
else
|
|
36
|
-
cluster_opts = Mongo::Config::DEFAULT_SHARDED_SIMPLE.dup
|
|
37
|
-
end
|
|
17
|
+
unless RUBY_VERSION < '1.9' || ENV.key?('JENKINS_CI')
|
|
18
|
+
require 'simplecov'
|
|
19
|
+
require 'coveralls'
|
|
38
20
|
|
|
39
|
-
|
|
21
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
|
22
|
+
SimpleCov::Formatter::HTMLFormatter,
|
|
23
|
+
Coveralls::SimpleCov::Formatter
|
|
24
|
+
]
|
|
40
25
|
|
|
41
|
-
|
|
42
|
-
|
|
26
|
+
SimpleCov.start do
|
|
27
|
+
add_group 'Driver', 'lib/mongo'
|
|
28
|
+
add_group 'BSON', 'lib/bson'
|
|
43
29
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
@@cluster = Mongo::Config::ClusterManager.new(config)
|
|
48
|
-
|
|
49
|
-
Test::Unit::TestCase.class_eval do
|
|
50
|
-
@@force_shutdown = false
|
|
51
|
-
|
|
52
|
-
def self.shutdown
|
|
53
|
-
if @@force_shutdown || /rake_test_loader/ !~ $0
|
|
54
|
-
@@cluster.stop
|
|
55
|
-
@@cluster.clobber
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
@@cluster.start
|
|
62
|
-
instance_variable_set("@#{kind}", @@cluster)
|
|
30
|
+
add_filter 'tasks'
|
|
31
|
+
add_filter 'test'
|
|
32
|
+
add_filter 'bin'
|
|
63
33
|
end
|
|
64
|
-
|
|
65
|
-
# Generic code for rescuing connection failures and retrying operations.
|
|
66
|
-
# This could be combined with some timeout functionality.
|
|
67
|
-
def rescue_connection_failure(max_retries=30)
|
|
68
|
-
retries = 0
|
|
69
|
-
begin
|
|
70
|
-
yield
|
|
71
|
-
rescue Mongo::ConnectionFailure => ex
|
|
72
|
-
#puts "Rescue attempt #{retries}: from #{ex}"
|
|
73
|
-
retries += 1
|
|
74
|
-
raise ex if retries > max_retries
|
|
75
|
-
sleep(2)
|
|
76
|
-
retry
|
|
77
|
-
end
|
|
78
|
-
end
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
def silently
|
|
82
|
-
warn_level = $VERBOSE
|
|
83
|
-
$VERBOSE = nil
|
|
84
|
-
begin
|
|
85
|
-
result = yield
|
|
86
|
-
ensure
|
|
87
|
-
$VERBOSE = warn_level
|
|
88
|
-
end
|
|
89
|
-
result
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
begin
|
|
93
|
-
silently { require 'shoulda' }
|
|
94
|
-
silently { require 'mocha/setup' }
|
|
95
|
-
rescue LoadError
|
|
96
|
-
puts <<MSG
|
|
97
|
-
|
|
98
|
-
This test suite requires shoulda and mocha.
|
|
99
|
-
You can install them as follows:
|
|
100
|
-
gem install shoulda
|
|
101
|
-
gem install mocha
|
|
102
|
-
|
|
103
|
-
MSG
|
|
104
|
-
exit
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
unless defined? MONGO_TEST_DB
|
|
108
|
-
MONGO_TEST_DB = 'ruby-test-db'
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
unless defined? TEST_PORT
|
|
112
|
-
TEST_PORT = ENV['MONGO_RUBY_DRIVER_PORT'] ? ENV['MONGO_RUBY_DRIVER_PORT'].to_i : Mongo::MongoClient::DEFAULT_PORT
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
unless defined? TEST_HOST
|
|
116
|
-
TEST_HOST = ENV['MONGO_RUBY_DRIVER_HOST'] || 'localhost'
|
|
117
34
|
end
|
|
118
35
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
include BSON
|
|
36
|
+
# required for at_exit, at_start hooks
|
|
37
|
+
require 'test-unit'
|
|
122
38
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
else
|
|
127
|
-
MongoClient.new(TEST_HOST, TEST_PORT, options)
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
def standard_connection(options={}, legacy=false)
|
|
132
|
-
self.class.standard_connection(options, legacy)
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
def self.host_port
|
|
136
|
-
"#{mongo_host}:#{mongo_port}"
|
|
137
|
-
end
|
|
138
|
-
|
|
139
|
-
def self.mongo_host
|
|
140
|
-
TEST_HOST
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
def self.mongo_port
|
|
144
|
-
TEST_PORT
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
def host_port
|
|
148
|
-
self.class.host_port
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
def mongo_host
|
|
152
|
-
self.class.mongo_host
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
def mongo_port
|
|
156
|
-
self.class.mongo_port
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
def method_name
|
|
160
|
-
caller[0]=~/`(.*?)'/
|
|
161
|
-
$1
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def step_down_command
|
|
165
|
-
# Adding force=true to avoid 'no secondaries within 10 seconds of my optime' errors
|
|
166
|
-
step_down_command = BSON::OrderedHash.new
|
|
167
|
-
step_down_command[:replSetStepDown] = 5
|
|
168
|
-
step_down_command[:force] = true
|
|
169
|
-
step_down_command
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
def new_mock_socket(host='localhost', port=27017)
|
|
173
|
-
socket = Object.new
|
|
174
|
-
socket.stubs(:setsockopt).with(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
|
175
|
-
socket.stubs(:close)
|
|
176
|
-
socket.stubs(:closed?)
|
|
177
|
-
socket.stubs(:checkin)
|
|
178
|
-
socket.stubs(:pool)
|
|
179
|
-
socket
|
|
180
|
-
end
|
|
39
|
+
require 'test/unit'
|
|
40
|
+
require 'shoulda'
|
|
41
|
+
require 'mocha/setup'
|
|
181
42
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
socket.stubs(:setsockopt).with(Socket::IPPROTO_TCP)
|
|
185
|
-
socket.stubs(:close)
|
|
186
|
-
socket.stubs(:closed?)
|
|
187
|
-
socket
|
|
188
|
-
end
|
|
43
|
+
# cluster manager
|
|
44
|
+
require 'tools/mongo_config'
|
|
189
45
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
46
|
+
# For kerberos testing.
|
|
47
|
+
begin
|
|
48
|
+
require 'mongo_kerberos'
|
|
49
|
+
rescue LoadError; end
|
|
193
50
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
rescue => e
|
|
198
|
-
if klass.to_s != e.class.to_s
|
|
199
|
-
flunk "Expected exception class #{klass} but got #{e.class}.\n #{e.backtrace}"
|
|
200
|
-
end
|
|
51
|
+
# test helpers
|
|
52
|
+
require 'helpers/general'
|
|
53
|
+
require 'helpers/test_unit'
|
|
201
54
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
end
|
|
209
|
-
end
|
|
55
|
+
# optional development and debug utilities
|
|
56
|
+
begin
|
|
57
|
+
require 'pry-rescue'
|
|
58
|
+
require 'pry-nav'
|
|
59
|
+
rescue LoadError
|
|
60
|
+
# failed to load, skipping pry
|
|
210
61
|
end
|
|
@@ -1,12 +1,26 @@
|
|
|
1
|
+
# Copyright (C) 2009-2013 MongoDB, Inc.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
1
15
|
require 'test_helper'
|
|
2
16
|
|
|
3
|
-
class
|
|
17
|
+
class ThreadingTest < Test::Unit::TestCase
|
|
4
18
|
|
|
5
19
|
include Mongo
|
|
6
20
|
|
|
7
21
|
def setup
|
|
8
22
|
@client = standard_connection(:pool_size => 10, :pool_timeout => 30)
|
|
9
|
-
@db = @client.db(
|
|
23
|
+
@db = @client.db(TEST_DB)
|
|
10
24
|
@coll = @db.collection('thread-test-collection')
|
|
11
25
|
@coll.drop
|
|
12
26
|
|
|
@@ -77,4 +91,30 @@ class TestThreading < Test::Unit::TestCase
|
|
|
77
91
|
assert thread_values.all?{|v| v == 1000}
|
|
78
92
|
assert_equal thread_values.size, n_threads
|
|
79
93
|
end
|
|
94
|
+
|
|
95
|
+
def test_threading
|
|
96
|
+
@coll.drop
|
|
97
|
+
@coll = @db.collection('thread-test-collection')
|
|
98
|
+
|
|
99
|
+
docs = []
|
|
100
|
+
1000.times {|i| docs << {:x => i}}
|
|
101
|
+
@coll.insert(docs)
|
|
102
|
+
|
|
103
|
+
threads = []
|
|
104
|
+
|
|
105
|
+
10.times do |i|
|
|
106
|
+
threads[i] = Thread.new do
|
|
107
|
+
sum = 0
|
|
108
|
+
@coll.find().each do |document|
|
|
109
|
+
sum += document["x"]
|
|
110
|
+
end
|
|
111
|
+
assert_equal 499500, sum
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
10.times do |i|
|
|
116
|
+
threads[i].join
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
80
120
|
end
|
data/test/tools/mongo_config.rb
CHANGED
|
@@ -1,4 +1,19 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
# Copyright (C) 2009-2013 MongoDB, Inc.
|
|
4
|
+
#
|
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
# you may not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
# See the License for the specific language governing permissions and
|
|
15
|
+
# limitations under the License.
|
|
16
|
+
|
|
2
17
|
require 'socket'
|
|
3
18
|
require 'fileutils'
|
|
4
19
|
require 'mongo'
|
|
@@ -26,7 +41,7 @@ module Mongo
|
|
|
26
41
|
class Config
|
|
27
42
|
DEFAULT_BASE_OPTS = { :host => 'localhost', :dbpath => 'data', :logpath => 'data/log' }
|
|
28
43
|
DEFAULT_REPLICA_SET = DEFAULT_BASE_OPTS.merge( :replicas => 3, :arbiters => 0 )
|
|
29
|
-
DEFAULT_SHARDED_SIMPLE = DEFAULT_BASE_OPTS.merge( :shards => 2, :configs => 1, :routers =>
|
|
44
|
+
DEFAULT_SHARDED_SIMPLE = DEFAULT_BASE_OPTS.merge( :shards => 2, :configs => 1, :routers => 2 )
|
|
30
45
|
DEFAULT_SHARDED_REPLICA = DEFAULT_SHARDED_SIMPLE.merge( :replicas => 3, :arbiters => 0)
|
|
31
46
|
|
|
32
47
|
IGNORE_KEYS = [:host, :command, :_id]
|
|
@@ -35,7 +50,7 @@ module Mongo
|
|
|
35
50
|
MONGODS_OPT_KEYS = [:mongods]
|
|
36
51
|
CLUSTER_OPT_KEYS = SHARDING_OPT_KEYS + REPLICA_OPT_KEYS + MONGODS_OPT_KEYS
|
|
37
52
|
|
|
38
|
-
FLAGS = [:noprealloc, :smallfiles, :logappend, :configsvr, :shardsvr, :quiet, :fastsync, :auth]
|
|
53
|
+
FLAGS = [:noprealloc, :smallfiles, :logappend, :configsvr, :shardsvr, :quiet, :fastsync, :auth, :ipv6]
|
|
39
54
|
|
|
40
55
|
DEFAULT_VERIFIES = 60
|
|
41
56
|
BASE_PORT = 3000
|
|
@@ -49,6 +64,7 @@ module Mongo
|
|
|
49
64
|
raise "missing required option" if [:host, :dbpath].any?{|k| !opts[k]}
|
|
50
65
|
|
|
51
66
|
config = opts.reject {|k,v| CLUSTER_OPT_KEYS.include?(k)}
|
|
67
|
+
|
|
52
68
|
kinds = CLUSTER_OPT_KEYS.select{|key| opts.has_key?(key)} # order is significant
|
|
53
69
|
|
|
54
70
|
replica_count = 0
|
|
@@ -67,9 +83,11 @@ module Mongo
|
|
|
67
83
|
make_config(opts)
|
|
68
84
|
when :routers
|
|
69
85
|
make_router(config, opts)
|
|
86
|
+
when :shards
|
|
87
|
+
make_standalone_shard(kind, opts)
|
|
70
88
|
else
|
|
71
89
|
make_mongod(kind, opts)
|
|
72
|
-
|
|
90
|
+
end
|
|
73
91
|
|
|
74
92
|
replica_count += 1 if [:replicas, :arbiters].member?(kind)
|
|
75
93
|
node
|
|
@@ -102,6 +120,8 @@ module Mongo
|
|
|
102
120
|
quiet = opts[:quiet] || true
|
|
103
121
|
fast_sync = opts[:fastsync] || false
|
|
104
122
|
auth = opts[:auth] || true
|
|
123
|
+
ipv6 = opts[:ipv6].nil? ? true : opts[:ipv6]
|
|
124
|
+
setParameter = opts[:setParameter] || 'enableTestCommands=1'
|
|
105
125
|
|
|
106
126
|
params.merge(:command => mongod,
|
|
107
127
|
:dbpath => path,
|
|
@@ -109,7 +129,23 @@ module Mongo
|
|
|
109
129
|
:noprealloc => noprealloc,
|
|
110
130
|
:quiet => quiet,
|
|
111
131
|
:fastsync => fast_sync,
|
|
112
|
-
:auth => auth
|
|
132
|
+
:auth => auth,
|
|
133
|
+
:ipv6 => ipv6,
|
|
134
|
+
:setParameter => setParameter)
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def self.key_file(opts)
|
|
138
|
+
keyFile = opts[:key_file] || '/test/fixtures/auth/keyfile'
|
|
139
|
+
keyFile = Dir.pwd << keyFile
|
|
140
|
+
system "chmod 600 #{keyFile}"
|
|
141
|
+
keyFile
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
# A regular mongod minus --auth and plus --keyFile.
|
|
145
|
+
def self.make_standalone_shard(kind, opts)
|
|
146
|
+
params = make_mongod(kind, opts)
|
|
147
|
+
params.delete(:auth)
|
|
148
|
+
params.merge(:keyFile => key_file(opts))
|
|
113
149
|
end
|
|
114
150
|
|
|
115
151
|
def self.make_replica(opts, id)
|
|
@@ -117,20 +153,18 @@ module Mongo
|
|
|
117
153
|
|
|
118
154
|
replSet = opts[:replSet] || 'ruby-driver-test'
|
|
119
155
|
oplogSize = opts[:oplog_size] || 5
|
|
120
|
-
keyFile = opts[:key_file] || '/test/tools/keyfile.txt'
|
|
121
|
-
|
|
122
|
-
keyFile = Dir.pwd << keyFile
|
|
123
|
-
system "chmod 600 #{keyFile}"
|
|
124
156
|
|
|
125
157
|
params.merge(:_id => id,
|
|
126
158
|
:replSet => replSet,
|
|
127
159
|
:oplogSize => oplogSize,
|
|
128
|
-
:keyFile =>
|
|
160
|
+
:keyFile => key_file(opts))
|
|
129
161
|
end
|
|
130
162
|
|
|
131
163
|
def self.make_config(opts)
|
|
132
164
|
params = make_mongod('configs', opts)
|
|
133
|
-
params.
|
|
165
|
+
params.delete(:auth)
|
|
166
|
+
params.merge(:configsvr => true,
|
|
167
|
+
:keyFile => key_file(opts))
|
|
134
168
|
end
|
|
135
169
|
|
|
136
170
|
def self.make_router(config, opts)
|
|
@@ -138,8 +172,9 @@ module Mongo
|
|
|
138
172
|
mongos = ENV['MONGOS'] || 'mongos'
|
|
139
173
|
|
|
140
174
|
params.merge(
|
|
141
|
-
:command
|
|
142
|
-
:configdb => self.configdb(config)
|
|
175
|
+
:command => mongos,
|
|
176
|
+
:configdb => self.configdb(config),
|
|
177
|
+
:keyFile => key_file(opts)
|
|
143
178
|
)
|
|
144
179
|
end
|
|
145
180
|
|
|
@@ -268,6 +303,11 @@ module Mongo
|
|
|
268
303
|
|
|
269
304
|
def initialize(config)
|
|
270
305
|
@config = config
|
|
306
|
+
cmd = init_config!
|
|
307
|
+
super(cmd, @config[:host], @config[:port])
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def init_config!
|
|
271
311
|
dbpath = @config[:dbpath]
|
|
272
312
|
[dbpath, File.dirname(@config[:logpath])].compact.each{|dir| FileUtils.mkdir_p(dir) unless File.directory?(dir) }
|
|
273
313
|
command = @config[:command] || 'mongod'
|
|
@@ -281,7 +321,6 @@ module Mongo
|
|
|
281
321
|
end
|
|
282
322
|
end
|
|
283
323
|
cmd = [command, arguments].flatten.compact
|
|
284
|
-
super(cmd, @config[:host], @config[:port])
|
|
285
324
|
end
|
|
286
325
|
|
|
287
326
|
def start(verifies = DEFAULT_VERIFIES)
|
|
@@ -301,8 +340,13 @@ module Mongo
|
|
|
301
340
|
sleep 1
|
|
302
341
|
end
|
|
303
342
|
end
|
|
304
|
-
|
|
305
|
-
|
|
343
|
+
if @config.delete(:setParameter)
|
|
344
|
+
@cmd = init_config!
|
|
345
|
+
start(verifies)
|
|
346
|
+
else
|
|
347
|
+
system "ps -fp #{@pid}; cat #{@config[:logpath]}"
|
|
348
|
+
raise Mongo::ConnectionFailure, "DbServer.start verify via connection probe failed - port:#{@port.inspect} @pid:#{@pid.inspect} kill:#{Process.kill(0, @pid).inspect} running?:#{running?.inspect} cmd:#{cmd.inspect}"
|
|
349
|
+
end
|
|
306
350
|
end
|
|
307
351
|
|
|
308
352
|
end
|
|
@@ -313,7 +357,7 @@ module Mongo
|
|
|
313
357
|
@config = config
|
|
314
358
|
@servers = {}
|
|
315
359
|
Mongo::Config::CLUSTER_OPT_KEYS.each do |key|
|
|
316
|
-
@servers[key] = @config[key].collect{|conf| DbServer.new(conf)} if @config[key]
|
|
360
|
+
@servers[key] = @config[key].collect{|conf| p conf; DbServer.new(conf)} if @config[key]
|
|
317
361
|
end
|
|
318
362
|
end
|
|
319
363
|
|
|
@@ -321,6 +365,35 @@ module Mongo
|
|
|
321
365
|
@servers.collect{|k,v| (!key || key == k) ? v : nil}.flatten.compact
|
|
322
366
|
end
|
|
323
367
|
|
|
368
|
+
def ensure_authenticated(client)
|
|
369
|
+
begin
|
|
370
|
+
client[TEST_DB].authenticate(TEST_USER, TEST_USER_PWD)
|
|
371
|
+
rescue Mongo::MongoArgumentError => ex
|
|
372
|
+
# client is already authenticated
|
|
373
|
+
raise ex unless ex.message =~ /already authenticated/
|
|
374
|
+
rescue Mongo::AuthenticationError => ex
|
|
375
|
+
# 1) The creds are wrong
|
|
376
|
+
# 2) Or the user doesn't exist
|
|
377
|
+
roles = [ 'dbAdminAnyDatabase',
|
|
378
|
+
'userAdminAnyDatabase',
|
|
379
|
+
'readWriteAnyDatabase',
|
|
380
|
+
'clusterAdmin' ]
|
|
381
|
+
begin
|
|
382
|
+
# Try to add the user for case (2)
|
|
383
|
+
client[TEST_DB].add_user(TEST_USER, TEST_USER_PWD, nil, :roles => roles)
|
|
384
|
+
client[TEST_DB].authenticate(TEST_USER, TEST_USER_PWD)
|
|
385
|
+
rescue Mongo::ConnectionFailure, Mongo::OperationFailure => ex
|
|
386
|
+
# Maybe not master, so try to authenticate
|
|
387
|
+
# 2.2 throws an OperationFailure if add_user fails
|
|
388
|
+
begin
|
|
389
|
+
client[TEST_DB].authenticate(TEST_USER, TEST_USER_PWD)
|
|
390
|
+
rescue => ex
|
|
391
|
+
# Maybe creds are wrong, nothing we can do
|
|
392
|
+
end
|
|
393
|
+
end
|
|
394
|
+
end
|
|
395
|
+
end
|
|
396
|
+
|
|
324
397
|
def command( cmd_servers, db_name, cmd, opts = {} )
|
|
325
398
|
ret = []
|
|
326
399
|
cmd = cmd.class == Array ? cmd : [ cmd ]
|
|
@@ -330,6 +403,7 @@ module Mongo
|
|
|
330
403
|
debug 3, cmd_server.inspect
|
|
331
404
|
cmd_server = cmd_server.config if cmd_server.is_a?(DbServer)
|
|
332
405
|
client = Mongo::MongoClient.new(cmd_server[:host], cmd_server[:port])
|
|
406
|
+
ensure_authenticated(client)
|
|
333
407
|
cmd.each do |c|
|
|
334
408
|
debug 3, "ClusterManager.command c:#{c.inspect}"
|
|
335
409
|
response = client[db_name].command( c, opts )
|
|
@@ -343,6 +417,10 @@ module Mongo
|
|
|
343
417
|
ret.size == 1 ? ret.first : ret
|
|
344
418
|
end
|
|
345
419
|
|
|
420
|
+
def replica_set?
|
|
421
|
+
!!config[:replicas]
|
|
422
|
+
end
|
|
423
|
+
|
|
346
424
|
def repl_set_get_status
|
|
347
425
|
command( @config[:replicas], 'admin', { :replSetGetStatus => 1 }, {:check_response => false } )
|
|
348
426
|
end
|
|
@@ -350,6 +428,7 @@ module Mongo
|
|
|
350
428
|
def repl_set_get_config
|
|
351
429
|
host, port = primary_name.split(":")
|
|
352
430
|
client = Mongo::MongoClient.new(host, port)
|
|
431
|
+
ensure_authenticated(client)
|
|
353
432
|
client['local']['system.replset'].find_one
|
|
354
433
|
end
|
|
355
434
|
|
|
@@ -368,27 +447,49 @@ module Mongo
|
|
|
368
447
|
end
|
|
369
448
|
|
|
370
449
|
def repl_set_startup
|
|
371
|
-
states
|
|
372
|
-
|
|
373
|
-
|
|
450
|
+
states = nil
|
|
451
|
+
healthy = false
|
|
452
|
+
|
|
453
|
+
80.times do
|
|
454
|
+
# enter the thunderdome...
|
|
455
|
+
states = repl_set_get_status.zip(repl_set_is_master)
|
|
374
456
|
healthy = states.all? do |status, is_master|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
457
|
+
# check replica set status for member list
|
|
458
|
+
next unless status['ok'] == 1.0 && (members = status['members'])
|
|
459
|
+
|
|
460
|
+
# ensure all replica set members are in a valid state
|
|
461
|
+
next unless members.all? { |m| [1,2,7].include?(m['state']) }
|
|
462
|
+
|
|
463
|
+
# check for primary replica set member
|
|
464
|
+
next unless (primary = members.find { |m| m['state'] == 1 })
|
|
465
|
+
|
|
466
|
+
# check replica set member optimes
|
|
467
|
+
primary_optime = (primary['optime']['ts'] ? primary['optime']['ts'] : primary['optime']).seconds
|
|
468
|
+
next unless primary_optime && members.all? do |m|
|
|
469
|
+
m_optime = (m['optime']['ts'] ? m['optime']['ts'] : m['optime']).seconds
|
|
470
|
+
m['state'] == 7 || primary_optime - m_optime < 5
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
# check replica set state
|
|
474
|
+
case status['myState']
|
|
475
|
+
when 1
|
|
476
|
+
is_master['ismaster'] == true &&
|
|
477
|
+
is_master['secondary'] == false
|
|
478
|
+
when 2
|
|
479
|
+
is_master['ismaster'] == false &&
|
|
480
|
+
is_master['secondary'] == true
|
|
481
|
+
when 7
|
|
482
|
+
is_master['ismaster'] == false &&
|
|
483
|
+
is_master['secondary'] == false
|
|
386
484
|
end
|
|
387
485
|
end
|
|
388
|
-
|
|
486
|
+
|
|
487
|
+
return healthy if healthy
|
|
389
488
|
sleep(1)
|
|
390
489
|
end
|
|
391
|
-
|
|
490
|
+
|
|
491
|
+
raise Mongo::OperationFailure,
|
|
492
|
+
"replSet startup failed - status: #{states.inspect}"
|
|
392
493
|
end
|
|
393
494
|
|
|
394
495
|
def repl_set_seeds
|
|
@@ -403,13 +504,19 @@ module Mongo
|
|
|
403
504
|
repl_set_seeds.join(',')
|
|
404
505
|
end
|
|
405
506
|
|
|
507
|
+
def members_uri
|
|
508
|
+
members = @config[:replicas] || @config[:routers]
|
|
509
|
+
members.collect{|node| "#{node[:host]}:#{node[:port]}"}.join(',')
|
|
510
|
+
end
|
|
511
|
+
|
|
406
512
|
def repl_set_name
|
|
407
513
|
@config[:replicas].first[:replSet]
|
|
408
514
|
end
|
|
409
515
|
|
|
410
516
|
def member_names_by_state(state)
|
|
411
517
|
states = Array(state)
|
|
412
|
-
status
|
|
518
|
+
# Any status with a REMOVED node won't have the full cluster state
|
|
519
|
+
status = repl_set_get_status.find {|status| status['members'].find {|m| m['state'] == 'REMOVED'}.nil?}
|
|
413
520
|
status['members'].find_all{|member| states.index(member['state']) }.collect{|member| member['name']}
|
|
414
521
|
end
|
|
415
522
|
|
|
@@ -513,7 +620,15 @@ module Mongo
|
|
|
513
620
|
end
|
|
514
621
|
|
|
515
622
|
def addshards(shards = @config[:shards])
|
|
516
|
-
|
|
623
|
+
begin
|
|
624
|
+
command( @config[:routers].first, 'admin', Array(shards).collect{|s| { :addshard => "#{s[:host]}:#{s[:port]}" } } )
|
|
625
|
+
rescue Mongo::OperationFailure => ex
|
|
626
|
+
# Because we cannot run the listshards command under the localhost
|
|
627
|
+
# exception in > 2.7.1, we run the risk of attempting to add the same shard twice.
|
|
628
|
+
# Our tests may add a local db to a shard, if the cluster is still up,
|
|
629
|
+
# then we can ignore this.
|
|
630
|
+
raise ex unless ex.message =~ /host already used/
|
|
631
|
+
end
|
|
517
632
|
end
|
|
518
633
|
|
|
519
634
|
def listshards
|
|
@@ -543,7 +658,8 @@ module Mongo
|
|
|
543
658
|
servers.each{|server| server.start}
|
|
544
659
|
# TODO - sharded replica sets - pending
|
|
545
660
|
if @config[:replicas]
|
|
546
|
-
repl_set_initiate if repl_set_get_status.first['
|
|
661
|
+
repl_set_initiate if repl_set_get_status.first['code'] == 94 ||
|
|
662
|
+
(repl_set_get_status.first['startupStatus'] && repl_set_get_status.first['startupStatus'] == 3)
|
|
547
663
|
repl_set_startup
|
|
548
664
|
end
|
|
549
665
|
if @config[:routers]
|
|
@@ -553,7 +669,31 @@ module Mongo
|
|
|
553
669
|
end
|
|
554
670
|
alias :restart :start
|
|
555
671
|
|
|
672
|
+
def delete_users
|
|
673
|
+
cmd_servers = replica_set? ? [ primary ] : routers
|
|
674
|
+
|
|
675
|
+
cmd_servers.each do |cmd_server|
|
|
676
|
+
next unless cmd_server
|
|
677
|
+
begin
|
|
678
|
+
client = Mongo::MongoClient.new(cmd_server.config[:host],
|
|
679
|
+
cmd_server.config[:port])
|
|
680
|
+
ensure_authenticated(client)
|
|
681
|
+
db = client[TEST_DB]
|
|
682
|
+
|
|
683
|
+
if client.server_version < '2.5'
|
|
684
|
+
db['system.users'].remove
|
|
685
|
+
else
|
|
686
|
+
db.command(:dropAllUsersFromDatabase => 1)
|
|
687
|
+
end
|
|
688
|
+
break
|
|
689
|
+
rescue Mongo::ConnectionFailure
|
|
690
|
+
end
|
|
691
|
+
end
|
|
692
|
+
end
|
|
693
|
+
|
|
556
694
|
def stop
|
|
695
|
+
start
|
|
696
|
+
delete_users
|
|
557
697
|
servers.each{|server| server.stop}
|
|
558
698
|
self
|
|
559
699
|
end
|