# Copyright 2015 Red Hat, Inc. # All Rights Reserved. # # 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 json import logging from oslo_concurrency import processutils as putils from oslo_utils import excutils from taskflow.patterns import linear_flow as lf from glance.async import utils from glance import i18n _LE = i18n._LE LOG = logging.getLogger(__name__) class _Introspect(utils.OptionalTask): """Taskflow to pull the embedded metadata out of image file""" def __init__(self, task_id, task_type, image_repo): self.task_id = task_id self.task_type = task_type self.image_repo = image_repo super(_Introspect, self).__init__( name='%s-Introspect-%s' % (task_type, task_id)) def execute(self, image_id, file_path): """Does the actual introspection :param image_id: Glance image ID :param file_path: Path to the file being introspected """ try: stdout, stderr = putils.trycmd('qemu-img', 'info', '--output=json', file_path, log_errors=putils.LOG_ALL_ERRORS) except OSError as exc: # NOTE(flaper87): errno == 2 means the executable file # was not found. For now, log an error and move forward # until we have a better way to enable/disable optional # tasks. if exc.errno != 2: with excutils.save_and_reraise_exception(): msg = (_LE('Failed to execute introspection ' '%(task_id)s: %(exc)s') % {'task_id': self.task_id, 'exc': exc.message}) LOG.error(msg) return if stderr: raise RuntimeError(stderr) metadata = json.loads(stdout) new_image = self.image_repo.get(image_id) new_image.virtual_size = metadata.get('virtual-size', 0) new_image.disk_format = metadata.get('format') self.image_repo.save(new_image) LOG.debug("%(task_id)s: Introspection successful: %(file)s" % {'task_id': self.task_id, 'file': file_path}) return new_image def get_flow(**kwargs): task_id = kwargs.get('task_id') task_type = kwargs.get('task_type') image_repo = kwargs.get('image_repo') LOG.debug("Flow: %(task_type)s with ID %(id)s on %(repo)s" % {'task_type': task_type, 'id': task_id, 'repo': image_repo}) return lf.Flow(task_type).add( _Introspect(task_id, task_type, image_repo), )