Ejemplo n.º 1
0
def size_checked_iter(response, image_meta, expected_size, image_iter,
                      notifier):
    image_id = image_meta['id']
    bytes_written = 0

    def notify_image_sent_hook(env):
        image_send_notification(bytes_written, expected_size,
                                image_meta, response.request, notifier)

    # Add hook to process after response is fully sent
    if 'eventlet.posthooks' in response.request.environ:
        response.request.environ['eventlet.posthooks'].append(
            (notify_image_sent_hook, (), {}))

    try:
        for chunk in image_iter:
            yield chunk
            bytes_written += len(chunk)
    except Exception as err:
        with excutils.save_and_reraise_exception():
            msg = (_LE("An error occurred reading from backend storage for "
                       "image %(image_id)s: %(err)s") % {'image_id': image_id,
                                                         'err': err})
            LOG.error(msg)

    if expected_size != bytes_written:
        msg = (_LE("Backend storage for image %(image_id)s "
                   "disconnected after writing only %(bytes_written)d "
                   "bytes") % {'image_id': image_id,
                               'bytes_written': bytes_written})
        LOG.error(msg)
        raise exception.GlanceException(_("Corrupt image download for "
                                          "image %(image_id)s") %
                                        {'image_id': image_id})
Ejemplo n.º 2
0
def run_task(task_id, task_type, context,
             task_repo=None, image_repo=None, image_factory=None):
    # TODO(nikhil): if task_repo is None get new task repo
    # TODO(nikhil): if image_repo is None get new image repo
    # TODO(nikhil): if image_factory is None get new image factory
    LOG.info(_LI("Loading known task scripts for task_id %(task_id)s "
                 "of type %(task_type)s"), {'task_id': task_id,
                                            'task_type': task_type})
    if task_type == 'import':
        image_import.run(task_id, context, task_repo,
                         image_repo, image_factory)

    else:
        msg = _LE("This task type %(task_type)s is not supported by the "
                  "current deployment of Glance. Please refer the "
                  "documentation provided by OpenStack or your operator "
                  "for more information.") % {'task_type': task_type}
        LOG.error(msg)
        task = task_repo.get(task_id)
        task.fail(msg)
        if task_repo:
            task_repo.save(task)
        else:
            LOG.error(_LE("Failed to save task %(task_id)s in DB as task_repo "
                          "is %(task_repo)s"), {"task_id": task_id,
                                                "task_repo": task_repo})
Ejemplo n.º 3
0
def _execute(t_id, task_repo, image_repo, image_factory):
    task = script_utils.get_task(task_repo, t_id)

    if task is None:
        # NOTE: This happens if task is not found in the database. In
        # such cases, there is no way to update the task status so,
        # it's ignored here.
        return

    try:
        task_input = script_utils.unpack_task_input(task)

        uri = script_utils.validate_location_uri(task_input.get('import_from'))
        image_id = import_image(image_repo, image_factory, task_input, t_id,
                                uri)

        task.succeed({'image_id': image_id})
    except Exception as e:
        # Note: The message string contains Error in it to indicate
        # in the task.message that it's a error message for the user.

        # TODO(nikhil): need to bring back save_and_reraise_exception when
        # necessary
        err_msg = ("Error: " + six.text_type(type(e)) + ': ' +
                   encodeutils.exception_to_unicode(e))
        log_msg = _LE(err_msg + ("Task ID %s" % task.task_id))  # noqa
        LOG.exception(log_msg)

        task.fail(_LE(err_msg))  # noqa
    finally:
        task_repo.save(task)
Ejemplo n.º 4
0
 def _load_config(self):
     try:
         conf_file = CONF.find_file(CONF.swift_store_config_file)
         CONFIG.read(conf_file)
     except Exception as e:
         msg = (_LE("swift config file %(conf_file)s:%(exc)s not found") % {
             'conf_file': CONF.swift_store_config_file,
             'exc': e
         })
         LOG.error(msg)
         raise exception.InvalidSwiftStoreConfiguration()
     account_params = {}
     account_references = CONFIG.sections()
     for ref in account_references:
         reference = {}
         try:
             reference['auth_address'] = CONFIG.get(ref, 'auth_address')
             reference['user'] = CONFIG.get(ref, 'user')
             reference['key'] = CONFIG.get(ref, 'key')
             account_params[ref] = reference
         except (ValueError, SyntaxError, configparser.NoOptionError) as e:
             LOG.exception(
                 _LE("Invalid format of swift store config "
                     "cfg"))
     return account_params
Ejemplo n.º 5
0
def _execute(t_id, task_repo, image_repo, image_factory):
    task = script_utils.get_task(task_repo, t_id)

    if task is None:
        # NOTE: This happens if task is not found in the database. In
        # such cases, there is no way to update the task status so,
        # it's ignored here.
        return

    try:
        task_input = script_utils.unpack_task_input(task)

        uri = script_utils.validate_location_uri(task_input.get('import_from'))
        image_id = import_image(image_repo, image_factory, task_input, t_id,
                                uri)

        task.succeed({'image_id': image_id})
    except Exception as e:
        # Note: The message string contains Error in it to indicate
        # in the task.message that it's a error message for the user.

        # TODO(nikhil): need to bring back save_and_reraise_exception when
        # necessary
        err_msg = ("Error: " + six.text_type(type(e)) + ': ' +
                   encodeutils.exception_to_unicode(e))
        log_msg = _LE(err_msg + ("Task ID %s" % task.task_id))  # noqa
        LOG.exception(log_msg)

        task.fail(_LE(err_msg))  # noqa
    finally:
        task_repo.save(task)
