Merge "Disable smoke test test_upload_too_many_objects" into mcp/ussuri
diff --git a/tempest/api/image/v2/admin/test_images.py b/tempest/api/image/v2/admin/test_images.py
index dbb8c58..9618591 100644
--- a/tempest/api/image/v2/admin/test_images.py
+++ b/tempest/api/image/v2/admin/test_images.py
@@ -12,10 +12,15 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
+import time
from tempest.api.image import base
+from tempest import config
from tempest.lib.common.utils import data_utils
from tempest.lib import decorators
+from tempest.lib import exceptions as lib_exc
+
+CONF = config.CONF
class BasicOperationsImagesAdminTest(base.BaseV2ImageAdminTest):
@@ -49,3 +54,45 @@
self.assertEqual(random_id_2, updated_image_info['owner'])
self.assertNotEqual(created_image_info['owner'],
updated_image_info['owner'])
+
+
+class ImageWebUploadAdminTest(base.BaseV2ImageAdminTest):
+ @classmethod
+ def skip_checks(cls):
+ super(ImageWebUploadAdminTest, cls).skip_checks()
+ enabled_methods = CONF.image_feature_enabled.enabled_import_methods
+ if "web-download" not in enabled_methods:
+ raise cls.skipException(
+ "Glance image upload via url feature disabled")
+
+ @decorators.idempotent_id('5b2ce43c-924c-4bae-bac0-f5d6ed69d72e')
+ def test_image_upload_via_url(self):
+ # Create image
+ image_name = data_utils.rand_name("image")
+ container_format = CONF.image.container_formats[0]
+ disk_format = CONF.image.disk_formats[0]
+ image = self.create_image(name=image_name,
+ container_format=container_format,
+ disk_format=disk_format,
+ visibility='private')
+ self.assertEqual('queued', image['status'])
+
+ # Upload image via url
+ image_uri = CONF.image.http_image
+ method = {"name": "web-download", "uri": image_uri}
+ self.admin_client.import_image(image_id=image["id"], method=method)
+
+ timeout = CONF.image.build_timeout
+ interval = CONF.image.build_interval
+
+ start_time = int(time.time())
+ while True:
+ body = self.admin_client.show_image(image['id'])
+ if body["status"] == "active":
+ break
+ if int(time.time()) - start_time >= timeout:
+ message = ('Image %(id)s failed to become active within '
+ 'the required time (%(timeout)s s).' %
+ {'id': image['id'], 'timeout': timeout})
+ raise lib_exc.TimeoutException(message)
+ time.sleep(interval)
diff --git a/tempest/config.py b/tempest/config.py
index d2f957c..b8bad9e 100644
--- a/tempest/config.py
+++ b/tempest/config.py
@@ -666,6 +666,9 @@
'are current one. In future, Tempest will '
'test v2 APIs only so this config option '
'will be removed.'),
+ cfg.ListOpt('enabled_import_methods',
+ default=[],
+ help="List of enabled image import methods")
]
network_group = cfg.OptGroup(name='network',
diff --git a/tempest/lib/common/rest_client.py b/tempest/lib/common/rest_client.py
index 431a0a0..2dbd356 100644
--- a/tempest/lib/common/rest_client.py
+++ b/tempest/lib/common/rest_client.py
@@ -93,6 +93,7 @@
self.build_interval = build_interval
self.build_timeout = build_timeout
self.trace_requests = trace_requests
+ self.ca_certs = ca_certs
self._skip_path = False
self.general_header_lc = set(('cache-control', 'connection',
diff --git a/tempest/lib/services/image/v2/images_client.py b/tempest/lib/services/image/v2/images_client.py
index 90778da..7680a9c 100644
--- a/tempest/lib/services/image/v2/images_client.py
+++ b/tempest/lib/services/image/v2/images_client.py
@@ -55,6 +55,19 @@
body = json.loads(body)
return rest_client.ResponseBody(resp, body)
+ def import_image(self, image_id, **kwargs):
+ """Import image.
+
+ For a full list of available parameters, please refer to the official
+ API reference:
+ https://docs.openstack.org/api-ref/image/v2/#import-an-image
+ """
+ data = json.dumps(kwargs)
+ url = 'images/%s/import' % image_id
+ resp, body = self.post(url, data)
+ self.expected_success(202, resp.status)
+ return rest_client.ResponseBody(resp, body)
+
def deactivate_image(self, image_id):
"""Deactivate image.
diff --git a/tempest/lib/services/object_storage/object_client.py b/tempest/lib/services/object_storage/object_client.py
index 383aff6..dcd8e49 100644
--- a/tempest/lib/services/object_storage/object_client.py
+++ b/tempest/lib/services/object_storage/object_client.py
@@ -12,6 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
+import ssl
from six.moves import http_client as httplib
from six.moves.urllib import parse as urlparse
@@ -118,7 +119,7 @@
path = str(parsed.path) + "/"
path += "%s/%s" % (str(container), str(object_name))
- conn = _create_connection(parsed)
+ conn = self._create_connection(parsed)
# Send the PUT request and the headers including the "Expect" header
conn.putrequest('PUT', path)
@@ -151,15 +152,17 @@
return resp.status, resp.reason
+ def _create_connection(self, parsed_url):
+ """Helper function to create connection with httplib
-def _create_connection(parsed_url):
- """Helper function to create connection with httplib
+ :param parsed_url: parsed url of the remote location
+ """
+ if parsed_url.scheme == 'https':
+ conn = httplib.HTTPSConnection(
+ parsed_url.netloc,
+ context=ssl.create_default_context(cafile=self.ca_certs),
+ )
+ else:
+ conn = httplib.HTTPConnection(parsed_url.netloc)
- :param parsed_url: parsed url of the remote location
- """
- if parsed_url.scheme == 'https':
- conn = httplib.HTTPSConnection(parsed_url.netloc)
- else:
- conn = httplib.HTTPConnection(parsed_url.netloc)
-
- return conn
+ return conn
diff --git a/tempest/scenario/test_object_storage_basic_ops.py b/tempest/scenario/test_object_storage_basic_ops.py
index b635ca0..1d90219 100644
--- a/tempest/scenario/test_object_storage_basic_ops.py
+++ b/tempest/scenario/test_object_storage_basic_ops.py
@@ -62,7 +62,9 @@
obj_url = '%s/%s/%s' % (self.object_client.base_url,
container_name, obj_name)
resp, _ = self.object_client.raw_request(obj_url, 'GET')
- self.assertEqual(resp.status, 401)
+ # TODO(mshalamov): RGW returns 404 code for unauthorized instead of 401
+ # https://tracker.ceph.com/issues/46295
+ self.assertIn(resp.status, [401, 404])
metadata_param = {'X-Container-Read': '.r:*'}
self.container_client.create_update_or_delete_container_metadata(
container_name, create_update_metadata=metadata_param,
diff --git a/tempest/tests/lib/services/object_storage/test_object_client.py b/tempest/tests/lib/services/object_storage/test_object_client.py
index 1749b03..be66222 100644
--- a/tempest/tests/lib/services/object_storage/test_object_client.py
+++ b/tempest/tests/lib/services/object_storage/test_object_client.py
@@ -31,15 +31,18 @@
self.object_client = object_client.ObjectClient(self.fake_auth,
'swift', 'region1')
- @mock.patch.object(object_client, '_create_connection')
+ @mock.patch('tempest.lib.services.object_storage.object_client.'
+ 'ObjectClient._create_connection')
def test_create_object_continue_no_data(self, mock_poc):
self._validate_create_object_continue(None, mock_poc)
- @mock.patch.object(object_client, '_create_connection')
+ @mock.patch('tempest.lib.services.object_storage.object_client.'
+ 'ObjectClient._create_connection')
def test_create_object_continue_with_data(self, mock_poc):
self._validate_create_object_continue('hello', mock_poc)
- @mock.patch.object(object_client, '_create_connection')
+ @mock.patch('tempest.lib.services.object_storage.object_client.'
+ 'ObjectClient._create_connection')
def test_create_continue_with_no_continue_received(self, mock_poc):
self._validate_create_object_continue('hello', mock_poc,
initial_status=201)