Skip to content

Commit d9044b0

Browse files
Merge pull request scylladb#33 from riptano/merge_ossnext_ngdg
Merge ossnext ngdg
2 parents c9b567a + 3712803 commit d9044b0

33 files changed

+517
-887
lines changed

CHANGELOG.rst

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,22 @@ Unreleased
2929

3030
Features
3131
--------
32+
* Allow passing ssl context for Twisted (PYTHON-1161)
33+
* ssl context and cloud support for Eventlet (PYTHON-1162)
34+
* Cloud Twisted support (PYTHON-1163)
35+
* Add additional_write_policy and read_repair to system schema parsing (PYTHON-1048)
36+
* Handle prepared id mismatch when repreparing on the fly (PYTHON-1124)
37+
* Remove *read_repair_chance table options (PYTHON-1140)
38+
* Flexible version parsing (PYTHON-1174)
39+
* Support NULL in collection deserializer (PYTHON-1123)
40+
* Avoid warnings about unspecified load balancing policy when connecting to a cloud cluster (PYTHON-1177)
41+
* [GRAPH] Ability to execute Fluent Graph queries asynchronously (PYTHON-1129)
3242
3343
Bug Fixes
3444
---------
45+
* re-raising the CQLEngineException will fail on Python 3 (PYTHON-1166)
46+
* asyncio message chunks can be processed discontinuously (PYTHON-1185)
47+
* Reconnect attempts persist after downed node removed from peers (PYTHON-1181)
3548

3649
Others
3750
------
@@ -96,6 +109,22 @@ Other
96109
* Write documentation examples for DSE 2.0 features (PYTHON-732)
97110
* DSE_V1 protocol should not include all of protocol v5 (PYTHON-694)
98111

112+
3.20.2
113+
======
114+
November 19, 2019
115+
116+
Bug Fixes
117+
---------
118+
* Fix import error for old python installation without SSLContext (PYTHON-1183)
119+
120+
3.20.1
121+
======
122+
November 6, 2019
123+
124+
Bug Fixes
125+
---------
126+
* ValueError: too many values to unpack (expected 2)" when there are two dashes in server version number (PYTHON-1172)
127+
99128
3.20.0
100129
======
101130
October 28, 2019

