Skip to content

Commit 7e659f0

Browse files
sfc-gh-stakedaankit-bhatnagar167
authored andcommitted
SNOW-57568: Added pendulum date type binding support.
SNOW-80673: Bump up version to 1.8.2
1 parent 570142f commit 7e659f0

File tree

11 files changed

+73
-21
lines changed

11 files changed

+73
-21
lines changed

DESCRIPTION.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ Source code is also available at: https://github.com/snowflakedb/snowflake-conne
99
Release Notes
1010
-------------------------------------------------------------------------------
1111

12+
- v1.8.2 (June 03,2019)
13+
14+
- Pendulum datatype support
15+
1216
- v1.8.1 (May 20,2019)
1317

1418
- Revoked OCSP Responses persists in Driver Cache + Logging Fix

connection.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -628,8 +628,8 @@ def __open_connection(self):
628628

629629
if self.host.endswith(u".privatelink.snowflakecomputing.com"):
630630
ocsp_cache_server = \
631-
u'http://ocsp{}/ocsp_response_cache.json'.format(
632-
self.host[self.host.index('.'):])
631+
u'http://ocsp.{}/ocsp_response_cache.json'.format(
632+
self.host)
633633
if 'SF_OCSP_RESPONSE_CACHE_SERVER_URL' not in os.environ:
634634
os.environ[
635635
'SF_OCSP_RESPONSE_CACHE_SERVER_URL'] = ocsp_cache_server

converter.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -534,7 +534,10 @@ def _datetime_to_snowflake(self, value):
534534
tzinfo_value = value.tzinfo
535535
if tzinfo_value:
536536
if pytz.utc != tzinfo_value:
537-
td = tzinfo_value.utcoffset(value, is_dst=False)
537+
try:
538+
td = tzinfo_value.utcoffset(value)
539+
except pytz.exceptions.AmbiguousTimeError:
540+
td = tzinfo_value.utcoffset(value, is_dst=False)
538541
else:
539542
td = ZERO_TIMEDELTA
540543
sign = u'+' if td >= ZERO_TIMEDELTA else u'-'

ocsp_asn1crypto.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,8 +194,8 @@ def process_ocsp_response(self, issuer, cert_id, ocsp_response):
194194

195195
if cur_time > ocsp_cert['tbs_certificate']['validity']['not_after'].native or \
196196
cur_time < ocsp_cert['tbs_certificate']['validity']['not_before'].native:
197-
debug_msg = "Certificate attached to OCSP response is invalid. OCSP response " \
198-
"current time - {0} certificate not before time - {1} certificate " \
197+
debug_msg = "Certificate attached to OCSP response is invalid. OCSP response "\
198+
"current time - {0} certificate not before time - {1} certificate "\
199199
"not after time - {2}. Consider running curl -o ocsp.der {3}".\
200200
format(cur_time,
201201
ocsp_cert['tbs_certificate']['validity']['not_before'].native,

ocsp_pyasn1.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,6 @@ def is_valid_time(self, cert_id, ocsp_response):
372372

373373
tbs_response_data = basic_ocsp_response.getComponentByName(
374374
'tbsResponseData')
375-
376375
single_response = tbs_response_data.getComponentByName('responses')[0]
377376
cert_status = single_response.getComponentByName('certStatus')
378377
try:
@@ -410,8 +409,7 @@ def process_ocsp_response(self, issuer, cert_id, ocsp_response):
410409
logger.debug("Certificate is attached in Basic OCSP Response")
411410
cert_der = der_encoder.encode(attached_certs[0])
412411
cert_openssl = load_certificate(FILETYPE_ASN1, cert_der)
413-
ocsp_cert = self._convert_openssl_to_pyasn1_certificate(
414-
cert_openssl)
412+
ocsp_cert = self._convert_openssl_to_pyasn1_certificate(cert_openssl)
415413

416414
cur_time = datetime.utcnow().replace(tzinfo=pytz.utc)
417415
tbs_certificate = ocsp_cert.getComponentByName('tbsCertificate')
@@ -467,8 +465,7 @@ def process_ocsp_response(self, issuer, cert_id, ocsp_response):
467465
"OCSP response may be malformed: {0}. ".format(cert_status)
468466
raise RevocationCheckError(
469467
msg=debug_msg,
470-
errno=ER_INVALID_OCSP_RESPONSE_CODE
471-
)
468+
errno=ER_INVALID_OCSP_RESPONSE_CODE)
472469
except RevocationCheckError as op_er:
473470
if not self.debug_ocsp_failure_url:
474471
debug_msg = op_er.msg

