mongo 2.0.4 → 2.0.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.tar.gz.sig +0 -0
- data/lib/mongo/address.rb +1 -1
- data/lib/mongo/address/ipv4.rb +8 -4
- data/lib/mongo/address/ipv6.rb +8 -4
- data/lib/mongo/address/unix.rb +2 -2
- data/lib/mongo/auth/user/view.rb +5 -1
- data/lib/mongo/bulk_write/bulk_writable.rb +5 -0
- data/lib/mongo/bulk_write/deletable.rb +0 -4
- data/lib/mongo/bulk_write/insertable.rb +0 -4
- data/lib/mongo/client.rb +30 -2
- data/lib/mongo/collection/view/aggregation.rb +17 -4
- data/lib/mongo/collection/view/map_reduce.rb +19 -2
- data/lib/mongo/database.rb +12 -0
- data/lib/mongo/database/view.rb +12 -0
- data/lib/mongo/grid/fs.rb +5 -5
- data/lib/mongo/loggable.rb +5 -3
- data/lib/mongo/logger.rb +21 -5
- data/lib/mongo/operation/aggregate.rb +18 -11
- data/lib/mongo/operation/aggregate/result.rb +16 -1
- data/lib/mongo/operation/map_reduce.rb +7 -9
- data/lib/mongo/operation/read/query.rb +1 -1
- data/lib/mongo/operation/read_preferrable.rb +11 -5
- data/lib/mongo/operation/result.rb +5 -1
- data/lib/mongo/operation/write.rb +1 -0
- data/lib/mongo/operation/write/command.rb +1 -0
- data/lib/mongo/operation/write/command/update_user.rb +43 -0
- data/lib/mongo/operation/write/update_user.rb +75 -0
- data/lib/mongo/protocol/reply.rb +12 -0
- data/lib/mongo/server/connection_pool/queue.rb +3 -3
- data/lib/mongo/socket.rb +22 -11
- data/lib/mongo/socket/ssl.rb +6 -3
- data/lib/mongo/version.rb +1 -1
- data/spec/mongo/auth/user/view_spec.rb +42 -0
- data/spec/mongo/client_spec.rb +19 -0
- data/spec/mongo/cluster_spec.rb +2 -1
- data/spec/mongo/collection/view/aggregation_spec.rb +34 -1
- data/spec/mongo/collection/view/map_reduce_spec.rb +92 -0
- data/spec/mongo/collection/view_spec.rb +14 -11
- data/spec/mongo/collection_spec.rb +13 -0
- data/spec/mongo/database_spec.rb +29 -0
- data/spec/mongo/grid/fs_spec.rb +32 -1
- data/spec/mongo/loggable_spec.rb +2 -1
- data/spec/mongo/operation/read/query_spec.rb +19 -0
- data/spec/mongo/operation/read_preferrable_spec.rb +192 -0
- data/spec/mongo/operation/write/update_user_spec.rb +46 -0
- data/spec/mongo/server/connection_pool/queue_spec.rb +4 -0
- data/spec/mongo/socket/ssl_spec.rb +21 -1
- data/spec/spec_helper.rb +4 -0
- data/spec/support/authorization.rb +6 -4
- data/spec/support/shared/operation.rb +12 -0
- metadata +9 -3
- metadata.gz.sig +0 -0
@@ -31,6 +31,16 @@ module Mongo
|
|
31
31
|
# @since 2.0.0
|
32
32
|
CURSOR_ID = 'id'.freeze
|
33
33
|
|
34
|
+
# The field name for the aggregation explain information.
|
35
|
+
#
|
36
|
+
# @since 2.0.5
|
37
|
+
EXPLAIN = 'stages'.freeze
|
38
|
+
|
39
|
+
# The legacy field name for the aggregation explain information.
|
40
|
+
#
|
41
|
+
# @since 2.0.5
|
42
|
+
EXPLAIN_LEGACY = 'serverPipeline'.freeze
|
43
|
+
|
34
44
|
# The field name for the first batch of a cursor.
|
35
45
|
#
|
36
46
|
# @since 2.0.0
|
@@ -70,11 +80,16 @@ module Mongo
|
|
70
80
|
#
|
71
81
|
# @since 2.0.0
|
72
82
|
def documents
|
73
|
-
reply.documents[0][RESULT] ||
|
83
|
+
reply.documents[0][RESULT] || explain_document ||
|
84
|
+
cursor_document[FIRST_BATCH]
|
74
85
|
end
|
75
86
|
|
76
87
|
private
|
77
88
|
|
89
|
+
def explain_document
|
90
|
+
first_document[EXPLAIN] || first_document[EXPLAIN_LEGACY]
|
91
|
+
end
|
92
|
+
|
78
93
|
def cursor_document
|
79
94
|
@cursor_document ||= reply.documents[0][CURSOR]
|
80
95
|
end
|
@@ -63,7 +63,7 @@ module Mongo
|
|
63
63
|
#
|
64
64
|
# @since 2.0.0
|
65
65
|
def execute(context)
|
66
|
-
unless
|
66
|
+
unless valid_context?(context)
|
67
67
|
raise Error::NeedPrimaryServer.new(ERROR_MESSAGE)
|
68
68
|
end
|
69
69
|
execute_message(context)
|
@@ -71,21 +71,19 @@ module Mongo
|
|
71
71
|
|
72
72
|
private
|
73
73
|
|
74
|
+
def valid_context?(context)
|
75
|
+
context.standalone? || context.mongos? || context.primary? || secondary_ok?
|
76
|
+
end
|
77
|
+
|
74
78
|
def execute_message(context)
|
75
79
|
context.with_connection do |connection|
|
76
80
|
Result.new(connection.dispatch([ message(context) ])).validate!
|
77
81
|
end
|
78
82
|
end
|
79
83
|
|
80
|
-
# Whether this operation can be executed on a replica set secondary server.
|
81
|
-
# The map reduce operation may not be executed on a secondary if the user has specified
|
82
|
-
# an output collection to which the results will be written.
|
83
|
-
#
|
84
|
-
# @return [ true, false ] Whether the operation can be executed on a secondary.
|
85
|
-
#
|
86
|
-
# @since 2.0.0
|
87
84
|
def secondary_ok?
|
88
|
-
selector[:out]
|
85
|
+
selector[:out].respond_to?(:keys) &&
|
86
|
+
selector[:out].keys.first.to_s.downcase == 'inline'
|
89
87
|
end
|
90
88
|
|
91
89
|
def query_coll
|
@@ -20,21 +20,27 @@ module Mongo
|
|
20
20
|
# @since 2.0.0
|
21
21
|
module ReadPreferrable
|
22
22
|
|
23
|
+
# The constant for slave ok flags.
|
24
|
+
#
|
25
|
+
# @since 2.0.5
|
26
|
+
SLAVE_OK = :slave_ok
|
27
|
+
|
23
28
|
private
|
24
29
|
|
25
30
|
def update_selector(context)
|
26
31
|
if context.mongos? && read_pref = read.to_mongos
|
27
|
-
selector
|
32
|
+
sel = selector[:$query] ? selector : { :$query => selector }
|
33
|
+
sel.merge(:$readPreference => read_pref)
|
28
34
|
else
|
29
35
|
selector
|
30
36
|
end
|
31
37
|
end
|
32
38
|
|
33
39
|
def update_options(context)
|
34
|
-
if context.slave_ok?
|
35
|
-
options.
|
36
|
-
|
37
|
-
|
40
|
+
if context.slave_ok? || (!context.mongos? && read.slave_ok?)
|
41
|
+
options.dup.tap do |opts|
|
42
|
+
(opts[:flags] ||= []) << SLAVE_OK
|
43
|
+
end
|
38
44
|
else
|
39
45
|
options
|
40
46
|
end
|
@@ -192,7 +192,7 @@ module Mongo
|
|
192
192
|
if first_document.has_key?(OK)
|
193
193
|
first_document[OK] == 1 && parser.message.empty?
|
194
194
|
else
|
195
|
-
parser.message.empty?
|
195
|
+
!query_failure? && parser.message.empty?
|
196
196
|
end
|
197
197
|
end
|
198
198
|
|
@@ -254,6 +254,10 @@ module Mongo
|
|
254
254
|
def first_document
|
255
255
|
@first_document ||= first || BSON::Document.new
|
256
256
|
end
|
257
|
+
|
258
|
+
def query_failure?
|
259
|
+
replies.first && replies.first.query_failure?
|
260
|
+
end
|
257
261
|
end
|
258
262
|
end
|
259
263
|
end
|
@@ -20,5 +20,6 @@ require 'mongo/operation/write/update'
|
|
20
20
|
require 'mongo/operation/write/create_index'
|
21
21
|
require 'mongo/operation/write/drop_index'
|
22
22
|
require 'mongo/operation/write/create_user'
|
23
|
+
require 'mongo/operation/write/update_user'
|
23
24
|
require 'mongo/operation/write/remove_user'
|
24
25
|
require 'mongo/operation/write/command'
|
@@ -19,4 +19,5 @@ require 'mongo/operation/write/command/update'
|
|
19
19
|
require 'mongo/operation/write/command/drop_index'
|
20
20
|
require 'mongo/operation/write/command/create_index'
|
21
21
|
require 'mongo/operation/write/command/create_user'
|
22
|
+
require 'mongo/operation/write/command/update_user'
|
22
23
|
require 'mongo/operation/write/command/remove_user'
|
@@ -0,0 +1,43 @@
|
|
1
|
+
|
2
|
+
# Copyright (C) 2014-2015 MongoDB, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Mongo
|
17
|
+
module Operation
|
18
|
+
module Write
|
19
|
+
module Command
|
20
|
+
|
21
|
+
# Update user command on non-legacy servers.
|
22
|
+
#
|
23
|
+
# @since 2.0.0
|
24
|
+
class UpdateUser
|
25
|
+
include Specifiable
|
26
|
+
include Executable
|
27
|
+
include Writable
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# The query selector for this update user command operation.
|
32
|
+
#
|
33
|
+
# @return [ Hash ] The selector describing this update user operation.
|
34
|
+
#
|
35
|
+
# @since 2.0.0
|
36
|
+
def selector
|
37
|
+
{ :updateUser => user.name, :digestPassword => false }.merge(user.spec)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
|
2
|
+
# Copyright (C) 2014-2015 MongoDB, Inc.
|
3
|
+
#
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
5
|
+
# you may not use this file except in compliance with the License.
|
6
|
+
# You may obtain a copy of the License at
|
7
|
+
#
|
8
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
9
|
+
#
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
13
|
+
# See the License for the specific language governing permissions and
|
14
|
+
# limitations under the License.
|
15
|
+
|
16
|
+
module Mongo
|
17
|
+
module Operation
|
18
|
+
module Write
|
19
|
+
|
20
|
+
# A MongoDB update user operation.
|
21
|
+
#
|
22
|
+
# @example Initialize the operation.
|
23
|
+
# Write::UpdateUser.new(:db_name => 'test', :user => user)
|
24
|
+
#
|
25
|
+
# @param [ Hash ] spec The specifications for the update.
|
26
|
+
#
|
27
|
+
# @option spec :user [ Auth::User ] The user to update.
|
28
|
+
# @option spec :db_name [ String ] The name of the database.
|
29
|
+
#
|
30
|
+
# @since 2.0.0
|
31
|
+
class UpdateUser
|
32
|
+
include Executable
|
33
|
+
include Specifiable
|
34
|
+
|
35
|
+
# Execute the operation.
|
36
|
+
#
|
37
|
+
# @note Updating users behaves different on 2.7+, 2.6.x, and
|
38
|
+
# 2.4- so we need to break this out into separate operations.
|
39
|
+
#
|
40
|
+
# @example Execute the operation.
|
41
|
+
# operation.execute(context)
|
42
|
+
#
|
43
|
+
# @param [ Mongo::Server::Context ] context The context for this operation.
|
44
|
+
#
|
45
|
+
# @return [ Result ] The operation result.
|
46
|
+
#
|
47
|
+
# @since 2.0.0
|
48
|
+
def execute(context)
|
49
|
+
if context.features.write_command_enabled?
|
50
|
+
execute_write_command(context)
|
51
|
+
else
|
52
|
+
execute_message(context)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def execute_write_command(context)
|
59
|
+
Result.new(Command::UpdateUser.new(spec).execute(context)).validate!
|
60
|
+
end
|
61
|
+
|
62
|
+
def execute_message(context)
|
63
|
+
context.with_connection do |connection|
|
64
|
+
Result.new(connection.dispatch([ message, gle ].compact)).validate!
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def message
|
69
|
+
user_spec = { user: user.name }.merge(user.spec)
|
70
|
+
Protocol::Update.new(db_name, Auth::User::COLLECTION, { user: user.name }, user_spec)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/mongo/protocol/reply.rb
CHANGED
@@ -26,6 +26,18 @@ module Mongo
|
|
26
26
|
# @api semipublic
|
27
27
|
class Reply < Message
|
28
28
|
|
29
|
+
# Determine if the reply had a query failure flag.
|
30
|
+
#
|
31
|
+
# @example Did the reply have a query failure.
|
32
|
+
# reply.query_failure?
|
33
|
+
#
|
34
|
+
# @return [ true, false ] If the query failed.
|
35
|
+
#
|
36
|
+
# @since 2.0.5
|
37
|
+
def query_failure?
|
38
|
+
flags.include?(:query_failure)
|
39
|
+
end
|
40
|
+
|
29
41
|
private
|
30
42
|
|
31
43
|
# The operation code required to specify a Reply message.
|
@@ -73,7 +73,7 @@ module Mongo
|
|
73
73
|
# @since 2.0.0
|
74
74
|
def enqueue(connection)
|
75
75
|
mutex.synchronize do
|
76
|
-
queue.
|
76
|
+
queue.unshift(connection)
|
77
77
|
resource.broadcast
|
78
78
|
end
|
79
79
|
end
|
@@ -96,7 +96,7 @@ module Mongo
|
|
96
96
|
@block = block
|
97
97
|
@connections = 0
|
98
98
|
@options = options
|
99
|
-
@queue = Array.new(min_size
|
99
|
+
@queue = Array.new(min_size) { create_connection }
|
100
100
|
@mutex = Mutex.new
|
101
101
|
@resource = ConditionVariable.new
|
102
102
|
end
|
@@ -155,7 +155,7 @@ module Mongo
|
|
155
155
|
def dequeue_connection
|
156
156
|
deadline = Time.now + wait_timeout
|
157
157
|
loop do
|
158
|
-
return queue.
|
158
|
+
return queue.pop unless queue.empty?
|
159
159
|
connection = create_connection
|
160
160
|
return connection if connection
|
161
161
|
wait_for_next!(deadline)
|
data/lib/mongo/socket.rb
CHANGED
@@ -56,13 +56,12 @@ module Mongo
|
|
56
56
|
#
|
57
57
|
# @since 2.0.0
|
58
58
|
def alive?
|
59
|
-
|
60
|
-
|
59
|
+
sock_arr = [ @socket ]
|
60
|
+
if Kernel::select(sock_arr, nil, sock_arr, 0)
|
61
|
+
eof?
|
61
62
|
else
|
62
63
|
true
|
63
64
|
end
|
64
|
-
rescue IOError
|
65
|
-
false
|
66
65
|
end
|
67
66
|
|
68
67
|
# Close the socket.
|
@@ -74,7 +73,7 @@ module Mongo
|
|
74
73
|
#
|
75
74
|
# @since 2.0.0
|
76
75
|
def close
|
77
|
-
socket.close rescue true
|
76
|
+
@socket.close rescue true
|
78
77
|
true
|
79
78
|
end
|
80
79
|
|
@@ -89,7 +88,7 @@ module Mongo
|
|
89
88
|
#
|
90
89
|
# @since 2.0.0
|
91
90
|
def gets(*args)
|
92
|
-
handle_errors { socket.gets(*args) }
|
91
|
+
handle_errors { @socket.gets(*args) }
|
93
92
|
end
|
94
93
|
|
95
94
|
# Create the new socket for the provided family - ipv4, piv6, or unix.
|
@@ -107,7 +106,7 @@ module Mongo
|
|
107
106
|
end
|
108
107
|
|
109
108
|
# Will read all data from the socket for the provided number of bytes.
|
110
|
-
# If
|
109
|
+
# If no data is returned, an exception will be raised.
|
111
110
|
#
|
112
111
|
# @example Read all the requested data from the socket.
|
113
112
|
# socket.read(4096)
|
@@ -122,8 +121,11 @@ module Mongo
|
|
122
121
|
def read(length)
|
123
122
|
handle_errors do
|
124
123
|
data = read_from_socket(length)
|
124
|
+
raise IOError unless (data.length > 0 || length == 0)
|
125
125
|
while data.length < length
|
126
|
-
|
126
|
+
chunk = read_from_socket(length - data.length)
|
127
|
+
raise IOError unless (chunk.length > 0 || length == 0)
|
128
|
+
data << chunk
|
127
129
|
end
|
128
130
|
data
|
129
131
|
end
|
@@ -138,7 +140,7 @@ module Mongo
|
|
138
140
|
#
|
139
141
|
# @since 2.0.0
|
140
142
|
def readbyte
|
141
|
-
handle_errors { socket.readbyte }
|
143
|
+
handle_errors { @socket.readbyte }
|
142
144
|
end
|
143
145
|
|
144
146
|
# Writes data to the socket instance.
|
@@ -152,13 +154,22 @@ module Mongo
|
|
152
154
|
#
|
153
155
|
# @since 2.0.0
|
154
156
|
def write(*args)
|
155
|
-
handle_errors { socket.write(*args) }
|
157
|
+
handle_errors { @socket.write(*args) }
|
158
|
+
end
|
159
|
+
|
160
|
+
# Tests if this socket has reached EOF. Primarily used for liveness checks.
|
161
|
+
#
|
162
|
+
# @since 2.0.5
|
163
|
+
def eof?
|
164
|
+
@socket.eof?
|
165
|
+
rescue IOError, SystemCallError => e
|
166
|
+
true
|
156
167
|
end
|
157
168
|
|
158
169
|
private
|
159
170
|
|
160
171
|
def read_from_socket(length)
|
161
|
-
socket.read(length) || String.new
|
172
|
+
@socket.read(length) || String.new
|
162
173
|
end
|
163
174
|
|
164
175
|
def set_socket_options(sock)
|
data/lib/mongo/socket/ssl.rb
CHANGED
@@ -29,6 +29,9 @@ module Mongo
|
|
29
29
|
# @return [ String ] host The host to connect to.
|
30
30
|
attr_reader :host
|
31
31
|
|
32
|
+
# @return [ String ] host_name The original host name.
|
33
|
+
attr_reader :host_name
|
34
|
+
|
32
35
|
# @return [ Hash ] The ssl options.
|
33
36
|
attr_reader :options
|
34
37
|
|
@@ -72,8 +75,8 @@ module Mongo
|
|
72
75
|
# @param [ Hash ] options The ssl options.
|
73
76
|
#
|
74
77
|
# @since 2.0.0
|
75
|
-
def initialize(host, port, timeout, family, options = {})
|
76
|
-
@host, @port, @timeout, @options = host, port, timeout, options
|
78
|
+
def initialize(host, port, host_name, timeout, family, options = {})
|
79
|
+
@host, @port, @host_name, @timeout, @options = host, port, host_name, timeout, options
|
77
80
|
@context = create_context(options)
|
78
81
|
@family = family
|
79
82
|
@tcp_socket = ::Socket.new(family, SOCK_STREAM, 0)
|
@@ -117,7 +120,7 @@ module Mongo
|
|
117
120
|
|
118
121
|
def verify_certificate!(socket)
|
119
122
|
if context.verify_mode == OpenSSL::SSL::VERIFY_PEER
|
120
|
-
unless OpenSSL::SSL.verify_certificate_identity(socket.peer_cert,
|
123
|
+
unless OpenSSL::SSL.verify_certificate_identity(socket.peer_cert, host_name)
|
121
124
|
raise Error::SocketError, 'SSL handshake failed due to a hostname mismatch.'
|
122
125
|
end
|
123
126
|
end
|
data/lib/mongo/version.rb
CHANGED
@@ -36,6 +36,48 @@ describe Mongo::Auth::User::View do
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
+
describe '#update' do
|
40
|
+
|
41
|
+
before do
|
42
|
+
view.create(
|
43
|
+
'durran',
|
44
|
+
password: 'password', roles: [ Mongo::Auth::Roles::READ_WRITE ]
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
after do
|
49
|
+
view.remove('durran')
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when a user password is updated' do
|
53
|
+
|
54
|
+
let!(:response) do
|
55
|
+
view.update(
|
56
|
+
'durran',
|
57
|
+
password: '123', roles: [ Mongo::Auth::Roles::READ_WRITE ]
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'updates the password' do
|
62
|
+
expect(response).to be_successful
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when the roles of a user are updated' do
|
67
|
+
|
68
|
+
let!(:response) do
|
69
|
+
view.update(
|
70
|
+
'durran',
|
71
|
+
password: 'password', roles: [ Mongo::Auth::Roles::READ ]
|
72
|
+
)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'updates the roles' do
|
76
|
+
expect(response).to be_successful
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
39
81
|
describe '#remove' do
|
40
82
|
|
41
83
|
context 'when user removal was successful' do
|