mongo 2.11.1 → 2.11.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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -1
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +24 -0
  5. data/lib/mongo/auth.rb +30 -10
  6. data/lib/mongo/auth/cr.rb +1 -0
  7. data/lib/mongo/auth/cr/conversation.rb +13 -13
  8. data/lib/mongo/auth/ldap.rb +2 -1
  9. data/lib/mongo/auth/ldap/conversation.rb +9 -12
  10. data/lib/mongo/auth/scram.rb +1 -0
  11. data/lib/mongo/auth/scram/conversation.rb +36 -27
  12. data/lib/mongo/auth/x509.rb +2 -1
  13. data/lib/mongo/auth/x509/conversation.rb +9 -9
  14. data/lib/mongo/client.rb +17 -6
  15. data/lib/mongo/cluster.rb +65 -49
  16. data/lib/mongo/cluster/sdam_flow.rb +87 -3
  17. data/lib/mongo/database.rb +1 -1
  18. data/lib/mongo/server.rb +13 -6
  19. data/lib/mongo/server/connection.rb +12 -4
  20. data/lib/mongo/server/connection_base.rb +7 -4
  21. data/lib/mongo/server/description.rb +34 -21
  22. data/lib/mongo/session.rb +10 -10
  23. data/lib/mongo/version.rb +1 -1
  24. data/spec/README.md +13 -0
  25. data/spec/integration/auth_spec.rb +27 -8
  26. data/spec/integration/client_construction_spec.rb +14 -0
  27. data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
  28. data/spec/mongo/auth/scram/conversation_spec.rb +23 -14
  29. data/spec/mongo/auth/x509/conversation_spec.rb +1 -1
  30. data/spec/mongo/client_construction_spec.rb +1 -21
  31. data/spec/mongo/cluster_spec.rb +38 -0
  32. data/spec/mongo/collection/view/map_reduce_spec.rb +1 -1
  33. data/spec/mongo/server/connection_spec.rb +67 -0
  34. data/spec/runners/sdam/verifier.rb +6 -3
  35. data/spec/spec_tests/data/sdam/rs/primary_address_change.yml +29 -0
  36. data/spec/spec_tests/data/sdam/rs/primary_mismatched_me.yml +27 -23
  37. data/spec/spec_tests/data/sdam/rs/primary_to_no_primary_mismatched_me.yml +56 -79
  38. data/spec/spec_tests/data/sdam/sharded/primary_address_change.yml +21 -0
  39. data/spec/spec_tests/data/sdam/sharded/primary_mismatched_me.yml +22 -0
  40. data/spec/spec_tests/data/sdam/single/primary_address_change.yml +24 -0
  41. data/spec/spec_tests/data/sdam/single/primary_mismatched_me.yml +25 -0
  42. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_me_mismatch.yml +159 -0
  43. data/spec/spec_tests/data/sdam_monitoring/{replica_set_other_seed.yml → replica_set_with_primary_change.yml} +97 -101
  44. data/spec/spec_tests/data/sdam_monitoring/replica_set_with_primary_removal.yml +22 -18
  45. data/spec/spec_tests/data/sdam_monitoring/standalone_to_rs_with_me_mismatch.yml +90 -0
  46. data/spec/support/cluster_config.rb +36 -0
  47. data/spec/support/constraints.rb +18 -18
  48. data/spec/support/server_discovery_and_monitoring.rb +2 -0
  49. metadata +18 -4
  50. metadata.gz.sig +0 -0
@@ -33,6 +33,7 @@ module Mongo
33
33
  # Constant for reading arbiter info from config.
34
34
  #
35
35
  # @since 2.0.0
36
+ # @deprecated
36
37
  ARBITER = 'arbiterOnly'.freeze
37
38
 
38
39
  # Constant for reading arbiters info from config.
@@ -53,16 +54,19 @@ module Mongo
53
54
  # Constant for the key for the message value.
54
55
  #
55
56
  # @since 2.0.0
