Skip to content

Commit

Permalink
SNOW-57568: Added pendulum date type binding support.
Browse files Browse the repository at this point in the history
SNOW-80673: Bump up version to 1.8.2
  • Loading branch information
sfc-gh-stakeda authored and ankit-bhatnagar167 committed Jun 3, 2019
1 parent 570142f commit 7e659f0
Show file tree
Hide file tree
Showing 11 changed files with 73 additions and 21 deletions.
4 changes: 4 additions & 0 deletions DESCRIPTION.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ Source code is also available at: https://github.com/snowflakedb/snowflake-conne
Release Notes
-------------------------------------------------------------------------------

- v1.8.2 (June 03,2019)

- Pendulum datatype support

- v1.8.1 (May 20,2019)

- Revoked OCSP Responses persists in Driver Cache + Logging Fix
Expand Down
4 changes: 2 additions & 2 deletions connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -628,8 +628,8 @@ def __open_connection(self):

if self.host.endswith(u".privatelink.snowflakecomputing.com"):
ocsp_cache_server = \
u'http://ocsp{}/ocsp_response_cache.json'.format(
self.host[self.host.index('.'):])
u'http://ocsp.{}/ocsp_response_cache.json'.format(
self.host)
if 'SF_OCSP_RESPONSE_CACHE_SERVER_URL' not in os.environ:
os.environ[
'SF_OCSP_RESPONSE_CACHE_SERVER_URL'] = ocsp_cache_server
Expand Down
5 changes: 4 additions & 1 deletion converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -534,7 +534,10 @@ def _datetime_to_snowflake(self, value):
tzinfo_value = value.tzinfo
if tzinfo_value:
if pytz.utc != tzinfo_value:
td = tzinfo_value.utcoffset(value, is_dst=False)
try:
td = tzinfo_value.utcoffset(value)
except pytz.exceptions.AmbiguousTimeError:
td = tzinfo_value.utcoffset(value, is_dst=False)
else:
td = ZERO_TIMEDELTA
sign = u'+' if td >= ZERO_TIMEDELTA else u'-'
Expand Down
4 changes: 2 additions & 2 deletions ocsp_asn1crypto.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,8 +194,8 @@ def process_ocsp_response(self, issuer, cert_id, ocsp_response):