ocsp_snowflake.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,7 @@ def __init__(
858858
if os.getenv("SF_OCSP_FAIL_OPEN") is not None:
859859
# failOpen Env Variable is for internal usage/ testing only.
860860
# Using it in production is not advised and not supported.
861-
self.FAIL_OPEN = os.getenv("SF_OCSP_FAIL_OPEN")
861+
self.FAIL_OPEN = os.getenv("SF_OCSP_FAIL_OPEN").lower() == 'true'
862862
else:
863863
self.FAIL_OPEN = use_fail_open
864864

@@ -893,6 +893,8 @@ def validate(self, hostname, connection, no_exception=False):
893893
"""
894894
logger.debug(u'validating certificate: %s', hostname)
895895

896+
do_retry = SnowflakeOCSP.get_ocsp_retry_choice()
897+
896898
m = not SnowflakeOCSP.OCSP_WHITELIST.match(hostname)
897899
if m or hostname.startswith("ocspssd"):
898900
logger.debug(u'skipping OCSP check: %s', hostname)
@@ -902,7 +904,7 @@ def validate(self, hostname, connection, no_exception=False):
902904
self.OCSP_CACHE_SERVER.reset_ocsp_endpoint(hostname)
903905

904906
cert_data = self.extract_certificate_chain(connection)
905-
return self._validate(hostname, cert_data, no_exception=no_exception)
907+
return self._validate(hostname, cert_data, do_retry, no_exception)
906908

907909
def _validate(
908910
self, hostname, cert_data, do_retry=True, no_exception=False):
@@ -924,6 +926,10 @@ def _validate(
924926
logger.debug('ok' if not any_err else 'failed')
925927
return results
926928

929+
@staticmethod
930+
def get_ocsp_retry_choice():
931+
return os.getenv("SF_OCSP_DO_RETRY", "true") == "true"
932+
927933
def is_cert_id_in_cache(self, cert_id, subject):
928934
"""
929935
Is OCSP CertID in cache?
@@ -1021,7 +1027,7 @@ def validate_by_direct_connection(self, issuer, subject, hostname=None, do_retry
10211027
logger.debug("getting OCSP response from CA's OCSP server")
10221028
ocsp_response = self._fetch_ocsp_response(req, subject,
10231029
cert_id, telemetry_data,
1024-
hostname)
1030+
hostname, do_retry)
10251031
else:
10261032
ocsp_url = self.extract_ocsp_url(subject)
10271033
cert_id_enc = self.encode_cert_id_base64(self.decode_cert_id_key(cert_id))

scripts/install.bat

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ copy parameters.py test
44

55
"%PYTHON%/python.exe" -m venv env
66
call env\Scripts\activate
7-
python -m pip install --upgrade pip
7+
# https://github.com/pypa/pip/issues/6566
8+
python -m pip install --upgrade pip==18.1
9+
pip install pendulum
810
pip install numpy
911
pip install pytest pytest-cov pytest-rerunfailures
1012
pip install .

scripts/install.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ else
3030
fi
3131

3232
source ./venv/bin/activate
33-
pip install numpy
33+
pip install numpy pendulum
3434
pip install pytest pytest-cov pytest-rerunfailures
3535
if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]] || [[ $PYTHON_VERSION == "2.7"* ]]; then
3636
pip install mock