57
+ # @deprecated
56
58
  MESSAGE = 'msg'.freeze
57
59
 
58
60
  # Constant for the message that indicates a sharded cluster.
59
61
  #
60
62
  # @since 2.0.0
63
+ # @deprecated
61
64
  MONGOS_MESSAGE = 'isdbgrid'.freeze
62
65
 
63
66
  # Constant for determining ghost servers.
64
67
  #
65
68
  # @since 2.0.0
69
+ # @deprecated
66
70
  REPLICA_SET = 'isreplicaset'.freeze
67
71
 
68
72
  # Constant for reading max bson size info from config.
@@ -129,6 +133,7 @@ module Mongo
129
133
  # Constant for reading primary info from config.
130
134
  #
131
135
  # @since 2.0.0
136
+ # @deprecated
132
137
  PRIMARY = 'ismaster'.freeze
133
138
 
134
139
  # Constant for reading primary host field from config.
@@ -139,6 +144,7 @@ module Mongo
139
144
  # Constant for reading secondary info from config.
140
145
  #
141
146
  # @since 2.0.0
147
+ # @deprecated
142
148
  SECONDARY = 'secondary'.freeze
143
149
 
144
150
  # Constant for reading replica set name info from config.
@@ -227,7 +233,7 @@ module Mongo
227
233
  # @return [ Float ] The moving average time the ismaster call took to complete.
228
234
  attr_reader :average_round_trip_time
229
235
 
230
- # Will return true if the server is an arbiter.
236
+ # Returns whether this server is an arbiter, per the SDAM spec.
231
237
  #
232
238
  # @example Is the server an arbiter?
233
239
  # description.arbiter?
@@ -236,7 +242,9 @@ module Mongo
236
242
  #
237
243
  # @since 2.0.0
238
244
  def arbiter?
239
- ok? && !!config[ARBITER] && !replica_set_name.nil?
245
+ ok? &&
246
+ config['arbiterOnly'] == true &&
247
+ !!config['setName']
240
248
  end
241
249
 
242
250
  # Get a list of all arbiters in the replica set.
@@ -251,7 +259,7 @@ module Mongo
251
259
  @arbiters ||= (config[ARBITERS] || []).map { |s| s.downcase }
252
260
  end
253
261
 
254
- # Is the server a ghost in a replica set?
262
+ # Whether this server is a ghost, per the SDAM spec.
255
263
  #
256
264
  # @example Is the server a ghost?
257
265
  # description.ghost?
@@ -260,7 +268,8 @@ module Mongo
260
268
  #
261
269
  # @since 2.0.0
262
270
  def ghost?
263
- ok? && !!config[REPLICA_SET]
271
+ ok? &&
272
+ config['isreplicaset'] == true
264
273
  end
265
274
 
266
275
  # Will return true if the server is hidden.
@@ -431,7 +440,7 @@ module Mongo
431
440
  config[LOGICAL_SESSION_TIMEOUT_MINUTES] if config[LOGICAL_SESSION_TIMEOUT_MINUTES]
432
441
  end
433
442
 
434
- # Is the server a mongos?
443
+ # Returns whether this server is a mongos, per the SDAM spec.
435
444
  #
436
445
  # @example Is the server a mongos?
437
446
  # description.mongos?
@@ -440,10 +449,10 @@ module Mongo
440
449
  #
441
450
  # @since 2.0.0
442
451
  def mongos?
443
- ok? && config[MESSAGE] == MONGOS_MESSAGE
452
+ ok? && config['msg'] == 'isdbgrid'
444
453
  end
445
454
 
446
- # Is the description of type other.
455
+ # Returns whether the server is an other, per the SDAM spec.
447
456
  #
448
457
  # @example Is the description of type other.
449
458
  # description.other?
@@ -455,11 +464,11 @@ module Mongo
455
464
  # The SDAM spec is slightly confusing on what "other" means,
456
465
  # but it's referred to it as "RSOther" which means a non-RS member
457
466
  # cannot be "other".