Ejemplo n.º 6
0
def main():
    """The main function."""

    try:
        config.parse_args()
    except RuntimeError as e:
        sys.exit("ERROR: %s" % encodeutils.exception_to_unicode(e))
    except SystemExit as e:
        sys.exit("Please specify one command")

    # Setup logging
    logging.setup(CONF, 'xmonitor')

    if CONF.token:
        CONF.slavetoken = CONF.token
        CONF.mastertoken = CONF.token

    command = lookup_command(CONF.command)

    try:
        command(CONF, CONF.args)
    except TypeError as e:
        LOG.error(_LE(command.__doc__) % {'prog': command.__name__})  # noqa
        sys.exit("ERROR: %s" % encodeutils.exception_to_unicode(e))
    except ValueError as e:
        LOG.error(_LE(command.__doc__) % {'prog': command.__name__})  # noqa
        sys.exit("ERROR: %s" % encodeutils.exception_to_unicode(e))
Ejemplo n.º 7
0
 def _run(self, task_id, task_type):
     task = self.task_repo.get(task_id)
     msg = _LE("This execution of Tasks is not setup. Please consult the "
               "project documentation for more information on the "
               "executors available.")
     LOG.error(msg)
     task.fail(_LE("Internal error occurred while trying to process task."))
     self.task_repo.save(task)
Ejemplo n.º 8
0
    def delete(self, req, id):
        """Deletes an existing image with the registry.

        :param req: wsgi Request object
        :param id:  The opaque internal identifier for the image

        :returns: 200 if delete was successful, a fault if not. On
            success, the body contains the deleted image
            information as a mapping.
        """
        try:
            deleted_image = self.db_api.image_destroy(req.context, id)
            LOG.info(_LI("Successfully deleted image %(id)s"), {'id': id})
            return dict(image=make_image_dict(deleted_image))
        except exception.ForbiddenPublicImage:
            LOG.info(_LI("Delete denied for public image %(id)s"), {'id': id})
            raise exc.HTTPForbidden()
        except exception.Forbidden:
            # If it's private and doesn't belong to them, don't let on
            # that it exists
            LOG.info(
                _LI("Access denied to image %(id)s but returning"
                    " 'not found'"), {'id': id})
            return exc.HTTPNotFound()
        except exception.ImageNotFound:
            LOG.info(_LI("Image %(id)s not found"), {'id': id})
            return exc.HTTPNotFound()
        except Exception:
            LOG.exception(_LE("Unable to delete image %s") % id)
            raise
Ejemplo n.º 9
0
 def _get_images(self, context, filters, **params):
     """Get images, wrapping in exception if necessary."""
     # NOTE(markwash): for backwards compatibility, is_public=True for
     # admins actually means "treat me as if I'm not an admin and show me
     # all my images"
     if context.is_admin and params.get('is_public') is True:
         params['admin_as_user'] = True
         del params['is_public']
     try:
         return self.db_api.image_get_all(context,
                                          filters=filters,
                                          **params)
     except exception.ImageNotFound:
         LOG.warn(
             _LW("Invalid marker. Image %(id)s could not be "
                 "found.") % {'id': params.get('marker')})
         msg = _("Invalid marker. Image could not be found.")
         raise exc.HTTPBadRequest(explanation=msg)
     except exception.Forbidden:
         LOG.warn(
             _LW("Access denied to image %(id)s but returning "
                 "'not found'") % {'id': params.get('marker')})
         msg = _("Invalid marker. Image could not be found.")
         raise exc.HTTPBadRequest(explanation=msg)
     except Exception:
         LOG.exception(_LE("Unable to get images"))
         raise
Ejemplo n.º 10
0
    def process_response(self, resp):
        """
        We intercept the response coming back from the main
        images Resource, removing image file from the cache
        if necessary
        """
        status_code = self.get_status_code(resp)
        if not 200 <= status_code < 300:
            return resp

        try:
            (image_id, method,
             version) = self._fetch_request_info(resp.request)
        except TypeError:
            return resp

        if method == 'GET' and status_code == 204:
            # Bugfix:1251055 - Don't cache non-existent image files.
            # NOTE: Both GET for an image without locations and DELETE return
            # 204 but DELETE should be processed.
            return resp

        method_str = '_process_%s_response' % method
        try:
            process_response_method = getattr(self, method_str)
        except AttributeError:
            LOG.error(_LE('could not find %s') % method_str)
            # Nothing to do here, move along
            return resp
        else:
            return process_response_method(resp, image_id, version=version)
def migrate_location_credentials(migrate_engine, to_quoted):
    """
    Migrate location credentials for swift uri's between the quoted
    and unquoted forms.

    :param migrate_engine: The configured db engine
    :param to_quoted: If True, migrate location credentials from
                      unquoted to quoted form.  If False, do the
                      reverse.
    """
    meta = sqlalchemy.schema.MetaData()
    meta.bind = migrate_engine

    images_table = sqlalchemy.Table('images', meta, autoload=True)

    images = list(
        images_table.select(
            images_table.c.location.startswith('swift')).execute())

    for image in images:
        try:
            fixed_uri = legacy_parse_uri(image['location'], to_quoted)
            images_table.update().where(
                images_table.c.id == image['id']).values(
                    location=fixed_uri).execute()
        except exception.BadStoreUri as e:
            reason = encodeutils.exception_to_unicode(e)
            msg = _LE("Invalid store uri for image: %(image_id)s. "
                      "Details: %(reason)s") % {
                          'image_id': image.id,
                          'reason': reason
                      }
            LOG.exception(msg)
            raise
