Files
openstacksdk/openstack/image/v1/_proxy.py
Monty Taylor 75ae5bf4aa Upload image via interop import if needed
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
2020-06-26 17:07:59 -05:00

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)