458
- if unknown? || replica_set_name.nil?
459
- return false
460
- end
461
- (!primary? && !secondary? && !passive? && !arbiter?) ||
462
- (hidden? && !replica_set_name.nil?)
467
+ ok? &&
468
+ !!config['setName'] && (
469
+ config['hidden'] == true ||
470
+ !primary? && !secondary? && !arbiter?
471
+ )
463
472
  end
464
473
 
465
474
  # Will return true if the server is passive.
@@ -498,7 +507,7 @@ module Mongo
498
507
  config[PRIMARY_HOST] && config[PRIMARY_HOST].downcase
499
508
  end
500
509
 
501
- # Will return true if the server is a primary.
510
+ # Returns whether this server is a primary, per the SDAM spec.
502
511
  #
503
512
  # @example Is the server a primary?
504
513
  # description.primary?
@@ -508,9 +517,8 @@ module Mongo
508
517
  # @since 2.0.0
509
518
  def primary?
510
519
  ok? &&
511
- !!config[PRIMARY] &&
512
- (primary_host.nil? || primary_host == address.to_s) &&
513
- !replica_set_name.nil?
520
+ config['ismaster'] == true &&
521
+ !!config['setName']
514
522
  end
515
523
 
516
524
  # Get the name of the replica set the server belongs to, returns nil if
@@ -538,7 +546,7 @@ module Mongo
538
546
  hosts + arbiters + passives
539
547
  end
540
548
 
541
- # Will return true if the server is a secondary.
549
+ # Returns whether this server is a secondary, per the SDAM spec.
542
550
  #
543
551
  # @example Is the server a secondary?
544
552
  # description.secondary?
@@ -547,7 +555,9 @@ module Mongo
547
555
  #
548
556
  # @since 2.0.0
549
557
  def secondary?
550
- ok? && !!config[SECONDARY] && !replica_set_name.nil?
558
+ ok? &&
559
+ config['secondary'] == true &&
560
+ !!config['setName']
551
561
  end
552
562
 
553
563
  # Returns the server type as a symbol.
@@ -569,7 +579,7 @@ module Mongo
569
579
  :unknown
570
580
  end
571
581
 
572
- # Is this server a standalone server?
582
+ # Returns whether this server is a standalone, per the SDAM spec.
573
583
  #
574
584
  # @example Is the server standalone?
575
585
  # description.standalone?
@@ -578,10 +588,13 @@ module Mongo
578
588
  #
579
589
  # @since 2.0.0
580
590
  def standalone?
581
- replica_set_name.nil? && !mongos? && !ghost? && !unknown?
591
+ ok? &&
592
+ config['msg'] != 'isdbgrid' &&
593
+ config['setName'].nil? &&
594
+ config['isreplicaset'] != true
582
595
  end
583
596
 
584
- # Is the server description currently unknown?
597
+ # Returns whether this server is an unknown, per the SDAM spec.
585
598
  #
586
599
  # @example Is the server description unknown?
587
600
  # description.unknown?
@@ -881,21 +881,21 @@ module Mongo
881
881
  end
882
882
  end
883
883
 
884
- # Validate the session.
884
+ # Validate the session for use by the specified client.
885
885
  #
886
- # @example
887
- # session.validate!(cluster)
886
+ # The session must not be ended and must have been created by a client
887
+ # with the same cluster as the client that the session is to be used with.
888
888
  #
889
- # @param [ Cluster ] cluster The cluster the session is attempted to be used with.
889
+ # @param [ Client ] client The client the session is to be used with.
890
890
  #
891
- # @return [ nil ] nil if the session is valid.
891
+ # @return [ Session ] self, if the session is valid.
892
892
  #
893
- # @raise [ Mongo::Error::InvalidSession ] Raise error if the session is not valid.
893
+ # @raise [ Mongo::Error::InvalidSession ] Exception raised if the session is not valid.
894
894
  #
895
895
  # @since 2.5.0
896
896
  # @api private