if cur_time > ocsp_cert['tbs_certificate']['validity']['not_after'].native or \
cur_time < ocsp_cert['tbs_certificate']['validity']['not_before'].native:
debug_msg = "Certificate attached to OCSP response is invalid. OCSP response " \
"current time - {0} certificate not before time - {1} certificate " \
debug_msg = "Certificate attached to OCSP response is invalid. OCSP response "\
"current time - {0} certificate not before time - {1} certificate "\
"not after time - {2}. Consider running curl -o ocsp.der {3}".\
format(cur_time,
ocsp_cert['tbs_certificate']['validity']['not_before'].native,
Expand Down
7 changes: 2 additions & 5 deletions ocsp_pyasn1.py
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,6 @@ def is_valid_time(self, cert_id, ocsp_response):

tbs_response_data = basic_ocsp_response.getComponentByName(
'tbsResponseData')

single_response = tbs_response_data.getComponentByName('responses')[0]
cert_status = single_response.getComponentByName('certStatus')
try:
Expand Down Expand Up @@ -410,8 +409,7 @@ def process_ocsp_response(self, issuer, cert_id, ocsp_response):
logger.debug("Certificate is attached in Basic OCSP Response")
cert_der = der_encoder.encode(attached_certs[0])
cert_openssl = load_certificate(FILETYPE_ASN1, cert_der)
ocsp_cert = self._convert_openssl_to_pyasn1_certificate(
cert_openssl)
ocsp_cert = self._convert_openssl_to_pyasn1_certificate(cert_openssl)

cur_time = datetime.utcnow().replace(tzinfo=pytz.utc)
tbs_certificate = ocsp_cert.getComponentByName('tbsCertificate')
Expand Down Expand Up @@ -467,8 +465,7 @@ def process_ocsp_response(self, issuer, cert_id, ocsp_response):
"OCSP response may be malformed: {0}. ".format(cert_status)
raise RevocationCheckError(
msg=debug_msg,
errno=ER_INVALID_OCSP_RESPONSE_CODE
)
errno=ER_INVALID_OCSP_RESPONSE_CODE)
except RevocationCheckError as op_er:
if not self.debug_ocsp_failure_url:
debug_msg = op_er.msg
Expand Down
12 changes: 9 additions & 3 deletions ocsp_snowflake.py
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ def __init__(
if os.getenv("SF_OCSP_FAIL_OPEN") is not None:
# failOpen Env Variable is for internal usage/ testing only.
# Using it in production is not advised and not supported.
self.FAIL_OPEN = os.getenv("SF_OCSP_FAIL_OPEN")
self.FAIL_OPEN = os.getenv("SF_OCSP_FAIL_OPEN").lower() == 'true'
else:
self.FAIL_OPEN = use_fail_open

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

do_retry = SnowflakeOCSP.get_ocsp_retry_choice()

m = not SnowflakeOCSP.OCSP_WHITELIST.match(hostname)
if m or hostname.startswith("ocspssd"):
logger.debug(u'skipping OCSP check: %s', hostname)
Expand All @@ -902,7 +904,7 @@ def validate(self, hostname, connection, no_exception=False):
self.OCSP_CACHE_SERVER.reset_ocsp_endpoint(hostname)

cert_data = self.extract_certificate_chain(connection)
return self._validate(hostname, cert_data, no_exception=no_exception)
return self._validate(hostname, cert_data, do_retry, no_exception)

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

@staticmethod
def get_ocsp_retry_choice():
return os.getenv("SF_OCSP_DO_RETRY", "true") == "true"

def is_cert_id_in_cache(self, cert_id, subject):
"""
Is OCSP CertID in cache?
Expand Down Expand Up @@ -1021,7 +1027,7 @@ def validate_by_direct_connection(self, issuer, subject, hostname=None, do_retry
logger.debug("getting OCSP response from CA's OCSP server")
ocsp_response = self._fetch_ocsp_response(req, subject,
cert_id, telemetry_data,
hostname)
hostname, do_retry)
else:
ocsp_url = self.extract_ocsp_url(subject)
cert_id_enc = self.encode_cert_id_base64(self.decode_cert_id_key(cert_id))
Expand Down
4 changes: 3 additions & 1 deletion scripts/install.bat
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ copy parameters.py test

"%PYTHON%/python.exe" -m venv env
call env\Scripts\activate
python -m pip install --upgrade pip
# https://github.com/pypa/pip/issues/6566
python -m pip install --upgrade pip==18.1
pip install pendulum
pip install numpy
pip install pytest pytest-cov pytest-rerunfailures
pip install .
Expand Down
2 changes: 1 addition & 1 deletion scripts/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ else
fi

source ./venv/bin/activate
pip install numpy
pip install numpy pendulum
pip install pytest pytest-cov pytest-rerunfailures
if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]] || [[ $PYTHON_VERSION == "2.7"* ]]; then
pip install mock
Expand Down
39 changes: 38 additions & 1 deletion test/test_bindings.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from datetime import datetime, date, timedelta
from datetime import time as datetime_time
from decimal import Decimal

import pendulum
import pytest
import pytz

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


def test_pendulum_binding(conn_cnx, db_parameters):
pendulum_test = pendulum.now()
try:
with conn_cnx() as cnx:
cnx.cursor().execute("""
create or replace table {name} (
c1 timestamp
)
""".format(name=db_parameters['name']))
c = cnx.cursor()
fmt = "insert into {name}(c1) values(%(v1)s)".format(
name=db_parameters['name']
)
c.execute(fmt, {'v1': pendulum_test})
assert len(cnx.cursor().execute(
"select count(*) from {name}".format(
name=db_parameters['name'])).fetchall()) == 1
with conn_cnx(paramstyle=u'qmark') as cnx:
cnx.cursor().execute("""
create or replace table {name} (c1 timestamp, c2 timestamp)
""".format(name=db_parameters['name']))
with conn_cnx(paramstyle=u'qmark') as cnx:
cnx.cursor().execute("""
insert into {name} values(?, ?)
""".format(name=db_parameters['name']), (pendulum_test, pendulum_test))
ret = cnx.cursor().execute("""
select * from {name}
""".format(name=db_parameters['name'])).fetchone()
assert convert_datetime_to_epoch(
ret[0]) == convert_datetime_to_epoch(pendulum_test)
finally:
with conn_cnx() as cnx:
cnx.cursor().execute("""
drop table if exists {name}
""".format(name=db_parameters['name']))


def test_binding_with_numeric(conn_cnx, db_parameters):
"""
Paramstyle numeric tests. Both qmark and numeric leverages server side
Expand Down
11 changes: 7 additions & 4 deletions test/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -488,6 +488,8 @@ def test_privatelink(db_parameters):
connection is used.
"""
try:
os.environ['SF_OCSP_FAIL_OPEN'] = 'false'
os.environ['SF_OCSP_DO_RETRY'] = 'false'
snowflake.connector.connect(
account='testaccount',
user='testuser',
Expand All @@ -499,10 +501,9 @@ def test_privatelink(db_parameters):
except OperationalError:
ocsp_url = os.getenv('SF_OCSP_RESPONSE_CACHE_SERVER_URL')
assert ocsp_url is not None, "OCSP URL should not be None"
assert ocsp_url.endswith(
'eu-central-1.privatelink.snowflakecomputing.com'
'/ocsp_response_cache.json')
assert ocsp_url.startswith('http://ocsp')
assert ocsp_url == "http://ocsp.testaccount.eu-central-1." \
"privatelink.snowflakecomputing.com/" \
"ocsp_response_cache.json"

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

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


def test_disable_request_pooling(db_parameters):
Expand Down
2 changes: 1 addition & 1 deletion version.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Update this for the versions
# Don't change the forth version number from None
VERSION = (1, 8, 1, None)
VERSION = (1, 8, 2, None)

0 comments on commit 7e659f0

Please sign in to comment.