Ejemplo n.º 12
0
    def delete(self, req, id):
        """Deletes an existing image with the registry.

        :param req: wsgi Request object
        :param id:  The opaque internal identifier for the image

        :returns: 200 if delete was successful, a fault if not. On
            success, the body contains the deleted image
            information as a mapping.
        """
        try:
            deleted_image = self.db_api.image_destroy(req.context, id)
            LOG.info(_LI("Successfully deleted image %(id)s"), {'id': id})
            return dict(image=make_image_dict(deleted_image))
        except exception.ForbiddenPublicImage:
            LOG.info(_LI("Delete denied for public image %(id)s"), {'id': id})
            raise exc.HTTPForbidden()
        except exception.Forbidden:
            # If it's private and doesn't belong to them, don't let on
            # that it exists
            LOG.info(_LI("Access denied to image %(id)s but returning"
                         " 'not found'"), {'id': id})
            return exc.HTTPNotFound()
        except exception.ImageNotFound:
            LOG.info(_LI("Image %(id)s not found"), {'id': id})
            return exc.HTTPNotFound()
        except Exception:
            LOG.exception(_LE("Unable to delete image %s") % id)
            raise
Ejemplo n.º 13
0
    def do_request(self, method, action, **kwargs):
        try:
            kwargs['headers'] = kwargs.get('headers', {})
            kwargs['headers'].update(self.identity_headers or {})
            if self._passed_request_id:
                request_id = self._passed_request_id
                if six.PY3 and isinstance(request_id, bytes):
                    request_id = request_id.decode('utf-8')
                kwargs['headers']['X-Openstack-Request-ID'] = request_id
            res = super(RegistryClient, self).do_request(method,
                                                         action,
                                                         **kwargs)
            status = res.status
            request_id = res.getheader('x-openstack-request-id')
            if six.PY3 and isinstance(request_id, bytes):
                request_id = request_id.decode('utf-8')
            LOG.debug("Registry request %(method)s %(action)s HTTP %(status)s"
                      " request id %(request_id)s",
                      {'method': method, 'action': action,
                       'status': status, 'request_id': request_id})

        except Exception as exc:
            with excutils.save_and_reraise_exception():
                exc_name = exc.__class__.__name__
                LOG.exception(_LE("Registry client request %(method)s "
                                  "%(action)s raised %(exc_name)s"),
                              {'method': method, 'action': action,
                               'exc_name': exc_name})
        return res
Ejemplo n.º 14
0
    def get_data(self, offset=0, chunk_size=None):
        if not self.image.locations:
            # NOTE(mclaren): This is the only set of arguments
            # which work with this exception currently, see:
            # https://bugs.launchpad.net/glance-store/+bug/1501443
            # When the above glance_store bug is fixed we can
            # add a msg as usual.
            raise store.NotFound(image=None)
        err = None
        for loc in self.image.locations:
            try:
                data, size = self.store_api.get_from_backend(
                    loc['url'],
                    offset=offset,
                    chunk_size=chunk_size,
                    context=self.context)

                return data
            except Exception as e:
                LOG.warn(
                    _LW('Get image %(id)s data failed: '
                        '%(err)s.') % {
                            'id': self.image.image_id,
                            'err': encodeutils.exception_to_unicode(e)
                        })
                err = e
        # tried all locations
        LOG.error(
            _LE('Glance tried all active locations to get data for '
                'image %s but all have failed.') % self.image.image_id)
        raise err
Ejemplo n.º 15
0
    def cache_tee_iter(self, image_id, image_iter, image_checksum):
        try:
            current_checksum = hashlib.md5()

            with self.driver.open_for_write(image_id) as cache_file:
                for chunk in image_iter:
                    try:
                        cache_file.write(chunk)
                    finally:
                        current_checksum.update(chunk)
                        yield chunk
                cache_file.flush()

                if (image_checksum and
                        image_checksum != current_checksum.hexdigest()):
                    msg = _("Checksum verification failed. Aborted "
                            "caching of image '%s'.") % image_id
                    raise exception.GlanceException(msg)

        except exception.GlanceException as e:
            with excutils.save_and_reraise_exception():
                # image_iter has given us bad, (size_checked_iter has found a
                # bad length), or corrupt data (checksum is wrong).
                LOG.exception(encodeutils.exception_to_unicode(e))
        except Exception as e:
            LOG.exception(_LE("Exception encountered while tee'ing "
                              "image '%(image_id)s' into cache: %(error)s. "
                              "Continuing with response.") %
                          {'image_id': image_id,
                           'error': encodeutils.exception_to_unicode(e)})

            # If no checksum provided continue responding even if
            # caching failed.
            for chunk in image_iter:
                yield chunk
Ejemplo n.º 16
0
    def get_data(self, offset=0, chunk_size=None):
        if not self.image.locations:
            # NOTE(mclaren): This is the only set of arguments
            # which work with this exception currently, see:
            # https://bugs.launchpad.net/glance-store/+bug/1501443
            # When the above glance_store bug is fixed we can
            # add a msg as usual.
            raise store.NotFound(image=None)
        err = None
        for loc in self.image.locations:
            try:
                data, size = self.store_api.get_from_backend(
                    loc['url'],
                    offset=offset,
                    chunk_size=chunk_size,
                    context=self.context)

                return data
            except Exception as e:
                LOG.warn(_LW('Get image %(id)s data failed: '
                             '%(err)s.')
                         % {'id': self.image.image_id,
                            'err': encodeutils.exception_to_unicode(e)})
                err = e
        # tried all locations
        LOG.error(_LE('Glance tried all active locations to get data for '
                      'image %s but all have failed.') % self.image.image_id)
        raise err