897
- def validate!(cluster)
898
- check_matching_cluster!(cluster)
897
+ def validate!(client)
898
+ check_matching_cluster!(client)
899
899
  check_if_ended!
900
900
  self
901
901
  end
@@ -1041,8 +1041,8 @@ module Mongo
1041
1041
  raise Mongo::Error::InvalidSession.new(SESSION_ENDED_ERROR_MSG) if ended?
1042
1042
  end
1043
1043
 
1044
- def check_matching_cluster!(cluster)
1045
- if @client.cluster != cluster
1044
+ def check_matching_cluster!(client)
1045
+ if @client.cluster != client.cluster
1046
1046
  raise Mongo::Error::InvalidSession.new(MISMATCHED_CLUSTER_ERROR_MSG)
1047
1047
  end
1048
1048
  end
@@ -17,5 +17,5 @@ module Mongo
17
17
  # The current version of the driver.
18
18
  #
19
19
  # @since 2.0.0
20
- VERSION = '2.11.1'.freeze
20
+ VERSION = '2.11.2'.freeze
21
21
  end
@@ -74,6 +74,19 @@ configuration is needed:
74
74
 
75
75
  rake
76
76
 
77
+ ### Replica Set With Arbiter
78
+
79
+ Some tests require an arbiter to be present in the replica set. Such a
80
+ deployment can be obtained by providing `--arbiter` argument to mlaunch:
81
+
82
+ mlaunch init --replicaset --arbiter --name ruby-driver-rs \
83
+ --dir /tmp/mdb-rs --setParameter enableTestCommands=1
84
+
85
+ To indicate to the test suite that the deployment contains an arbiter, set
86
+ HAVE_ARBITER environment variable as follows:
87
+
88
+ HAVE_ARBITER=1 rake
89
+
77
90
  ### Sharded Cluster
78
91
 
79
92
  A sharded cluster can be configured with mlaunch:
@@ -41,7 +41,7 @@ describe 'Auth' do
41
41
  it 'indicates scram-sha-1 was used' do
42
42
  expect do
43
43
  connection.connect!
44
- end.to raise_error(Mongo::Auth::Unauthorized, /User nonexistent_user \(mechanism: scram\) is not authorized to access admin.*\(used mechanism: SCRAM-SHA-1\)/)
44
+ end.to raise_error(Mongo::Auth::Unauthorized, /User nonexistent_user \(mechanism: scram\) is not authorized to access admin.*used mechanism: SCRAM-SHA-1/)
45
45
  end
46
46
  end
47
47
 
@@ -53,7 +53,7 @@ describe 'Auth' do
53
53
  it 'indicates scram-sha-1 was used' do
54
54
  expect do
55
55
  connection.connect!
56
- end.to raise_error(Mongo::Auth::Unauthorized, /User nonexistent_user \(mechanism: scram\) is not authorized to access admin.*\(used mechanism: SCRAM-SHA-1\)/)
56
+ end.to raise_error(Mongo::Auth::Unauthorized, /User nonexistent_user \(mechanism: scram\) is not authorized to access admin.*used mechanism: SCRAM-SHA-1/)
57
57
  end
58
58
  end
59
59
  end
@@ -73,7 +73,7 @@ describe 'Auth' do
73
73
  it 'indicates scram-sha-1 was used' do
74
74
  expect do
75
75
  connection.connect!
76
- end.to raise_error(Mongo::Auth::Unauthorized, /User existing_user \(mechanism: scram\) is not authorized to access admin.*\(used mechanism: SCRAM-SHA-1\)/)
76
+ end.to raise_error(Mongo::Auth::Unauthorized, /User existing_user \(mechanism: scram\) is not authorized to access admin.*used mechanism: SCRAM-SHA-1/)
77
77
  end
78
78
  end
79
79
 
@@ -85,7 +85,7 @@ describe 'Auth' do
85
85
  it 'indicates scram-sha-256 was used' do
86
86
  expect do
87
87
  connection.connect!
