Add image upload support

There are at least 2 known mechanisms in the wild for uploading images
to public glance endpoints that are completely different. Based on which
version of the API we're running switch between them seamlessly. Note
that the wait parameter isn't going to do anything for v1 because it's a
sync call - maybe we should throw an error if someone tries to leave if
set to false?

Change-Id: Ifccf8aaa6cd7793a1b827914e7da4b2b82248544
This commit is contained in:
Monty Taylor 2015-01-07 11:37:24 -05:00
parent 9344803010
commit fe14bc166e
1 changed files with 66 additions and 1 deletions

View File

@ -37,6 +37,7 @@ from troveclient import exceptions as trove_exceptions
from shade import meta
__version__ = pbr.version.VersionInfo('shade').version_string()
IMAGE_MD5_KEY = 'org.openstack.shade.md5'
class OpenStackCloudException(Exception):
@ -410,7 +411,7 @@ class OpenStackCloud(object):
self._image_cache = self._get_images_from_cloud()
return self._image_cache
def get_image_name(self, image_id, exclude):
def get_image_name(self, image_id, exclude=None):
image = self.get_image(image_id, exclude)
if image:
return image.id
@ -433,6 +434,70 @@ class OpenStackCloud(object):
raise OpenStackCloudException(
"Error finding image from %s" % name_or_id)
def create_image(
self, name, filename, container='images', md5=None
disk_format=None, container_format=None,
wait=False, timeout=3600, **kwargs):
if not md5:
md5 = self._get_file_md5(filename)
current_image = self.get_image(name)
if current_image.get(IMAGE_MD5_KEY, '') == md5:
self.log.debug(
"image {name} exists and is up to date".format(name=name))
return
kwargs[IMAGE_MD5_KEY] = md5
# This makes me want to die inside
if self._get_glance_api_version() == '2':
self._upload_image_v2(
name, filename, container,
current_image=current_image,
wait=wait, timeout=timeout, **kwargs)
else:
self._upload_image_v1(name, filename, md5=md5)
def _upload_image_v1(self, name, filename,
disk_format=None, container_format=None, **image_properties):
image = self.glance_client.images.create(
name=name, is_public=False, disk_format=disk_format,
container_format=container_format, **image_properties)
image.update(data=open(filename, 'rb'))
return image.id
def _upload_image_v2(
self, name, filename, container, current_image=None,
wait=False, timeout=3600, **image_properties):
self.create_object(
container, name, filename, md5=image_properties['md5'])
if not current_image:
current_image = self.get_image(name)
# TODO(mordred): Can we do something similar to what nodepool does
# using glance properties to not delete then upload but instead make a
# new "good" image and then mark the old one as "bad"
# self.glance_client.images.delete(current_image)
image_properties['name'] = name
task = self.glance_client.tasks.create(
type='import', input=dict(
import_from='{container}/{name}'.format(
container=container, name=name),
image_properties=image_properties))
if wait:
expire = time.time() + timeout
while time.time() < expire:
status = self.glance_client.tasks.get(task.id)
if status.status == 'success':
return status.result['image_id']
if status.status == 'failure':
raise OpenStackCloudException(
"Image creation failed: {message}".format(
message=status.message))
time.sleep(10)
raise OpenStackCloudException(
"Timeout waiting for the image to import.")
else:
return task
def _get_volumes_from_cloud(self):
try:
return self.cinder_client.volumes.list()