Ejemplo n.º 17
0
    def new_task_executor(self, context):
        try:
            # NOTE(flaper87): Backwards compatibility layer.
            # It'll allow us to provide a deprecation path to
            # users that are currently consuming the `eventlet`
            # executor.
            task_executor = CONF.task.task_executor
            if task_executor == 'eventlet':
                # NOTE(jokke): Making sure we do not log the deprecation
                # warning 1000 times or anything crazy like that.
                if not TaskExecutorFactory.eventlet_deprecation_warned:
                    msg = _LW("The `eventlet` executor has been deprecated. "
                              "Use `taskflow` instead.")
                    LOG.warn(msg)
                    TaskExecutorFactory.eventlet_deprecation_warned = True
                task_executor = 'taskflow'

            executor_cls = ('xmonitor.async.%s_executor.'
                            'TaskExecutor' % task_executor)
            LOG.debug("Loading %s executor", task_executor)
            executor = importutils.import_class(executor_cls)
            return executor(context, self.task_repo, self.image_repo,
                            self.image_factory)
        except ImportError:
            with excutils.save_and_reraise_exception():
                LOG.exception(
                    _LE("Failed to load the %s executor provided "
                        "in the config.") % CONF.task.task_executor)
Ejemplo n.º 18
0
def safe_delete_from_backend(context, image_id, location):
    """
    Given a location, delete an image from the store and
    update location status to db.

    This function try to handle all known exceptions which might be raised
    by those calls on store and DB modules in its implementation.

    :param context: The request context
    :param image_id: The image identifier
    :param location: The image location entry
    """

    try:
        ret = store_api.delete_from_backend(location['url'], context=context)
        location['status'] = 'deleted'
        if 'id' in location:
            db_api.get_api().image_location_delete(context, image_id,
                                                   location['id'], 'deleted')
        return ret
    except store_api.NotFound:
        msg = _LW('Failed to delete image %s in store from URI') % image_id
        LOG.warn(msg)
    except store_api.StoreDeleteNotSupported as e:
        LOG.warn(encodeutils.exception_to_unicode(e))
    except store_api.UnsupportedBackend:
        exc_type = sys.exc_info()[0].__name__
        msg = (_LE('Failed to delete image %(image_id)s from store: %(exc)s') %
               dict(image_id=image_id, exc=exc_type))
        LOG.error(msg)
Ejemplo n.º 19
0
def safe_delete_from_backend(context, image_id, location):
    """
    Given a location, delete an image from the store and
    update location status to db.

    This function try to handle all known exceptions which might be raised
    by those calls on store and DB modules in its implementation.

    :param context: The request context
    :param image_id: The image identifier
    :param location: The image location entry
    """

    try:
        ret = store_api.delete_from_backend(location['url'], context=context)
        location['status'] = 'deleted'
        if 'id' in location:
            db_api.get_api().image_location_delete(context, image_id,
                                                   location['id'], 'deleted')
        return ret
    except store_api.NotFound:
        msg = _LW('Failed to delete image %s in store from URI') % image_id
        LOG.warn(msg)
    except store_api.StoreDeleteNotSupported as e:
        LOG.warn(encodeutils.exception_to_unicode(e))
    except store_api.UnsupportedBackend:
        exc_type = sys.exc_info()[0].__name__
        msg = (_LE('Failed to delete image %(image_id)s from store: %(exc)s') %
               dict(image_id=image_id, exc=exc_type))
        LOG.error(msg)
Ejemplo n.º 20
0
def _load_strategies():
    """Load all strategy modules."""
    modules = {}
    namespace = "xmonitor.common.image_location_strategy.modules"
    ex = stevedore.extension.ExtensionManager(namespace)
    for module_name in ex.names():
        try:
            mgr = stevedore.driver.DriverManager(namespace=namespace,
                                                 name=module_name,
                                                 invoke_on_load=False)

            # Obtain module name
            strategy_name = str(mgr.driver.get_strategy_name())
            if strategy_name in modules:
                msg = (_('%(strategy)s is registered as a module twice. '
                         '%(module)s is not being used.') % {
                             'strategy': strategy_name,
                             'module': module_name
                         })
                LOG.warn(msg)
            else:
                # Initialize strategy module
                mgr.driver.init()
                modules[strategy_name] = mgr.driver
        except Exception as e:
            LOG.error(
                _LE("Failed to load location strategy module "
                    "%(module)s: %(e)s") % {
                        'module': module_name,
                        'e': e
                    })
    return modules
def migrate_location_credentials(migrate_engine, to_quoted):
    """
    Migrate location credentials for swift uri's between the quoted
    and unquoted forms.

    :param migrate_engine: The configured db engine
    :param to_quoted: If True, migrate location credentials from
                      unquoted to quoted form.  If False, do the
                      reverse.
    """
    meta = sqlalchemy.schema.MetaData()
    meta.bind = migrate_engine

    images_table = sqlalchemy.Table('images', meta, autoload=True)

    images = list(images_table.select(images_table.c.location.startswith(
                                      'swift')).execute())

    for image in images:
        try:
            fixed_uri = legacy_parse_uri(image['location'], to_quoted)
            images_table.update().where(
                images_table.c.id == image['id']).values(
                    location=fixed_uri).execute()
        except exception.BadStoreUri as e:
            reason = encodeutils.exception_to_unicode(e)
            msg = _LE("Invalid store uri for image: %(image_id)s. "
                      "Details: %(reason)s") % {'image_id': image.id,
                                                'reason': reason}
            LOG.exception(msg)
            raise
Ejemplo n.º 22
0
def _load_strategies():
    """Load all strategy modules."""
    modules = {}
    namespace = "xmonitor.common.image_location_strategy.modules"
    ex = stevedore.extension.ExtensionManager(namespace)
    for module_name in ex.names():
        try:
            mgr = stevedore.driver.DriverManager(
                namespace=namespace,
                name=module_name,
                invoke_on_load=False)

            # Obtain module name
            strategy_name = str(mgr.driver.get_strategy_name())
            if strategy_name in modules:
                msg = (_('%(strategy)s is registered as a module twice. '
                         '%(module)s is not being used.') %
                       {'strategy': strategy_name, 'module': module_name})
                LOG.warn(msg)
            else:
                # Initialize strategy module
                mgr.driver.init()
                modules[strategy_name] = mgr.driver
        except Exception as e:
            LOG.error(_LE("Failed to load location strategy module "
                          "%(module)s: %(e)s") % {'module': module_name,
                                                  'e': e})
    return modules
