185 lines
6.3 KiB
Python
185 lines
6.3 KiB
Python
# Copyright 2014 OpenStack Foundation
|
|
# 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 futurist
|
|
from oslo_log import log as logging
|
|
|
|
from glance.i18n import _LE
|
|
|
|
|
|
LOG = logging.getLogger(__name__)
|
|
|
|
|
|
class TaskExecutor(object):
|
|
"""Base class for Asynchronous task executors. It does not support the
|
|
execution mechanism.
|
|
|
|
Provisions the extensible classes with necessary variables to utilize
|
|
important Glance modules like, context, task_repo, image_repo,
|
|
image_factory.
|
|
|
|
Note:
|
|
It also gives abstraction for the standard pre-processing and
|
|
post-processing operations to be executed by a task. These may include
|
|
validation checks, security checks, introspection, error handling etc.
|
|
The aim is to give developers an abstract sense of the execution
|
|
pipeline logic.
|
|
|
|
Args:
|
|
context: glance.context.RequestContext object for AuthZ and AuthN
|
|
checks
|
|
task_repo: glance.db.TaskRepo object which acts as a translator for
|
|
glance.domain.Task and glance.domain.TaskStub objects
|
|
into ORM semantics
|
|
image_repo: glance.db.ImageRepo object which acts as a translator for
|
|
glance.domain.Image object into ORM semantics
|
|
image_factory: glance.domain.ImageFactory object to be used for
|
|
creating new images for certain types of tasks viz. import, cloning
|
|
admin_repo: glance.db.ImageRepo object which acts as a translator for
|
|
glance.domain.Image object into ORM semantics, but with an admin
|
|
context (optional)
|
|
"""
|
|
|
|
def __init__(self, context, task_repo, image_repo, image_factory,
|
|
admin_repo=None):
|
|
self.context = context
|
|
self.task_repo = task_repo
|
|
self.image_repo = image_repo
|
|
self.image_factory = image_factory
|
|
self.admin_repo = admin_repo
|
|
|
|
def begin_processing(self, task_id):
|
|
task = self.task_repo.get(task_id)
|
|
task.begin_processing()
|
|
self.task_repo.save(task)
|
|
|
|
# start running
|
|
self._run(task_id, task.type)
|
|
|
|
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)
|
|
|
|
|
|
class ThreadPoolModel(object):
|
|
"""Base class for an abstract ThreadPool.
|
|
|
|
Do not instantiate this directly, use one of the concrete
|
|
implementations.
|
|
"""
|
|
|
|
DEFAULTSIZE = 1
|
|
|
|
@staticmethod
|
|
def get_threadpool_executor_class():
|
|
"""Returns a futurist.ThreadPoolExecutor class."""
|
|
pass
|
|
|
|
def __init__(self, size=None):
|
|
if size is None:
|
|
size = self.DEFAULTSIZE
|
|
|
|
threadpool_cls = self.get_threadpool_executor_class()
|
|
LOG.debug('Creating threadpool model %r with size %i',
|
|
threadpool_cls.__name__, size)
|
|
self.pool = threadpool_cls(size)
|
|
|
|
def spawn(self, fn, *args, **kwargs):
|
|
"""Spawn a function with args using the thread pool."""
|
|
LOG.debug('Spawning with %s: %s(%s, %s)' % (
|
|
self.get_threadpool_executor_class().__name__,
|
|
fn, args, kwargs))
|
|
return self.pool.submit(fn, *args, **kwargs)
|
|
|
|
|
|
class EventletThreadPoolModel(ThreadPoolModel):
|
|
"""A ThreadPoolModel suitable for use with evenlet/greenthreads."""
|
|
DEFAULTSIZE = 1024
|
|
|
|
@staticmethod
|
|
def get_threadpool_executor_class():
|
|
return futurist.GreenThreadPoolExecutor
|
|
|
|
|
|
class NativeThreadPoolModel(ThreadPoolModel):
|
|
"""A ThreadPoolModel suitable for use with native threads."""
|
|
DEFAULTSIZE = 16
|
|
|
|
@staticmethod
|
|
def get_threadpool_executor_class():
|
|
return futurist.ThreadPoolExecutor
|
|
|
|
|
|
_THREADPOOL_MODEL = None
|
|
|
|
|
|
def set_threadpool_model(thread_type):
|
|
"""Set the system-wide threadpool model.
|
|
|
|
This sets the type of ThreadPoolModel to use globally in the process.
|
|
It should be called very early in init, and only once.
|
|
|
|
:param thread_type: A string indicating the threading type in use,
|
|
either "eventlet" or "native"
|
|
:raises: RuntimeError if the model is already set or some thread_type
|
|
other than one of the supported ones is provided.
|
|
"""
|
|
global _THREADPOOL_MODEL
|
|
|
|
if thread_type == 'native':
|
|
model = NativeThreadPoolModel
|
|
elif thread_type == 'eventlet':
|
|
model = EventletThreadPoolModel
|
|
else:
|
|
raise RuntimeError(
|
|
('Invalid thread type %r '
|
|
'(must be "native" or "eventlet")') % (thread_type))
|
|
|
|
if _THREADPOOL_MODEL is model:
|
|
# Re-setting the same model is fine...
|
|
return
|
|
|
|
if _THREADPOOL_MODEL is not None:
|
|
# ...changing it is not.
|
|
raise RuntimeError('Thread model is already set')
|
|
|
|
LOG.info('Threadpool model set to %r', model.__name__)
|
|
_THREADPOOL_MODEL = model
|
|
|
|
|
|
def get_threadpool_model():
|
|
"""Returns the system-wide threadpool model class.
|
|
|
|
This must be called after set_threadpool_model() whenever
|
|
some code needs to know what the threadpool implementation is.
|
|
|
|
This may only be called after set_threadpool_model() has been
|
|
called to set the desired threading mode. If it is called before
|
|
the model is set, it will raise AssertionError. This would likely
|
|
be the case if this got run in a test before the model was
|
|
initialized, or if glance modules that use threading were imported
|
|
and run from some other code without setting the model first.
|
|
|
|
:raises: AssertionError if the model has not yet been set.
|
|
"""
|
|
global _THREADPOOL_MODEL
|
|
assert _THREADPOOL_MODEL
|
|
return _THREADPOOL_MODEL
|