Merge "clean up trys in test_servers"
diff --git a/tempest/common/rest_client.py b/tempest/common/rest_client.py
index 6147aa1..d68b9ed 100644
--- a/tempest/common/rest_client.py
+++ b/tempest/common/rest_client.py
@@ -15,6 +15,7 @@
# License for the specific language governing permissions and limitations
# under the License.
+import collections
import hashlib
import httplib2
import json
@@ -60,6 +61,8 @@
'location', 'proxy-authenticate',
'retry-after', 'server',
'vary', 'www-authenticate'))
+ dscv = self.config.identity.disable_ssl_certificate_validation
+ self.http_obj = httplib2.Http(disable_ssl_certificate_validation=dscv)
def _set_auth(self):
"""
@@ -105,8 +108,6 @@
params['headers'] = {'User-Agent': 'Test-Client', 'X-Auth-User': user,
'X-Auth-Key': password}
- dscv = self.config.identity.disable_ssl_certificate_validation
- self.http_obj = httplib2.Http(disable_ssl_certificate_validation=dscv)
resp, body = self.http_obj.request(auth_url, 'GET', **params)
try:
return resp['x-auth-token'], resp['x-server-management-url']
@@ -132,8 +133,6 @@
}
}
- dscv = self.config.identity.disable_ssl_certificate_validation
- self.http_obj = httplib2.Http(disable_ssl_certificate_validation=dscv)
headers = {'Content-Type': 'application/json'}
body = json.dumps(creds)
resp, body = self.http_obj.request(auth_url, 'POST',
@@ -259,23 +258,14 @@
# Usually RFC2616 says error responses SHOULD contain an explanation.
# The warning is normal for SHOULD/SHOULD NOT case
- # Likely it will cause error
- if not body and resp.status >= 400:
+ # Likely it will cause an error
+ if not resp_body and resp.status >= 400:
self.LOG.warning("status >= 400 response with empty body")
- def request(self, method, url,
- headers=None, body=None, depth=0):
+ def _request(self, method, url,
+ headers=None, body=None):
"""A simple HTTP request interface."""
- if (self.token is None) or (self.base_url is None):
- self._set_auth()
-
- dscv = self.config.identity.disable_ssl_certificate_validation
- self.http_obj = httplib2.Http(disable_ssl_certificate_validation=dscv)
- if headers is None:
- headers = {}
- headers['X-Auth-Token'] = self.token
-
req_url = "%s/%s" % (self.base_url, url)
self._log_request(method, req_url, headers, body)
resp, resp_body = self.http_obj.request(req_url, method,
@@ -283,12 +273,37 @@
self._log_response(resp, resp_body)
self.response_checker(method, url, headers, body, resp, resp_body)
- self._error_checker(method, url, headers, body, resp, resp_body, depth)
+ return resp, resp_body
+ def request(self, method, url,
+ headers=None, body=None):
+ retry = 0
+ if (self.token is None) or (self.base_url is None):
+ self._set_auth()
+
+ if headers is None:
+ headers = {}
+ headers['X-Auth-Token'] = self.token
+
+ resp, resp_body = self._request(method, url,
+ headers=headers, body=body)
+
+ while (resp.status == 413 and
+ 'retry-after' in resp and
+ not self.is_absolute_limit(
+ resp, self._parse_resp(resp_body)) and
+ retry < MAX_RECURSION_DEPTH):
+ retry += 1
+ delay = int(resp['retry-after'])
+ time.sleep(delay)
+ resp, resp_body = self._request(method, url,
+ headers=headers, body=body)
+ self._error_checker(method, url, headers, body,
+ resp, resp_body)
return resp, resp_body
def _error_checker(self, method, url,
- headers, body, resp, resp_body, depth=0):
+ headers, body, resp, resp_body):
# NOTE(mtreinish): Check for httplib response from glance_http. The
# object can't be used here because importing httplib breaks httplib2.
@@ -340,9 +355,10 @@
if resp.status == 413:
if parse_resp:
resp_body = self._parse_resp(resp_body)
- #Checking whether Absolute/Rate limit
- return self.check_over_limit(resp_body, method, url, headers, body,
- depth)
+ if self.is_absolute_limit(resp, resp_body):
+ raise exceptions.OverLimit(resp_body)
+ else:
+ raise exceptions.RateLimitExceeded(resp_body)
if resp.status == 422:
if parse_resp:
@@ -372,34 +388,14 @@
resp_body = self._parse_resp(resp_body)
raise exceptions.RestClientException(str(resp.status))
- def check_over_limit(self, resp_body, method, url,
- headers, body, depth):
- self.is_absolute_limit(resp_body['overLimit'])
- return self.is_rate_limit_retry_max_recursion_depth(
- resp_body['overLimit'], method, url, headers,
- body, depth)
-
- def is_absolute_limit(self, resp_body):
- if 'exceeded' in resp_body['message']:
- raise exceptions.OverLimit(resp_body['message'])
- else:
- return
-
- def is_rate_limit_retry_max_recursion_depth(self, resp_body, method,
- url, headers, body, depth):
- if 'retryAfter' in resp_body:
- if depth < MAX_RECURSION_DEPTH:
- delay = resp_body['retryAfter']
- time.sleep(int(delay))
- return self.request(method, url, headers=headers,
- body=body,
- depth=depth + 1)
- else:
- raise exceptions.RateLimitExceeded(
- message=resp_body['overLimitFault']['message'],
- details=resp_body['overLimitFault']['details'])
- else:
- raise exceptions.OverLimit(resp_body['message'])
+ def is_absolute_limit(self, resp, resp_body):
+ if (not isinstance(resp_body, collections.Mapping) or
+ 'retry-after' not in resp):
+ return True
+ over_limit = resp_body.get('overLimit', None)
+ if not over_limit:
+ return True
+ return 'exceed' in over_limit.get('message', 'blabla')
def wait_for_resource_deletion(self, id):
"""Waits for a resource to be deleted."""
@@ -426,9 +422,8 @@
def _parse_resp(self, body):
return xml_to_json(etree.fromstring(body))
- def check_over_limit(self, resp_body, method, url,
- headers, body, depth):
- self.is_absolute_limit(resp_body)
- return self.is_rate_limit_retry_max_recursion_depth(
- resp_body, method, url, headers,
- body, depth)
+ def is_absolute_limit(self, resp, resp_body):
+ if (not isinstance(resp_body, collections.Mapping) or
+ 'retry-after' not in resp):
+ return True
+ return 'exceed' in resp_body.get('message', 'blabla')