Ejemplo n.º 23
0
    def execute(self, image_id):
        """Finishing the task flow

        :param image_id: Glance Image ID
        """
        task = script_utils.get_task(self.task_repo, self.task_id)
        if task is None:
            return
        try:
            task.succeed({'image_id': image_id})
        except Exception as e:
            # Note: The message string contains Error in it to indicate
            # in the task.message that it's a error message for the user.

            # TODO(nikhil): need to bring back save_and_reraise_exception when
            # necessary
            err_msg = ("Error: " + six.text_type(type(e)) + ': ' +
                       encodeutils.exception_to_unicode(e))
            log_msg = err_msg + _LE("Task ID %s") % task.task_id
            LOG.exception(log_msg)

            task.fail(err_msg)
        finally:
            self.task_repo.save(task)

        LOG.info(_LI("%(task_id)s of %(task_type)s completed"), {
            'task_id': self.task_id,
            'task_type': self.task_type
        })
Ejemplo n.º 24
0
    def process_response(self, resp):
        """
        We intercept the response coming back from the main
        images Resource, removing image file from the cache
        if necessary
        """
        status_code = self.get_status_code(resp)
        if not 200 <= status_code < 300:
            return resp

        try:
            (image_id, method, version) = self._fetch_request_info(
                resp.request)
        except TypeError:
            return resp

        if method == 'GET' and status_code == 204:
            # Bugfix:1251055 - Don't cache non-existent image files.
            # NOTE: Both GET for an image without locations and DELETE return
            # 204 but DELETE should be processed.
            return resp

        method_str = '_process_%s_response' % method
        try:
            process_response_method = getattr(self, method_str)
        except AttributeError:
            LOG.error(_LE('could not find %s') % method_str)
            # Nothing to do here, move along
            return resp
        else:
            return process_response_method(resp, image_id, version=version)
Ejemplo n.º 25
0
    def execute(self, image_id):
        """Finishing the task flow

        :param image_id: Glance Image ID
        """
        task = script_utils.get_task(self.task_repo, self.task_id)
        if task is None:
            return
        try:
            task.succeed({'image_id': image_id})
        except Exception as e:
            # Note: The message string contains Error in it to indicate
            # in the task.message that it's a error message for the user.

            # TODO(nikhil): need to bring back save_and_reraise_exception when
            # necessary
            err_msg = ("Error: " + six.text_type(type(e)) + ': ' +
                       encodeutils.exception_to_unicode(e))
            log_msg = err_msg + _LE("Task ID %s") % task.task_id
            LOG.exception(log_msg)

            task.fail(err_msg)
        finally:
            self.task_repo.save(task)

        LOG.info(_LI("%(task_id)s of %(task_type)s completed"),
                 {'task_id': self.task_id, 'task_type': self.task_type})
Ejemplo n.º 26
0
    def new_task_executor(self, context):
        try:
            # NOTE(flaper87): Backwards compatibility layer.
            # It'll allow us to provide a deprecation path to
            # users that are currently consuming the `eventlet`
            # executor.
            task_executor = CONF.task.task_executor
            if task_executor == 'eventlet':
                # NOTE(jokke): Making sure we do not log the deprecation
                # warning 1000 times or anything crazy like that.
                if not TaskExecutorFactory.eventlet_deprecation_warned:
                    msg = _LW("The `eventlet` executor has been deprecated. "
                              "Use `taskflow` instead.")
                    LOG.warn(msg)
                    TaskExecutorFactory.eventlet_deprecation_warned = True
                task_executor = 'taskflow'

            executor_cls = ('xmonitor.async.%s_executor.'
                            'TaskExecutor' % task_executor)
            LOG.debug("Loading %s executor", task_executor)
            executor = importutils.import_class(executor_cls)
            return executor(context,
                            self.task_repo,
                            self.image_repo,
                            self.image_factory)
        except ImportError:
            with excutils.save_and_reraise_exception():
                LOG.exception(_LE("Failed to load the %s executor provided "
                                  "in the config.") % CONF.task.task_executor)
Ejemplo n.º 27
0
    def _run(self, task_id, task_type):
        LOG.debug('Taskflow executor picked up the execution of task ID '
                  '%(task_id)s of task type '
                  '%(task_type)s', {'task_id': task_id,
                                    'task_type': task_type})

        task = script_utils.get_task(self.task_repo, task_id)
        if task is None:
            # NOTE: This happens if task is not found in the database. In
            # such cases, there is no way to update the task status so,
            # it's ignored here.
            return

        flow = self._get_flow(task)
        executor = self._fetch_an_executor()
        try:
            engine = engines.load(
                flow,
                engine=CONF.taskflow_executor.engine_mode, executor=executor,
                max_workers=CONF.taskflow_executor.max_workers)
            with llistener.DynamicLoggingListener(engine, log=LOG):
                engine.run()
        except Exception as exc:
            with excutils.save_and_reraise_exception():
                LOG.error(_LE('Failed to execute task %(task_id)s: %(exc)s') %
                          {'task_id': task_id,
                           'exc': encodeutils.exception_to_unicode(exc)})
                # TODO(sabari): Check for specific exceptions and update the
                # task failure message.
                task.fail(_('Task failed due to Internal Error'))
                self.task_repo.save(task)
        finally:
            if executor is not None:
                executor.shutdown()
