Refactor _connect to be called only once

Rather than establishing a new HTTP(S) connection for every operation
this refactors HTTP[S]Connect into RedfishConnection._connect,
and calls it only once, during __init__.
This commit is contained in:
Devananda van der Veen 2015-04-01 03:52:45 -07:00
parent 695181c8b2
commit c8df358c28
2 changed files with 49 additions and 36 deletions

View File

@ -138,19 +138,55 @@ class RedfishConnection(object):
def __init__(self, host, user_name, password,
auth_token=None, enforce_SSL=True):
"""Initialize a connection to a Redfish service."""
super(RedfishConnection, self).__init__()
self.host = host
self.user_name = user_name
self.password = password
self.auth_token = auth_token
self.enforce_SSL = enforce_SSL
# TODO: cache the token returned by this call
auth_dict = {'Password': self.password, 'UserName': self.user_name}
self.rest_post('/rest/v1/Sessions', None, json.dumps(auth_dict))
# If the http schema wasn't specified, default to HTTPS
if host[0:4] != 'http':
host = 'https://' + host
self.host = host
self._connect()
if not self.auth_token:
# TODO: cache the token returned by this call
LOG.debug('Initiating session with host %s', self.host)
auth_dict = {'Password': self.password, 'UserName': self.user_name}
self.rest_post('/rest/v1/Sessions', None, json.dumps(auth_dict))
# TODO: do some schema discovery here and cache the result
LOG.debug('Connection established to host %s.', self.host)
# self.schema = ...
LOG.info('Connection established to host %s', self.host)
def _connect(self):
LOG.debug("Establishing connection to host %s", self.host)
url = urlparse(self.host)
if url.scheme == 'https':
# New in Python 2.7.9, SSL enforcement is defaulted on.
# It can be opted-out of, which might be useful for debugging
# some things. The below case is the Opt-Out condition and
# should be used with GREAT caution.
if (sys.version_info.major == 2
and sys.version_info.minor == 7
and sys.version_info.micro >= 9
and self.enforce_SSL == False):
cont = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
cont.verify_mode = ssl.CERT_NONE
self.connection = httplib.HTTPSConnection(
host=url.netloc, strict=True, context=cont)
else:
self.connection = httplib.HTTPSConnection(
host=url.netloc, strict=True)
elif url.scheme == 'http':
self.connection = httplib.HTTPConnection(
host=url.netloc, strict=True)
else:
raise exception.RedfishException(
message='Unknown connection schema')
def _op(self, operation, suburi, request_headers=None, request_body=None):
"""
@ -178,40 +214,16 @@ class RedfishConnection(object):
self.user_name + ":" + self.password))
# TODO: add support for other types of auth
# TODO: think about redirects....
redir_count = 4
while redir_count:
conn = None
if url.scheme == 'https':
# New in Python 2.7.9, SSL enforcement is defaulted on.
# It can be opted-out of, which might be useful for debugging
# some things. The below case is the Opt-Out condition and
# should be used with GREAT caution.
if (sys.version_info.major == 2
and sys.version_info.minor == 7
and sys.version_info.micro >= 9
and self.enforce_SSL == False):
cont = ssl.SSLContext(ssl.PROTOCOL_TLSv1)
cont.verify_mode = ssl.CERT_NONE
conn = httplib.HTTPSConnection(
host=url.netloc, strict=True, context=cont)
else:
conn = httplib.HTTPSConnection(host=url.netloc,
strict=True)
elif url.scheme == 'http':
conn = httplib.HTTPConnection(host=url.netloc, strict=True)
else:
raise exception.RedfishException(
message='Unknown connection schema')
# NOTE: Do not assume every HTTP operation will return a JSON body.
# For example, ExtendedError structures are only required for
# HTTP 400 errors and are optional elsewhere as they are mostly
# redundant for many of the other HTTP status code. In particular,
# 200 OK responses should not have to return any body.
conn.request(operation, url.path, headers=request_headers,
body=json.dumps(request_body))
resp = conn.getresponse()
self.connection.request(operation, url.path,
headers=request_headers, body=json.dumps(request_body))
resp = self.connection.getresponse()
body = resp.read()
# NOTE: this makes sure the headers names are all lower case
# because HTTP says they are case insensitive
@ -228,9 +240,7 @@ class RedfishConnection(object):
response = dict()
try:
LOG.debug("BODY: %s." % body.decode('utf-8'))
response = json.loads(body.decode('utf-8'))
LOG.debug("Loaded json: %s" % response)
except ValueError: # if it doesn't decode as json
# NOTE: resources may return gzipped content, so try to decode
# as gzip (we should check the headers for Content-Encoding=gzip)

View File

@ -102,6 +102,8 @@ class TestRedfishConnection(base.TestCase):
# Headers ae lower cased when returned
self.assertIn('fake-header', res[1].keys())
self.assertIn('foo', res[2].keys())
self.con_mock.request.assert_called_with(
'GET', '/v1/test', body='null', headers=mock.ANY)
# TODO: add test for redirects
@ -113,6 +115,7 @@ class TestRedfishConnection(base.TestCase):
body = '{"fake": "body"}'
json_body = json.dumps(body)
con = connection.RedfishConnection(*get_fake_params())
res = con.rest_put('/v1/test', '', body)
self.con_mock.assert_called_with('GET', '/v1/test', {}, json_body)
res = con.rest_post('/v1/test', '', body)
self.assertEqual(200, res[0])
self.con_mock.request.assert_called_with(
'POST', '/v1/test', body=json_body, headers=mock.ANY)