Merge "Requests session keyword arguments for sushy connector"
This commit is contained in:
commit
6e2d337a9b
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
features:
|
||||
- |
|
||||
Adds functionality to pass different requests library session
|
||||
arguments to sushy connector.
|
|
@ -13,7 +13,6 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import json
|
||||
import logging
|
||||
|
||||
import requests
|
||||
|
@ -55,7 +54,8 @@ class Connector(object):
|
|||
"""Close this connector and the associated HTTP session."""
|
||||
self._session.close()
|
||||
|
||||
def _op(self, method, path='', data=None, headers=None):
|
||||
def _op(self, method, path='', data=None, headers=None,
|
||||
**extra_session_req_kwargs):
|
||||
"""Generic RESTful request handler.
|
||||
|
||||
:param method: The HTTP method to be used, e.g: GET, POST,
|
||||
|
@ -63,29 +63,24 @@ class Connector(object):
|
|||
:param path: The sub-URI path to the resource.
|
||||
:param data: Optional JSON data.
|
||||
:param headers: Optional dictionary of headers.
|
||||
:param extra_session_req_kwargs: Optional keyword argument to pass
|
||||
requests library arguments which would pass on to requests session
|
||||
object.
|
||||
:returns: The response object from the requests library.
|
||||
:raises: ConnectionError
|
||||
:raises: HTTPError
|
||||
"""
|
||||
json_data = None
|
||||
if headers is None:
|
||||
headers = {}
|
||||
|
||||
if data is not None:
|
||||
json_data = json.dumps(data)
|
||||
headers['Content-Type'] = 'application/json'
|
||||
|
||||
url = parse.urljoin(self._url, path)
|
||||
# TODO(lucasagomes): We should mask the data to remove sensitive
|
||||
# information
|
||||
LOG.debug('HTTP request: %(method)s %(url)s; '
|
||||
'headers: %(headers)s; body: %(data)s',
|
||||
LOG.debug('HTTP request: %(method)s %(url)s; headers: %(headers)s; '
|
||||
'body: %(data)s; session arguments: %(session)s;',
|
||||
{'method': method, 'url': url, 'headers': headers,
|
||||
'data': json_data})
|
||||
'data': data, 'session': extra_session_req_kwargs})
|
||||
try:
|
||||
response = self._session.request(method, url,
|
||||
data=json_data,
|
||||
headers=headers)
|
||||
response = self._session.request(method, url, json=data,
|
||||
headers=headers,
|
||||
**extra_session_req_kwargs)
|
||||
except requests.ConnectionError as e:
|
||||
raise exceptions.ConnectionError(url=url, error=e)
|
||||
# If we received an AccessError, and we
|
||||
|
@ -99,9 +94,9 @@ class Connector(object):
|
|||
self._auth.refresh_session()
|
||||
LOG.debug("Authentication refreshed successfully, "
|
||||
"retrying the call.")
|
||||
response = self._session.request(method, url,
|
||||
data=json_data,
|
||||
headers=headers)
|
||||
response = self._session.request(method, url, json=data,
|
||||
headers=headers,
|
||||
**extra_session_req_kwargs)
|
||||
else:
|
||||
raise
|
||||
|
||||
|
@ -112,65 +107,90 @@ class Connector(object):
|
|||
|
||||
return response
|
||||
|
||||
def get(self, path='', data=None, headers=None):
|
||||
def get(self, path='', data=None, headers=None,
|
||||
**extra_session_req_kwargs):
|
||||
"""HTTP GET method.
|
||||
|
||||
:param path: Optional sub-URI path to the resource.
|
||||
:param data: Optional JSON data.
|
||||
:param headers: Optional dictionary of headers.
|
||||
:param extra_session_req_kwargs: Optional keyword argument to pass
|
||||
requests library arguments which would pass on to requests session
|
||||
object.
|
||||
:returns: The response object from the requests library.
|
||||
:raises: ConnectionError
|
||||
:raises: HTTPError
|
||||
"""
|
||||
return self._op('GET', path, data, headers)
|
||||
return self._op('GET', path, data=data, headers=headers,
|
||||
**extra_session_req_kwargs)
|
||||
|
||||
def post(self, path='', data=None, headers=None):
|
||||
def post(self, path='', data=None, headers=None,
|
||||
**extra_session_req_kwargs):
|
||||
"""HTTP POST method.
|
||||
|
||||
:param path: Optional sub-URI path to the resource.
|
||||
:param data: Optional JSON data.
|
||||
:param headers: Optional dictionary of headers.
|
||||
:param extra_session_req_kwargs: Optional keyword argument to pass
|
||||
requests library arguments which would pass on to requests session
|
||||
object.
|
||||
:returns: The response object from the requests library.
|
||||
:raises: ConnectionError
|
||||
:raises: HTTPError
|
||||
"""
|
||||
return self._op('POST', path, data, headers)
|
||||
return self._op('POST', path, data=data, headers=headers,
|
||||
**extra_session_req_kwargs)
|
||||
|
||||
def patch(self, path='', data=None, headers=None):
|
||||
def patch(self, path='', data=None, headers=None,
|
||||
**extra_session_req_kwargs):
|
||||
"""HTTP PATCH method.
|
||||
|
||||
:param path: Optional sub-URI path to the resource.
|
||||
:param data: Optional JSON data.
|
||||
:param headers: Optional dictionary of headers.
|
||||
:param extra_session_req_kwargs: Optional keyword argument to pass
|
||||
requests library arguments which would pass on to requests session
|
||||
object.
|
||||
:returns: The response object from the requests library.
|
||||
:raises: ConnectionError
|
||||
:raises: HTTPError
|
||||
"""
|
||||
return self._op('PATCH', path, data, headers)
|
||||
return self._op('PATCH', path, data=data, headers=headers,
|
||||
**extra_session_req_kwargs)
|
||||
|
||||
def put(self, path='', data=None, headers=None):
|
||||
def put(self, path='', data=None, headers=None,
|
||||
**extra_session_req_kwargs):
|
||||
"""HTTP PUT method.
|
||||
|
||||
:param path: Optional sub-URI path to the resource.
|
||||
:param data: Optional JSON data.
|
||||
:param headers: Optional dictionary of headers.
|
||||
:param extra_session_req_kwargs: Optional keyword argument to pass
|
||||
requests library arguments which would pass on to requests session
|
||||
object.
|
||||
:returns: The response object from the requests library.
|
||||
:raises: ConnectionError
|
||||
:raises: HTTPError
|
||||
"""
|
||||
return self._op('PUT', path, data, headers)
|
||||
return self._op('PUT', path, data=data, headers=headers,
|
||||
**extra_session_req_kwargs)
|
||||
|
||||
def delete(self, path='', data=None, headers=None):
|
||||
def delete(self, path='', data=None, headers=None,
|
||||
**extra_session_req_kwargs):
|
||||
"""HTTP DELETE method.
|
||||
|
||||
:param path: Optional sub-URI path to the resource.
|
||||
:param data: Optional JSON data.
|
||||
:param headers: Optional dictionary of headers.
|
||||
:param extra_session_req_kwargs: Optional keyword argument to pass
|
||||
requests library arguments which would pass on to requests session
|
||||
object.
|
||||
:returns: The response object from the requests library.
|
||||
:raises: ConnectionError
|
||||
:raises: HTTPError
|
||||
"""
|
||||
return self._op('DELETE', path, data, headers)
|
||||
return self._op('DELETE', path, data=data, headers=headers,
|
||||
**extra_session_req_kwargs)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
|
|
@ -48,35 +48,35 @@ class ConnectorMethodsTestCase(base.TestCase):
|
|||
self.conn.get(path='fake/path', data=self.data.copy(),
|
||||
headers=self.headers.copy())
|
||||
mock__op.assert_called_once_with(mock.ANY, 'GET', 'fake/path',
|
||||
self.data, self.headers)
|
||||
data=self.data, headers=self.headers)
|
||||
|
||||
@mock.patch.object(connector.Connector, '_op', autospec=True)
|
||||
def test_post(self, mock__op):
|
||||
self.conn.post(path='fake/path', data=self.data.copy(),
|
||||
headers=self.headers.copy())
|
||||
mock__op.assert_called_once_with(mock.ANY, 'POST', 'fake/path',
|
||||
self.data, self.headers)
|
||||
data=self.data, headers=self.headers)
|
||||
|
||||
@mock.patch.object(connector.Connector, '_op', autospec=True)
|
||||
def test_patch(self, mock__op):
|
||||
self.conn.patch(path='fake/path', data=self.data.copy(),
|
||||
headers=self.headers.copy())
|
||||
mock__op.assert_called_once_with(mock.ANY, 'PATCH', 'fake/path',
|
||||
self.data, self.headers)
|
||||
data=self.data, headers=self.headers)
|
||||
|
||||
@mock.patch.object(connector.Connector, '_op', autospec=True)
|
||||
def test_put(self, mock__op):
|
||||
self.conn.put(path='fake/path', data=self.data.copy(),
|
||||
headers=self.headers.copy())
|
||||
mock__op.assert_called_once_with(mock.ANY, 'PUT', 'fake/path',
|
||||
self.data, self.headers)
|
||||
data=self.data, headers=self.headers)
|
||||
|
||||
@mock.patch.object(connector.Connector, '_op', autospec=True)
|
||||
def test_delete(self, mock__op):
|
||||
self.conn.delete(path='fake/path', data=self.data.copy(),
|
||||
headers=self.headers.copy())
|
||||
mock__op.assert_called_once_with(mock.ANY, 'DELETE', 'fake/path',
|
||||
self.data, self.headers)
|
||||
data=self.data, headers=self.headers)
|
||||
|
||||
def test_set_auth(self):
|
||||
mock_auth = mock.MagicMock()
|
||||
|
@ -119,59 +119,52 @@ class ConnectorOpTestCase(base.TestCase):
|
|||
self.request.return_value.status_code = http_client.OK
|
||||
|
||||
def test_ok_get(self):
|
||||
expected_headers = self.headers.copy()
|
||||
|
||||
self.conn._op('GET', path='fake/path', headers=self.headers)
|
||||
self.request.assert_called_once_with(
|
||||
'GET', 'http://foo.bar:1234/fake/path',
|
||||
data=None, headers=expected_headers)
|
||||
headers=self.headers, json=None)
|
||||
|
||||
def test_ok_get_url_redirect_false(self):
|
||||
self.conn._op('GET', path='fake/path', headers=self.headers,
|
||||
allow_redirects=False)
|
||||
self.request.assert_called_once_with(
|
||||
'GET', 'http://foo.bar:1234/fake/path',
|
||||
headers=self.headers, json=None, allow_redirects=False)
|
||||
|
||||
def test_ok_post(self):
|
||||
expected_headers = self.headers.copy()
|
||||
expected_headers['Content-Type'] = 'application/json'
|
||||
|
||||
self.conn._op('POST', path='fake/path', data=self.data.copy(),
|
||||
headers=self.headers)
|
||||
self.request.assert_called_once_with(
|
||||
'POST', 'http://foo.bar:1234/fake/path',
|
||||
data=json.dumps(self.data), headers=expected_headers)
|
||||
json=self.data, headers=self.headers)
|
||||
|
||||
def test_ok_put(self):
|
||||
expected_headers = self.headers.copy()
|
||||
expected_headers['Content-Type'] = 'application/json'
|
||||
|
||||
self.conn._op('PUT', path='fake/path', data=self.data.copy(),
|
||||
headers=self.headers)
|
||||
self.request.assert_called_once_with(
|
||||
'PUT', 'http://foo.bar:1234/fake/path',
|
||||
data=json.dumps(self.data), headers=expected_headers)
|
||||
json=self.data, headers=self.headers)
|
||||
|
||||
def test_ok_delete(self):
|
||||
expected_headers = self.headers.copy()
|
||||
|
||||
self.conn._op('DELETE', path='fake/path', headers=self.headers.copy())
|
||||
self.request.assert_called_once_with(
|
||||
'DELETE', 'http://foo.bar:1234/fake/path',
|
||||
data=None, headers=expected_headers)
|
||||
headers=self.headers, json=None)
|
||||
|
||||
def test_ok_post_with_session(self):
|
||||
self.conn._session.headers = {}
|
||||
self.conn._session.headers['X-Auth-Token'] = 'asdf1234'
|
||||
expected_headers = self.headers.copy()
|
||||
expected_headers['Content-Type'] = 'application/json'
|
||||
|
||||
self.conn._op('POST', path='fake/path', data=self.data,
|
||||
headers=self.headers)
|
||||
self.conn._op('POST', path='fake/path', headers=self.headers,
|
||||
data=self.data)
|
||||
self.request.assert_called_once_with(
|
||||
'POST', 'http://foo.bar:1234/fake/path',
|
||||
data=json.dumps(self.data), headers=expected_headers)
|
||||
json=self.data, headers=expected_headers)
|
||||
self.assertEqual(self.conn._session.headers,
|
||||
{'X-Auth-Token': 'asdf1234'})
|
||||
|
||||
def test_timed_out_session_unable_to_create_session(self):
|
||||
self.conn._auth.can_refresh_session.return_value = False
|
||||
expected_headers = self.headers.copy()
|
||||
expected_headers['Content-Type'] = 'application/json'
|
||||
self.conn._session = self.session
|
||||
self.request = self.session.request
|
||||
self.request.return_value.status_code = http_client.FORBIDDEN
|
||||
|
@ -190,8 +183,6 @@ class ConnectorOpTestCase(base.TestCase):
|
|||
self.session = mock.Mock(spec=requests.Session)
|
||||
self.conn._session = self.session
|
||||
self.request = self.session.request
|
||||
first_expected_headers = self.headers.copy()
|
||||
first_expected_headers['Content-Type'] = 'application/json'
|
||||
first_response = mock.Mock()
|
||||
first_response.status_code = http_client.FORBIDDEN
|
||||
second_response = mock.Mock()
|
||||
|
|
Loading…
Reference in New Issue