Ejemplo n.º 28
0
 def begin_processing(self, task_id):
     try:
         super(TaskExecutor, self).begin_processing(task_id)
     except exception.ImportTaskError as exc:
         LOG.error(_LE('Failed to execute task %(task_id)s: %(exc)s') %
                   {'task_id': task_id, 'exc': exc.msg})
         task = self.task_repo.get(task_id)
         task.fail(exc.msg)
         self.task_repo.save(task)
Ejemplo n.º 29
0
 def _compile_rule(self, rule):
     try:
         return re.compile(rule)
     except Exception as e:
         msg = (_LE("Encountered a malformed property protection rule"
                    " %(rule)s: %(error)s.") % {'rule': rule,
                                                'error': e})
         LOG.error(msg)
         raise InvalidPropProtectConf()
Ejemplo n.º 30
0
    def revert(self, image_id, result, **kwargs):
        if isinstance(result, failure.Failure):
            LOG.exception(_LE('Task: %(task_id)s failed to import image '
                              '%(image_id)s to the filesystem.') %
                          {'task_id': self.task_id, 'image_id': image_id})
            return

        if os.path.exists(result.split("file://")[-1]):
            store_api.delete_from_backend(result)
Ejemplo n.º 31
0
 def _compile_rule(self, rule):
     try:
         return re.compile(rule)
     except Exception as e:
         msg = (_LE("Encountered a malformed property protection rule"
                    " %(rule)s: %(error)s.") % {
                        'rule': rule,
                        'error': e
                    })
         LOG.error(msg)
         raise InvalidPropProtectConf()
Ejemplo n.º 32
0
def db_load_metadefs(engine,
                     metadata_path=None,
                     merge=False,
                     prefer_new=False,
                     overwrite=False):
    meta = MetaData()
    meta.bind = engine

    if not merge and (prefer_new or overwrite):
        LOG.error(
            _LE("To use --prefer_new or --overwrite you need to combine "
                "of these options with --merge option."))
        return

    if prefer_new and overwrite and merge:
        LOG.error(
            _LE("Please provide no more than one option from this list: "
                "--prefer_new, --overwrite"))
        return

    _populate_metadata(meta, metadata_path, merge, prefer_new, overwrite)
Ejemplo n.º 33
0
 def _cleanup_namespace(self, namespace_repo, namespace, namespace_created):
     if namespace_created:
         try:
             namespace_obj = namespace_repo.get(namespace.namespace)
             namespace_obj.delete()
             namespace_repo.remove(namespace_obj)
             LOG.debug("Cleaned up namespace %(namespace)s ",
                       {'namespace': namespace.namespace})
         except exception:
             msg = (_LE("Failed to delete namespace %(namespace)s ") %
                    {'namespace': namespace.namespace})
             LOG.error(msg)
Ejemplo n.º 34
0
    def revert(self, image_id, result, **kwargs):
        if isinstance(result, failure.Failure):
            LOG.exception(
                _LE('Task: %(task_id)s failed to import image '
                    '%(image_id)s to the filesystem.') % {
                        'task_id': self.task_id,
                        'image_id': image_id
                    })
            return

        if os.path.exists(result.split("file://")[-1]):
            store_api.delete_from_backend(result)
Ejemplo n.º 35
0
 def _verify_and_respawn_children(self, pid, status):
     if len(self.stale_children) == 0:
         LOG.debug('No stale children')
     if os.WIFEXITED(status) and os.WEXITSTATUS(status) != 0:
         LOG.error(
             _LE('Not respawning child %d, cannot '
                 'recover from termination') % pid)
         if not self.children and not self.stale_children:
             LOG.info(_LI('All workers have terminated. Exiting'))
             self.running = False
     else:
         if len(self.children) < get_num_workers():
             self.run_child()
Ejemplo n.º 36
0
 def _load_config(self):
     try:
         conf_file = CONF.find_file(CONF.swift_store_config_file)
         CONFIG.read(conf_file)
     except Exception as e:
         msg = (_LE("swift config file %(conf_file)s:%(exc)s not found") %
                {'conf_file': CONF.swift_store_config_file, 'exc': e})
         LOG.error(msg)
         raise exception.InvalidSwiftStoreConfiguration()
     account_params = {}
     account_references = CONFIG.sections()
     for ref in account_references:
         reference = {}
         try:
             reference['auth_address'] = CONFIG.get(ref, 'auth_address')
             reference['user'] = CONFIG.get(ref, 'user')
             reference['key'] = CONFIG.get(ref, 'key')
             account_params[ref] = reference
         except (ValueError, SyntaxError, configparser.NoOptionError) as e:
             LOG.exception(_LE("Invalid format of swift store config "
                               "cfg"))
     return account_params
Ejemplo n.º 37
0
 def _cleanup_namespace(self, namespace_repo, namespace, namespace_created):
     if namespace_created:
         try:
             namespace_obj = namespace_repo.get(namespace.namespace)
             namespace_obj.delete()
             namespace_repo.remove(namespace_obj)
             LOG.debug("Cleaned up namespace %(namespace)s ",
                       {'namespace': namespace.namespace})
         except exception:
             msg = (_LE("Failed to delete namespace %(namespace)s ") % {
                 'namespace': namespace.namespace
             })
             LOG.error(msg)
