PYTHON-1418 - More spec updates
This commit is contained in:
parent
e554d6116c
commit
e42897e79e
@ -133,12 +133,14 @@ class MongoClient(common.BaseObject):
|
||||
resolved to one or more DNS `SRV records
|
||||
<https://en.wikipedia.org/wiki/SRV_record>`_ which will be used
|
||||
as the seed list for connecting to the MongoDB deployment. When using
|
||||
SRV support configuration options can be specified using `TXT records
|
||||
SRV URIs, the `authSource` and `replicaSet` configuration options can
|
||||
be specified using `TXT records
|
||||
<https://en.wikipedia.org/wiki/TXT_record>`_. See the
|
||||
`Initial DNS Seedlist Discovery spec
|
||||
<https://github.com/mongodb/specifications/blob/master/source/
|
||||
initial-dns-seedlist-discovery/initial-dns-seedlist-discovery.rst>`_
|
||||
for more details.
|
||||
for more details. Note that the use of SRV URIs implicitly enables
|
||||
TLS support. Pass ssl=false in the URI to override.
|
||||
|
||||
.. note:: MongoClient creation will block waiting for answers from
|
||||
DNS when mongodb+srv:// URIs are used.
|
||||
|
||||
@ -278,6 +278,10 @@ else:
|
||||
return text
|
||||
|
||||
|
||||
_ALLOWED_TXT_OPTS = frozenset(
|
||||
['authsource', 'authSource', 'replicaset', 'replicaSet'])
|
||||
|
||||
|
||||
def _get_dns_srv_hosts(hostname):
|
||||
try:
|
||||
results = resolver.query('_mongodb._tcp.' + hostname, 'SRV')
|
||||
@ -295,6 +299,8 @@ def _get_dns_txt_options(hostname):
|
||||
return None
|
||||
except Exception as exc:
|
||||
raise ConfigurationError(str(exc))
|
||||
if len(results) > 1:
|
||||
raise ConfigurationError('Only one TXT record is supported')
|
||||
return (
|
||||
b'&'.join([b''.join(res.strings) for res in results])).decode('utf-8')
|
||||
|
||||
@ -410,6 +416,10 @@ def parse_uri(uri, default_port=DEFAULT_PORT, validate=True, warn=False):
|
||||
dns_options = _get_dns_txt_options(fqdn)
|
||||
if dns_options:
|
||||
options = split_options(dns_options, validate, warn)
|
||||
if set(options) - _ALLOWED_TXT_OPTS:
|
||||
raise ConfigurationError(
|
||||
"Only authSource and replicaSet are supported from DNS")
|
||||
options["ssl"] = True if validate else 'true'
|
||||
else:
|
||||
nodes = split_hosts(hosts, default_port=default_port)
|
||||
|
||||
|
||||
@ -8,5 +8,9 @@
|
||||
"localhost:27018",
|
||||
"localhost:27019"
|
||||
],
|
||||
"options": {
|
||||
"replicaSet": "repl0",
|
||||
"ssl": true
|
||||
},
|
||||
"comment": "Is correct, as returned host name shared the URI root \"test.build.10gen.cc\"."
|
||||
}
|
||||
|
||||
7
test/dns/misformatted-option.json
Normal file
7
test/dns/misformatted-option.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"uri": "mongodb+srv://test8.test.build.10gen.cc/",
|
||||
"seeds": [],
|
||||
"hosts": [],
|
||||
"error": true,
|
||||
"comment": "Should fail because the options in the TXT record are incorrectly formatted (misses value)."
|
||||
}
|
||||
@ -7,5 +7,9 @@
|
||||
"localhost:27017",
|
||||
"localhost:27018",
|
||||
"localhost:27019"
|
||||
]
|
||||
],
|
||||
"options": {
|
||||
"replicaSet": "repl0",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"uri": "mongodb+srv://test11.test.build.10gen.cc/?replicaSet=repl0",
|
||||
"uri": "mongodb+srv://test11.test.build.10gen.cc/",
|
||||
"seeds": [
|
||||
"localhost.test.build.10gen.cc:27017"
|
||||
],
|
||||
@ -9,8 +9,7 @@
|
||||
"localhost:27019"
|
||||
],
|
||||
"options": {
|
||||
"connectTimeoutMS": 150000,
|
||||
"replicaSet": "repl0",
|
||||
"socketTimeoutMS": 250000
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"uri": "mongodb+srv://test5.test.build.10gen.cc/?replicaSet=repl0",
|
||||
"uri": "mongodb+srv://test5.test.build.10gen.cc/",
|
||||
"seeds": [
|
||||
"localhost.test.build.10gen.cc:27017"
|
||||
],
|
||||
@ -9,8 +9,8 @@
|
||||
"localhost:27019"
|
||||
],
|
||||
"options": {
|
||||
"connectTimeoutMS": 300000,
|
||||
"replicaSet": "repl0",
|
||||
"socketTimeoutMS": 300000
|
||||
"authSource": "thisDB",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
|
||||
7
test/dns/parent-part-mismatch5.json
Normal file
7
test/dns/parent-part-mismatch5.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"uri": "mongodb+srv://test19.test.build.10gen.cc/",
|
||||
"seeds": [],
|
||||
"hosts": [],
|
||||
"error": true,
|
||||
"comment": "Should fail because one of the returned host names' domain name parts \"evil\" mismatches \"test\"."
|
||||
}
|
||||
7
test/dns/returned-parent-wrong.json
Normal file
7
test/dns/returned-parent-wrong.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"uri": "mongodb+srv://test12.test.build.10gen.cc/",
|
||||
"seeds": [],
|
||||
"hosts": [],
|
||||
"error": true,
|
||||
"comment": "Should fail because returned host name is too short and mismatches a parent."
|
||||
}
|
||||
@ -8,5 +8,9 @@
|
||||
"localhost:27017",
|
||||
"localhost:27018",
|
||||
"localhost:27019"
|
||||
]
|
||||
],
|
||||
"options": {
|
||||
"replicaSet": "repl0",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,5 +8,9 @@
|
||||
"localhost:27017",
|
||||
"localhost:27018",
|
||||
"localhost:27019"
|
||||
]
|
||||
],
|
||||
"options": {
|
||||
"replicaSet": "repl0",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,16 +1,7 @@
|
||||
{
|
||||
"uri": "mongodb+srv://test6.test.build.10gen.cc/?replicaSet=repl0",
|
||||
"seeds": [
|
||||
"localhost.test.build.10gen.cc:27017"
|
||||
],
|
||||
"hosts": [
|
||||
"localhost:27017",
|
||||
"localhost:27018",
|
||||
"localhost:27019"
|
||||
],
|
||||
"options": {
|
||||
"connectTimeoutMS": 200000,
|
||||
"replicaSet": "repl0",
|
||||
"socketTimeoutMS": 200000
|
||||
}
|
||||
"uri": "mongodb+srv://test6.test.build.10gen.cc/",
|
||||
"seeds": [],
|
||||
"hosts": [],
|
||||
"error": true,
|
||||
"comment": "Should fail because there are two TXT records."
|
||||
}
|
||||
|
||||
@ -1,25 +0,0 @@
|
||||
{
|
||||
"uri": "mongodb+srv://test7.test.build.10gen.cc/?replicaSet=repl0&readPreferenceTags=dc:fr,item:cheese&readPreferenceTags=dc:de,item:hotdog",
|
||||
"seeds": [
|
||||
"localhost.test.build.10gen.cc:27017"
|
||||
],
|
||||
"hosts": [
|
||||
"localhost:27017",
|
||||
"localhost:27018",
|
||||
"localhost:27019"
|
||||
],
|
||||
"options": {
|
||||
"replicaSet": "repl0",
|
||||
"readPreference": "secondaryPreferred",
|
||||
"readPreferenceTags": [
|
||||
{
|
||||
"dc": "fr",
|
||||
"item": "cheese"
|
||||
},
|
||||
{
|
||||
"dc": "de",
|
||||
"item": "hotdog"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
{
|
||||
"uri": "mongodb+srv://test6.test.build.10gen.cc/?replicaSet=repl0&connectTimeoutMS=250000",
|
||||
"uri": "mongodb+srv://test5.test.build.10gen.cc/?authSource=otherDB",
|
||||
"seeds": [
|
||||
"localhost.test.build.10gen.cc:27017"
|
||||
],
|
||||
@ -9,8 +9,8 @@
|
||||
"localhost:27019"
|
||||
],
|
||||
"options": {
|
||||
"connectTimeoutMS": 250000,
|
||||
"replicaSet": "repl0",
|
||||
"socketTimeoutMS": 200000
|
||||
"authSource": "otherDB",
|
||||
"ssl": true
|
||||
}
|
||||
}
|
||||
7
test/dns/txt-record-with-unallowed-option.json
Normal file
7
test/dns/txt-record-with-unallowed-option.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"uri": "mongodb+srv://test7.test.build.10gen.cc/",
|
||||
"seeds": [],
|
||||
"hosts": [],
|
||||
"error": true,
|
||||
"comment": "Should fail because \"ssl\" is not an allowed option."
|
||||
}
|
||||
@ -1,7 +0,0 @@
|
||||
{
|
||||
"uri": "mongodb+srv://test10.test.build.10gen.cc/?replicaSet=repl0",
|
||||
"seeds": [],
|
||||
"hosts": [],
|
||||
"error": true,
|
||||
"comment": "Should fail because the value of socketTimeoutMS is not an integer."
|
||||
}
|
||||
@ -44,6 +44,7 @@ class TestDNS(unittest.TestCase):
|
||||
def create_test(test_case):
|
||||
|
||||
@client_context.require_replica_set
|
||||
@client_context.require_ssl
|
||||
def run_test(self):
|
||||
if not _HAVE_DNSPYTHON:
|
||||
raise unittest.SkipTest("DNS tests require the dnspython module")
|
||||
@ -57,8 +58,10 @@ def create_test(test_case):
|
||||
hosts = frozenset(split_hosts(','.join(hosts)))
|
||||
if options:
|
||||
for key, value in options.items():
|
||||
# Convert numbers to strings for comparison
|
||||
if isinstance(value, (int, float)):
|
||||
# Convert numbers / booleans to strings for comparison
|
||||
if isinstance(value, bool):
|
||||
options[key] = 'true' if value else 'false'
|
||||
elif isinstance(value, (int, float)):
|
||||
options[key] = str(value)
|
||||
|
||||
if seeds:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user