mongo 1.9.2 → 1.10.0.rc0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/LICENSE +1 -1
- data/README.md +94 -334
- data/Rakefile +6 -4
- data/VERSION +1 -1
- data/bin/mongo_console +13 -6
- data/lib/mongo.rb +22 -27
- data/lib/mongo/bulk_write_collection_view.rb +352 -0
- data/lib/mongo/collection.rb +128 -188
- data/lib/mongo/collection_writer.rb +348 -0
- data/lib/mongo/connection.rb +19 -0
- data/lib/mongo/{util → connection}/node.rb +15 -1
- data/lib/mongo/{util → connection}/pool.rb +34 -19
- data/lib/mongo/{util → connection}/pool_manager.rb +8 -2
- data/lib/mongo/{util → connection}/sharding_pool_manager.rb +1 -1
- data/lib/mongo/connection/socket.rb +18 -0
- data/lib/mongo/{util → connection/socket}/socket_util.rb +5 -2
- data/lib/mongo/{util → connection/socket}/ssl_socket.rb +3 -4
- data/lib/mongo/{util → connection/socket}/tcp_socket.rb +25 -15
- data/lib/mongo/{util → connection/socket}/unix_socket.rb +6 -4
- data/lib/mongo/cursor.rb +113 -47
- data/lib/mongo/db.rb +203 -131
- data/lib/mongo/{exceptions.rb → exception.rb} +7 -1
- data/lib/mongo/functional.rb +19 -0
- data/lib/mongo/functional/authentication.rb +303 -0
- data/lib/mongo/{util → functional}/logging.rb +1 -1
- data/lib/mongo/{util → functional}/read_preference.rb +49 -1
- data/lib/mongo/{util → functional}/uri_parser.rb +81 -69
- data/lib/mongo/{util → functional}/write_concern.rb +2 -1
- data/{test/unit/pool_test.rb → lib/mongo/gridfs.rb} +5 -10
- data/lib/mongo/gridfs/grid.rb +1 -3
- data/lib/mongo/gridfs/grid_ext.rb +1 -1
- data/lib/mongo/gridfs/grid_file_system.rb +1 -1
- data/lib/mongo/gridfs/grid_io.rb +1 -1
- data/lib/mongo/legacy.rb +63 -8
- data/lib/mongo/mongo_client.rb +128 -154
- data/lib/mongo/mongo_replica_set_client.rb +17 -11
- data/lib/mongo/mongo_sharded_client.rb +2 -1
- data/lib/mongo/networking.rb +19 -10
- data/lib/mongo/utils.rb +19 -0
- data/lib/mongo/{util → utils}/conversions.rb +1 -1
- data/lib/mongo/{util → utils}/core_ext.rb +1 -1
- data/lib/mongo/{util → utils}/server_version.rb +1 -1
- data/lib/mongo/{util → utils}/support.rb +10 -57
- data/lib/mongo/{util → utils}/thread_local_variable_manager.rb +1 -1
- data/test/functional/authentication_test.rb +8 -21
- data/test/functional/bulk_write_collection_view_test.rb +782 -0
- data/test/functional/{connection_test.rb → client_test.rb} +153 -78
- data/test/functional/collection_test.rb +343 -97
- data/test/functional/collection_writer_test.rb +83 -0
- data/test/functional/conversions_test.rb +1 -3
- data/test/functional/cursor_fail_test.rb +3 -3
- data/test/functional/cursor_message_test.rb +3 -3
- data/test/functional/cursor_test.rb +38 -3
- data/test/functional/db_api_test.rb +5 -5
- data/test/functional/db_connection_test.rb +2 -2
- data/test/functional/db_test.rb +35 -11
- data/test/functional/grid_file_system_test.rb +2 -2
- data/test/functional/grid_io_test.rb +2 -2
- data/test/functional/grid_test.rb +2 -2
- data/test/functional/pool_test.rb +2 -3
- data/test/functional/safe_test.rb +5 -5
- data/test/functional/ssl_test.rb +22 -102
- data/test/functional/support_test.rb +1 -1
- data/test/functional/timeout_test.rb +6 -22
- data/test/functional/uri_test.rb +113 -12
- data/test/functional/write_concern_test.rb +6 -6
- data/test/helpers/general.rb +50 -0
- data/test/helpers/test_unit.rb +309 -0
- data/test/replica_set/authentication_test.rb +8 -23
- data/test/replica_set/basic_test.rb +41 -14
- data/test/replica_set/client_test.rb +179 -117
- data/test/replica_set/complex_connect_test.rb +6 -7
- data/test/replica_set/connection_test.rb +46 -38
- data/test/replica_set/count_test.rb +2 -2
- data/test/replica_set/cursor_test.rb +8 -8
- data/test/replica_set/insert_test.rb +64 -2
- data/test/replica_set/max_values_test.rb +59 -10
- data/test/replica_set/pinning_test.rb +2 -2
- data/test/replica_set/query_test.rb +2 -2
- data/test/replica_set/read_preference_test.rb +6 -6
- data/test/replica_set/refresh_test.rb +7 -7
- data/test/replica_set/replication_ack_test.rb +5 -5
- data/test/replica_set/ssl_test.rb +24 -106
- data/test/sharded_cluster/basic_test.rb +43 -15
- data/test/shared/authentication/basic_auth_shared.rb +215 -0
- data/test/shared/authentication/sasl_plain_shared.rb +96 -0
- data/test/shared/ssl_shared.rb +173 -0
- data/test/test_helper.rb +31 -199
- data/test/threading/basic_test.rb +29 -3
- data/test/tools/mongo_config.rb +45 -20
- data/test/tools/mongo_config_test.rb +1 -1
- data/test/unit/client_test.rb +136 -57
- data/test/unit/collection_test.rb +31 -55
- data/test/unit/connection_test.rb +135 -72
- data/test/unit/cursor_test.rb +2 -2
- data/test/unit/db_test.rb +19 -15
- data/test/unit/grid_test.rb +2 -2
- data/test/unit/mongo_sharded_client_test.rb +17 -15
- data/test/unit/node_test.rb +2 -2
- data/test/unit/pool_manager_test.rb +7 -5
- data/test/unit/read_pref_test.rb +82 -2
- data/test/unit/read_test.rb +14 -14
- data/test/unit/safe_test.rb +9 -9
- data/test/unit/sharding_pool_manager_test.rb +11 -5
- data/test/unit/write_concern_test.rb +9 -9
- metadata +71 -56
- metadata.gz.sig +0 -0
- data/test/functional/threading_test.rb +0 -109
- data/test/shared/authentication.rb +0 -121
- data/test/unit/util_test.rb +0 -69
data/lib/mongo/db.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (C) 2013
|
1
|
+
# Copyright (C) 2009-2013 MongoDB, Inc.
|
2
2
|
#
|
3
3
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
4
|
# you may not use this file except in compliance with the License.
|
@@ -12,9 +12,6 @@
|
|
12
12
|
# See the License for the specific language governing permissions and
|
13
13
|
# limitations under the License.
|
14
14
|
|
15
|
-
require 'socket'
|
16
|
-
require 'thread'
|
17
|
-
|
18
15
|
module Mongo
|
19
16
|
|
20
17
|
# A MongoDB database.
|
@@ -27,6 +24,7 @@ module Mongo
|
|
27
24
|
SYSTEM_USER_COLLECTION = 'system.users'
|
28
25
|
SYSTEM_JS_COLLECTION = 'system.js'
|
29
26
|
SYSTEM_COMMAND_COLLECTION = '$cmd'
|
27
|
+
MAX_TIME_MS_CODE = 50
|
30
28
|
|
31
29
|
PROFILE_LEVEL = {
|
32
30
|
:off => 0,
|
@@ -63,7 +61,10 @@ module Mongo
|
|
63
61
|
attr_reader :name, :write_concern
|
64
62
|
|
65
63
|
# The Mongo::MongoClient instance connecting to the MongoDB server.
|
66
|
-
attr_reader :
|
64
|
+
attr_reader :client
|
65
|
+
|
66
|
+
# for backward compatibility
|
67
|
+
alias_method :connection, :client
|
67
68
|
|
68
69
|
# The length of time that Collection.ensure_index should cache index calls
|
69
70
|
attr_accessor :cache_time
|
@@ -99,81 +100,66 @@ module Mongo
|
|
99
100
|
# on initialization or at the time of an operation.
|
100
101
|
#
|
101
102
|
# @option opts [Integer] :cache_time (300) Set the time that all ensure_index calls should cache the command.
|
102
|
-
|
103
|
-
# @core databases constructor_details
|
103
|
+
|
104
104
|
def initialize(name, client, opts={})
|
105
|
-
|
106
|
-
|
105
|
+
# A database name of '$external' is permitted for some auth types
|
106
|
+
Support.validate_db_name(name) unless name == '$external'
|
107
|
+
|
108
|
+
@name = name
|
109
|
+
@client = client
|
107
110
|
@strict = opts[:strict]
|
108
111
|
@pk_factory = opts[:pk]
|
109
112
|
|
110
113
|
@write_concern = get_write_concern(opts, client)
|
111
114
|
|
112
|
-
@read = opts[:read] || @
|
113
|
-
|
114
|
-
@tag_sets = opts.fetch(:tag_sets, @connection.tag_sets)
|
115
|
-
@acceptable_latency = opts.fetch(:acceptable_latency, @connection.acceptable_latency)
|
116
|
-
@cache_time = opts[:cache_time] || 300 #5 minutes.
|
117
|
-
end
|
115
|
+
@read = opts[:read] || @client.read
|
116
|
+
ReadPreference::validate(@read)
|
118
117
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
# @param [String] username
|
123
|
-
# @param [String] password
|
124
|
-
# @param [Boolean] save_auth
|
125
|
-
# Save this authentication to the client object using MongoClient#add_auth. This
|
126
|
-
# will ensure that the authentication will be applied to all sockets and upon
|
127
|
-
# database reconnect.
|
128
|
-
# @param source [String] Database with user credentials. This should be used to
|
129
|
-
# authenticate against a database when the credentials exist elsewhere.
|
130
|
-
#
|
131
|
-
# @note save_auth must be true when using connection pooling or providing a source
|
132
|
-
# for credentials.
|
133
|
-
#
|
134
|
-
# @return [Boolean]
|
135
|
-
#
|
136
|
-
# @raise [AuthenticationError]
|
137
|
-
#
|
138
|
-
# @core authenticate authenticate-instance_method
|
139
|
-
def authenticate(username, password=nil, save_auth=true, source=nil)
|
140
|
-
if (@connection.pool_size > 1 || source) && !save_auth
|
141
|
-
raise MongoArgumentError, "If using connection pooling or delegated auth, " +
|
142
|
-
":save_auth must be set to true."
|
143
|
-
end
|
118
|
+
@tag_sets = opts.fetch(:tag_sets, @client.tag_sets)
|
119
|
+
@acceptable_latency = opts.fetch(:acceptable_latency,
|
120
|
+
@client.acceptable_latency)
|
144
121
|
|
145
|
-
|
146
|
-
|
147
|
-
issue_authentication(username, password, save_auth,
|
148
|
-
:socket => socket, :source => source)
|
149
|
-
ensure
|
150
|
-
socket.checkin if socket
|
151
|
-
end
|
122
|
+
@cache_time = opts[:cache_time] || 300 #5 minutes.
|
123
|
+
end
|
152
124
|
|
153
|
-
|
125
|
+
# Authenticate with the given username and password.
|
126
|
+
#
|
127
|
+
# @param username [String] The username.
|
128
|
+
# @param password [String] The user's password. This is not required for
|
129
|
+
# some authentication mechanisms.
|
130
|
+
# @param save_auth [Boolean]
|
131
|
+
# Save this authentication to the client object using
|
132
|
+
# MongoClient#add_auth. This will ensure that the authentication will
|
133
|
+
# be applied to all sockets and upon database reconnect.
|
134
|
+
# @param source [String] Database with user credentials. This should be
|
135
|
+
# used to authenticate against a database when the credentials exist
|
136
|
+
# elsewhere.
|
137
|
+
# @param mechanism [String] The authentication mechanism to be used.
|
138
|
+
#
|
139
|
+
# @note The ability to disable the save_auth option has been deprecated.
|
140
|
+
# With save_auth=false specified, driver authentication behavior during
|
141
|
+
# failovers and reconnections becomes unreliable. This option still
|
142
|
+
# exists for API compatibility, but it no longer has any effect if
|
143
|
+
# disabled and now always uses the default behavior (safe_auth=true).
|
144
|
+
#
|
145
|
+
# @raise [AuthenticationError] Raised if authentication fails.
|
146
|
+
# @return [Boolean] The result of the authentication operation.
|
147
|
+
def authenticate(username, password=nil, save_auth=nil, source=nil, mechanism=nil)
|
148
|
+
warn "[DEPRECATED] Disabling the 'save_auth' option no longer has " +
|
149
|
+
"any effect. Please see the API documentation for more details " +
|
150
|
+
"on this change." unless save_auth.nil?
|
151
|
+
|
152
|
+
@client.add_auth(self.name, username, password, source, mechanism)
|
154
153
|
true
|
155
154
|
end
|
156
155
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
db = source ? @connection[source] : self
|
165
|
-
|
166
|
-
auth = BSON::OrderedHash.new
|
167
|
-
auth['authenticate'] = 1
|
168
|
-
auth['user'] = username
|
169
|
-
auth['nonce'] = nonce
|
170
|
-
auth['key'] = Mongo::Support.auth_key(username, password, nonce)
|
171
|
-
if ok?(doc = db.command(auth, :check_response => false, :socket => opts[:socket]))
|
172
|
-
@connection.add_auth(name, username, password, source) if save_auth
|
173
|
-
else
|
174
|
-
message = "Failed to authenticate user '#{username}' on db '#{db.name}'"
|
175
|
-
raise Mongo::AuthenticationError.new(message, doc['code'], doc)
|
176
|
-
end
|
156
|
+
# Deauthorizes use for this database for this client connection. Also removes
|
157
|
+
# the saved authentication in the MongoClient class associated with this
|
158
|
+
# database.
|
159
|
+
#
|
160
|
+
# @return [Boolean]
|
161
|
+
def logout(opts={})
|
162
|
+
@client.remove_auth(self.name)
|
177
163
|
true
|
178
164
|
end
|
179
165
|
|
@@ -224,18 +210,22 @@ module Mongo
|
|
224
210
|
#
|
225
211
|
# @return [Hash] an object representing the user.
|
226
212
|
def add_user(username, password=nil, read_only=false, opts={})
|
227
|
-
users = self[SYSTEM_USER_COLLECTION]
|
228
|
-
user = users.find_one({:user => username}) || {:user => username}
|
229
|
-
user['pwd'] = Mongo::Support.hash_password(username, password) if password
|
230
|
-
user['readOnly'] = true if read_only
|
231
|
-
user.merge!(opts)
|
232
213
|
begin
|
233
|
-
|
214
|
+
user_info = command(:usersInfo => username)
|
215
|
+
# MongoDB >= 2.5.3 requires the use of commands to manage users.
|
216
|
+
# "Command not found" error didn't return an error code (59) before
|
217
|
+
# MongoDB 2.4.7 so we assume that a nil error code means the usersInfo
|
218
|
+
# command doesn't exist and we should fall back to the legacy add user code.
|
234
219
|
rescue OperationFailure => ex
|
235
|
-
|
236
|
-
|
220
|
+
raise ex unless ex.error_code == Mongo::ErrorCode::COMMAND_NOT_FOUND || ex.error_code.nil?
|
221
|
+
return legacy_add_user(username, password, read_only, opts)
|
222
|
+
end
|
223
|
+
|
224
|
+
if user_info.key?('users') && !user_info['users'].empty?
|
225
|
+
update_user(username, password, opts)
|
226
|
+
else
|
227
|
+
create_user(username, password, read_only, opts)
|
237
228
|
end
|
238
|
-
user
|
239
229
|
end
|
240
230
|
|
241
231
|
# Remove the given user from this database. Returns false if the user
|
@@ -245,32 +235,13 @@ module Mongo
|
|
245
235
|
#
|
246
236
|
# @return [Boolean]
|
247
237
|
def remove_user(username)
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
# Deauthorizes use for this database for this client connection. Also removes
|
256
|
-
# any saved authentication in the MongoClient class associated with this
|
257
|
-
# database.
|
258
|
-
#
|
259
|
-
# @raise [MongoDBError] if logging out fails.
|
260
|
-
#
|
261
|
-
# @return [Boolean]
|
262
|
-
def logout(opts={})
|
263
|
-
auth = @connection.auths.find { |a| a[:db_name] == name }
|
264
|
-
db = auth && auth[:source] ? @connection[auth[:source]] : self
|
265
|
-
auth ? @connection.logout_pools(db.name) : db.issue_logout(opts)
|
266
|
-
@connection.remove_auth(db.name)
|
267
|
-
end
|
268
|
-
|
269
|
-
def issue_logout(opts={})
|
270
|
-
unless ok?(doc = command({:logout => 1}, :socket => opts[:socket]))
|
271
|
-
raise MongoDBError, "Error logging out: #{doc.inspect}"
|
238
|
+
begin
|
239
|
+
command(:dropUser => username)
|
240
|
+
rescue OperationFailure => ex
|
241
|
+
raise ex unless ex.error_code == Mongo::ErrorCode::COMMAND_NOT_FOUND || ex.error_code.nil?
|
242
|
+
response = self[SYSTEM_USER_COLLECTION].remove({:user => username}, :w => 1)
|
243
|
+
response.key?('n') && response['n'] > 0 ? response : false
|
272
244
|
end
|
273
|
-
true
|
274
245
|
end
|
275
246
|
|
276
247
|
# Get an array of collection names in this database.
|
@@ -451,6 +422,7 @@ module Mongo
|
|
451
422
|
|
452
423
|
cmd = BSON::OrderedHash.new
|
453
424
|
cmd[:$eval] = code
|
425
|
+
cmd.merge!(args.pop) if args.last.respond_to?(:keys) && args.last.key?(:nolock)
|
454
426
|
cmd[:args] = args
|
455
427
|
doc = command(cmd)
|
456
428
|
doc['retval']
|
@@ -468,7 +440,7 @@ module Mongo
|
|
468
440
|
cmd = BSON::OrderedHash.new
|
469
441
|
cmd[:renameCollection] = "#{@name}.#{from}"
|
470
442
|
cmd[:to] = "#{@name}.#{to}"
|
471
|
-
doc = DB.new('admin', @
|
443
|
+
doc = DB.new('admin', @client).command(cmd, :check_response => false)
|
472
444
|
ok?(doc) || raise(MongoDBError, "Error renaming collection: #{doc.inspect}")
|
473
445
|
end
|
474
446
|
|
@@ -509,7 +481,7 @@ module Mongo
|
|
509
481
|
#
|
510
482
|
# @return [Hash]
|
511
483
|
def stats
|
512
|
-
self.command(
|
484
|
+
self.command(:dbstats => 1)
|
513
485
|
end
|
514
486
|
|
515
487
|
# Return +true+ if the supplied +doc+ contains an 'ok' field with the value 1.
|
@@ -531,8 +503,8 @@ module Mongo
|
|
531
503
|
# to see how it works.
|
532
504
|
#
|
533
505
|
# @param [OrderedHash, Hash] selector an OrderedHash, or a standard Hash with just one
|
534
|
-
# key, specifying the command to be performed. In Ruby 1.9, OrderedHash isn't necessary
|
535
|
-
# hashes are ordered by default.
|
506
|
+
# key, specifying the command to be performed. In Ruby 1.9 and above, OrderedHash isn't necessary
|
507
|
+
# because hashes are ordered by default.
|
536
508
|
#
|
537
509
|
# @option opts [Boolean] :check_response (true) If +true+, raises an exception if the
|
538
510
|
# command fails.
|
@@ -540,48 +512,59 @@ module Mongo
|
|
540
512
|
# @option opts [:primary, :secondary] :read Read preference for this command. See Collection#find for
|
541
513
|
# more details.
|
542
514
|
# @option opts [String] :comment (nil) a comment to include in profiling logs
|
515
|
+
# @option opts [Boolean] :compile_regex (true) whether BSON regex objects should be compiled into Ruby regexes.
|
516
|
+
# If false, a BSON::Regex object will be returned instead.
|
543
517
|
#
|
544
518
|
# @return [Hash]
|
545
|
-
#
|
546
|
-
# @core commands command_instance-method
|
547
519
|
def command(selector, opts={})
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
520
|
+
raise MongoArgumentError, "Command must be given a selector" unless selector.respond_to?(:keys) && !selector.empty?
|
521
|
+
|
522
|
+
opts = opts.dup
|
523
|
+
# deletes :check_response and returns the value, if nil defaults to the block result
|
524
|
+
check_response = opts.delete(:check_response) { true }
|
525
|
+
|
526
|
+
# build up the command hash
|
527
|
+
command = opts.key?(:socket) ? { :socket => opts.delete(:socket) } : {}
|
528
|
+
command.merge!(:comment => opts.delete(:comment)) if opts.key?(:comment)
|
529
|
+
command.merge!(:compile_regex => opts.delete(:compile_regex)) if opts.key?(:compile_regex)
|
530
|
+
command[:limit] = -1
|
531
|
+
command[:read] = Mongo::ReadPreference::cmd_read_pref(opts.delete(:read), selector) if opts.key?(:read)
|
532
|
+
|
533
|
+
if RUBY_VERSION < '1.9' && selector.class != BSON::OrderedHash
|
534
|
+
if selector.keys.length > 1
|
535
|
+
raise MongoArgumentError, "DB#command requires an OrderedHash when hash contains multiple keys"
|
536
|
+
end
|
537
|
+
if opts.keys.size > 0
|
538
|
+
# extra opts will be merged into the selector, so make sure it's an OH in versions < 1.9
|
539
|
+
selector = selector.dup
|
540
|
+
selector = BSON::OrderedHash.new.merge!(selector)
|
560
541
|
end
|
561
542
|
end
|
562
543
|
|
544
|
+
# arbitrary opts are merged into the selector
|
545
|
+
command[:selector] = selector.merge!(opts)
|
546
|
+
|
563
547
|
begin
|
564
|
-
result = Cursor.new(
|
565
|
-
system_command_collection,
|
566
|
-
:limit => -1,
|
567
|
-
:selector => selector,
|
568
|
-
:socket => socket,
|
569
|
-
:read => read_pref,
|
570
|
-
:comment => opts[:comment]).next_document
|
548
|
+
result = Cursor.new(system_command_collection, command).next_document
|
571
549
|
rescue OperationFailure => ex
|
572
|
-
|
550
|
+
if check_response
|
551
|
+
raise OperationFailure.new("Database command '#{selector.keys.first}' failed: #{ex.message}", ex.error_code, ex.result)
|
552
|
+
else
|
553
|
+
result = ex.result
|
554
|
+
end
|
573
555
|
end
|
574
556
|
|
575
557
|
raise OperationFailure,
|
576
558
|
"Database command '#{selector.keys.first}' failed: returned null." unless result
|
577
559
|
|
578
|
-
if check_response && !ok?(result)
|
560
|
+
if check_response && (!ok?(result) || result['writeErrors'] || result['writeConcernError'])
|
579
561
|
message = "Database command '#{selector.keys.first}' failed: ("
|
580
562
|
message << result.map do |key, value|
|
581
563
|
"#{key}: '#{value}'"
|
582
564
|
end.join('; ')
|
583
565
|
message << ').'
|
584
566
|
code = result['code'] || result['assertionCode']
|
567
|
+
raise ExecutionTimeout.new(message, code, result) if code == MAX_TIME_MS_CODE
|
585
568
|
raise OperationFailure.new(message, code, result)
|
586
569
|
end
|
587
570
|
|
@@ -618,8 +601,6 @@ module Mongo
|
|
618
601
|
# get the results using DB#profiling_info.
|
619
602
|
#
|
620
603
|
# @return [Symbol] :off, :slow_only, or :all
|
621
|
-
#
|
622
|
-
# @core profiling profiling_level-instance_method
|
623
604
|
def profiling_level
|
624
605
|
cmd = BSON::OrderedHash.new
|
625
606
|
cmd[:profile] = -1
|
@@ -677,5 +658,96 @@ module Mongo
|
|
677
658
|
def system_command_collection
|
678
659
|
Collection.new(SYSTEM_COMMAND_COLLECTION, self)
|
679
660
|
end
|
661
|
+
|
662
|
+
# Create a new user.
|
663
|
+
#
|
664
|
+
# @param username [String] The username.
|
665
|
+
# @param password [String] The user's password.
|
666
|
+
# @param read_only [Boolean] Create a read-only user (deprecated in MongoDB >= 2.6)
|
667
|
+
# @param opts [Hash]
|
668
|
+
#
|
669
|
+
# @private
|
670
|
+
def create_user(username, password, read_only, opts)
|
671
|
+
if read_only || !opts.key?(:roles)
|
672
|
+
warn "Creating a user with the read_only option or without roles is " +
|
673
|
+
"deprecated in MongoDB >= 2.6"
|
674
|
+
end
|
675
|
+
|
676
|
+
# The password is always salted and hashed by the driver.
|
677
|
+
if opts.key?(:digestPassword)
|
678
|
+
raise MongoArgumentError,
|
679
|
+
"The digestPassword option is not available via DB#add_user. " +
|
680
|
+
"Use DB#command(:createUser => ...) instead for this option."
|
681
|
+
end
|
682
|
+
|
683
|
+
opts = opts.dup
|
684
|
+
pwd = Mongo::Authentication.hash_password(username, password) if password
|
685
|
+
create_opts = pwd ? { :pwd => pwd } : {}
|
686
|
+
# specify that the server shouldn't digest the password because the driver does
|
687
|
+
create_opts[:digestPassword] = false
|
688
|
+
unless opts.key?(:roles)
|
689
|
+
if name == 'admin'
|
690
|
+
roles = read_only ? ['readAnyDatabase'] : ['root']
|
691
|
+
else
|
692
|
+
roles = read_only ? ['read'] : ["dbOwner"]
|
693
|
+
end
|
694
|
+
create_opts[:roles] = roles
|
695
|
+
end
|
696
|
+
create_opts[:writeConcern] =
|
697
|
+
opts.key?(:writeConcern) ? opts.delete(:writeConcern) : { :w => 1 }
|
698
|
+
create_opts.merge!(opts)
|
699
|
+
command({ :createUser => username }, create_opts)
|
700
|
+
end
|
701
|
+
|
702
|
+
# Update a user.
|
703
|
+
#
|
704
|
+
# @param username [String] The username.
|
705
|
+
# @param password [String] The user's password.
|
706
|
+
# @param opts [Hash]
|
707
|
+
#
|
708
|
+
# @private
|
709
|
+
def update_user(username, password, opts)
|
710
|
+
# The password is always salted and hashed by the driver.
|
711
|
+
if opts.key?(:digestPassword)
|
712
|
+
raise MongoArgumentError,
|
713
|
+
"The digestPassword option is not available via DB#add_user. " +
|
714
|
+
"Use DB#command(:createUser => ...) instead for this option."
|
715
|
+
end
|
716
|
+
|
717
|
+
opts = opts.dup
|
718
|
+
pwd = Mongo::Authentication.hash_password(username, password) if password
|
719
|
+
update_opts = pwd ? { :pwd => pwd } : {}
|
720
|
+
# specify that the server shouldn't digest the password because the driver does
|
721
|
+
update_opts[:digestPassword] = false
|
722
|
+
update_opts[:writeConcern] =
|
723
|
+
opts.key?(:writeConcern) ? opts.delete(:writeConcern) : { :w => 1 }
|
724
|
+
update_opts.merge!(opts)
|
725
|
+
command({ :updateUser => username }, update_opts)
|
726
|
+
end
|
727
|
+
|
728
|
+
# Create a user in MongoDB versions < 2.5.3.
|
729
|
+
# Called by #add_user if the 'usersInfo' command fails.
|
730
|
+
#
|
731
|
+
# @param username [String] The username.
|
732
|
+
# @param password [String] (nil) The user's password.
|
733
|
+
# @param read_only [Boolean] (false) Create a read-only user.
|
734
|
+
# @param opts [Hash]
|
735
|
+
#
|
736
|
+
# @private
|
737
|
+
def legacy_add_user(username, password=nil, read_only=false, opts={})
|
738
|
+
users = self[SYSTEM_USER_COLLECTION]
|
739
|
+
user = users.find_one(:user => username) || {:user => username}
|
740
|
+
user['pwd'] =
|
741
|
+
Mongo::Authentication.hash_password(username, password) if password
|
742
|
+
user['readOnly'] = true if read_only
|
743
|
+
user.merge!(opts)
|
744
|
+
begin
|
745
|
+
users.save(user)
|
746
|
+
rescue OperationFailure => ex
|
747
|
+
# adding first admin user fails GLE in MongoDB 2.2
|
748
|
+
raise ex unless ex.message =~ /login/
|
749
|
+
end
|
750
|
+
user
|
751
|
+
end
|
680
752
|
end
|
681
753
|
end
|