Ejemplo n.º 38
0
def run_task(task_id,
             task_type,
             context,
             task_repo=None,
             image_repo=None,
             image_factory=None):
    # TODO(nikhil): if task_repo is None get new task repo
    # TODO(nikhil): if image_repo is None get new image repo
    # TODO(nikhil): if image_factory is None get new image factory
    LOG.info(
        _LI("Loading known task scripts for task_id %(task_id)s "
            "of type %(task_type)s"), {
                'task_id': task_id,
                'task_type': task_type
            })
    if task_type == 'import':
        image_import.run(task_id, context, task_repo, image_repo,
                         image_factory)

    else:
        msg = _LE("This task type %(task_type)s is not supported by the "
                  "current deployment of Glance. Please refer the "
                  "documentation provided by OpenStack or your operator "
                  "for more information.") % {
                      'task_type': task_type
                  }
        LOG.error(msg)
        task = task_repo.get(task_id)
        task.fail(msg)
        if task_repo:
            task_repo.save(task)
        else:
            LOG.error(
                _LE("Failed to save task %(task_id)s in DB as task_repo "
                    "is %(task_repo)s"), {
                        "task_id": task_id,
                        "task_repo": task_repo
                    })
Ejemplo n.º 39
0
def get_task(task_repo, task_id):
    """Gets a TaskProxy object.

    :param task_repo: TaskRepo object used to perform DB operations
    :param task_id: ID of the Task
    """
    task = None
    try:
        task = task_repo.get(task_id)
    except exception.NotFound:
        msg = _LE('Task not found for task_id %s') % task_id
        LOG.exception(msg)

    return task
Ejemplo n.º 40
0
    def _get_delete_jobs(self):
        try:
            records = self.db_queue.get_all_locations()
        except Exception as err:
            LOG.error(_LE("Can not get scrub jobs from queue: %s") %
                      encodeutils.exception_to_unicode(err))
            return {}

        delete_jobs = {}
        for image_id, loc_id, loc_uri in records:
            if image_id not in delete_jobs:
                delete_jobs[image_id] = []
            delete_jobs[image_id].append((image_id, loc_id, loc_uri))
        return delete_jobs
Ejemplo n.º 41
0
def get_task(task_repo, task_id):
    """Gets a TaskProxy object.

    :param task_repo: TaskRepo object used to perform DB operations
    :param task_id: ID of the Task
    """
    task = None
    try:
        task = task_repo.get(task_id)
    except exception.NotFound:
        msg = _LE('Task not found for task_id %s') % task_id
        LOG.exception(msg)

    return task
Ejemplo n.º 42
0
    def create(self, req, body):
        """Registers a new image with the registry.

        :param req: wsgi Request object
        :param body: Dictionary of information about the image

        :returns: The newly-created image information as a mapping,
            which will include the newly-created image's internal id
            in the 'id' field
        """
        image_data = body['image']

        # Ensure the image has a status set
        image_data.setdefault('status', 'active')

        # Set up the image owner
        if not req.context.is_admin or 'owner' not in image_data:
            image_data['owner'] = req.context.owner

        image_id = image_data.get('id')
        if image_id and not uuidutils.is_uuid_like(image_id):
            LOG.info(
                _LI("Rejecting image creation request for invalid image "
                    "id '%(bad_id)s'"), {'bad_id': image_id})
            msg = _("Invalid image id format")
            return exc.HTTPBadRequest(explanation=msg)

        if 'location' in image_data:
            image_data['locations'] = [image_data.pop('location')]

        try:
            image_data = _normalize_image_location_for_db(image_data)
            image_data = self.db_api.image_create(req.context, image_data)
            image_data = dict(image=make_image_dict(image_data))
            LOG.info(_LI("Successfully created image %(id)s"),
                     {'id': image_data['image']['id']})
            return image_data
        except exception.Duplicate:
            msg = _("Image with identifier %s already exists!") % image_id
            LOG.warn(msg)
            return exc.HTTPConflict(msg)
        except exception.Invalid as e:
            msg = (_("Failed to add image metadata. "
                     "Got error: %s") % encodeutils.exception_to_unicode(e))
            LOG.error(msg)
            return exc.HTTPBadRequest(msg)
        except Exception:
            LOG.exception(_LE("Unable to create image %s"), image_id)
            raise
Ejemplo n.º 43
0
    def _restore(self, artifact_repo, artifact):
        """Restore the artifact to queued status.

        :param artifact_repo: The instance of ArtifactRepo
        :param artifact: The artifact will be restored
        """
        try:
            if artifact_repo and artifact:
                artifact.state = 'creating'
                artifact_repo.save(artifact)
        except Exception as e:
            msg = (_LE("Unable to restore artifact %(artifact_id)s: %(e)s") %
                   {'artifact_id': artifact.id,
                    'e': encodeutils.exception_to_unicode(e)})
            LOG.exception(msg)
Ejemplo n.º 44
0
def cooperative_iter(iter):
    """
    Return an iterator which schedules after each
    iteration. This can prevent eventlet thread starvation.

    :param iter: an iterator to wrap
    """
    try:
        for chunk in iter:
            sleep(0)
            yield chunk
    except Exception as err:
        with excutils.save_and_reraise_exception():
            msg = _LE("Error: cooperative_iter exception %s") % err
            LOG.error(msg)
Ejemplo n.º 45
0
def safe_kill(req, image_id, from_state):
    """
    Mark image killed without raising exceptions if it fails.

    Since _kill is meant to be called from exceptions handlers, it should
    not raise itself, rather it should just log its error.

    :param req: The WSGI/Webob Request object
    :param image_id: Opaque image identifier
    :param from_state: Permitted current status for transition to 'killed'
    """
    try:
        _kill(req, image_id, from_state)
    except Exception:
        LOG.exception(_LE("Unable to kill image %(id)s: ") % {'id': image_id})
Ejemplo n.º 46
0
def safe_kill(req, image_id, from_state):
    """
    Mark image killed without raising exceptions if it fails.

    Since _kill is meant to be called from exceptions handlers, it should
    not raise itself, rather it should just log its error.

    :param req: The WSGI/Webob Request object
    :param image_id: Opaque image identifier
    :param from_state: Permitted current status for transition to 'killed'
    """
    try:
        _kill(req, image_id, from_state)
    except Exception:
        LOG.exception(_LE("Unable to kill image %(id)s: ") % {'id': image_id})