test/test_bindings.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
from datetime import datetime, date, timedelta
2626
from datetime import time as datetime_time
2727
from decimal import Decimal
28-
28+
import pendulum
2929
import pytest
3030
import pytz
3131

@@ -184,6 +184,43 @@ def test_binding(conn_cnx, db_parameters):
184184
""".format(name=db_parameters['name']))
185185

186186

187+
def test_pendulum_binding(conn_cnx, db_parameters):
188+
pendulum_test = pendulum.now()
189+
try:
190+
with conn_cnx() as cnx:
191+
cnx.cursor().execute("""
192+
create or replace table {name} (
193+
c1 timestamp
194+
)
195+
""".format(name=db_parameters['name']))
196+
c = cnx.cursor()
197+
fmt = "insert into {name}(c1) values(%(v1)s)".format(
198+
name=db_parameters['name']
199+
)
200+
c.execute(fmt, {'v1': pendulum_test})
201+
assert len(cnx.cursor().execute(
202+
"select count(*) from {name}".format(
203+
name=db_parameters['name'])).fetchall()) == 1
204+
with conn_cnx(paramstyle=u'qmark') as cnx:
205+
cnx.cursor().execute("""
206+
create or replace table {name} (c1 timestamp, c2 timestamp)
207+
""".format(name=db_parameters['name']))
208+
with conn_cnx(paramstyle=u'qmark') as cnx:
209+
cnx.cursor().execute("""
210+
insert into {name} values(?, ?)
211+
""".format(name=db_parameters['name']), (pendulum_test, pendulum_test))
212+
ret = cnx.cursor().execute("""
213+
select * from {name}
214+
""".format(name=db_parameters['name'])).fetchone()
215+
assert convert_datetime_to_epoch(
216+
ret[0]) == convert_datetime_to_epoch(pendulum_test)
217+
finally:
218+
with conn_cnx() as cnx:
219+
cnx.cursor().execute("""
220+
drop table if exists {name}
221+
""".format(name=db_parameters['name']))
222+
223+
187224
def test_binding_with_numeric(conn_cnx, db_parameters):
188225
"""
189226
Paramstyle numeric tests. Both qmark and numeric leverages server side

test/test_connection.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@ def test_privatelink(db_parameters):
488488
connection is used.
489489
"""
490490
try:
491+
os.environ['SF_OCSP_FAIL_OPEN'] = 'false'
492+
os.environ['SF_OCSP_DO_RETRY'] = 'false'
491493
snowflake.connector.connect(
492494
account='testaccount',
493495
user='testuser',
@@ -499,10 +501,9 @@ def test_privatelink(db_parameters):
499501
except OperationalError:
500502
ocsp_url = os.getenv('SF_OCSP_RESPONSE_CACHE_SERVER_URL')
501503
assert ocsp_url is not None, "OCSP URL should not be None"
502-
assert ocsp_url.endswith(
503-
'eu-central-1.privatelink.snowflakecomputing.com'
504-
'/ocsp_response_cache.json')
505-
assert ocsp_url.startswith('http://ocsp')
504+
assert ocsp_url == "http://ocsp.testaccount.eu-central-1." \
505+
"privatelink.snowflakecomputing.com/" \
506+
"ocsp_response_cache.json"
506507

507508
cnx = snowflake.connector.connect(
508509
user=db_parameters['user'],
@@ -518,6 +519,8 @@ def test_privatelink(db_parameters):
518519

519520
ocsp_url = os.getenv('SF_OCSP_RESPONSE_CACHE_SERVER_URL')
520521
assert ocsp_url is None, "OCSP URL should be None: {0}".format(ocsp_url)
522+
del os.environ['SF_OCSP_DO_RETRY']
523+
del os.environ['SF_OCSP_FAIL_OPEN']
521524

522525

523526
def test_disable_request_pooling(db_parameters):

0 commit comments

Comments
 (0)