159 lines
6.1 KiB
Python
159 lines
6.1 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 hashlib
|
|
import os
|
|
import six
|
|
|
|
from oslo_log import log as logging
|
|
from oslo_utils import fileutils
|
|
|
|
from zun.common import exception
|
|
from zun.common.i18n import _
|
|
from zun.common import utils as common_utils
|
|
import zun.conf
|
|
from zun.image import driver
|
|
from zun.image.glance import utils
|
|
|
|
CONF = zun.conf.CONF
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class GlanceDriver(driver.ContainerImageDriver):
|
|
|
|
def __init__(self):
|
|
super(GlanceDriver, self).__init__()
|
|
|
|
def _search_image_on_host(self, context, repo):
|
|
LOG.debug('Searching for image %s locally', repo)
|
|
images_directory = CONF.glance.images_directory
|
|
try:
|
|
# TODO(mkrai): Change this to search image entry in zun db
|
|
# after the image endpoint is merged.
|
|
image_meta = utils.find_image(context, repo)
|
|
except exception.ImageNotFound:
|
|
return None
|
|
if image_meta:
|
|
out_path = os.path.join(images_directory,
|
|
image_meta.id + '.tar')
|
|
if os.path.isfile(out_path):
|
|
return {
|
|
'image': repo,
|
|
'path': out_path,
|
|
'checksum': image_meta.checksum}
|
|
else:
|
|
return None
|
|
|
|
def pull_image(self, context, repo, tag, image_pull_policy):
|
|
# TODO(shubhams): glance driver does not handle tags
|
|
# once metadata is stored in db then handle tags
|
|
image_loaded = False
|
|
image = self._search_image_on_host(context, repo)
|
|
if image:
|
|
image_path = image['path']
|
|
image_checksum = image['checksum']
|
|
md5sum = hashlib.md5()
|
|
with open(image_path, 'rb') as fd:
|
|
while True:
|
|
# read 10MB of data each time
|
|
data = fd.read(10 * 1024 * 1024)
|
|
if not data:
|
|
break
|
|
md5sum.update(data)
|
|
md5sum = md5sum.hexdigest()
|
|
if md5sum == image_checksum:
|
|
image_loaded = True
|
|
return image, image_loaded
|
|
|
|
if not common_utils.should_pull_image(image_pull_policy, bool(image)):
|
|
if image:
|
|
LOG.debug('Image %s present locally', repo)
|
|
image_loaded = True
|
|
return image, image_loaded
|
|
else:
|
|
message = _('Image %s not present with pull policy of Never'
|
|
) % repo
|
|
raise exception.ImageNotFound(message)
|
|
|
|
LOG.debug('Pulling image from glance %s', repo)
|
|
try:
|
|
glance = utils.create_glanceclient(context)
|
|
image_meta = utils.find_image(context, repo)
|
|
LOG.debug('Image %s was found in glance, downloading now...', repo)
|
|
image_chunks = glance.images.data(image_meta.id)
|
|
except exception.ImageNotFound:
|
|
LOG.error('Image %s was not found in glance', repo)
|
|
raise
|
|
except Exception as e:
|
|
msg = _('Cannot download image from glance: {0}')
|
|
raise exception.ZunException(msg.format(e))
|
|
try:
|
|
images_directory = CONF.glance.images_directory
|
|
fileutils.ensure_tree(images_directory)
|
|
out_path = os.path.join(images_directory, image_meta.id + '.tar')
|
|
with open(out_path, 'wb') as fd:
|
|
for chunk in image_chunks:
|
|
fd.write(chunk)
|
|
except Exception as e:
|
|
msg = _('Error occurred while writing image: {0}')
|
|
raise exception.ZunException(msg.format(e))
|
|
LOG.debug('Image %(repo)s was downloaded to path : %(path)s',
|
|
{'repo': repo, 'path': out_path})
|
|
return {'image': repo, 'path': out_path}, image_loaded
|
|
|
|
def search_image(self, context, repo, tag, exact_match):
|
|
# TODO(mkrai): glance driver does not handle tags
|
|
# once metadata is stored in db then handle tags
|
|
LOG.debug('Searching image in glance %s', repo)
|
|
try:
|
|
# TODO(hongbin): find image by both repo and tag
|
|
images = utils.find_images(context, repo, exact_match)
|
|
return images
|
|
except Exception as e:
|
|
raise exception.ZunException(six.text_type(e))
|
|
|
|
def create_image(self, context, image_name):
|
|
"""Create an image."""
|
|
LOG.debug('Creating a new image in glance %s', image_name)
|
|
try:
|
|
img = utils.create_image(context, image_name)
|
|
return img
|
|
except Exception as e:
|
|
raise exception.ZunException(six.text_type(e))
|
|
|
|
def update_image(self, context, img_id, disk_format='qcow2',
|
|
container_format='docker', tag=None):
|
|
"""Update an image."""
|
|
LOG.debug('Updating an image %s in glance', img_id)
|
|
try:
|
|
if tag is not None:
|
|
tags = []
|
|
tags.append(tag)
|
|
img = utils.update_image_tags(context, img_id,
|
|
tags)
|
|
img = utils.update_image_format(context, img_id, disk_format,
|
|
container_format)
|
|
return img
|
|
except Exception as e:
|
|
raise exception.ZunException(six.text_type(e))
|
|
|
|
def upload_image_data(self, context, img_id, data):
|
|
"""Update an image."""
|
|
LOG.debug('Uploading an image to glance %s', img_id)
|
|
try:
|
|
img = utils.upload_image_data(context, img_id, data)
|
|
return img
|
|
except Exception as e:
|
|
raise exception.ZunException(six.text_type(e))
|