Merge "Add Tempest gate job for stable/train"
diff --git a/releasenotes/notes/fix-credential-logging-98089c897d801355.yaml b/releasenotes/notes/fix-credential-logging-98089c897d801355.yaml
new file mode 100644
index 0000000..9534a72
--- /dev/null
+++ b/releasenotes/notes/fix-credential-logging-98089c897d801355.yaml
@@ -0,0 +1,9 @@
+---
+features:
+ - |
+ A new kwarg, ``log_req_body``, was added to the
+ ``tempest.lib.common.rest_client.RestClient`` method ``raw_request()``.
+ This kwarg takes in a string which will be used in place of the request
+ body, which is logged by default. The intent of this option is to be used
+ for security reasons to avoid logging sensitive information that are part
+ of request bodies.
diff --git a/releasenotes/source/index.rst b/releasenotes/source/index.rst
index 1d0d914..43c102c 100644
--- a/releasenotes/source/index.rst
+++ b/releasenotes/source/index.rst
@@ -6,6 +6,7 @@
:maxdepth: 1
unreleased
+ v22.0.0
v21.0.0
v20.0.0
v19.0.0
diff --git a/releasenotes/source/v22.0.0.rst b/releasenotes/source/v22.0.0.rst
new file mode 100644
index 0000000..519b081
--- /dev/null
+++ b/releasenotes/source/v22.0.0.rst
@@ -0,0 +1,6 @@
+=====================
+v22.0.0 Release Notes
+=====================
+
+.. release-notes:: 22.0.0 Release Notes
+ :version: 22.0.0
diff --git a/tempest/api/image/v2/test_images.py b/tempest/api/image/v2/test_images.py
index c938cee..5a27a43 100644
--- a/tempest/api/image/v2/test_images.py
+++ b/tempest/api/image/v2/test_images.py
@@ -57,6 +57,13 @@
self.assertIn('status', image)
self.assertEqual('queued', image['status'])
+ # NOTE: This Glance API returns different status codes for image
+ # condition. In this empty data case, Glance should return 204,
+ # so here should check the status code.
+ image_file = self.client.show_image_file(image['id'])
+ self.assertEqual(0, len(image_file.data))
+ self.assertEqual(204, image_file.response.status)
+
# Now try uploading an image file
file_content = data_utils.random_bytes()
image_file = six.BytesIO(file_content)
@@ -115,17 +122,6 @@
visibility='private')
self.assertEqual('queued', image['status'])
- # NOTE: This Glance API returns different status codes for image
- # condition. In this empty data case, Glance should return 204,
- # so here should check the status code.
- image_file = self.client.show_image_file(image['id'])
- self.assertEqual(0, len(image_file.data))
- self.assertEqual(204, image_file.response.status)
-
- # Now try uploading an image file
- image_file = six.BytesIO(data_utils.random_bytes())
- self.client.store_image_file(image['id'], image_file)
-
# Update Image
new_image_name = data_utils.rand_name('new-image')
self.client.update_image(image['id'], [
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 6cc0561..431a0a0 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -556,7 +556,8 @@
return resp, resp_body
- def raw_request(self, url, method, headers=None, body=None, chunked=False):
+ def raw_request(self, url, method, headers=None, body=None, chunked=False,
+ log_req_body=None):
"""Send a raw HTTP request without the keystone catalog or auth
This method sends a HTTP request in the same manner as the request()
@@ -572,6 +573,11 @@
explicitly requires no headers use an empty dict.
:param str body: Body to send with the request
:param bool chunked: sends the body with chunked encoding
+ :param str log_req_body: Whether to log the request body or not.
+ It is default to None which means request
+ body is safe to log otherwise pass any string
+ you want to log in place of request body.
+ For example: '<omitted>'
:rtype: tuple
:return: a tuple with the first entry containing the response headers
and the second the response body
@@ -585,8 +591,9 @@
url, method, headers=headers,
body=body, chunked=chunked)
end = time.time()
+ req_body = body if log_req_body is None else log_req_body
self._log_request(method, url, resp, secs=(end - start),
- req_headers=headers, req_body=body,
+ req_headers=headers, req_body=req_body,
resp_body=resp_body)
return resp, resp_body
diff --git a/tempest/lib/services/identity/v2/token_client.py b/tempest/lib/services/identity/v2/token_client.py
index 458c862..9f10f58 100644
--- a/tempest/lib/services/identity/v2/token_client.py
+++ b/tempest/lib/services/identity/v2/token_client.py
@@ -105,9 +105,8 @@
headers = self.get_headers(accept_type="json")
resp, resp_body = self.raw_request(url, method,
- headers=headers, body=body)
- self._log_request(method, url, resp, req_headers=headers,
- req_body='<omitted>', resp_body=resp_body)
+ headers=headers, body=body,
+ log_req_body='<omitted>')
if resp.status in [401, 403]:
resp_body = json.loads(resp_body)
diff --git a/tempest/lib/services/identity/v3/token_client.py b/tempest/lib/services/identity/v3/token_client.py
index d591f03..6956297 100644
--- a/tempest/lib/services/identity/v3/token_client.py
+++ b/tempest/lib/services/identity/v3/token_client.py
@@ -160,10 +160,8 @@
headers = self.get_headers(accept_type="json")
resp, resp_body = self.raw_request(url, method,
- headers=headers, body=body)
- self._log_request(method, url, resp, req_headers=headers,
- req_body='<omitted>', resp_body=resp_body)
-
+ headers=headers, body=body,
+ log_req_body='<omitted>')
if resp.status in [401, 403]:
resp_body = json.loads(resp_body)
raise exceptions.Unauthorized(resp_body['error']['message'])
diff --git a/tempest/tests/lib/fake_identity.py b/tempest/tests/lib/fake_identity.py
index 8bae34f..9d7b0fd 100644
--- a/tempest/tests/lib/fake_identity.py
+++ b/tempest/tests/lib/fake_identity.py
@@ -192,7 +192,7 @@
def _fake_v3_response(self, uri, method="GET", body=None, headers=None,
- redirections=5, connection_type=None):
+ redirections=5, connection_type=None, log_req_body=None):
fake_headers = {
"x-subject-token": TOKEN
}
@@ -202,7 +202,7 @@
def _fake_v3_response_domain_scope(self, uri, method="GET", body=None,
headers=None, redirections=5,
- connection_type=None):
+ connection_type=None, log_req_body=None):
fake_headers = {
"status": "201",
"x-subject-token": TOKEN
@@ -213,7 +213,7 @@
def _fake_v3_response_no_scope(self, uri, method="GET", body=None,
headers=None, redirections=5,
- connection_type=None):
+ connection_type=None, log_req_body=None):
fake_headers = {
"status": "201",
"x-subject-token": TOKEN
@@ -223,7 +223,7 @@
def _fake_v2_response(self, uri, method="GET", body=None, headers=None,
- redirections=5, connection_type=None):
+ redirections=5, connection_type=None, log_req_body=None):
return (fake_http.fake_http_response({}, status=200),
json.dumps(IDENTITY_V2_RESPONSE))
diff --git a/tempest/tests/lib/services/identity/v2/test_token_client.py b/tempest/tests/lib/services/identity/v2/test_token_client.py
index a592ada..5b4e210 100644
--- a/tempest/tests/lib/services/identity/v2/test_token_client.py
+++ b/tempest/tests/lib/services/identity/v2/test_token_client.py
@@ -86,6 +86,9 @@
with mock.patch.object(token_client_v2, 'raw_request') as mock_raw_r:
mock_raw_r.return_value = response, body
resp, body = token_client_v2.request('GET', 'fake_uri')
+ mock_raw_r.assert_called_once_with('fake_uri', 'GET',
+ headers=mock.ANY, body=None,
+ log_req_body='<omitted>')
self.assertIsInstance(body, dict)
def test_request_with_bytes_body(self):
diff --git a/tempest/tests/lib/services/identity/v3/test_token_client.py b/tempest/tests/lib/services/identity/v3/test_token_client.py
index a9c58df..656e10a 100644
--- a/tempest/tests/lib/services/identity/v3/test_token_client.py
+++ b/tempest/tests/lib/services/identity/v3/test_token_client.py
@@ -136,6 +136,9 @@
mock_raw_r.return_value = (
fake_identity._fake_v3_response(None, None))
resp, body = token_client_v3.request('GET', 'fake_uri')
+ mock_raw_r.assert_called_once_with('fake_uri', 'GET',
+ headers=mock.ANY, body=None,
+ log_req_body='<omitted>')
self.assertIsInstance(body, dict)