88
- end.to raise_error(Mongo::Auth::Unauthorized, /User existing_user \(mechanism: scram256\) is not authorized to access admin.*\(used mechanism: SCRAM-SHA-256\)/)
88
+ end.to raise_error(Mongo::Auth::Unauthorized, /User existing_user \(mechanism: scram256\) is not authorized to access admin.*used mechanism: SCRAM-SHA-256/)
89
89
  end
90
90
  end
91
91
  end
@@ -101,7 +101,7 @@ describe 'Auth' do
101
101
  it 'indicates scram-sha-1 was requested and used' do
102
102
  expect do
103
103
  connection.connect!
104
- end.to raise_error(Mongo::Auth::Unauthorized, /User nonexistent_user \(mechanism: scram\) is not authorized to access admin.*\(used mechanism: SCRAM-SHA-1\)/)
104
+ end.to raise_error(Mongo::Auth::Unauthorized, /User nonexistent_user \(mechanism: scram\) is not authorized to access admin.*used mechanism: SCRAM-SHA-1/)
105
105
  end
106
106
  end
107
107
 
@@ -114,7 +114,7 @@ describe 'Auth' do
114
114
  it 'indicates scram-sha-256 was requested and used' do
115
115
  expect do
116
116
  connection.connect!
117
- end.to raise_error(Mongo::Auth::Unauthorized, /User nonexistent_user \(mechanism: scram256\) is not authorized to access admin.*\(used mechanism: SCRAM-SHA-256\)/)
117
+ end.to raise_error(Mongo::Auth::Unauthorized, /User nonexistent_user \(mechanism: scram256\) is not authorized to access admin.*used mechanism: SCRAM-SHA-256/)
118
118
  end
119
119
  end
120
120
  end
@@ -123,10 +123,29 @@ describe 'Auth' do
123
123
  let(:options) { SpecConfig.instance.ssl_options.merge(
124
124
  user: 'nonexistent_user', password: 'foo') }
125
125
 
126
- it 'reports auth source used' do
126
+ it 'reports which server authentication was attempted against' do
127
127
  expect do
128
128
  connection.connect!
