diff --git a/pymongo/pool.py b/pymongo/pool.py index acce1c1ec..654dbf3ab 100644 --- a/pymongo/pool.py +++ b/pymongo/pool.py @@ -616,6 +616,8 @@ class SocketInfo(object): if self.opts.load_balanced and _MOCK_SERVICE_ID: process_id = doc.get('topologyVersion', {}).get('processId') doc.setdefault('serviceId', process_id) + if not self.opts.load_balanced: + doc.pop('serviceId', None) ismaster = IsMaster(doc, awaitable=awaitable) self.is_writable = ismaster.is_writable self.max_wire_version = ismaster.max_wire_version @@ -653,6 +655,9 @@ class SocketInfo(object): unpacked_docs = reply.unpack_response() response_doc = unpacked_docs[0] helpers._check_command_response(response_doc, self.max_wire_version) + # Remove after PYTHON-2712. + if not self.opts.load_balanced: + response_doc.pop('serviceId', None) return response_doc def command(self, dbname, spec, slave_ok=False, diff --git a/pymongo/topology_description.py b/pymongo/topology_description.py index 1c5a1f456..4282c4ff3 100644 --- a/pymongo/topology_description.py +++ b/pymongo/topology_description.py @@ -361,7 +361,7 @@ def updated_topology_description(topology_description, server_description): topology_description._topology_settings) if topology_type == TOPOLOGY_TYPE.Unknown: - if server_type == SERVER_TYPE.Standalone: + if server_type in (SERVER_TYPE.Standalone, SERVER_TYPE.LoadBalancer): if len(topology_description._topology_settings.seeds) == 1: topology_type = TOPOLOGY_TYPE.Single else: diff --git a/test/test_topology.py b/test/test_topology.py index f3db8cbde..9a4bf512c 100644 --- a/test/test_topology.py +++ b/test/test_topology.py @@ -18,6 +18,8 @@ import sys sys.path[0:0] = [""] +from bson.objectid import ObjectId + from pymongo import common from pymongo.read_preferences import ReadPreference, Secondary from pymongo.server_type import SERVER_TYPE @@ -276,7 +278,7 @@ class TestMultiServerTopology(TopologyTest): 'setName': 'rs', 'hosts': ['a', 'b']}) - self.assertTrue( + self.assertEqual( t.description.topology_type_name, 'ReplicaSetWithPrimary') self.assertTrue(t.description.has_writable_server()) self.assertTrue(t.description.has_readable_server()) @@ -301,7 +303,7 @@ class TestMultiServerTopology(TopologyTest): 'setName': 'rs', 'hosts': ['a', 'b']}) - self.assertTrue( + self.assertEqual( t.description.topology_type_name, 'ReplicaSetNoPrimary') self.assertFalse(t.description.has_writable_server()) self.assertFalse(t.description.has_readable_server()) @@ -326,7 +328,7 @@ class TestMultiServerTopology(TopologyTest): 'hosts': ['a', 'b'], 'tags': {'tag': 'exists'}}) - self.assertTrue( + self.assertEqual( t.description.topology_type_name, 'ReplicaSetWithPrimary') self.assertTrue(t.description.has_writable_server()) self.assertTrue(t.description.has_readable_server()) @@ -621,6 +623,26 @@ class TestMultiServerTopology(TopologyTest): "]>" % (t._topology_id,)) + def test_unexpected_load_balancer(self): + # Note: This behavior should not be reachable in practice but we + # should handle it gracefully nonetheless. See PYTHON-2791. + # Load balancers are included in topology with a single seed. + t = create_mock_topology(seeds=['a']) + mock_lb_response = {'ok': 1, 'msg': 'isdbgrid', + 'serviceId': ObjectId(), 'maxWireVersion': 13} + got_ismaster(t, ('a', 27017), mock_lb_response) + sds = t.description.server_descriptions() + self.assertIn(('a', 27017), sds) + self.assertEqual(sds[('a', 27017)].server_type_name, 'LoadBalancer') + self.assertEqual(t.description.topology_type_name, 'Single') + self.assertTrue(t.description.has_writable_server()) + + # Load balancers are removed from a topology with multiple seeds. + t = create_mock_topology(seeds=['a', 'b']) + got_ismaster(t, ('a', 27017), mock_lb_response) + self.assertNotIn(('a', 27017), t.description.server_descriptions()) + self.assertEqual(t.description.topology_type_name, 'Unknown') + def wait_for_master(topology): """Wait for a Topology to discover a writable server.