"Fossies" - the Fresh Open Source Software Archive

Member "glance-20.0.1/glance/async_/flows/_internal_plugins/copy_image.py" (12 Aug 2020, 5679 Bytes) of package /linux/misc/openstack/glance-20.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "copy_image.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 20.0.0_vs_20.0.1.

    1 # Copyright 2020 Red Hat, Inc.
    2 # All Rights Reserved.
    3 #
    4 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    5 #    not use this file except in compliance with the License. You may obtain
    6 #    a copy of the License at
    7 #
    8 #         http://www.apache.org/licenses/LICENSE-2.0
    9 #
   10 #    Unless required by applicable law or agreed to in writing, software
   11 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
   12 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   13 #    License for the specific language governing permissions and limitations
   14 #    under the License.
   15 import os
   16 
   17 import glance_store as store_api
   18 from oslo_config import cfg
   19 from oslo_log import log as logging
   20 from taskflow.patterns import linear_flow as lf
   21 from taskflow import task
   22 from taskflow.types import failure
   23 
   24 from glance.common import exception
   25 from glance.i18n import _, _LE
   26 
   27 LOG = logging.getLogger(__name__)
   28 
   29 CONF = cfg.CONF
   30 
   31 
   32 class _CopyImage(task.Task):
   33 
   34     default_provides = 'file_uri'
   35 
   36     def __init__(self, task_id, task_type, image_repo, image_id):
   37         self.task_id = task_id
   38         self.task_type = task_type
   39         self.image_repo = image_repo
   40         self.image_id = image_id
   41         super(_CopyImage, self).__init__(
   42             name='%s-CopyImage-%s' % (task_type, task_id))
   43 
   44         self.staging_store = store_api.get_store_from_store_identifier(
   45             'os_glance_staging_store')
   46 
   47     def execute(self):
   48         """Create temp file into store and return path to it
   49 
   50         :param image_id: Glance Image ID
   51         """
   52         image = self.image_repo.get(self.image_id)
   53         # NOTE (abhishekk): If ``all_stores_must_succeed`` is set to True
   54         # and copying task fails then we keep data in staging area as it
   55         # is so that if second call is made to copy the same image then
   56         # no need to copy the data in staging area again.
   57         file_path = "%s/%s" % (getattr(
   58             CONF, 'os_glance_staging_store').filesystem_store_datadir,
   59             self.image_id)
   60 
   61         if os.path.exists(file_path):
   62             # NOTE (abhishekk): If previous copy-image operation is failed
   63             # due to power failure, network failure or any other reason and
   64             # the image data here is partial then clear the staging area and
   65             # re-stage the fresh image data.
   66             # Ref: https://bugs.launchpad.net/glance/+bug/1885003
   67             size_in_staging = os.path.getsize(file_path)
   68             if image.size == size_in_staging:
   69                 return file_path, 0
   70             else:
   71                 LOG.debug(("Found partial image data in staging "
   72                            "%(fn)s, deleting it to re-stage "
   73                            "again"), {'fn': file_path})
   74                 try:
   75                     os.unlink(file_path)
   76                 except OSError as e:
   77                     LOG.error(_LE("Deletion of staged "
   78                                   "image data from %(fn)s has failed because "
   79                                   "[Errno %(en)d]"), {'fn': file_path,
   80                                                       'en': e.errno})
   81                     raise
   82 
   83         # At first search image in default_backend
   84         default_store = CONF.glance_store.default_backend
   85         for loc in image.locations:
   86             if loc['metadata'].get('store') == default_store:
   87                 try:
   88                     return self._copy_to_staging_store(loc)
   89                 except store_api.exceptions.NotFound:
   90                     msg = (_LE("Image not present in default store, searching "
   91                                "in all glance-api specific available "
   92                                "stores"))
   93                     LOG.error(msg)
   94                     break
   95 
   96         available_backends = CONF.enabled_backends
   97         for loc in image.locations:
   98             image_backend = loc['metadata'].get('store')
   99             if (image_backend in available_backends.keys()
  100                     and image_backend != default_store):
  101                 try:
  102                     return self._copy_to_staging_store(loc)
  103                 except store_api.exceptions.NotFound:
  104                     LOG.error(_LE('Image: %(img_id)s is not present in store '
  105                                   '%(store)s.'),
  106                               {'img_id': self.image_id,
  107                                'store': image_backend})
  108                     continue
  109 
  110         raise exception.NotFound(_("Image not found in any configured "
  111                                    "store"))
  112 
  113     def _copy_to_staging_store(self, loc):
  114         store_backend = loc['metadata'].get('store')
  115         image_data, size = store_api.get(loc['url'], store_backend)
  116         msg = ("Found image, copying it in staging area")
  117         LOG.debug(msg)
  118         return self.staging_store.add(self.image_id, image_data, size)[0]
  119 
  120     def revert(self, result, **kwargs):
  121         if isinstance(result, failure.Failure):
  122             LOG.error(_LE('Task: %(task_id)s failed to copy image '
  123                           '%(image_id)s.'),
  124                       {'task_id': self.task_id,
  125                        'image_id': self.image_id})
  126 
  127 
  128 def get_flow(**kwargs):
  129     """Return task flow for web-download.
  130 
  131     :param task_id: Task ID.
  132     :param task_type: Type of the task.
  133     :param image_repo: Image repository used.
  134     :param uri: URI the image data is downloaded from.
  135     """
  136     task_id = kwargs.get('task_id')
  137     task_type = kwargs.get('task_type')
  138     image_repo = kwargs.get('image_repo')
  139     image_id = kwargs.get('image_id')
  140 
  141     return lf.Flow(task_type).add(
  142         _CopyImage(task_id, task_type, image_repo, image_id),
  143     )