Functional tests for new Image Import API
Added new functional tests for glance-direct and web-download import methods of new Image Import API. Closes-Bug: #1761544 Change-Id: I2687d2524221c6ad0f6c233ac949bc2383c0fd7a
This commit is contained in:
parent
8329cde3c3
commit
c611c92dc1
|
@ -15,6 +15,7 @@
|
|||
|
||||
import os
|
||||
import signal
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from oslo_serialization import jsonutils
|
||||
|
@ -135,6 +136,269 @@ class TestImages(functional.FunctionalTest):
|
|||
self.assertEqual(http.UNAUTHORIZED, response.status_code)
|
||||
self.stop_servers()
|
||||
|
||||
def test_image_import_using_glance_direct(self):
|
||||
self.api_server.enable_image_import = True
|
||||
self.start_servers(**self.__dict__.copy())
|
||||
|
||||
# Image list should be empty
|
||||
path = self._url('/v2/images')
|
||||
response = requests.get(path, headers=self._headers())
|
||||
self.assertEqual(http.OK, response.status_code)
|
||||
images = jsonutils.loads(response.text)['images']
|
||||
self.assertEqual(0, len(images))
|
||||
|
||||
# glance-direct should be available in discovery response
|
||||
path = self._url('/v2/info/import')
|
||||
response = requests.get(path, headers=self._headers())
|
||||
self.assertEqual(http.OK, response.status_code)
|
||||
discovery_calls = jsonutils.loads(
|
||||
response.text)['import-methods']['value']
|
||||
self.assertIn("glance-direct", discovery_calls)
|
||||
|
||||
# Create an image
|
||||
path = self._url('/v2/images')
|
||||
headers = self._headers({'content-type': 'application/json'})
|
||||
data = jsonutils.dumps({'name': 'image-1', 'type': 'kernel',
|
||||
'disk_format': 'aki',
|
||||
'container_format': 'aki'})
|
||||
response = requests.post(path, headers=headers, data=data)
|
||||
self.assertEqual(http.CREATED, response.status_code)
|
||||
|
||||
# Returned image entity should have a generated id and status
|
||||
image = jsonutils.loads(response.text)
|
||||
image_id = image['id']
|
||||
checked_keys = set([
|
||||
u'status',
|
||||
u'name',
|
||||
u'tags',
|
||||
u'created_at',
|
||||
u'updated_at',
|
||||
u'visibility',
|
||||
u'self',
|
||||
u'protected',
|
||||
u'id',
|
||||
u'file',
|
||||
u'min_disk',
|
||||
u'type',
|
||||
u'min_ram',
|
||||
u'schema',
|
||||
u'disk_format',
|
||||
u'container_format',
|
||||
u'owner',
|
||||
u'checksum',
|
||||
u'size',
|
||||
u'virtual_size',
|
||||
])
|
||||
self.assertEqual(checked_keys, set(image.keys()))
|
||||
expected_image = {
|
||||
'status': 'queued',
|
||||
'name': 'image-1',
|
||||
'tags': [],
|
||||
'visibility': 'shared',
|
||||
'self': '/v2/images/%s' % image_id,
|
||||
'protected': False,
|
||||
'file': '/v2/images/%s/file' % image_id,
|
||||
'min_disk': 0,
|
||||
'type': 'kernel',
|
||||
'min_ram': 0,
|
||||
'schema': '/v2/schemas/image',
|
||||
}
|
||||
for key, value in expected_image.items():
|
||||
self.assertEqual(value, image[key], key)
|
||||
|
||||
# Image list should now have one entry
|
||||
path = self._url('/v2/images')
|
||||
response = requests.get(path, headers=self._headers())
|
||||
self.assertEqual(http.OK, response.status_code)
|
||||
images = jsonutils.loads(response.text)['images']
|
||||
self.assertEqual(1, len(images))
|
||||
self.assertEqual(image_id, images[0]['id'])
|
||||
|
||||
def _verify_image_checksum_and_status(checksum=None, status=None):
|
||||
# Checksum should be populated and status should be active
|
||||
path = self._url('/v2/images/%s' % image_id)
|
||||
response = requests.get(path, headers=self._headers())
|
||||
self.assertEqual(http.OK, response.status_code)
|
||||
image = jsonutils.loads(response.text)
|
||||
self.assertEqual(checksum, image['checksum'])
|
||||
self.assertEqual(status, image['status'])
|
||||
|
||||
# Upload some image data to staging area
|
||||
path = self._url('/v2/images/%s/stage' % image_id)
|
||||
headers = self._headers({'Content-Type': 'application/octet-stream'})
|
||||
response = requests.put(path, headers=headers, data='ZZZZZ')
|
||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||
|
||||
# Verify image is in uploading state and checksum is None
|
||||
_verify_image_checksum_and_status(status='uploading')
|
||||
|
||||
# Import image to store
|
||||
path = self._url('/v2/images/%s/import' % image_id)
|
||||
headers = self._headers({
|
||||
'content-type': 'application/json',
|
||||
'X-Roles': 'admin',
|
||||
})
|
||||
data = jsonutils.dumps({'method': {
|
||||
'name': 'glance-direct'
|
||||
}})
|
||||
response = requests.post(path, headers=headers, data=data)
|
||||
self.assertEqual(http.ACCEPTED, response.status_code)
|
||||
|
||||
# Verify image is in active state and checksum is set
|
||||
# NOTE(abhishekk): As import is a async call we need to provide
|
||||
# some timelap to complete the call.
|
||||
time.sleep(0.5)
|
||||
_verify_image_checksum_and_status(
|
||||
checksum='8f113e38d28a79a5a451b16048cc2b72',
|
||||
status='active')
|
||||
|
||||
# Ensure the size is updated to reflect the data uploaded
|
||||
path = self._url('/v2/images/%s' % image_id)
|
||||
response = requests.get(path, headers=self._headers())
|
||||
self.assertEqual(http.OK, response.status_code)
|
||||
self.assertEqual(5, jsonutils.loads(response.text)['size'])
|
||||
|
||||
# Deleting image should work
|
||||
path = self._url('/v2/images/%s' % image_id)
|
||||
response = requests.delete(path, headers=self._headers())
|
||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||
|
||||
# Image list should now be empty
|
||||
path = self._url('/v2/images')
|
||||
response = requests.get(path, headers=self._headers())
|
||||
self.assertEqual(http.OK, response.status_code)
|
||||
images = jsonutils.loads(response.text)['images']
|
||||
self.assertEqual(0, len(images))
|
||||
|
||||
self.stop_servers()
|
||||
|
||||
def test_image_import_using_web_download(self):
|
||||
self.api_server.enable_image_import = True
|
||||
self.config(node_staging_uri="file:///tmp/staging/")
|
||||
self.start_servers(**self.__dict__.copy())
|
||||
|
||||
# Image list should be empty
|
||||
path = self._url('/v2/images')
|
||||
response = requests.get(path, headers=self._headers())
|
||||
self.assertEqual(http.OK, response.status_code)
|
||||
images = jsonutils.loads(response.text)['images']
|
||||
self.assertEqual(0, len(images))
|
||||
|
||||
# web-download should be available in discovery response
|
||||
path = self._url('/v2/info/import')
|
||||
response = requests.get(path, headers=self._headers())
|
||||
self.assertEqual(http.OK, response.status_code)
|
||||
discovery_calls = jsonutils.loads(
|
||||
response.text)['import-methods']['value']
|
||||
self.assertIn("web-download", discovery_calls)
|
||||
|
||||
# Create an image
|
||||
path = self._url('/v2/images')
|
||||
headers = self._headers({'content-type': 'application/json'})
|
||||
data = jsonutils.dumps({'name': 'image-1', 'type': 'kernel',
|
||||
'disk_format': 'aki',
|
||||
'container_format': 'aki'})
|
||||
response = requests.post(path, headers=headers, data=data)
|
||||
self.assertEqual(http.CREATED, response.status_code)
|
||||
|
||||
# Returned image entity should have a generated id and status
|
||||
image = jsonutils.loads(response.text)
|
||||
image_id = image['id']
|
||||
checked_keys = set([
|
||||
u'status',
|
||||
u'name',
|
||||
u'tags',
|
||||
u'created_at',
|
||||
u'updated_at',
|
||||
u'visibility',
|
||||
u'self',
|
||||
u'protected',
|
||||
u'id',
|
||||
u'file',
|
||||
u'min_disk',
|
||||
u'type',
|
||||
u'min_ram',
|
||||
u'schema',
|
||||
u'disk_format',
|
||||
u'container_format',
|
||||
u'owner',
|
||||
u'checksum',
|
||||
u'size',
|
||||
u'virtual_size',
|
||||
])
|
||||
self.assertEqual(checked_keys, set(image.keys()))
|
||||
expected_image = {
|
||||
'status': 'queued',
|
||||
'name': 'image-1',
|
||||
'tags': [],
|
||||
'visibility': 'shared',
|
||||
'self': '/v2/images/%s' % image_id,
|
||||
'protected': False,
|
||||
'file': '/v2/images/%s/file' % image_id,
|
||||
'min_disk': 0,
|
||||
'type': 'kernel',
|
||||
'min_ram': 0,
|
||||
'schema': '/v2/schemas/image',
|
||||
}
|
||||
for key, value in expected_image.items():
|
||||
self.assertEqual(value, image[key], key)
|
||||
|
||||
# Image list should now have one entry
|
||||
path = self._url('/v2/images')
|
||||
response = requests.get(path, headers=self._headers())
|
||||
self.assertEqual(http.OK, response.status_code)
|
||||
images = jsonutils.loads(response.text)['images']
|
||||
self.assertEqual(1, len(images))
|
||||
self.assertEqual(image_id, images[0]['id'])
|
||||
|
||||
def _verify_image_checksum_and_status(checksum=None, status=None):
|
||||
# Checksum should be populated and status should be active
|
||||
path = self._url('/v2/images/%s' % image_id)
|
||||
response = requests.get(path, headers=self._headers())
|
||||
self.assertEqual(http.OK, response.status_code)
|
||||
image = jsonutils.loads(response.text)
|
||||
self.assertEqual(checksum, image['checksum'])
|
||||
self.assertEqual(status, image['status'])
|
||||
|
||||
# Verify image is in queued state and checksum is None
|
||||
_verify_image_checksum_and_status(status='queued')
|
||||
|
||||
# Import image to store
|
||||
path = self._url('/v2/images/%s/import' % image_id)
|
||||
headers = self._headers({
|
||||
'content-type': 'application/json',
|
||||
'X-Roles': 'admin',
|
||||
})
|
||||
data = jsonutils.dumps({'method': {
|
||||
'name': 'web-download',
|
||||
'uri': 'https://www.openstack.org/assets/openstack-logo/'
|
||||
'2016R/OpenStack-Logo-Horizontal.eps.zip'
|
||||
}})
|
||||
response = requests.post(path, headers=headers, data=data)
|
||||
self.assertEqual(http.ACCEPTED, response.status_code)
|
||||
|
||||
# Verify image is in active state and checksum is set
|
||||
# NOTE(abhishekk): As import is a async call we need to provide
|
||||
# some timelap to complete the call.
|
||||
time.sleep(5)
|
||||
_verify_image_checksum_and_status(
|
||||
checksum='bcd65f8922f61a9e6a20572ad7aa2bdd',
|
||||
status='active')
|
||||
|
||||
# Deleting image should work
|
||||
path = self._url('/v2/images/%s' % image_id)
|
||||
response = requests.delete(path, headers=self._headers())
|
||||
self.assertEqual(http.NO_CONTENT, response.status_code)
|
||||
|
||||
# Image list should now be empty
|
||||
path = self._url('/v2/images')
|
||||
response = requests.get(path, headers=self._headers())
|
||||
self.assertEqual(http.OK, response.status_code)
|
||||
images = jsonutils.loads(response.text)['images']
|
||||
self.assertEqual(0, len(images))
|
||||
|
||||
self.stop_servers()
|
||||
|
||||
def test_image_lifecycle(self):
|
||||
# Image list should be empty
|
||||
self.api_server.show_multiple_locations = True
|
||||
|
|
Loading…
Reference in New Issue