Skip to content

Commit

Permalink
0.9.2-6 - now handling *ConnectionAbortedError* properly in hcpsdk.Co…
Browse files Browse the repository at this point in the history
…nnection() by closing and re-opening the connection on the same target IP address
  • Loading branch information
Simont3 committed Mar 9, 2015
1 parent 60bbe29 commit e00af09
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 15 deletions.
Binary file modified Documentation/HCPsdk.pdf
Binary file not shown.
8 changes: 8 additions & 0 deletions src/CHANGELOG.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
Release History
===============

**0.9.2-6 2015-03-08**

* Fixed:

now handling *ConnectionAbortedError* properly in hcpsdk.Connection()
by closing and re-opening the connection on the same target IP
address

**0.9.2-5 2015-03-07**

* Fixed:
Expand Down
45 changes: 35 additions & 10 deletions src/hcpsdk/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,11 @@ def __init__(self, target, timeout=30, idletime=30, retries=0, debuglevel=0):
"""
self.logger = logging.getLogger(__name__ + '.Connection')

# This is here to allow test cases to inject error situations.
# You need to set _fail to an exception object...
self._fail = None
#################

self.__target = target # an initialized Target object
self.__address = None # the assigned IP address to use
self.__timeout = timeout # the timeout for this Connection (secs)
Expand Down Expand Up @@ -432,6 +437,12 @@ def request(self, method, url, body=None, params=None, headers=None):
if initialretry:
self.__con = self._connect()
initialretry = False

# This is to allow a test case to inject an error situation...
if self._fail:
raise self._fail
####################

s_t = time.time()
self.__con.request(method, url, body=body, headers=headers)
self.__service_time1 = self.__service_time2 = time.time() - s_t
Expand All @@ -445,13 +456,28 @@ def request(self, method, url, body=None, params=None, headers=None):
our self again...
"""
if not initialretry:
self.logger.log(logging.DEBUG, 'Connection needs to be opened',
exc_info=True, stack_info=True)
self.logger.log(logging.DEBUG, 'Connection needs to be opened')
initialretry = True
continue
else:
raise HcpsdkError('Not connected, retry failed ({})'
.format(str(e)))
except ConnectionAbortedError as e:
"""
This is a trigger for the case that HCP aborts a connection for
whatever reason. We close the connection and try to open a new one
on the same IP.
"""
self.logger.exception('ConnectionAbortedError: {} Request for {} failed (retry)'
.format(method, url))
self._fail = None
try:
self.__con.close()
except:
self.logger.log(logging.WARNING, 'con.close() for {} failed ({})'
.format(url, e))
initialretry = True
continue
except ssl.SSLError as e:
self.logger.log(logging.DEBUG, 'ssl.SSLError: {}'.format(str(e)))
raise HcpsdkCertificateError(str(e))
Expand All @@ -467,13 +493,10 @@ def request(self, method, url, body=None, params=None, headers=None):
self.close()
raise HcpsdkTimeoutError('Timeout ({} retries) - {}'.format(retries, url))
except http.client.HTTPException as e:
self.logger.log(logging.WARNING, 'http.client.HTTPException: {}'
.format(str(e)),
exc_info=True, stack_info=True)
raise e
self.logger.exception('unexpected HTTPException')
raise HcpsdkError(str(e))
except Exception as e:
self.logger.log(logging.WARNING, 'Exception: {}'.format(str(e)),
exc_info=True, stack_info=True)
self.logger.exception('unexpected Exception')
raise HcpsdkError(str(e))
else:
try:
Expand Down Expand Up @@ -635,8 +658,10 @@ def close(self):
try:
self._cancel_idletimer()
self.__con.close()
except:
pass
except Exception as e:
self.logger.exception('Connection object close failed: IP {} ({})'
.format(self.__address, self.__target.fqdn))

self.logger.log(logging.DEBUG, 'Connection object closed: IP {} ({})'
.format(self.__address, self.__target.fqdn))

Expand Down
2 changes: 1 addition & 1 deletion src/hcpsdk/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class _Version(object):
release = 0
major = 9
minor = 2
build = 5
build = 6

fullversion = '{}.{}.{}-{}'.format(release, major, minor, build)

Expand Down
7 changes: 5 additions & 2 deletions src/tests/init_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,13 @@
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import sys
import os.path
sys.path.insert(0, os.path.abspath('..'))
import hcpsdk

# primary HCP
P_HCP = 'hcp1.snomis.local'
P_HCP = 'hcp.snomis.local'
P_ADMIN = 'admin.' + P_HCP
P_TENANT = 'm.' + P_HCP
P_NS_GOOD = 'n1.' + P_TENANT
Expand Down Expand Up @@ -60,4 +63,4 @@

R_ADMUSER = "service"
R_ADMPWD = "service01"
R_ADMAUTH = hcpsdk.NativeAuthorization(R_ADMUSER, R_ADMPWD)
R_ADMAUTH = hcpsdk.NativeAuthorization(R_ADMUSER, R_ADMPWD)
45 changes: 43 additions & 2 deletions src/tests/test_020_hcpsdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,20 @@
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

import unittest
import sys
import os.path
sys.path.insert(0, os.path.abspath('..'))
import hcpsdk
print(hcpsdk.version())
import unittest
import ssl
import http.client
from pprint import pprint

import init_tests as it


# @unittest.skip("demonstrating skipping")
class TestHcpsdk_1_Target(unittest.TestCase):

def test_1_10_ip_address_available(self):
Expand Down Expand Up @@ -265,5 +270,41 @@ def test_6_10_get(self):
self.assertEqual(self.r.status, 404)


# @unittest.skip("demonstrating skipping")
class TestHcpsdk_7_ConnectionAbortedError(unittest.TestCase):
'''
Make sure we get the proper error if an ConnectionAbortedError is raised
'''
def setUp(self):
self.T_HCPFILE = '/rest/hcpsdk/TestHCPsdk_20_access'
self.hcptarget = hcpsdk.Target(it.P_NS_GOOD, it.P_AUTH, it.P_SSLPORT, dnscache=it.P_DNSCACHE)
self.con = hcpsdk.Connection(self.hcptarget)

def tearDown(self):
self.con.close()
del self.hcptarget

def test_7_10_putput(self):
"""
Ingest a file
"""
T_BUF = '0123456789ABCDEF' * 64
r = self.con.PUT(self.T_HCPFILE, T_BUF)
self.assertEqual(r.status, 201)

self.con._fail = ConnectionAbortedError
r = self.con.HEAD(self.T_HCPFILE)
self.assertEqual(r.status, 200)

def test_7_90_delete(self):
"""
Delete a file
"""
r = self.con.DELETE(self.T_HCPFILE)
self.assertEqual(r.status, 200)




if __name__ == '__main__':
unittest.main()
unittest.main()

0 comments on commit e00af09

Please sign in to comment.