129
- end.to raise_error(Mongo::Auth::Unauthorized, /User nonexistent_user.*is not authorized to access admin \(auth source: admin\)/)
129
+ end.to raise_error(Mongo::Auth::Unauthorized, /used server: #{connection.address.to_s}/)
130
+ end
131
+
132
+ context 'with default auth source' do
133
+ it 'reports auth source used' do
134
+ expect do
135
+ connection.connect!
136
+ end.to raise_error(Mongo::Auth::Unauthorized, /auth source: admin/)
137
+ end
138
+ end
139
+
140
+ context 'with custom auth source' do
141
+ let(:options) { SpecConfig.instance.ssl_options.merge(
142
+ user: 'nonexistent_user', password: 'foo', auth_source: 'authdb') }
143
+
144
+ it 'reports auth source used' do
145
+ expect do
146
+ connection.connect!
147
+ end.to raise_error(Mongo::Auth::Unauthorized, /auth source: authdb/)
148
+ end
130
149
  end
131
150
  end
132
151
 
@@ -82,6 +82,20 @@ describe 'Client construction' do
82
82
  expect(client.cluster.topology).to be_a(Mongo::Cluster::Topology::Single)
83
83
  expect(client.options[:connect]).to eq :direct
84
84
  end
85
+
86
+ context 'direct connection with mismached me' do
87
+ let(:address) { ClusterConfig.instance.alternate_address.to_s }
88
+
89
+ let(:client) do
90
+ new_local_client([address], SpecConfig.instance.test_options)
91
+ end
92
+
93
+ let(:server) { client.cluster.next_primary }
94
+
95
+ it 'sets server type to primary' do
96
+ expect(server.description).to be_primary
97
+ end
98
+ end
85
99
  end
86
100
 
87
101
  context 'in sharded topology' do
@@ -17,7 +17,7 @@ describe Mongo::Auth::LDAP::Conversation do
17
17
  describe '#start' do
18
18
 
19
19
  let(:query) do
20
- conversation.start
20
+ conversation.start(nil)
21
21
  end
22
22
 
23
23
  let(:selector) do
@@ -7,6 +7,15 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
7
7
  described_class.new(user, mechanism)
8
8
  end
9
9
 
10
+ let(:connection) do
11
+ double('connection').tap do |connection|
12
+ features = double('features')
13
+ allow(features).to receive(:op_msg_enabled?)
14
+ allow(connection).to receive(:features).and_return(features)
15
+ allow(connection).to receive(:server)
16
+ end
17
+ end
18
+
10
19
  context 'when SCRAM-SHA-1 is used' do
11
20
  min_server_fcv '3.0'
12
21
 
@@ -28,7 +37,7 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
28
37
  describe '#start' do
29
38
 
30
39
  let(:query) do
31
- conversation.start
40
+ conversation.start(nil)
32
41
  end
33
42
 
34
43
  before do
@@ -85,7 +94,7 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
85
94
  end
86
95
 
87
96
  let(:query) do
88
- conversation.continue(reply)
97
+ conversation.continue(reply, connection)
89
98
  end
90
99
 
91
100
  let(:selector) do
@@ -117,7 +126,7 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
117
126
 
118
127
  it 'raises an error' do
119
128
  expect {
120
- conversation.continue(reply)
129
+ conversation.continue(reply, connection)
121
130
  }.to raise_error(Mongo::Error::InvalidNonce)
122
131
  end
123
132
  end
@@ -170,8 +179,8 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
170
179
  end
171
180
 
172
181
  let(:query) do
173
- conversation.continue(continue_reply)
174
- conversation.finalize(reply)
182
+ conversation.continue(continue_reply, connection)
183
+ conversation.finalize(reply, connection)
175
184
  end
176
185
 
177
186
  let(:selector) do
@@ -199,8 +208,8 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
199
208
 
200
209
  it 'raises an error' do
201
210
  expect {
202
- conversation.continue(continue_reply)
203
- conversation.finalize(reply)
211
+ conversation.continue(continue_reply, connection)
212
+ conversation.finalize(reply, connection)
204
213
  }.to raise_error(Mongo::Error::InvalidSignature)
205
214
  end
206
215
  end
@@ -226,7 +235,7 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
226
235
  describe '#start' do
227
236
 
228
237
  let(:query) do
229
- conversation.start
238
+ conversation.start(nil)
230
239
  end
231
240
 
232
241
  before do
@@ -283,7 +292,7 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
283
292
  end
284
293
 
285
294
  let(:query) do
286
- conversation.continue(reply)
295
+ conversation.continue(reply, connection)
287
296
  end
288
297
 
289
298
  let(:selector) do
@@ -315,7 +324,7 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
315
324
 
316
325
  it 'raises an error' do
317
326
  expect {
318
- conversation.continue(reply)
327
+ conversation.continue(reply, connection)
319
328
  }.to raise_error(Mongo::Error::InvalidNonce)
320
329
  end
321
330
  end
@@ -368,8 +377,8 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
368
377
  end
369
378
 
370
379
  let(:query) do
371
- conversation.continue(continue_reply)
372
- conversation.finalize(reply)
380
+ conversation.continue(continue_reply, connection)
381
+ conversation.finalize(reply, connection)
373
382
  end
374
383
 
375
384
  let(:selector) do
@@ -397,8 +406,8 @@ describe Mongo::Auth::SCRAM::Conversation, retry: 3 do
397
406
 
398
407
  it 'raises an error' do
399
408
  expect {
400
- conversation.continue(continue_reply)
401
- conversation.finalize(reply)
409
+ conversation.continue(continue_reply, connection)
410
+ conversation.finalize(reply, connection)
402
411
  }.to raise_error(Mongo::Error::InvalidSignature)
403
412
  end
404
413
  end