Ejemplo n.º 47
0
    def _delete(self, image_repo, image):
        """Delete the image.

        :param image_repo: The instance of ImageRepo
        :param image: The image that will be deleted
        """
        try:
            if image_repo and image:
                image.status = 'killed'
                image_repo.save(image)
        except Exception as e:
            msg = (_LE("Unable to delete image %(image_id)s: %(e)s") %
                   {'image_id': image.image_id,
                    'e': encodeutils.exception_to_unicode(e)})
            LOG.exception(msg)
Ejemplo n.º 48
0
    def create(self, req, body):
        """Registers a new image with the registry.

        :param req: wsgi Request object
        :param body: Dictionary of information about the image

        :returns: The newly-created image information as a mapping,
            which will include the newly-created image's internal id
            in the 'id' field
        """
        image_data = body['image']

        # Ensure the image has a status set
        image_data.setdefault('status', 'active')

        # Set up the image owner
        if not req.context.is_admin or 'owner' not in image_data:
            image_data['owner'] = req.context.owner

        image_id = image_data.get('id')
        if image_id and not uuidutils.is_uuid_like(image_id):
            LOG.info(_LI("Rejecting image creation request for invalid image "
                         "id '%(bad_id)s'"), {'bad_id': image_id})
            msg = _("Invalid image id format")
            return exc.HTTPBadRequest(explanation=msg)

        if 'location' in image_data:
            image_data['locations'] = [image_data.pop('location')]

        try:
            image_data = _normalize_image_location_for_db(image_data)
            image_data = self.db_api.image_create(req.context, image_data)
            image_data = dict(image=make_image_dict(image_data))
            LOG.info(_LI("Successfully created image %(id)s"),
                     {'id': image_data['image']['id']})
            return image_data
        except exception.Duplicate:
            msg = _("Image with identifier %s already exists!") % image_id
            LOG.warn(msg)
            return exc.HTTPConflict(msg)
        except exception.Invalid as e:
            msg = (_("Failed to add image metadata. "
                     "Got error: %s") % encodeutils.exception_to_unicode(e))
            LOG.error(msg)
            return exc.HTTPBadRequest(msg)
        except Exception:
            LOG.exception(_LE("Unable to create image %s"), image_id)
            raise
Ejemplo n.º 49
0
    def _restore(self, image_repo, image):
        """
        Restore the image to queued status.

        :param image_repo: The instance of ImageRepo
        :param image: The image will be restored
        """
        try:
            if image_repo and image:
                image.status = 'queued'
                image_repo.save(image)
        except Exception as e:
            msg = (_LE("Unable to restore image %(image_id)s: %(e)s") %
                   {'image_id': image.image_id,
                    'e': encodeutils.exception_to_unicode(e)})
            LOG.exception(msg)
Ejemplo n.º 50
0
    def _delete(self, image_repo, image):
        """Delete the image.

        :param image_repo: The instance of ImageRepo
        :param image: The image that will be deleted
        """
        try:
            if image_repo and image:
                image.status = 'killed'
                image_repo.save(image)
        except Exception as e:
            msg = (_LE("Unable to delete image %(image_id)s: %(e)s") % {
                'image_id': image.image_id,
                'e': encodeutils.exception_to_unicode(e)
            })
            LOG.exception(msg)
Ejemplo n.º 51
0
    def _restore(self, artifact_repo, artifact):
        """Restore the artifact to queued status.

        :param artifact_repo: The instance of ArtifactRepo
        :param artifact: The artifact will be restored
        """
        try:
            if artifact_repo and artifact:
                artifact.state = 'creating'
                artifact_repo.save(artifact)
        except Exception as e:
            msg = (_LE("Unable to restore artifact %(artifact_id)s: %(e)s") % {
                'artifact_id': artifact.id,
                'e': encodeutils.exception_to_unicode(e)
            })
            LOG.exception(msg)
Ejemplo n.º 52
0
    def __init__(self, namespace):
        self.mgr = enabled.EnabledExtensionManager(
            check_func=self._gen_check_func(),
            namespace=namespace,
            propagate_map_exceptions=True,
            on_load_failure_callback=self._on_load_failure)
        self.plugin_map = {'by_typename': {},
                           'by_endpoint': {}}

        def _add_extension(ext):
            """
            Plugins can be loaded as entry_point=single plugin and
            entry_point=PLUGIN_LIST, where PLUGIN_LIST is a python variable
            holding a list of plugins
            """
            def _load_one(plugin):
                if issubclass(plugin, definitions.ArtifactType):
                    # make sure that have correct plugin name
                    art_name = plugin.metadata.type_name
                    if art_name != ext.name:
                        raise exception.ArtifactNonMatchingTypeName(
                            name=art_name, plugin=ext.name)
                    # make sure that no plugin with the same name and version
                    # already exists
                    exists = self._get_plugins(ext.name)
                    new_tv = plugin.metadata.type_version
                    if any(e.metadata.type_version == new_tv for e in exists):
                        raise exception.ArtifactDuplicateNameTypeVersion()
                self._add_plugin("by_endpoint", plugin.metadata.endpoint,
                                 plugin)
                self._add_plugin("by_typename", plugin.metadata.type_name,
                                 plugin)

            if isinstance(ext.plugin, list):
                for p in ext.plugin:
                    _load_one(p)
            else:
                _load_one(ext.plugin)

        # (ivasilevskaya) that looks pretty bad as RuntimeError is too general,
        # but stevedore has awful exception wrapping with no specific class
        # for this very case (no extensions for given namespace found)
        try:
            self.mgr.map(_add_extension)
        except RuntimeError as re:
            LOG.error(_LE("Unable to load artifacts: %s") % re.message)