
We have support for interop import already, but it's not stitched in to the image upload call. Add support for using it. We're adding this as a fallback for the case that PUT is turned off due to operator concerns about the need for scratch space. That means we don't want existing users to all of a sudden start uploading via import. However, if they do want to use import, we want that to work, so there is now a flag. Change-Id: I26e7ba5704d58a21f7ae2011e8c21e9b9310751a
217 lines
8.6 KiB
Python
217 lines
8.6 KiB
Python
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
|
# not use this file except in compliance with the License. You may obtain
|
|
# a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
# 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 warnings
|
|
|
|
from openstack.cloud import exc
|
|
from openstack import exceptions
|
|
from openstack.image import _base_proxy
|
|
from openstack.image.v1 import image as _image
|
|
|
|
|
|
class Proxy(_base_proxy.BaseImageProxy):
|
|
|
|
def _create_image(self, **kwargs):
|
|
"""Create image resource from attributes
|
|
"""
|
|
return self._create(_image.Image, **kwargs)
|
|
|
|
def upload_image(self, **attrs):
|
|
"""Upload a new image from attributes
|
|
|
|
.. warning:
|
|
This method is deprecated - and also doesn't work very well.
|
|
Please stop using it immediately and switch to
|
|
`create_image`.
|
|
|
|
:param dict attrs: Keyword arguments which will be used to create
|
|
a :class:`~openstack.image.v1.image.Image`,
|
|
comprised of the properties on the Image class.
|
|
|
|
:returns: The results of image creation
|
|
:rtype: :class:`~openstack.image.v1.image.Image`
|
|
"""
|
|
warnings.warn("upload_image is deprecated. Use create_image instead.")
|
|
return self._create(_image.Image, **attrs)
|
|
|
|
def _upload_image(
|
|
self, name, filename, data, meta, wait, timeout,
|
|
use_import=False,
|
|
**image_kwargs,
|
|
):
|
|
if use_import:
|
|
raise exceptions.SDKException(
|
|
"Glance v1 does not support image import")
|
|
# NOTE(mordred) wait and timeout parameters are unused, but
|
|
# are present for ease at calling site.
|
|
if filename and not data:
|
|
image_data = open(filename, 'rb')
|
|
else:
|
|
image_data = data
|
|
image_kwargs['properties'].update(meta)
|
|
image_kwargs['name'] = name
|
|
|
|
# TODO(mordred) Convert this to use image Resource
|
|
image = self._connection._get_and_munchify(
|
|
'image',
|
|
self.post('/images', json=image_kwargs))
|
|
checksum = image_kwargs['properties'].get(self._IMAGE_MD5_KEY, '')
|
|
|
|
try:
|
|
# Let us all take a brief moment to be grateful that this
|
|
# is not actually how OpenStack APIs work anymore
|
|
headers = {
|
|
'x-glance-registry-purge-props': 'false',
|
|
}
|
|
if checksum:
|
|
headers['x-image-meta-checksum'] = checksum
|
|
|
|
image = self._connection._get_and_munchify(
|
|
'image',
|
|
self.put(
|
|
'/images/{id}'.format(id=image.id),
|
|
headers=headers, data=image_data))
|
|
|
|
except exc.OpenStackCloudHTTPError:
|
|
self.log.debug(
|
|
"Deleting failed upload of image %s", name)
|
|
try:
|
|
self.delete('/images/{id}'.format(id=image.id))
|
|
except exc.OpenStackCloudHTTPError:
|
|
# We're just trying to clean up - if it doesn't work - shrug
|
|
self.log.warning(
|
|
"Failed deleting image after we failed uploading it.",
|
|
exc_info=True)
|
|
raise
|
|
return self._connection._normalize_image(image)
|
|
|
|
def _update_image_properties(self, image, meta, properties):
|
|
properties.update(meta)
|
|
img_props = {}
|
|
for k, v in iter(properties.items()):
|
|
if image.properties.get(k, None) != v:
|
|
img_props['x-image-meta-{key}'.format(key=k)] = v
|
|
if not img_props:
|
|
return False
|
|
self.put(
|
|
'/images/{id}'.format(id=image.id), headers=img_props)
|
|
self._connection.list_images.invalidate(self._connection)
|
|
return True
|
|
|
|
def _existing_image(self, **kwargs):
|
|
return _image.Image.existing(connection=self._connection, **kwargs)
|
|
|
|
def delete_image(self, image, ignore_missing=True):
|
|
"""Delete an image
|
|
|
|
:param image: The value can be either the ID of an image or a
|
|
:class:`~openstack.image.v1.image.Image` instance.
|
|
:param bool ignore_missing: When set to ``False``
|
|
:class:`~openstack.exceptions.ResourceNotFound` will be
|
|
raised when the image does not exist.
|
|
When set to ``True``, no exception will be set when
|
|
attempting to delete a nonexistent image.
|
|
|
|
:returns: ``None``
|
|
"""
|
|
self._delete(_image.Image, image, ignore_missing=ignore_missing)
|
|
|
|
def find_image(self, name_or_id, ignore_missing=True):
|
|
"""Find a single image
|
|
|
|
:param name_or_id: The name or ID of a image.
|
|
:param bool ignore_missing: When set to ``False``
|
|
:class:`~openstack.exceptions.ResourceNotFound` will be
|
|
raised when the resource does not exist.
|
|
When set to ``True``, None will be returned when
|
|
attempting to find a nonexistent resource.
|
|
:returns: One :class:`~openstack.image.v1.image.Image` or None
|
|
"""
|
|
return self._find(_image.Image, name_or_id,
|
|
ignore_missing=ignore_missing)
|
|
|
|
def get_image(self, image):
|
|
"""Get a single image
|
|
|
|
:param image: The value can be the ID of an image or a
|
|
:class:`~openstack.image.v1.image.Image` instance.
|
|
|
|
:returns: One :class:`~openstack.image.v1.image.Image`
|
|
:raises: :class:`~openstack.exceptions.ResourceNotFound`
|
|
when no resource can be found.
|
|
"""
|
|
return self._get(_image.Image, image)
|
|
|
|
def images(self, **query):
|
|
"""Return a generator of images
|
|
|
|
:param kwargs query: Optional query parameters to be sent to limit
|
|
the resources being returned.
|
|
|
|
:returns: A generator of image objects
|
|
:rtype: :class:`~openstack.image.v1.image.Image`
|
|
"""
|
|
return self._list(_image.Image, base_path='/images/detail', **query)
|
|
|
|
def update_image(self, image, **attrs):
|
|
"""Update a image
|
|
|
|
:param image: Either the ID of a image or a
|
|
:class:`~openstack.image.v1.image.Image` instance.
|
|
:attrs kwargs: The attributes to update on the image represented
|
|
by ``value``.
|
|
|
|
:returns: The updated image
|
|
:rtype: :class:`~openstack.image.v1.image.Image`
|
|
"""
|
|
return self._update(_image.Image, image, **attrs)
|
|
|
|
def download_image(self, image, stream=False, output=None,
|
|
chunk_size=1024):
|
|
"""Download an image
|
|
|
|
This will download an image to memory when ``stream=False``, or allow
|
|
streaming downloads using an iterator when ``stream=True``.
|
|
For examples of working with streamed responses, see
|
|
:ref:`download_image-stream-true`.
|
|
|
|
:param image: The value can be either the ID of an image or a
|
|
:class:`~openstack.image.v2.image.Image` instance.
|
|
|
|
:param bool stream: When ``True``, return a :class:`requests.Response`
|
|
instance allowing you to iterate over the
|
|
response data stream instead of storing its entire
|
|
contents in memory. See
|
|
:meth:`requests.Response.iter_content` for more
|
|
details. *NOTE*: If you do not consume
|
|
the entirety of the response you must explicitly
|
|
call :meth:`requests.Response.close` or otherwise
|
|
risk inefficiencies with the ``requests``
|
|
library's handling of connections.
|
|
|
|
|
|
When ``False``, return the entire
|
|
contents of the response.
|
|
:param output: Either a file object or a path to store data into.
|
|
:param int chunk_size: size in bytes to read from the wire and buffer
|
|
at one time. Defaults to 1024
|
|
|
|
:returns: When output is not given - the bytes comprising the given
|
|
Image when stream is False, otherwise a :class:`requests.Response`
|
|
instance. When output is given - a
|
|
:class:`~openstack.image.v2.image.Image` instance.
|
|
"""
|
|
|
|
image = self._get_resource(_image.Image, image)
|
|
|
|
return image.download(
|
|
self, stream=stream, output=output, chunk_size=chunk_size)
|