mongo 2.14.1 → 2.15.0.alpha
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/README.md +4 -1
- data/Rakefile +8 -15
- data/lib/mongo/auth/aws/conversation.rb +1 -4
- data/lib/mongo/auth/base.rb +13 -7
- data/lib/mongo/auth/conversation_base.rb +32 -0
- data/lib/mongo/auth/cr/conversation.rb +6 -29
- data/lib/mongo/auth/gssapi/conversation.rb +4 -15
- data/lib/mongo/auth/ldap/conversation.rb +3 -14
- data/lib/mongo/auth/sasl_conversation_base.rb +1 -13
- data/lib/mongo/auth/scram_conversation_base.rb +7 -34
- data/lib/mongo/auth/user/view.rb +16 -9
- data/lib/mongo/auth/x509/conversation.rb +4 -25
- data/lib/mongo/bulk_write.rb +21 -18
- data/lib/mongo/client.rb +82 -6
- data/lib/mongo/cluster/reapers/cursor_reaper.rb +6 -2
- data/lib/mongo/cluster.rb +19 -2
- data/lib/mongo/collection/view/aggregation.rb +1 -1
- data/lib/mongo/collection/view/change_stream.rb +1 -1
- data/lib/mongo/collection/view/iterable.rb +7 -17
- data/lib/mongo/collection/view/map_reduce.rb +2 -2
- data/lib/mongo/collection/view/readable.rb +42 -20
- data/lib/mongo/collection/view/writable.rb +14 -14
- data/lib/mongo/collection.rb +6 -6
- data/lib/mongo/cursor.rb +2 -12
- data/lib/mongo/database/view.rb +1 -1
- data/lib/mongo/database.rb +8 -3
- data/lib/mongo/error/bulk_write_error.rb +17 -3
- data/lib/mongo/error/internal_driver_error.rb +22 -0
- data/lib/mongo/error/operation_failure.rb +21 -2
- data/lib/mongo/error/parser.rb +65 -12
- data/lib/mongo/error/server_api_conflict.rb +23 -0
- data/lib/mongo/error/server_api_not_supported.rb +24 -0
- data/lib/mongo/error/unmet_dependency.rb +21 -0
- data/lib/mongo/error.rb +9 -1
- data/lib/mongo/index/view.rb +21 -11
- data/lib/mongo/monitoring/event/server_heartbeat_failed.rb +27 -16
- data/lib/mongo/monitoring/event/server_heartbeat_succeeded.rb +26 -15
- data/lib/mongo/monitoring.rb +13 -4
- data/lib/mongo/operation/collections_info/command.rb +2 -2
- data/lib/mongo/operation/collections_info.rb +18 -1
- data/lib/mongo/operation/context.rb +99 -0
- data/lib/mongo/operation/indexes.rb +15 -1
- data/lib/mongo/operation/insert/command.rb +2 -2
- data/lib/mongo/operation/insert/legacy.rb +2 -2
- data/lib/mongo/operation/insert/op_msg.rb +2 -2
- data/lib/mongo/operation/list_collections/result.rb +4 -1
- data/lib/mongo/operation/parallel_scan/command.rb +2 -1
- data/lib/mongo/operation/result.rb +2 -0
- data/lib/mongo/operation/shared/executable.rb +24 -14
- data/lib/mongo/operation/shared/executable_no_validate.rb +2 -2
- data/lib/mongo/operation/shared/op_msg_or_command.rb +1 -7
- data/lib/mongo/operation/shared/op_msg_or_find_command.rb +1 -7
- data/lib/mongo/operation/shared/polymorphic_operation.rb +39 -0
- data/lib/mongo/operation/shared/read_preference_supported.rb +36 -38
- data/lib/mongo/operation/shared/response_handling.rb +23 -23
- data/lib/mongo/operation/shared/sessions_supported.rb +15 -5
- data/lib/mongo/operation/shared/write.rb +8 -18
- data/lib/mongo/operation.rb +2 -2
- data/lib/mongo/protocol/compressed.rb +51 -5
- data/lib/mongo/protocol/message.rb +20 -2
- data/lib/mongo/protocol/msg.rb +38 -13
- data/lib/mongo/protocol/query.rb +11 -11
- data/lib/mongo/query_cache.rb +30 -0
- data/lib/mongo/retryable.rb +1 -1
- data/lib/mongo/server/app_metadata.rb +52 -18
- data/lib/mongo/server/connection.rb +5 -0
- data/lib/mongo/server/connection_base.rb +13 -10
- data/lib/mongo/server/connection_pool.rb +6 -2
- data/lib/mongo/server/description/features.rb +9 -8
- data/lib/mongo/server/description.rb +4 -0
- data/lib/mongo/server/monitor/app_metadata.rb +1 -1
- data/lib/mongo/server/monitor/connection.rb +9 -10
- data/lib/mongo/server/monitor.rb +20 -1
- data/lib/mongo/server/pending_connection.rb +24 -6
- data/lib/mongo/server/push_monitor.rb +11 -1
- data/lib/mongo/server.rb +7 -1
- data/lib/mongo/server_selector/secondary_preferred.rb +7 -2
- data/lib/mongo/session/session_pool.rb +4 -2
- data/lib/mongo/session.rb +2 -2
- data/lib/mongo/socket/ssl.rb +8 -0
- data/lib/mongo/socket.rb +29 -4
- data/lib/mongo/uri/options_mapper.rb +38 -0
- data/lib/mongo/utils.rb +15 -0
- data/lib/mongo/version.rb +1 -1
- data/lib/mongo.rb +23 -0
- data/spec/README.md +24 -1
- data/spec/integration/auth_spec.rb +25 -15
- data/spec/integration/bulk_write_error_message_spec.rb +41 -0
- data/spec/integration/change_stream_spec.rb +4 -4
- data/spec/integration/command_monitoring_spec.rb +2 -2
- data/spec/integration/connection_spec.rb +2 -0
- data/spec/integration/docs_examples_spec.rb +8 -1
- data/spec/integration/fork_reconnect_spec.rb +4 -1
- data/spec/integration/ocsp_verifier_spec.rb +13 -7
- data/spec/integration/operation_failure_code_spec.rb +1 -1
- data/spec/integration/operation_failure_message_spec.rb +90 -0
- data/spec/integration/query_cache_spec.rb +0 -45
- data/spec/integration/reconnect_spec.rb +1 -1
- data/spec/integration/snappy_compression_spec.rb +25 -0
- data/spec/integration/srv_monitoring_spec.rb +1 -1
- data/spec/integration/transactions_examples_spec.rb +6 -0
- data/spec/integration/zlib_compression_spec.rb +1 -1
- data/spec/integration/zstd_compression_spec.rb +26 -0
- data/spec/lite_spec_helper.rb +7 -1
- data/spec/mongo/address_spec.rb +15 -11
- data/spec/mongo/auth/ldap/conversation_spec.rb +1 -1
- data/spec/mongo/auth/ldap_spec.rb +5 -1
- data/spec/mongo/auth/scram_negotiation_spec.rb +1 -1
- data/spec/mongo/auth/scram_spec.rb +1 -1
- data/spec/mongo/auth/x509/conversation_spec.rb +3 -3
- data/spec/mongo/client_construction_spec.rb +207 -33
- data/spec/mongo/client_spec.rb +17 -0
- data/spec/mongo/cluster_spec.rb +1 -0
- data/spec/mongo/collection/view/explainable_spec.rb +1 -1
- data/spec/mongo/collection/view/readable_spec.rb +33 -19
- data/spec/mongo/collection_crud_spec.rb +4357 -0
- data/spec/mongo/collection_ddl_spec.rb +534 -0
- data/spec/mongo/collection_spec.rb +5 -4859
- data/spec/mongo/database_spec.rb +66 -4
- data/spec/mongo/error/bulk_write_error_spec.rb +3 -3
- data/spec/mongo/error/parser_spec.rb +37 -6
- data/spec/mongo/index/view_spec.rb +4 -0
- data/spec/mongo/monitoring/event/server_heartbeat_failed_spec.rb +1 -1
- data/spec/mongo/monitoring/event/server_heartbeat_succeeded_spec.rb +1 -1
- data/spec/mongo/operation/aggregate_spec.rb +2 -1
- data/spec/mongo/operation/collections_info_spec.rb +4 -1
- data/spec/mongo/operation/command_spec.rb +6 -3
- data/spec/mongo/operation/create_index_spec.rb +6 -3
- data/spec/mongo/operation/create_user_spec.rb +6 -3
- data/spec/mongo/operation/delete/bulk_spec.rb +9 -6
- data/spec/mongo/operation/delete_spec.rb +11 -7
- data/spec/mongo/operation/drop_index_spec.rb +6 -2
- data/spec/mongo/operation/find/legacy_spec.rb +3 -1
- data/spec/mongo/operation/get_more_spec.rb +3 -1
- data/spec/mongo/operation/indexes_spec.rb +5 -1
- data/spec/mongo/operation/insert/bulk_spec.rb +10 -7
- data/spec/mongo/operation/insert_spec.rb +15 -12
- data/spec/mongo/operation/map_reduce_spec.rb +5 -2
- data/spec/mongo/operation/read_preference_legacy_spec.rb +19 -9
- data/spec/mongo/operation/read_preference_op_msg_spec.rb +3 -3
- data/spec/mongo/operation/remove_user_spec.rb +6 -3
- data/spec/mongo/operation/result_spec.rb +1 -1
- data/spec/mongo/operation/update/bulk_spec.rb +9 -6
- data/spec/mongo/operation/update_spec.rb +10 -7
- data/spec/mongo/operation/update_user_spec.rb +4 -1
- data/spec/mongo/protocol/compressed_spec.rb +26 -12
- data/spec/mongo/query_cache_middleware_spec.rb +55 -0
- data/spec/mongo/retryable_spec.rb +3 -2
- data/spec/mongo/server/app_metadata_shared.rb +7 -33
- data/spec/mongo/server/app_metadata_spec.rb +2 -0
- data/spec/mongo/server/connection_pool/populator_spec.rb +3 -1
- data/spec/mongo/server/connection_pool_spec.rb +1 -1
- data/spec/mongo/server/connection_spec.rb +24 -17
- data/spec/mongo/server/monitor/connection_spec.rb +17 -7
- data/spec/mongo/server/monitor_spec.rb +9 -1
- data/spec/mongo/server_selector/secondary_preferred_spec.rb +6 -6
- data/spec/mongo/server_spec.rb +15 -2
- data/spec/mongo/socket/ssl_spec.rb +40 -0
- data/spec/mongo/socket_spec.rb +2 -2
- data/spec/mongo/tls_context_hooks_spec.rb +37 -0
- data/spec/runners/connection_string.rb +0 -4
- data/spec/runners/crud/requirement.rb +40 -3
- data/spec/runners/crud/verifier.rb +8 -0
- data/spec/runners/transactions/operation.rb +1 -1
- data/spec/runners/transactions/test.rb +1 -0
- data/spec/runners/unified/assertions.rb +249 -0
- data/spec/runners/unified/change_stream_operations.rb +26 -0
- data/spec/runners/unified/crud_operations.rb +199 -0
- data/spec/runners/unified/ddl_operations.rb +96 -0
- data/spec/runners/unified/entity_map.rb +39 -0
- data/spec/runners/unified/error.rb +25 -0
- data/spec/runners/unified/event_subscriber.rb +91 -0
- data/spec/runners/unified/exceptions.rb +21 -0
- data/spec/runners/unified/grid_fs_operations.rb +55 -0
- data/spec/runners/unified/support_operations.rb +250 -0
- data/spec/runners/unified/test.rb +393 -0
- data/spec/runners/unified/test_group.rb +28 -0
- data/spec/runners/unified/using_hash.rb +31 -0
- data/spec/runners/unified.rb +96 -0
- data/spec/shared/lib/mrss/cluster_config.rb +0 -3
- data/spec/shared/lib/mrss/docker_runner.rb +0 -3
- data/spec/shared/lib/mrss/lite_constraints.rb +0 -16
- data/spec/shared/lib/mrss/server_version_registry.rb +0 -3
- data/spec/shared/lib/mrss/spec_organizer.rb +0 -3
- data/spec/shared/shlib/server.sh +1 -1
- data/spec/spec_helper.rb +4 -1
- data/spec/spec_tests/crud_unified_spec.rb +10 -0
- data/spec/spec_tests/data/change_streams/change-streams.yml +0 -1
- data/spec/spec_tests/data/crud_unified/estimatedDocumentCount.yml +267 -0
- data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-4.9.yml +60 -0
- data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount.yml → estimatedDocumentCount-pre4.9.yml} +2 -0
- data/spec/spec_tests/data/retryable_reads/estimatedDocumentCount-serverErrors-4.9.yml +146 -0
- data/spec/spec_tests/data/retryable_reads/{estimatedDocumentCount-serverErrors.yml → estimatedDocumentCount-serverErrors-pre4.9.yml} +2 -0
- data/spec/spec_tests/data/retryable_reads/listIndexNames.yml +1 -1
- data/spec/spec_tests/data/unified/valid-fail/operation-failure.yml +31 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-change-streams.yml +220 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-command-monitoring.yml +102 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-crud.yml +184 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-gridfs.yml +155 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-retryable-reads.yml +193 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-retryable-writes.yml +210 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-sessions.yml +215 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-transactions-convenient-api.yml +235 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-transactions-mongos-pin-auto.yml +169 -0
- data/spec/spec_tests/data/unified/valid-pass/poc-transactions.yml +170 -0
- data/spec/spec_tests/data/uri_options/compression-options.yml +1 -1
- data/spec/spec_tests/data/versioned_api/crud-api-version-1-strict.yml +416 -0
- data/spec/spec_tests/data/versioned_api/crud-api-version-1.yml +409 -0
- data/spec/spec_tests/data/versioned_api/runcommand-helper-no-api-version-declared.yml +67 -0
- data/spec/spec_tests/data/versioned_api/test-commands-deprecation-errors.yml +47 -0
- data/spec/spec_tests/data/versioned_api/test-commands-strict-mode.yml +44 -0
- data/spec/spec_tests/data/versioned_api/transaction-handling.yml +180 -0
- data/spec/spec_tests/unified_spec.rb +15 -0
- data/spec/spec_tests/uri_options_spec.rb +16 -0
- data/spec/spec_tests/versioned_api_spec.rb +10 -0
- data/spec/support/client_registry.rb +4 -8
- data/spec/support/client_registry_macros.rb +4 -4
- data/spec/support/common_shortcuts.rb +15 -1
- data/spec/support/shared/session.rb +2 -2
- data/spec/support/spec_config.rb +42 -11
- data/spec/support/utils.rb +64 -3
- data.tar.gz.sig +0 -0
- metadata +1005 -915
- metadata.gz.sig +0 -0
- data/lib/mongo/operation/shared/collections_info_or_list_collections.rb +0 -58
- data/lib/mongo/operation/shared/op_msg_or_list_indexes_command.rb +0 -47
- data/spec/integration/secondary_reads_spec.rb +0 -102
- data/spec/support/cluster_config.rb +0 -207
data/lib/mongo/server/monitor.rb
CHANGED
@@ -63,6 +63,10 @@ module Mongo
|
|
63
63
|
# @option options [ Float ] :heartbeat_interval The interval between
|
64
64
|
# regular server checks.
|
65
65
|
# @option options [ Logger ] :logger A custom logger to use.
|
66
|
+
# @option options [ Mongo::Server::Monitor::AppMetadata ] :monitor_app_metadata
|
67
|
+
# The metadata to use for regular monitoring connection.
|
68
|
+
# @option options [ Mongo::Server::Monitor::AppMetadata ] :push_monitor_app_metadata
|
69
|
+
# The metadata to use for push monitor's connection.
|
66
70
|
# @option options [ Float ] :socket_timeout The timeout, in seconds, to
|
67
71
|
# execute operations on the monitoring connection.
|
68
72
|
#
|
@@ -72,6 +76,12 @@ module Mongo
|
|
72
76
|
unless monitoring.is_a?(Monitoring)
|
73
77
|
raise ArgumentError, "Wrong monitoring type: #{monitoring.inspect}"
|
74
78
|
end
|
79
|
+
unless options[:app_metadata]
|
80
|
+
raise ArgumentError, 'App metadata is required'
|
81
|
+
end
|
82
|
+
unless options[:push_monitor_app_metadata]
|
83
|
+
raise ArgumentError, 'Push monitor app metadata is required'
|
84
|
+
end
|
75
85
|
@server = server
|
76
86
|
@event_listeners = event_listeners
|
77
87
|
@monitoring = monitoring
|
@@ -273,7 +283,15 @@ module Mongo
|
|
273
283
|
if @connection
|
274
284
|
result = server.round_trip_time_averager.measure do
|
275
285
|
begin
|
276
|
-
|
286
|
+
ismaster_bytes = if server_api = options[:server_api]
|
287
|
+
ismaster_doc = Monitor::Connection::ISMASTER.merge(
|
288
|
+
Utils.transform_server_api(server_api)
|
289
|
+
)
|
290
|
+
Protocol::Query.new(Database::ADMIN, Database::COMMAND, ismaster_doc, limit: -1).serialize.to_s
|
291
|
+
else
|
292
|
+
Monitor::Connection::ISMASTER_BYTES
|
293
|
+
end
|
294
|
+
message = @connection.dispatch_bytes(ismaster_bytes)
|
277
295
|
message.documents.first
|
278
296
|
rescue Mongo::Error
|
279
297
|
@connection.disconnect!
|
@@ -297,6 +315,7 @@ module Mongo
|
|
297
315
|
monitoring,
|
298
316
|
**Utils.shallow_symbolize_keys(options.merge(
|
299
317
|
socket_timeout: heartbeat_interval + connection.socket_timeout,
|
318
|
+
app_metadata: options[:push_monitor_app_metadata],
|
300
319
|
)),
|
301
320
|
)
|
302
321
|
end
|
@@ -63,6 +63,11 @@ module Mongo
|
|
63
63
|
end
|
64
64
|
|
65
65
|
result = handshake!(speculative_auth_doc: speculative_auth_doc)
|
66
|
+
|
67
|
+
if description.unknown?
|
68
|
+
raise Error::InternalDriverError, "Connection description cannot be unknown after successful handshake: #{description.inspect}"
|
69
|
+
end
|
70
|
+
|
66
71
|
if speculative_auth_doc && (speculative_auth_result = result['speculativeAuthenticate'])
|
67
72
|
unless description.features.scram_sha_1_enabled?
|
68
73
|
raise Error::InvalidServerAuthResponse, "Speculative auth succeeded on a pre-3.0 server"
|
@@ -80,11 +85,15 @@ module Mongo
|
|
80
85
|
speculative_auth_result: speculative_auth_result,
|
81
86
|
)
|
82
87
|
else
|
83
|
-
raise
|
88
|
+
raise Error::InternalDriverError, "Speculative auth unexpectedly succeeded for mechanism #{speculative_auth_user.mechanism.inspect}"
|
84
89
|
end
|
85
90
|
elsif !description.arbiter?
|
86
91
|
authenticate!
|
87
92
|
end
|
93
|
+
|
94
|
+
if description.unknown?
|
95
|
+
raise Error::InternalDriverError, "Connection description cannot be unknown after successful authentication: #{description.inspect}"
|
96
|
+
end
|
88
97
|
end
|
89
98
|
|
90
99
|
private
|
@@ -96,7 +105,7 @@ module Mongo
|
|
96
105
|
# this particular connection.
|
97
106
|
def handshake!(speculative_auth_doc: nil)
|
98
107
|
unless socket
|
99
|
-
raise Error::
|
108
|
+
raise Error::InternalDriverError, "Cannot handshake because there is no usable socket (for #{address})"
|
100
109
|
end
|
101
110
|
|
102
111
|
ismaster_doc = app_metadata.validated_document
|
@@ -104,18 +113,27 @@ module Mongo
|
|
104
113
|
ismaster_doc = ismaster_doc.merge(speculativeAuthenticate: speculative_auth_doc)
|
105
114
|
end
|
106
115
|
|
116
|
+
if server_api = options[:server_api]
|
117
|
+
ismaster_doc = ismaster_doc.merge(
|
118
|
+
Utils.transform_server_api(server_api)
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
107
122
|
ismaster_command = Protocol::Query.new(Database::ADMIN, Database::COMMAND,
|
108
123
|
ismaster_doc, :limit => -1)
|
109
124
|
|
110
|
-
|
125
|
+
doc = nil
|
111
126
|
@server.handle_handshake_failure! do
|
112
127
|
begin
|
113
128
|
response = @server.round_trip_time_averager.measure do
|
114
129
|
add_server_diagnostics do
|
115
130
|
socket.write(ismaster_command.serialize.to_s)
|
116
|
-
Protocol::Message.deserialize(socket, Protocol::Message::MAX_MESSAGE_SIZE)
|
131
|
+
Protocol::Message.deserialize(socket, Protocol::Message::MAX_MESSAGE_SIZE)
|
117
132
|
end
|
118
133
|
end
|
134
|
+
result = Operation::Result.new([response])
|
135
|
+
result.validate!
|
136
|
+
doc = result.documents.first
|
119
137
|
rescue => exc
|
120
138
|
msg = "Failed to handshake with #{address}"
|
121
139
|
Utils.warn_bg_exception(msg, exc,
|
@@ -127,9 +145,9 @@ module Mongo
|
|
127
145
|
end
|
128
146
|
end
|
129
147
|
|
130
|
-
post_handshake(
|
148
|
+
post_handshake(doc, @server.round_trip_time_averager.average_round_trip_time)
|
131
149
|
|
132
|
-
|
150
|
+
doc
|
133
151
|
end
|
134
152
|
|
135
153
|
# @param [ String | nil ] speculative_auth_client_nonce The client
|
@@ -33,6 +33,9 @@ module Mongo
|
|
33
33
|
if topology_version.nil?
|
34
34
|
raise ArgumentError, 'Topology version must be provided but it was nil'
|
35
35
|
end
|
36
|
+
unless options[:app_metadata]
|
37
|
+
raise ArgumentError, 'App metadata is required'
|
38
|
+
end
|
36
39
|
@monitor = monitor
|
37
40
|
@topology_version = topology_version
|
38
41
|
@monitoring = monitoring
|
@@ -139,7 +142,9 @@ module Mongo
|
|
139
142
|
raise
|
140
143
|
end
|
141
144
|
@server_pushing = resp_msg.flags.include?(:more_to_come)
|
142
|
-
result = resp_msg
|
145
|
+
result = Operation::Result.new(resp_msg)
|
146
|
+
result.validate!
|
147
|
+
result.documents.first
|
143
148
|
end
|
144
149
|
|
145
150
|
def write_ismaster
|
@@ -147,6 +152,11 @@ module Mongo
|
|
147
152
|
topologyVersion: topology_version.to_doc,
|
148
153
|
maxAwaitTimeMS: monitor.heartbeat_interval * 1000,
|
149
154
|
)
|
155
|
+
if server_api = options[:server_api]
|
156
|
+
payload.update(
|
157
|
+
Utils.transform_server_api(server_api)
|
158
|
+
)
|
159
|
+
end
|
150
160
|
|
151
161
|
req_msg = Protocol::Msg.new([:exhaust_allowed], {}, payload)
|
152
162
|
@lock.synchronize { @connection }.write_bytes(req_msg.serialize.to_s)
|
data/lib/mongo/server.rb
CHANGED
@@ -71,7 +71,8 @@ module Mongo
|
|
71
71
|
unless options[:monitoring_io] == false
|
72
72
|
@monitor = Monitor.new(self, event_listeners, monitoring,
|
73
73
|
options.merge(
|
74
|
-
app_metadata:
|
74
|
+
app_metadata: cluster.monitor_app_metadata,
|
75
|
+
push_monitor_app_metadata: cluster.push_monitor_app_metadata,
|
75
76
|
heartbeat_interval: cluster.heartbeat_interval,
|
76
77
|
))
|
77
78
|
unless _monitor == false
|
@@ -172,6 +173,11 @@ module Mongo
|
|
172
173
|
:cluster_time,
|
173
174
|
:update_cluster_time
|
174
175
|
|
176
|
+
# @api private
|
177
|
+
def_delegators :cluster,
|
178
|
+
:monitor_app_metadata,
|
179
|
+
:push_monitor_app_metadata
|
180
|
+
|
175
181
|
def_delegators :features,
|
176
182
|
:check_driver_support!
|
177
183
|
|
@@ -86,8 +86,13 @@ module Mongo
|
|
86
86
|
#
|
87
87
|
# @since 2.0.0
|
88
88
|
def to_mongos
|
89
|
-
|
90
|
-
|
89
|
+
if tag_sets.empty? && max_staleness.nil? && hedge.nil?
|
90
|
+
# The server preference is not sent to mongos as part of the query
|
91
|
+
# selector if there are no tag sets, for maximum backwards compatibility.
|
92
|
+
nil
|
93
|
+
else
|
94
|
+
to_doc
|
95
|
+
end
|
91
96
|
end
|
92
97
|
|
93
98
|
private
|
@@ -119,8 +119,10 @@ module Mongo
|
|
119
119
|
},
|
120
120
|
db_name: Database::ADMIN,
|
121
121
|
)
|
122
|
-
|
123
|
-
|
122
|
+
context = Operation::Context.new(options: {
|
123
|
+
server_api: server.options[:server_api],
|
124
|
+
})
|
125
|
+
op.execute(server, context: context)
|
124
126
|
end
|
125
127
|
rescue Mongo::Error, Error::AuthError
|
126
128
|
end
|
data/lib/mongo/session.rb
CHANGED
@@ -582,7 +582,7 @@ module Mongo
|
|
582
582
|
txn_num: txn_num,
|
583
583
|
write_concern: write_concern,
|
584
584
|
}
|
585
|
-
Operation::Command.new(spec).execute(server, client: @client)
|
585
|
+
Operation::Command.new(spec).execute(server, context: Operation::Context.new(client: @client, session: self))
|
586
586
|
end
|
587
587
|
end
|
588
588
|
ensure
|
@@ -629,7 +629,7 @@ module Mongo
|
|
629
629
|
db_name: 'admin',
|
630
630
|
session: self,
|
631
631
|
txn_num: txn_num
|
632
|
-
).execute(server, client: @client)
|
632
|
+
).execute(server, context: Operation::Context.new(client: @client, session: self))
|
633
633
|
end
|
634
634
|
end
|
635
635
|
|
data/lib/mongo/socket/ssl.rb
CHANGED
@@ -106,6 +106,8 @@ module Mongo
|
|
106
106
|
begin
|
107
107
|
@tcp_socket.setsockopt(IPPROTO_TCP, TCP_NODELAY, 1)
|
108
108
|
set_socket_options(@tcp_socket)
|
109
|
+
run_tls_context_hooks
|
110
|
+
|
109
111
|
connect!
|
110
112
|
rescue
|
111
113
|
@tcp_socket.close
|
@@ -379,6 +381,12 @@ module Mongo
|
|
379
381
|
def human_address
|
380
382
|
"#{host}:#{port} (#{host_name}:#{port}, TLS)"
|
381
383
|
end
|
384
|
+
|
385
|
+
def run_tls_context_hooks
|
386
|
+
Mongo.tls_context_hooks.each do |hook|
|
387
|
+
hook.call(@context)
|
388
|
+
end
|
389
|
+
end
|
382
390
|
end
|
383
391
|
end
|
384
392
|
end
|
data/lib/mongo/socket.rb
CHANGED
@@ -30,6 +30,7 @@ module Mongo
|
|
30
30
|
# Error message for TLS related exceptions.
|
31
31
|
#
|
32
32
|
# @since 2.0.0
|
33
|
+
# @deprecated
|
33
34
|
SSL_ERROR = 'MongoDB may not be configured with TLS support'.freeze
|
34
35
|
|
35
36
|
# Error message for timeouts on socket calls.
|
@@ -154,7 +155,14 @@ module Mongo
|
|
154
155
|
#
|
155
156
|
# @since 2.0.0
|
156
157
|
def close
|
157
|
-
|
158
|
+
begin
|
159
|
+
# Sometimes it seems the close call can hang for a long time
|
160
|
+
::Timeout.timeout(5) do
|
161
|
+
@socket.close
|
162
|
+
end
|
163
|
+
rescue
|
164
|
+
# Silence all errors
|
165
|
+
end
|
158
166
|
true
|
159
167
|
end
|
160
168
|
|
@@ -326,8 +334,21 @@ module Mongo
|
|
326
334
|
else
|
327
335
|
select_args = [nil, [@socket], [@socket], select_timeout]
|
328
336
|
end
|
329
|
-
|
330
|
-
|
337
|
+
rv = Kernel.select(*select_args)
|
338
|
+
if BSON::Environment.jruby?
|
339
|
+
# Ignore the return value of Kernel.select.
|
340
|
+
# On JRuby, select appears to return nil prior to timeout expiration
|
341
|
+
# (apparently due to a EAGAIN) which then causes us to fail the read
|
342
|
+
# even though we could have retried it.
|
343
|
+
# Check the deadline ourselves.
|
344
|
+
if deadline
|
345
|
+
select_timeout = deadline - Time.now
|
346
|
+
if select_timeout <= 0
|
347
|
+
raise Errno::ETIMEDOUT, "Took more than #{_timeout} seconds to receive data"
|
348
|
+
end
|
349
|
+
end
|
350
|
+
elsif rv.nil?
|
351
|
+
raise Errno::ETIMEDOUT, "Took more than #{_timeout} seconds to receive data (select call timed out)"
|
331
352
|
end
|
332
353
|
retry
|
333
354
|
end
|
@@ -398,6 +419,10 @@ module Mongo
|
|
398
419
|
set_option(sock, :TCP_KEEPCNT, DEFAULT_TCP_KEEPCNT)
|
399
420
|
set_option(sock, :TCP_KEEPIDLE, DEFAULT_TCP_KEEPIDLE)
|
400
421
|
rescue
|
422
|
+
# JRuby 9.2.13.0 and lower do not define TCP_KEEPINTVL etc. constants.
|
423
|
+
# JRuby 9.2.14.0 defines the constants but does not allow to get or
|
424
|
+
# set them with this error:
|
425
|
+
# Errno::ENOPROTOOPT: Protocol not available - Protocol not available
|
401
426
|
end
|
402
427
|
|
403
428
|
def set_option(sock, option, default)
|
@@ -422,7 +447,7 @@ module Mongo
|
|
422
447
|
rescue IOError, SystemCallError => e
|
423
448
|
raise Error::SocketError, "#{e.class}: #{e} (for #{human_address})"
|
424
449
|
rescue OpenSSL::SSL::SSLError => e
|
425
|
-
raise Error::SocketError, "#{e.class}: #{e} (for #{human_address})
|
450
|
+
raise Error::SocketError, "#{e.class}: #{e} (for #{human_address})"
|
426
451
|
end
|
427
452
|
end
|
428
453
|
|
@@ -82,6 +82,44 @@ module Mongo
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
+
def smc_to_ruby(opts)
|
86
|
+
uri_options = {}
|
87
|
+
|
88
|
+
opts.each do |key, value|
|
89
|
+
strategy = URI_OPTION_MAP[key.downcase]
|
90
|
+
if strategy.nil?
|
91
|
+
log_warn("Unsupported URI option '#{key}' on URI '#{@string}'. It will be ignored.")
|
92
|
+
return
|
93
|
+
end
|
94
|
+
|
95
|
+
group = strategy[:group]
|
96
|
+
target = if group
|
97
|
+
uri_options[group] || {}
|
98
|
+
else
|
99
|
+
uri_options
|
100
|
+
end
|
101
|
+
|
102
|
+
if key == 'readConcernLevel'
|
103
|
+
value = value.to_sym
|
104
|
+
end
|
105
|
+
|
106
|
+
#value = apply_transform(key, value, strategy[:type])
|
107
|
+
# Sometimes the value here would be nil, for example if we are processing
|
108
|
+
# read preference tags or auth mechanism properties and all of the
|
109
|
+
# data within is invalid. Ignore such options.
|
110
|
+
unless value.nil?
|
111
|
+
merge_uri_option(target, value, strategy[:name])
|
112
|
+
end
|
113
|
+
|
114
|
+
if group && !target.empty? && !uri_options.key?(group)
|
115
|
+
uri_options[group] = target
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
#p uri_options
|
120
|
+
uri_options
|
121
|
+
end
|
122
|
+
|
85
123
|
# Converts Ruby options provided to "standardized MongoClient options".
|
86
124
|
#
|
87
125
|
# @param [ Hash ] opts Ruby options to convert.
|
data/lib/mongo/utils.rb
CHANGED
@@ -69,5 +69,20 @@ module Mongo
|
|
69
69
|
module_function def camelize(sym)
|
70
70
|
sym.to_s.gsub(/_(\w)/) { $1.upcase }
|
71
71
|
end
|
72
|
+
|
73
|
+
# @note server_api must have symbol keys or be a BSON::Document.
|
74
|
+
module_function def transform_server_api(server_api)
|
75
|
+
{}.tap do |doc|
|
76
|
+
if version = server_api[:version]
|
77
|
+
doc['apiVersion'] = version
|
78
|
+
end
|
79
|
+
unless server_api[:strict].nil?
|
80
|
+
doc['apiStrict'] = server_api[:strict]
|
81
|
+
end
|
82
|
+
unless server_api[:deprecation_errors].nil?
|
83
|
+
doc['apiDeprecationErrors'] = server_api[:deprecation_errors]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
72
87
|
end
|
73
88
|
end
|
data/lib/mongo/version.rb
CHANGED
data/lib/mongo.rb
CHANGED
@@ -78,4 +78,27 @@ module Mongo
|
|
78
78
|
module_function def clear_ocsp_cache
|
79
79
|
Socket::OcspCache.clear
|
80
80
|
end
|
81
|
+
|
82
|
+
# This is a user-settable list of hooks that will be invoked when any new
|
83
|
+
# TLS socket is connected. Each hook should be a Proc that takes
|
84
|
+
# an OpenSSL::SSL::SSLContext object as an argument. These hooks can be used
|
85
|
+
# to modify the TLS context (for example to disallow certain ciphers).
|
86
|
+
#
|
87
|
+
# @return [ Array<Proc> ] The list of procs to be invoked when a TLS socket
|
88
|
+
# is connected (may be an empty Array).
|
89
|
+
module_function def tls_context_hooks
|
90
|
+
@tls_context_hooks ||= []
|
91
|
+
end
|
92
|
+
|
93
|
+
# Set the TLS context hooks.
|
94
|
+
#
|
95
|
+
# @param [ Array<Proc> ] hooks An Array of Procs, each of which should take
|
96
|
+
# an OpenSSL::SSL::SSLContext object as an argument.
|
97
|
+
module_function def tls_context_hooks=(hooks)
|
98
|
+
unless hooks.is_a?(Array) && hooks.all? { |hook| hook.is_a?(Proc) }
|
99
|
+
raise ArgumentError, "TLS context hooks must be an array of Procs"
|
100
|
+
end
|
101
|
+
|
102
|
+
@tls_context_hooks = hooks
|
103
|
+
end
|
81
104
|
end
|
data/spec/README.md
CHANGED
@@ -512,13 +512,36 @@ To test compression, set the `compressors` URI option:
|
|
512
512
|
|
513
513
|
MONGODB_URI="mongodb://localhost:27017/?compressors=zlib" rake
|
514
514
|
|
515
|
-
Note that as of this writing, the driver
|
515
|
+
Note that as of this writing, the driver supports
|
516
|
+
[ztsd](https://docs.mongodb.com/manual/reference/glossary/#term-zstd),
|
517
|
+
[snappy](https://docs.mongodb.com/manual/reference/glossary/#term-snappy)
|
518
|
+
and [zlib](https://docs.mongodb.com/manual/reference/glossary/#term-zlib)
|
519
|
+
compression.
|
520
|
+
|
516
521
|
Servers 4.2+ enable zlib by default; to test older servers, explicitly enable
|
517
522
|
zlib compression when launching the server:
|
518
523
|
|
519
524
|
mongod --dbpath /tmp/mdb --setParameter enableTestCommands=1 \
|
520
525
|
--networkMessageCompressors snappy,zlib
|
521
526
|
|
527
|
+
## Server API
|
528
|
+
|
529
|
+
To specify server API parameters, use the `SERVER_API` environment variable.
|
530
|
+
The server API parameters cannot be specified via URI options.
|
531
|
+
|
532
|
+
Both YAML and JSON syntaxes are accepted:
|
533
|
+
|
534
|
+
SERVER_API='{version: "1", strict: true}' rake
|
535
|
+
|
536
|
+
SERVER_API='{"version":"1","strict":true}' rake
|
537
|
+
|
538
|
+
Note that the input must be valid YAML or JSON and the version number must
|
539
|
+
be a string, therefore all of the following specifications are invalid:
|
540
|
+
|
541
|
+
SERVER_API='{version:"1",strict:true}' rake
|
542
|
+
SERVER_API='{version: 1}' rake
|
543
|
+
SERVER_API='{"version":1,"strict":true}' rake
|
544
|
+
|
522
545
|
## Other Options
|
523
546
|
|
524
547
|
Generally, all URI options recognized by the driver may be set for a test run,
|
@@ -10,8 +10,12 @@ describe 'Auth' do
|
|
10
10
|
authorized_client.cluster.next_primary
|
11
11
|
end
|
12
12
|
|
13
|
+
let(:base_options) do
|
14
|
+
SpecConfig.instance.monitoring_options
|
15
|
+
end
|
16
|
+
|
13
17
|
let(:connection) do
|
14
|
-
Mongo::Server::Connection.new(server, options)
|
18
|
+
Mongo::Server::Connection.new(server, base_options.merge(options))
|
15
19
|
end
|
16
20
|
|
17
21
|
before(:all) do
|
@@ -31,8 +35,9 @@ describe 'Auth' do
|
|
31
35
|
context 'user mechanism not provided' do
|
32
36
|
|
33
37
|
context 'user does not exist' do
|
34
|
-
let(:options)
|
35
|
-
user: 'nonexistent_user'
|
38
|
+
let(:options) do
|
39
|
+
{user: 'nonexistent_user' }
|
40
|
+
end
|
36
41
|
|
37
42
|
before do
|
38
43
|
expect(connection.app_metadata.send(:document)[:saslSupportedMechs]).to eq('admin.nonexistent_user')
|
@@ -63,8 +68,9 @@ describe 'Auth' do
|
|
63
68
|
end
|
64
69
|
|
65
70
|
context 'user exists' do
|
66
|
-
let(:options)
|
67
|
-
user: 'existing_user', password: 'bogus'
|
71
|
+
let(:options) do
|
72
|
+
{user: 'existing_user', password: 'bogus'}
|
73
|
+
end
|
68
74
|
|
69
75
|
before do
|
70
76
|
expect(connection.app_metadata.send(:document)[:saslSupportedMechs]).to eq("admin.existing_user")
|
@@ -99,8 +105,9 @@ describe 'Auth' do
|
|
99
105
|
min_server_fcv '3.0'
|
100
106
|
|
101
107
|
context 'scram-sha-1 requested' do
|
102
|
-
let(:options)
|
103
|
-
user: 'nonexistent_user', auth_mech: :scram
|
108
|
+
let(:options) do
|
109
|
+
{user: 'nonexistent_user', auth_mech: :scram}
|
110
|
+
end
|
104
111
|
|
105
112
|
it 'indicates scram-sha-1 was requested and used' do
|
106
113
|
expect do
|
@@ -112,8 +119,9 @@ describe 'Auth' do
|
|
112
119
|
context 'scram-sha-256 requested' do
|
113
120
|
min_server_fcv '4.0'
|
114
121
|
|
115
|
-
let(:options)
|
116
|
-
user: 'nonexistent_user', auth_mech: :scram256
|
122
|
+
let(:options) do
|
123
|
+
{user: 'nonexistent_user', auth_mech: :scram256}
|
124
|
+
end
|
117
125
|
|
118
126
|
it 'indicates scram-sha-256 was requested and used' do
|
119
127
|
expect do
|
@@ -124,8 +132,9 @@ describe 'Auth' do
|
|
124
132
|
end
|
125
133
|
|
126
134
|
context 'when authentication fails' do
|
127
|
-
let(:options)
|
128
|
-
user: 'nonexistent_user', password: 'foo'
|
135
|
+
let(:options) do
|
136
|
+
{user: 'nonexistent_user', password: 'foo'}
|
137
|
+
end
|
129
138
|
|
130
139
|
it 'reports which server authentication was attempted against' do
|
131
140
|
expect do
|
@@ -142,8 +151,9 @@ describe 'Auth' do
|
|
142
151
|
end
|
143
152
|
|
144
153
|
context 'with custom auth source' do
|
145
|
-
let(:options)
|
146
|
-
user: 'nonexistent_user', password: 'foo', auth_source: 'authdb'
|
154
|
+
let(:options) do
|
155
|
+
{user: 'nonexistent_user', password: 'foo', auth_source: 'authdb'}
|
156
|
+
end
|
147
157
|
|
148
158
|
it 'reports auth source used' do
|
149
159
|
expect do
|
@@ -240,7 +250,7 @@ describe 'Auth' do
|
|
240
250
|
require_no_auth
|
241
251
|
|
242
252
|
let(:client) do
|
243
|
-
new_local_client(SpecConfig.instance.addresses, SpecConfig.instance.
|
253
|
+
new_local_client(SpecConfig.instance.addresses, SpecConfig.instance.monitoring_options.merge(
|
244
254
|
auth_source: 'foo'))
|
245
255
|
end
|
246
256
|
|
@@ -254,7 +264,7 @@ describe 'Auth' do
|
|
254
264
|
require_x509_auth
|
255
265
|
|
256
266
|
let(:client) do
|
257
|
-
new_local_client(SpecConfig.instance.addresses,
|
267
|
+
new_local_client(SpecConfig.instance.addresses, base_options.merge(
|
258
268
|
auth_mech: :mongodb_x509))
|
259
269
|
end
|
260
270
|
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'BulkWriteError message' do
|
4
|
+
let(:client) { authorized_client }
|
5
|
+
let(:collection_name) { 'bulk_write_error_message_spec' }
|
6
|
+
let(:collection) { client[collection_name] }
|
7
|
+
|
8
|
+
before do
|
9
|
+
collection.delete_many
|
10
|
+
end
|
11
|
+
|
12
|
+
context 'a bulk write with one error' do
|
13
|
+
it 'reports code name, code and message' do
|
14
|
+
begin
|
15
|
+
collection.insert_many([
|
16
|
+
{_id: 1},
|
17
|
+
{_id: 1},
|
18
|
+
{_id: 1},
|
19
|
+
], ordered: true)
|
20
|
+
fail('Should have raised')
|
21
|
+
rescue Mongo::Error::BulkWriteError => e
|
22
|
+
e.message.should =~ %r,\A\[11000\]: (insertDocument :: caused by :: 11000 )?E11000 duplicate key error (collection|index):,
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'a bulk write with multiple errors' do
|
28
|
+
it 'reports code name, code and message' do
|
29
|
+
begin
|
30
|
+
collection.insert_many([
|
31
|
+
{_id: 1},
|
32
|
+
{_id: 1},
|
33
|
+
{_id: 1},
|
34
|
+
], ordered: false)
|
35
|
+
fail('Should have raised')
|
36
|
+
rescue Mongo::Error::BulkWriteError => e
|
37
|
+
e.message.should =~ %r,\AMultiple errors: \[11000\]: (insertDocument :: caused by :: 11000 )?E11000 duplicate key error (collection|index):.*\[11000\]: (insertDocument :: caused by :: 11000 )?E11000 duplicate key error (collection|index):,
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -98,7 +98,7 @@ describe 'Change stream integration', retry: 4 do
|
|
98
98
|
it 'watch raises error' do
|
99
99
|
expect do
|
100
100
|
client['change-stream'].watch
|
101
|
-
end.to raise_error(Mongo::Error::OperationFailure, /Failing command due to 'failCommand' failpoint
|
101
|
+
end.to raise_error(Mongo::Error::OperationFailure, /10107\b.*Failing command due to 'failCommand' failpoint/)
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
@@ -283,7 +283,7 @@ describe 'Change stream integration', retry: 4 do
|
|
283
283
|
|
284
284
|
expect do
|
285
285
|
enum.next
|
286
|
-
end.to raise_error(Mongo::Error::OperationFailure, /Failing command due to 'failCommand' failpoint
|
286
|
+
end.to raise_error(Mongo::Error::OperationFailure, /101\b.*Failing command due to 'failCommand' failpoint/)
|
287
287
|
end
|
288
288
|
end
|
289
289
|
end
|
@@ -414,7 +414,7 @@ describe 'Change stream integration', retry: 4 do
|
|
414
414
|
|
415
415
|
expect do
|
416
416
|
enum.try_next
|
417
|
-
end.to raise_error(Mongo::Error::OperationFailure, /Failing command due to 'failCommand' failpoint
|
417
|
+
end.to raise_error(Mongo::Error::OperationFailure, /10107\b.*Failing command due to 'failCommand' failpoint/)
|
418
418
|
end
|
419
419
|
end
|
420
420
|
|
@@ -441,7 +441,7 @@ describe 'Change stream integration', retry: 4 do
|
|
441
441
|
|
442
442
|
expect do
|
443
443
|
enum.try_next
|
444
|
-
end.to raise_error(Mongo::Error::OperationFailure, /Failing command due to 'failCommand' failpoint
|
444
|
+
end.to raise_error(Mongo::Error::OperationFailure, /10107\b.*Failing command due to 'failCommand' failpoint/)
|
445
445
|
end
|
446
446
|
end
|
447
447
|
end
|
@@ -135,8 +135,8 @@ describe 'Command monitoring' do
|
|
135
135
|
|
136
136
|
subscriber.clear_events!
|
137
137
|
expect do
|
138
|
-
command.execute(server,
|
139
|
-
end.to raise_error(Mongo::Error::OperationFailure, /Not enough data-bearing nodes
|
138
|
+
command.execute(server, context: Mongo::Operation::Context.new(session: session))
|
139
|
+
end.to raise_error(Mongo::Error::OperationFailure, /100\b.*Not enough data-bearing nodes/)
|
140
140
|
|
141
141
|
expect(subscriber.started_events.length).to eq(1)
|
142
142
|
event = subscriber.started_events.first
|
@@ -232,6 +232,8 @@ describe 'Connections' do
|
|
232
232
|
end
|
233
233
|
|
234
234
|
describe 'wire protocol version range update' do
|
235
|
+
require_no_required_api_version
|
236
|
+
|
235
237
|
# 3.2 wire protocol is 4.
|
236
238
|
# Wire protocol < 2 means only scram auth is available,
|
237
239
|
# which is not supported by modern mongos.
|