Skip to content
This repository has been archived by the owner on Oct 15, 2020. It is now read-only.

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add connection timeout
Browse files Browse the repository at this point in the history
We've had situations where we've hit against a system time-out when
connecting to OneView.  That timeout was over 2 minutes long.  To avoid
this we've added a timeout field to the config json, and if present the
value is used as a timeout in http.client.HTTPSConnection.
eamonnotoole committed Dec 18, 2017
1 parent c47cb42 commit 8a91a71
Showing 6 changed files with 77 additions and 12 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 4.4.1 (Unreleased)
#### Notes
Added the capability to set a connection timeout when connecting to the HPE OneView Appliance


# 4.4.0
#### Notes
Enabled usage of a CA Certificate file for establishing a SSL connection to the HPE OneView Appliance.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -98,6 +98,7 @@ export ONEVIEWSDK_API_VERSION='300'
export ONEVIEWSDK_AUTH_LOGIN_DOMAIN='authdomain'
export ONEVIEWSDK_SSL_CERTIFICATE='<path_to_cert.crt_file>'
export ONEVIEWSDK_PROXY='<proxy_host>:<proxy_port>'
export ONEVIEWSDK_CONNECTION_TIMEOUT='<connection time-out in seconds>'
```

:lock: Tip: Make sure no unauthorized person has access to the environment variables, since the password is stored in clear-text.
@@ -244,6 +245,20 @@ build_plans = image_streamer_client.build_plans.get_all()

You can find more usage examples in the folder ```/examples/image_streamer```

### OneView Connection Timeout
By default the system timeout is used when connecting to OneView. If you want to change this,
then the timeout can be set by either:

1. Setting the appropriate environment variable:
```bash
export ONEVIEWSDK_CONNECTION_TIMEOUT='<connection time-out in seconds>'
```

2. Setting the time-out in the JSON configuration file using the following syntax:
```json
"timeout": <timeout in seconds>
```

## Exception handling

All exceptions raised by the OneView Python SDK inherit from HPOneViewException.
21 changes: 16 additions & 5 deletions hpOneView/connection.py
Original file line number Diff line number Diff line change
@@ -54,7 +54,7 @@


class connection(object):
def __init__(self, applianceIp, api_version=300, sslBundle=False):
def __init__(self, applianceIp, api_version=300, sslBundle=False, timeout=None):
self._session = None
self._host = applianceIp
self._cred = None
@@ -74,6 +74,7 @@ def __init__(self, applianceIp, api_version=300, sslBundle=False):
self._numTotalRecords = 0
self._numDisplayedRecords = 0
self._validateVersion = False
self._timeout = timeout

def validateVersion(self):
version = self.get(uri['version'])
@@ -148,6 +149,9 @@ def do_http(self, method, path, body, custom_headers=None):
conn.close()
time.sleep(1)
continue
except http.client.HTTPException:
raise HPOneViewException('Failure during login attempt.\n %s' % traceback.format_exc())

return resp, body

def download_to_stream(self, stream_writer, url, body='', method='GET', custom_headers=None):
@@ -182,6 +186,8 @@ def download_to_stream(self, stream_writer, url, body='', method='GET', custom_h
conn.close()
time.sleep(1)
continue
except http.client.HTTPException as e:
raise HPOneViewException(str(e))

return successful_connected

@@ -209,22 +215,27 @@ def get_connection(self):
context.load_verify_locations(self._sslTrustedBundle)
if self._doProxy is False:
conn = http.client.HTTPSConnection(self._host,
context=context)
context=context,
timeout=self._timeout)
else:
conn = http.client.HTTPSConnection(self._proxyHost,
self._proxyPort,
context=context)
context=context,
timeout=self._timeout)
conn.set_tunnel(self._host, 443)
else:
context.verify_mode = ssl.CERT_NONE
if self._doProxy is False:
conn = http.client.HTTPSConnection(self._host,
context=context)
context=context,
timeout=self._timeout)
else:
conn = http.client.HTTPSConnection(self._proxyHost,
self._proxyPort,
context=context)
context=context,
timeout=self._timeout)
conn.set_tunnel(self._host, 443)

return conn

def _open(self, name, mode):
10 changes: 6 additions & 4 deletions hpOneView/oneview_client.py
Original file line number Diff line number Diff line change
@@ -116,7 +116,8 @@ class OneViewClient(object):
DEFAULT_API_VERSION = 300

def __init__(self, config):
self.__connection = connection(config["ip"], config.get('api_version', self.DEFAULT_API_VERSION), config.get('ssl_certificate', False))
self.__connection = connection(config["ip"], config.get('api_version', self.DEFAULT_API_VERSION), config.get('ssl_certificate', False),
config.get('timeout'))
self.__image_streamer_ip = config.get("image_streamer_ip")
self.__set_proxy(config)
self.__connection.login(config["credentials"])
@@ -216,8 +217,8 @@ def from_environment_variables(cls):
Construct OneViewClient using environment variables.
Allowed variables: ONEVIEWSDK_IP (required), ONEVIEWSDK_USERNAME (required), ONEVIEWSDK_PASSWORD (required),
ONEVIEWSDK_AUTH_LOGIN_DOMAIN, ONEVIEWSDK_API_VERSION, ONEVIEWSDK_IMAGE_STREAMER_IP, ONEVIEWSDK_SESSIONID, ONEVIEWSDK_SSL_CERTIFICATE
and ONEVIEWSDK_PROXY.
ONEVIEWSDK_AUTH_LOGIN_DOMAIN, ONEVIEWSDK_API_VERSION, ONEVIEWSDK_IMAGE_STREAMER_IP, ONEVIEWSDK_SESSIONID, ONEVIEWSDK_SSL_CERTIFICATE,
ONEVIEWSDK_CONNECTION_TIMEOUT and ONEVIEWSDK_PROXY.
Returns:
OneViewClient:
@@ -231,13 +232,14 @@ def from_environment_variables(cls):
password = os.environ.get('ONEVIEWSDK_PASSWORD', '')
proxy = os.environ.get('ONEVIEWSDK_PROXY', '')
sessionID = os.environ.get('ONEVIEWSDK_SESSIONID', '')
timeout = os.environ.get('ONEVIEWSDK_CONNECTION_TIMEOUT')

config = dict(ip=ip,
image_streamer_ip=image_streamer_ip,
api_version=api_version,
ssl_certificate=ssl_certificate,
credentials=dict(userName=username, authLoginDomain=auth_login_domain, password=password, sessionID=sessionID),
proxy=proxy)
proxy=proxy, timeout=timeout)

return cls(config)

28 changes: 27 additions & 1 deletion tests/unit/test_connection.py
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@
import os.path

from mock import patch, call, Mock, ANY
from http.client import HTTPSConnection, BadStatusLine
from http.client import HTTPSConnection, BadStatusLine, HTTPException
from hpOneView.connection import connection
from hpOneView.exceptions import HPOneViewException

@@ -604,6 +604,20 @@ def test_download_to_stream_when_error_status_with_empty_body(self, mock_get_con
else:
self.fail()

@patch.object(connection, 'get_connection')
def test_download_to_stream_with_timeout_error(self, mock_get_connection):

mock_conn = mock_get_connection.return_value = Mock()
mock_response = Mock()
mock_conn.getresponse.side_effect = [HTTPException('timed out'), mock_response]

mock_stream = Mock()

with self.assertRaises(HPOneViewException) as context:
resp, body = self.connection.download_to_stream(mock_stream, '/rest/download.zip')

self.assertTrue('timed out' in context.exception.msg)

@patch.object(mmap, 'mmap')
@patch.object(shutil, 'copyfileobj')
@patch.object(os.path, 'getsize')
@@ -858,6 +872,18 @@ def test_do_http_with_bad_status_line(self, mock_get_connection):

mock_conn.close.assert_has_calls([call(), call()])

@patch.object(connection, 'get_connection')
def test_do_http_with_timeout_error(self, mock_get_connection):

mock_conn = mock_get_connection.return_value = Mock()
mock_response = Mock()
mock_conn.getresponse.side_effect = [HTTPException('timed out'), mock_response]

with self.assertRaises(HPOneViewException) as context:
resp, body = self.connection.do_http('POST', '/rest/test', 'body')

self.assertTrue('timed out' in context.exception.msg)

@patch.object(connection, 'get')
@patch.object(connection, 'post')
def test_login(self, mock_post, mock_get):
10 changes: 8 additions & 2 deletions tests/unit/test_oneview_client.py
Original file line number Diff line number Diff line change
@@ -99,7 +99,8 @@
'ONEVIEWSDK_PASSWORD': 'secret123',
'ONEVIEWSDK_API_VERSION': '201',
'ONEVIEWSDK_AUTH_LOGIN_DOMAIN': 'authdomain',
'ONEVIEWSDK_PROXY': '172.16.100.195:9999'
'ONEVIEWSDK_PROXY': '172.16.100.195:9999',
'ONEVIEWSDK_CONNECTION_TIMEOUT': '20'
}

OS_ENVIRON_CONFIG_FULL_WITH_SESSIONID = {
@@ -109,7 +110,9 @@
'ONEVIEWSDK_PASSWORD': 'secret123',
'ONEVIEWSDK_SESSIONID': '123',
'ONEVIEWSDK_API_VERSION': '201',
'ONEVIEWSDK_PROXY': '172.16.100.195:9999'
'ONEVIEWSDK_PROXY': '172.16.100.195:9999',
'ONEVIEWSDK_CONNECTION_TIMEOUT': '20'

}


@@ -296,6 +299,7 @@ def test_from_environment_variables_is_passing_right_arguments_to_the_constructo
OneViewClient.from_environment_variables()
mock_cls.assert_called_once_with({'api_version': 201,
'proxy': '172.16.100.195:9999',
'timeout': '20',
'ip': '172.16.100.199',
'ssl_certificate': '',
'image_streamer_ip': '172.172.172.172',
@@ -312,6 +316,7 @@ def test_from_environment_variables_is_passing_right_arguments_to_the_constructo
OneViewClient.from_environment_variables()
mock_cls.assert_called_once_with({'api_version': 201,
'proxy': '172.16.100.195:9999',
'timeout': '20',
'ip': '172.16.100.199',
'image_streamer_ip': '172.172.172.172',
'ssl_certificate': '',
@@ -328,6 +333,7 @@ def test_from_environment_variables_is_passing_right_arguments_to_the_constructo
OneViewClient.from_environment_variables()
mock_cls.assert_called_once_with({'api_version': 300,
'proxy': '',
'timeout': None,
'ip': '172.16.100.199',
'image_streamer_ip': '',
'ssl_certificate': '',

0 comments on commit 8a91a71

Please sign in to comment.