build.yaml

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,8 @@ schedules:
4646
EXCLUDE_LONG=1
4747
matrix:
4848
exclude:
49-
- python: [2.7, 3.4, 3.6, 3.7]
50-
- cassandra: ['2.0', '2.1', '2.2', '3.0', 'test-dse']
49+
- python: [2.7, 3.4, 3.7]
50+
- cassandra: ['2.0', '2.1', '2.2', '3.0', 'test-dse', dse-4.8', 'dse-5.0']
5151

5252
release_test:
5353
schedule: per_commit
@@ -57,17 +57,17 @@ schedules:
5757
env_vars: |
5858
EVENT_LOOP_MANAGER='libev'
5959
60-
ngdg:
60+
tmpngdg:
6161
schedule: adhoc
6262
branches:
63-
include: [ngdg_master_ft]
63+
include: [merge_ossnext_ngdg]
6464
env_vars: |
6565
EVENT_LOOP_MANAGER='libev'
6666
EXCLUDE_LONG=1
6767
matrix:
6868
exclude:
6969
- python: [2.7, 3.4, 3.6, 3.7]
70-
- cassandra: ['dse-4.8', 'dse-5.0', dse-6.0', 'dse-6.7']
70+
- cassandra: ['2.1', '2.2', '3.0', '3.11', 'dse-4.8', 'dse-5.0', 'dse-5.1', 'dse-6.0', 'dse-6.7']
7171

7272
weekly_master:
7373
schedule: 0 10 * * 6
@@ -258,6 +258,7 @@ build:
258258
"tests/integration/standard/test_metrics.py"
259259
"tests/integration/standard/test_query.py"
260260
"tests/integration/simulacron/test_endpoint.py"
261+
"tests/integration/long/test_ssl.py"
261262
)
262263
EVENT_LOOP_MANAGER=$EVENT_LOOP_MANAGER CCM_ARGS="$CCM_ARGS" DSE_VERSION=$DSE_VERSION CASSANDRA_VERSION=$CCM_CASSANDRA_VERSION MAPPED_CASSANDRA_VERSION=$MAPPED_CASSANDRA_VERSION VERIFY_CYTHON=$FORCE_CYTHON nosetests -s -v --logging-format="[%(levelname)s] %(asctime)s %(thread)d: %(message)s" --with-ignore-docstrings --with-xunit --xunit-file=standard_results.xml ${EVENT_LOOP_TESTS[@]} || true
263264
exit 0

cassandra/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ def emit(self, record):
2222

2323
logging.getLogger('cassandra').addHandler(NullHandler())
2424

25-
__version_info__ = (3, 20, 0, '20191030+labs')
25+
__version_info__ = (3, 20, 2, '20191104+labs')
2626
__version__ = '.'.join(map(str, __version_info__))
2727

2828

cassandra/cluster.py

Lines changed: 34 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from __future__ import absolute_import
2020

2121
import atexit
22+
from binascii import hexlify
2223
from collections import defaultdict
2324
from concurrent.futures import ThreadPoolExecutor, FIRST_COMPLETED, wait as wait_futures
2425
from copy import copy
@@ -39,16 +40,6 @@
3940
import weakref
4041
from weakref import WeakValueDictionary
4142

42-
try:
43-
from cassandra.io.twistedreactor import TwistedConnection
44-
except ImportError:
45-
TwistedConnection = None
46-
47-
try:
48-
from weakref import WeakSet
49-
except ImportError:
50-
from cassandra.util import WeakSet # NOQA
51-
5243
from cassandra import (ConsistencyLevel, AuthenticationFailed,
5344
OperationTimedOut, UnsupportedOperation,
5445
SchemaTargetType, DriverException, ProtocolVersion,
@@ -101,6 +92,21 @@
10192
from cassandra.datastax.graph.query import _request_timeout_key, _GraphSONContextRowFactory
10293
from cassandra.datastax import cloud as dscloud
10394

95+
try:
96+
from cassandra.io.twistedreactor import TwistedConnection
97+
except ImportError:
98+
TwistedConnection = None
99+
100+
try:
101+
from cassandra.io.eventletreactor import EventletConnection
102+
except ImportError:
103+
EventletConnection = None
104+
105+
try:
106+
from weakref import WeakSet
107+
except ImportError:
108+
from cassandra.util import WeakSet # NOQA
109+
104110
if six.PY3:
105111
long = int
106112

@@ -1104,14 +1110,14 @@ def __init__(self,
11041110
self.connection_class = connection_class
11051111

11061112
if cloud is not None:
1113+
self.cloud = cloud
11071114
if contact_points is not _NOT_SET or endpoint_factory or ssl_context or ssl_options:
11081115
raise ValueError("contact_points, endpoint_factory, ssl_context, and ssl_options "
11091116
"cannot be specified with a cloud configuration")
11101117

1111-
cloud_config = dscloud.get_cloud_config(
1112-
cloud,
1113-
create_pyopenssl_context=self.connection_class is TwistedConnection
1114-
)
1118+
uses_twisted = TwistedConnection and issubclass(self.connection_class, TwistedConnection)
1119+
uses_eventlet = EventletConnection and issubclass(self.connection_class, EventletConnection)
1120+
cloud_config = dscloud.get_cloud_config(cloud, create_pyopenssl_context=uses_twisted or uses_eventlet)
11151121

11161122
ssl_context = cloud_config.ssl_context
11171123
ssl_options = {'check_hostname': True}
@@ -1241,7 +1247,7 @@ def __init__(self,
12411247
profiles.setdefault(EXEC_PROFILE_GRAPH_ANALYTICS_DEFAULT,
12421248
GraphAnalyticsExecutionProfile(load_balancing_policy=lbp))
12431249

1244-
if self._contact_points_explicit:
1250+
if self._contact_points_explicit and not self.cloud: # avoid this warning for cloud users.
12451251
if self._config_mode is _ConfigMode.PROFILES:
12461252
default_lbp_profiles = self.profile_manager._profiles_without_explicit_lbps()
12471253
if default_lbp_profiles:
@@ -2027,6 +2033,10 @@ def on_remove(self, host):
20272033
listener.on_remove(host)
20282034
self.control_connection.on_remove(host)
20292035

2036+
reconnection_handler = host.get_and_set_reconnection_handler(None)
2037+
if reconnection_handler:
2038+
reconnection_handler.cancel()
2039+
20302040
def signal_connection_failure(self, host, connection_exc, is_host_addition, expect_host_to_be_down=False):
20312041
is_down = host.signal_connection_failure(connection_exc)
20322042
if is_down:
@@ -4648,6 +4658,15 @@ def _execute_after_prepare(self, host, connection, pool, response):
46484658
if isinstance(response, ResultMessage):
46494659
if response.kind == RESULT_KIND_PREPARED:
46504660
if self.prepared_statement:
4661+
if self.prepared_statement.query_id != response.query_id:
4662+
self._set_final_exception(DriverException(
4663+
"ID mismatch while trying to reprepare (expected {expected}, got {got}). "
4664+
"This prepared statement won't work anymore. "
4665+
"This usually happens when you run a 'USE...' "
4666+
"query after the statement was prepared.".format(
4667+
expected=hexlify(self.prepared_statement.query_id), got=hexlify(response.query_id)
4668+
)
4669+
))
46514670
self.prepared_statement.result_metadata = response.column_metadata
46524671
new_metadata_id = response.result_metadata_id
46534672
if new_metadata_id is not None:

cassandra/connection.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,7 @@
2626
import sys
2727
from threading import Thread, Event, RLock, Condition
2828
import time
29-
30-
try:
31-
import ssl
32-
except ImportError:
33-
ssl = None # NOQA
29+
import ssl
3430

3531
if 'gevent.monkey' in sys.modules:
3632
from gevent.queue import Queue, Empty
@@ -772,6 +768,15 @@ def factory(cls, endpoint, timeout, *args, **kwargs):
772768
else:
773769
return conn
774770

771+
def _wrap_socket_from_context(self):
772+
self._socket = self.ssl_context.wrap_socket(self._socket, **(self.ssl_options or {}))
773+
774+
def _initiate_connection(self, sockaddr):
775+
self._socket.connect(sockaddr)
776+
777+
def _match_hostname(self):
778+
ssl.match_hostname(self._socket.getpeercert(), self.endpoint.address)
779+
775780
def _get_socket_addresses(self):
776781
address, port = self.endpoint.resolve()
777782

@@ -791,17 +796,16 @@ def _connect_socket(self):
791796
try:
792797
self._socket = self._socket_impl.socket(af, socktype, proto)
793798
if self.ssl_context:
794-
self._socket = self.ssl_context.wrap_socket(self._socket,
795-
**(self.ssl_options or {}))
799+
self._wrap_socket_from_context()
796800
elif self.ssl_options:
797801
if not self._ssl_impl:
798802
raise RuntimeError("This version of Python was not compiled with SSL support")
799803
self._socket = self._ssl_impl.wrap_socket(self._socket, **self.ssl_options)
800804
self._socket.settimeout(self.connect_timeout)
801-
self._socket.connect(sockaddr)
805+
self._initiate_connection(sockaddr)
802806
self._socket.settimeout(None)
803807
if self._check_hostname:
804-
ssl.match_hostname(self._socket.getpeercert(), self.endpoint.address)
808+
self._match_hostname()
805809
sockerr = None
806810
break
807811
except socket.error as err:

cassandra/cqlengine/management.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ def _sync_table(model, connection=None):
232232
except CQLEngineException as ex:
233233
# 1.2 doesn't return cf names, so we have to examine the exception
234234
# and ignore if it says the column family already exists
235-
if "Cannot add already existing column family" not in unicode(ex):
235+
if "Cannot add already existing column family" not in six.text_type(ex):
236236
raise
237237
else:
238238
log.debug(format_log_context("sync_table checking existing table %s", keyspace=ks_name, connection=connection), cf_name)

cassandra/cqltypes.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -813,9 +813,12 @@ def deserialize_safe(cls, byts, protocol_version):
813813
for _ in range(numelements):
814814
itemlen = unpack(byts[p:p + length])
815815
p += length
816-
item = byts[p:p + itemlen]
817-
p += itemlen
818-
result.append(subtype.from_binary(item, inner_proto))
816+
if itemlen < 0:
817+
result.append(None)
818+
else:
819+
item = byts[p:p + itemlen]
820+
p += itemlen
821+
result.append(subtype.from_binary(item, inner_proto))
819822
return cls.adapter(result)
820823

821824
@classmethod
@@ -867,14 +870,23 @@ def deserialize_safe(cls, byts, protocol_version):
867870
for _ in range(numelements):
868871
key_len = unpack(byts[p:p + length])
869872
p += length
870-
keybytes = byts[p:p + key_len]
871-
p += key_len
873+
if key_len < 0:
874+
keybytes = None
875+
key = None
876+
else:
877+
keybytes = byts[p:p + key_len]
878+
p += key_len
879+
key = key_type.from_binary(keybytes, inner_proto)
880+
872881
val_len = unpack(byts[p:p + length])
873882
p += length
874-
valbytes = byts[p:p + val_len]
875-
p += val_len
876-
key = key_type.from_binary(keybytes, inner_proto)
877-
val = value_type.from_binary(valbytes, inner_proto)
883+
if val_len < 0:
884+
val = None
885+
else:
886+
valbytes = byts[p:p + val_len]
887+
p += val_len
888+
val = value_type.from_binary(valbytes, inner_proto)
889+
878890
themap._insert_unchecked(key, keybytes, val)
879891
return themap
880892

cassandra/datastax/cloud/__init__.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
import os
1616
import logging
1717
import json
18+
import sys
1819
import tempfile
1920
import shutil
21+
import six
2022
from six.moves.urllib.request import urlopen
2123

2224
_HAS_SSL = True
@@ -135,7 +137,8 @@ def read_metadata_info(config, cloud_config):
135137
response = urlopen(url, context=config.ssl_context, timeout=timeout)
136138
except Exception as e:
137139
log.exception(e)
138-
raise DriverException("Unable to connect to the metadata service at %s" % url)
140+
raise DriverException("Unable to connect to the metadata service at %s. "
141+
"Check the cluster status in the Constellation cloud console. " % url)
139142

140143
if response.code != 200:
141144
raise DriverException(("Error while fetching the metadata at: %s. "
@@ -177,8 +180,12 @@ def _ssl_context_from_cert(ca_cert_location, cert_location, key_location):
177180
def _pyopenssl_context_from_cert(ca_cert_location, cert_location, key_location):
178181
try:
179182
from OpenSSL import SSL
180-
except ImportError:
181-
return None
183+
except ImportError as e:
184+
six.reraise(
185+
ImportError,
186+
ImportError("PyOpenSSL must be installed to connect to Apollo with the Eventlet or Twisted event loops"),
187+
sys.exc_info()[2]
188+
)
182189
ssl_context = SSL.Context(SSL.TLSv1_METHOD)
183190
ssl_context.set_verify(SSL.VERIFY_PEER, callback=lambda _1, _2, _3, _4, ok: ok)
184191
ssl_context.use_certificate_file(cert_location)

0 commit comments

Comments
 (0)