Merge "Add support for PartialTask list"

This commit is contained in:
Jenkins 2014-02-22 12:10:27 +00:00 committed by Gerrit Code Review
commit 7130d9fe18
17 changed files with 452 additions and 238 deletions

View File

@ -72,6 +72,13 @@ def proxy_task(context, task):
return ImmutableTaskProxy(task) return ImmutableTaskProxy(task)
def proxy_task_details(context, task, task_details):
if is_task_mutable(context, task):
return task_details
else:
return ImmutableTaskDetailsProxy(task_details)
class ImageRepoProxy(glance.domain.proxy.Repo): class ImageRepoProxy(glance.domain.proxy.Repo):
def __init__(self, image_repo, context): def __init__(self, image_repo, context):
@ -326,9 +333,7 @@ class ImmutableTaskProxy(object):
task_id = _immutable_attr('base', 'task_id') task_id = _immutable_attr('base', 'task_id')
type = _immutable_attr('base', 'type') type = _immutable_attr('base', 'type')
status = _immutable_attr('base', 'status') status = _immutable_attr('base', 'status')
input = _immutable_attr('base', 'input')
owner = _immutable_attr('base', 'owner') owner = _immutable_attr('base', 'owner')
message = _immutable_attr('base', 'message')
expires_at = _immutable_attr('base', 'expires_at') expires_at = _immutable_attr('base', 'expires_at')
created_at = _immutable_attr('base', 'created_at') created_at = _immutable_attr('base', 'created_at')
updated_at = _immutable_attr('base', 'updated_at') updated_at = _immutable_attr('base', 'updated_at')
@ -349,6 +354,15 @@ class ImmutableTaskProxy(object):
raise exception.Forbidden(message) raise exception.Forbidden(message)
class ImmutableTaskDetailsProxy(object):
def __init__(self, base):
self.base = base
input = _immutable_attr('base', 'input')
message = _immutable_attr('base', 'message')
result = _immutable_attr('base', 'result')
class ImageProxy(glance.domain.proxy.Image): class ImageProxy(glance.domain.proxy.Image):
def __init__(self, image, context): def __init__(self, image, context):
@ -372,6 +386,13 @@ class TaskProxy(glance.domain.proxy.Task):
super(TaskProxy, self).__init__(task) super(TaskProxy, self).__init__(task)
class TaskDetailsProxy(glance.domain.proxy.TaskDetails):
def __init__(self, task_details):
self.task_details = task_details
super(TaskDetailsProxy, self).__init__(task_details)
class TaskFactoryProxy(glance.domain.proxy.TaskFactory): class TaskFactoryProxy(glance.domain.proxy.TaskFactory):
def __init__(self, task_factory, context): def __init__(self, task_factory, context):
@ -379,9 +400,8 @@ class TaskFactoryProxy(glance.domain.proxy.TaskFactory):
self.context = context self.context = context
super(TaskFactoryProxy, self).__init__( super(TaskFactoryProxy, self).__init__(
task_factory, task_factory,
proxy_class=TaskProxy, task_proxy_class=TaskProxy,
proxy_kwargs=None task_details_proxy_class=TaskDetailsProxy)
)
def new_task(self, **kwargs): def new_task(self, **kwargs):
owner = kwargs.get('owner', self.context.owner) owner = kwargs.get('owner', self.context.owner)
@ -397,17 +417,19 @@ class TaskFactoryProxy(glance.domain.proxy.TaskFactory):
raise exception.Forbidden(message % owner) raise exception.Forbidden(message % owner)
class TaskRepoProxy(glance.domain.proxy.Repo): class TaskRepoProxy(glance.domain.proxy.TaskRepo):
def __init__(self, task_repo, context): def __init__(self, task_repo, context):
self.task_repo = task_repo self.task_repo = task_repo
self.context = context self.context = context
super(TaskRepoProxy, self).__init__(task_repo) super(TaskRepoProxy, self).__init__(task_repo)
def get(self, task_id): def get_task_and_details(self, task_id):
task = self.task_repo.get(task_id) task, task_details = self.task_repo.get_task_and_details(task_id)
return proxy_task(self.context, task) return proxy_task(self.context, task), proxy_task_details(self.context,
task,
task_details)
def list(self, *args, **kwargs): def list_tasks(self, *args, **kwargs):
tasks = self.task_repo.list(*args, **kwargs) tasks = self.task_repo.list_tasks(*args, **kwargs)
return [proxy_task(self.context, t) for t in tasks] return [proxy_task(self.context, t) for t in tasks]

View File

@ -357,34 +357,44 @@ class TaskProxy(glance.domain.proxy.Task):
self.base.run(executor) self.base.run(executor)
class TaskRepoProxy(glance.domain.proxy.Repo): class TaskDetailsProxy(glance.domain.proxy.TaskDetails):
def __init__(self, task_repo, context, policy): def __init__(self, task_details, context, policy):
self.task_details = task_details
self.context = context self.context = context
self.policy = policy self.policy = policy
super(TaskDetailsProxy, self).__init__(task_details)
class TaskRepoProxy(glance.domain.proxy.TaskRepo):
def __init__(self, task_repo, context, task_policy):
self.context = context
self.policy = task_policy
self.task_repo = task_repo self.task_repo = task_repo
proxy_kwargs = {'context': self.context, 'policy': self.policy} proxy_kwargs = {'context': self.context, 'policy': self.policy}
super(TaskRepoProxy, self).__init__( super(TaskRepoProxy,
task_repo, self).__init__(task_repo,
item_proxy_class=TaskProxy, task_proxy_class=TaskProxy,
item_proxy_kwargs=proxy_kwargs task_proxy_kwargs=proxy_kwargs,
) task_details_proxy_class=TaskDetailsProxy,
task_details_proxy_kwargs=proxy_kwargs)
def get(self, task_id): def get_task_and_details(self, task_id):
self.policy.enforce(self.context, 'get_task', {}) self.policy.enforce(self.context, 'get_task', {})
return super(TaskRepoProxy, self).get(task_id) return super(TaskRepoProxy, self).get_task_and_details(task_id)
def list(self, *args, **kwargs): def list_tasks(self, *args, **kwargs):
self.policy.enforce(self.context, 'get_tasks', {}) self.policy.enforce(self.context, 'get_tasks', {})
return super(TaskRepoProxy, self).list(*args, **kwargs) return super(TaskRepoProxy, self).list_tasks(*args, **kwargs)
def add(self, task): def add(self, task, task_details=None):
self.policy.enforce(self.context, 'add_task', {}) self.policy.enforce(self.context, 'add_task', {})
return super(TaskRepoProxy, self).add(task) super(TaskRepoProxy, self).add(task, task_details)
def save(self, task): def save(self, task, task_details=None):
self.policy.enforce(self.context, 'modify_task', {}) self.policy.enforce(self.context, 'modify_task', {})
return super(TaskRepoProxy, self).save(task) super(TaskRepoProxy, self).save(task, task_details)
class TaskFactoryProxy(glance.domain.proxy.TaskFactory): class TaskFactoryProxy(glance.domain.proxy.TaskFactory):
@ -396,6 +406,7 @@ class TaskFactoryProxy(glance.domain.proxy.TaskFactory):
proxy_kwargs = {'context': self.context, 'policy': self.policy} proxy_kwargs = {'context': self.context, 'policy': self.policy}
super(TaskFactoryProxy, self).__init__( super(TaskFactoryProxy, self).__init__(
task_factory, task_factory,
proxy_class=TaskProxy, task_proxy_class=TaskProxy,
proxy_kwargs=proxy_kwargs task_proxy_kwargs=proxy_kwargs,
) task_details_proxy_class=TaskDetailsProxy,
task_details_proxy_kwargs=proxy_kwargs)

View File

@ -57,17 +57,19 @@ class TasksController(object):
live_time = CONF.task.task_time_to_live live_time = CONF.task.task_time_to_live
try: try:
new_task = task_factory.new_task(task_type=task['type'], new_task = task_factory.new_task(task_type=task['type'],
task_input=task['input'],
owner=req.context.owner, owner=req.context.owner,
task_time_to_live=live_time) task_time_to_live=live_time)
task_repo.add(new_task) new_task_details = task_factory.new_task_details(new_task.task_id,
task['input'])
task_repo.add(new_task, new_task_details)
except exception.Forbidden as e: except exception.Forbidden as e:
msg = (_("Forbidden to create task. Reason: %(reason)s") msg = (_("Forbidden to create task. Reason: %(reason)s")
% {'reason': unicode(e)}) % {'reason': unicode(e)})
LOG.info(msg) LOG.info(msg)
raise webob.exc.HTTPForbidden(explanation=unicode(e)) raise webob.exc.HTTPForbidden(explanation=unicode(e))
return new_task result = {'task': new_task, 'task_details': new_task_details}
return result
def index(self, req, marker=None, limit=None, sort_key='created_at', def index(self, req, marker=None, limit=None, sort_key='created_at',
sort_dir='desc', filters=None): sort_dir='desc', filters=None):
@ -82,7 +84,11 @@ class TasksController(object):
task_repo = self.gateway.get_task_repo(req.context) task_repo = self.gateway.get_task_repo(req.context)
try: try:
tasks = task_repo.list(marker, limit, sort_key, sort_dir, filters) tasks = task_repo.list_tasks(marker,
limit,
sort_key,
sort_dir,
filters)
if len(tasks) != 0 and len(tasks) == limit: if len(tasks) != 0 and len(tasks) == limit:
result['next_marker'] = tasks[-1].task_id result['next_marker'] = tasks[-1].task_id
except (exception.NotFound, exception.InvalidSortKey, except (exception.NotFound, exception.InvalidSortKey,
@ -98,7 +104,7 @@ class TasksController(object):
def get(self, req, task_id): def get(self, req, task_id):
try: try:
task_repo = self.gateway.get_task_repo(req.context) task_repo = self.gateway.get_task_repo(req.context)
task = task_repo.get(task_id) task, task_details = task_repo.get_task_and_details(task_id)
except exception.NotFound as e: except exception.NotFound as e:
msg = (_("Failed to find task %(task_id)s. Reason: %(reason)s") % msg = (_("Failed to find task %(task_id)s. Reason: %(reason)s") %
{'task_id': task_id, 'reason': unicode(e)}) {'task_id': task_id, 'reason': unicode(e)})
@ -109,7 +115,8 @@ class TasksController(object):
{'task_id': task_id, 'reason': unicode(e)}) {'task_id': task_id, 'reason': unicode(e)})
LOG.info(msg) LOG.info(msg)
raise webob.exc.HTTPForbidden(explanation=unicode(e)) raise webob.exc.HTTPForbidden(explanation=unicode(e))
return task result = {'task': task, 'task_details': task_details}
return result
class RequestDeserializer(wsgi.JSONRequestDeserializer): class RequestDeserializer(wsgi.JSONRequestDeserializer):
@ -226,11 +233,15 @@ class ResponseSerializer(wsgi.JSONResponseSerializer):
self.partial_task_schema = partial_task_schema \ self.partial_task_schema = partial_task_schema \
or _get_partial_task_schema() or _get_partial_task_schema()
def _format_task(self, task, schema): def _format_task(self, schema, task, task_details=None):
task_view = {} task_view = {}
attributes = ['type', 'status', 'input', 'result', 'owner', 'message'] task_attributes = ['type', 'status', 'owner']
for key in attributes: task_details_attributes = ['input', 'result', 'message']
for key in task_attributes:
task_view[key] = getattr(task, key) task_view[key] = getattr(task, key)
if task_details:
for key in task_details_attributes:
task_view[key] = getattr(task_details, key)
task_view['id'] = task.task_id task_view['id'] = task.task_id
if task.expires_at: if task.expires_at:
task_view['expires_at'] = timeutils.isotime(task.expires_at) task_view['expires_at'] = timeutils.isotime(task.expires_at)
@ -241,12 +252,19 @@ class ResponseSerializer(wsgi.JSONResponseSerializer):
task_view = schema.filter(task_view) # domain task_view = schema.filter(task_view) # domain
return task_view return task_view
def create(self, response, task): def create(self, response, result):
response.status_int = 201 response.status_int = 201
self.get(response, task) task = result['task']
task_details = result['task_details']
self._get(response, task, task_details)
def get(self, response, task): def get(self, response, result):
task_view = self._format_task(task, self.task_schema) task = result['task']
task_details = result['task_details']
self._get(response, task, task_details)
def _get(self, response, task, task_details):
task_view = self._format_task(self.task_schema, task, task_details)
body = json.dumps(task_view, ensure_ascii=False) body = json.dumps(task_view, ensure_ascii=False)
response.unicode_body = unicode(body) response.unicode_body = unicode(body)
response.content_type = 'application/json' response.content_type = 'application/json'
@ -256,8 +274,8 @@ class ResponseSerializer(wsgi.JSONResponseSerializer):
params.pop('marker', None) params.pop('marker', None)
query = urllib.urlencode(params) query = urllib.urlencode(params)
body = { body = {
'tasks': [self._format_task(i, self.partial_task_schema) 'tasks': [self._format_task(self.partial_task_schema, task)
for i in result['tasks']], for task in result['tasks']],
'first': '/v2/tasks', 'first': '/v2/tasks',
'schema': '/v2/schemas/tasks', 'schema': '/v2/schemas/tasks',
} }

View File

@ -286,47 +286,62 @@ class TaskRepo(object):
def _format_task_from_db(self, db_task): def _format_task_from_db(self, db_task):
return glance.domain.Task( return glance.domain.Task(
task_id=db_task['id'], task_id=db_task['id'],
type=db_task['type'], task_type=db_task['type'],
status=db_task['status'], status=db_task['status'],
input=db_task['input'],
result=db_task['result'],
owner=db_task['owner'], owner=db_task['owner'],
message=db_task['message'],
expires_at=db_task['expires_at'], expires_at=db_task['expires_at'],
created_at=db_task['created_at'], created_at=db_task['created_at'],
updated_at=db_task['updated_at'], updated_at=db_task['updated_at'],
) )
def _format_task_to_db(self, task): def _format_task_details_from_db(self, db_task):
return {'id': task.task_id, return glance.domain.TaskDetails(
task_id=db_task['id'],
task_input=db_task['input'],
result=db_task['result'],
message=db_task['message'],
)
def _format_task_to_db(self, task, task_details=None):
task = {'id': task.task_id,
'type': task.type, 'type': task.type,
'status': task.status, 'status': task.status,
'input': task.input, 'input': None,
'result': task.result, 'result': None,
'owner': task.owner, 'owner': task.owner,
'message': task.message, 'message': None,
'expires_at': task.expires_at, 'expires_at': task.expires_at,
'created_at': task.created_at, 'created_at': task.created_at,
'updated_at': task.updated_at} 'updated_at': task.updated_at}
if task_details is not None:
task.update({
'input': task_details.input,
'result': task_details.result,
'message': task_details.message,
})
return task
def __init__(self, context, db_api): def __init__(self, context, db_api):
self.context = context self.context = context
self.db_api = db_api self.db_api = db_api
def get(self, task_id): def get_task_and_details(self, task_id):
try: try:
db_api_task = self.db_api.task_get(self.context, task_id) db_api_task = self.db_api.task_get(self.context, task_id)
except (exception.NotFound, exception.Forbidden): except (exception.NotFound, exception.Forbidden):
msg = _('Could not find task %s') % task_id msg = _('Could not find task %s') % task_id
raise exception.NotFound(msg) raise exception.NotFound(msg)
return self._format_task_from_db(db_api_task) return (self._format_task_from_db(db_api_task),
self._format_task_details_from_db(db_api_task))
def list(self, def list_tasks(self,
marker=None, marker=None,
limit=None, limit=None,
sort_key='created_at', sort_key='created_at',
sort_dir='desc', sort_dir='desc',
filters=None): filters=None):
db_api_tasks = self.db_api.task_get_all(self.context, db_api_tasks = self.db_api.task_get_all(self.context,
filters=filters, filters=filters,
marker=marker, marker=marker,
@ -335,8 +350,8 @@ class TaskRepo(object):
sort_dir=sort_dir) sort_dir=sort_dir)
return [self._format_task_from_db(task) for task in db_api_tasks] return [self._format_task_from_db(task) for task in db_api_tasks]
def save(self, task): def save(self, task, task_details=None):
task_values = self._format_task_to_db(task) task_values = self._format_task_to_db(task, task_details)
try: try:
updated_values = self.db_api.task_update(self.context, updated_values = self.db_api.task_update(self.context,
task.task_id, task.task_id,
@ -346,8 +361,8 @@ class TaskRepo(object):
raise exception.NotFound(msg) raise exception.NotFound(msg)
task.updated_at = updated_values['updated_at'] task.updated_at = updated_values['updated_at']
def add(self, task): def add(self, task, task_details=None):
task_values = self._format_task_to_db(task) task_values = self._format_task_to_db(task, task_details)
updated_values = self.db_api.task_create(self.context, task_values) updated_values = self.db_api.task_create(self.context, task_values)
task.created_at = updated_values['created_at'] task.created_at = updated_values['created_at']
task.updated_at = updated_values['updated_at'] task.updated_at = updated_values['updated_at']

View File

@ -814,8 +814,7 @@ def task_get_all(context, filters=None, marker=None, limit=None,
filtered_tasks = [] filtered_tasks = []
for task in tasks: for task in tasks:
task_info = DATA['task_info'][task['id']] filtered_tasks.append(_format_task_from_db(task, task_info_ref=None))
filtered_tasks.append(_format_task_from_db(task, task_info))
return filtered_tasks return filtered_tasks

View File

@ -1153,8 +1153,7 @@ def task_get_all(context, filters=None, marker=None, limit=None,
filters = filters or {} filters = filters or {}
session = _get_session() session = _get_session()
query = session.query(models.Task)\ query = session.query(models.Task)
.options(sa_orm.joinedload(models.Task.info))
if not (context.is_admin or admin_as_user == True) and \ if not (context.is_admin or admin_as_user == True) and \
context.owner is not None: context.owner is not None:
@ -1191,11 +1190,7 @@ def task_get_all(context, filters=None, marker=None, limit=None,
tasks = [] tasks = []
for task_ref in task_refs: for task_ref in task_refs:
# NOTE(venkatesh): call to task_ref.info does not make any tasks.append(_task_format(task_ref, task_info_ref=None))
# separate query call to fetch task info as it has been
# eagerly loaded using joinedload(models.Task.info) method above.
task_info_ref = task_ref.info
tasks.append(_task_format(task_ref, task_info_ref))
return tasks return tasks

View File

@ -310,22 +310,19 @@ class Task(object):
_supported_task_status = ('pending', 'processing', 'success', 'failure') _supported_task_status = ('pending', 'processing', 'success', 'failure')
def __init__(self, task_id, type, status, input, result, owner, message, def __init__(self, task_id, task_type, status, owner,
expires_at, created_at, updated_at, task_time_to_live=48): expires_at, created_at, updated_at, task_time_to_live=48):
if type not in self._supported_task_type: if task_type not in self._supported_task_type:
raise exception.InvalidTaskType(type) raise exception.InvalidTaskType(task_type)
if status not in self._supported_task_status: if status not in self._supported_task_status:
raise exception.InvalidTaskStatus(status) raise exception.InvalidTaskStatus(status)
self.task_id = task_id self.task_id = task_id
self._status = status self._status = status
self.type = type self.type = task_type
self.input = input
self.result = result
self.owner = owner self.owner = owner
self.message = message
self.expires_at = expires_at self.expires_at = expires_at
# NOTE(nikhil): We use '_time_to_live' to determine how long a # NOTE(nikhil): We use '_time_to_live' to determine how long a
# task should live from the time it succeeds or fails. # task should live from the time it succeeds or fails.
@ -387,13 +384,23 @@ class Task(object):
self.expires_at = timeutils.utcnow() + self._time_to_live self.expires_at = timeutils.utcnow() + self._time_to_live
class TaskDetails(object):
def __init__(self, task_id, task_input, message, result):
if task_id is None:
raise exception.TaskException(_('task_id is required to create '
'a new TaskDetails object'))
self.task_id = task_id
self.input = task_input
self.message = message
self.result = result
class TaskFactory(object): class TaskFactory(object):
def new_task(self, task_type, task_input, owner, task_time_to_live=48): def new_task(self, task_type, owner, task_time_to_live=48):
task_id = str(uuid.uuid4()) task_id = str(uuid.uuid4())
status = 'pending' status = 'pending'
result = None
message = None
# Note(nikhil): expires_at would be set on the task, only when it # Note(nikhil): expires_at would be set on the task, only when it
# succeeds or fails. # succeeds or fails.
expires_at = None expires_at = None
@ -403,12 +410,12 @@ class TaskFactory(object):
task_id, task_id,
task_type, task_type,
status, status,
task_input,
result,
owner, owner,
message,
expires_at, expires_at,
created_at, created_at,
updated_at, updated_at,
task_time_to_live task_time_to_live
) )
def new_task_details(self, task_id, task_input, message=None, result=None):
return TaskDetails(task_id, task_input, message, result)

View File

@ -39,11 +39,44 @@ class Helper(object):
return self.proxy_class(obj, **self.proxy_kwargs) return self.proxy_class(obj, **self.proxy_kwargs)
def unproxy(self, obj): def unproxy(self, obj):
if self.proxy_class is None: if obj is None or self.proxy_class is None:
return obj return obj
return obj.base return obj.base
class TaskRepo(object):
def __init__(self,
base,
task_proxy_class=None, task_proxy_kwargs=None,
task_details_proxy_class=None,
task_details_proxy_kwargs=None):
self.base = base
self.task_proxy_helper = Helper(task_proxy_class, task_proxy_kwargs)
self.task_details_proxy_helper = Helper(task_details_proxy_class,
task_details_proxy_kwargs)
def get_task_and_details(self, task_id):
task, task_details = self.base.get_task_and_details(task_id)
return (self.task_proxy_helper.proxy(task),
self.task_details_proxy_helper.proxy(task_details))
def list_tasks(self, *args, **kwargs):
tasks = self.base.list_tasks(*args, **kwargs)
return [self.task_proxy_helper.proxy(task) for task in tasks]
def add(self, task, task_details=None):
self.base.add(self.task_proxy_helper.unproxy(task),
self.task_details_proxy_helper.unproxy(task_details))
def save(self, task, task_details=None):
self.base.save(self.task_proxy_helper.unproxy(task),
self.task_details_proxy_helper.unproxy(task_details))
def remove(self, task):
base_task = self.task_proxy_helper.unproxy(task)
self.base.remove(base_task)
class Repo(object): class Repo(object):
def __init__(self, base, item_proxy_class=None, item_proxy_kwargs=None): def __init__(self, base, item_proxy_class=None, item_proxy_kwargs=None):
self.base = base self.base = base
@ -141,10 +174,7 @@ class Task(object):
task_id = _proxy('base', 'task_id') task_id = _proxy('base', 'task_id')
type = _proxy('base', 'type') type = _proxy('base', 'type')
status = _proxy('base', 'status') status = _proxy('base', 'status')
input = _proxy('base', 'input')
result = _proxy('base', 'result')
owner = _proxy('base', 'owner') owner = _proxy('base', 'owner')
message = _proxy('base', 'message')
expires_at = _proxy('base', 'expires_at') expires_at = _proxy('base', 'expires_at')
created_at = _proxy('base', 'created_at') created_at = _proxy('base', 'created_at')
updated_at = _proxy('base', 'updated_at') updated_at = _proxy('base', 'updated_at')
@ -162,11 +192,32 @@ class Task(object):
self.base.fail(message) self.base.fail(message)
class TaskDetails(object):
def __init__(self, base):
self.base = base
task_id = _proxy('base', 'task_id')
input = _proxy('base', 'input')
result = _proxy('base', 'result')
message = _proxy('base', 'message')
class TaskFactory(object): class TaskFactory(object):
def __init__(self, base, proxy_class=None, proxy_kwargs=None): def __init__(self,
self.helper = Helper(proxy_class, proxy_kwargs) base,
task_proxy_class=None,
task_proxy_kwargs=None,
task_details_proxy_class=None,
task_details_proxy_kwargs=None):
self.task_helper = Helper(task_proxy_class, task_proxy_kwargs)
self.task_details_helper = Helper(task_details_proxy_class,
task_details_proxy_kwargs)
self.base = base self.base = base
def new_task(self, **kwargs): def new_task(self, **kwargs):
t = self.base.new_task(**kwargs) t = self.base.new_task(**kwargs)
return self.helper.proxy(t) return self.task_helper.proxy(t)
def new_task_details(self, task_id, task_input, message=None, result=None):
td = self.base.new_task_details(task_id, task_input, message, result)
return self.task_details_helper.proxy(td)

View File

@ -293,36 +293,42 @@ class ImageProxy(glance.domain.proxy.Image):
self.notifier.info('image.activate', payload) self.notifier.info('image.activate', payload)
class TaskRepoProxy(glance.domain.proxy.Repo): class TaskRepoProxy(glance.domain.proxy.TaskRepo):
def __init__(self, task_repo, context, notifier): def __init__(self, task_repo, context, notifier):
self.task_repo = task_repo self.task_repo = task_repo
self.context = context self.context = context
self.notifier = notifier self.notifier = notifier
proxy_kwargs = {'context': self.context, 'notifier': self.notifier} proxy_kwargs = {'context': self.context, 'notifier': self.notifier}
super(TaskRepoProxy, self).__init__(task_repo, super(TaskRepoProxy, self) \
item_proxy_class=TaskProxy, .__init__(task_repo,
item_proxy_kwargs=proxy_kwargs) task_proxy_class=TaskProxy,
task_proxy_kwargs=proxy_kwargs,
task_details_proxy_class=TaskDetailsProxy,
task_details_proxy_kwargs=proxy_kwargs)
def add(self, task): def add(self, task, task_details=None):
self.notifier.info('task.create', self.notifier.info('task.create',
format_task_notification(task)) format_task_notification(task))
return super(TaskRepoProxy, self).add(task) super(TaskRepoProxy, self).add(task, task_details)
def remove(self, task): def remove(self, task):
payload = format_task_notification(task) payload = format_task_notification(task)
payload['deleted'] = True payload['deleted'] = True
payload['deleted_at'] = timeutils.isotime() payload['deleted_at'] = timeutils.isotime()
self.notifier.info('task.delete', payload) self.notifier.info('task.delete', payload)
return super(TaskRepoProxy, self).add(task) super(TaskRepoProxy, self).remove(task)
class TaskFactoryProxy(glance.domain.proxy.TaskFactory): class TaskFactoryProxy(glance.domain.proxy.TaskFactory):
def __init__(self, factory, context, notifier): def __init__(self, task_factory, context, notifier):
kwargs = {'context': context, 'notifier': notifier} kwargs = {'context': context, 'notifier': notifier}
super(TaskFactoryProxy, self).__init__(factory, super(TaskFactoryProxy, self).__init__(
proxy_class=TaskProxy, task_factory,
proxy_kwargs=kwargs) task_proxy_class=TaskProxy,
task_proxy_kwargs=kwargs,
task_details_proxy_class=TaskDetailsProxy,
task_details_proxy_kwargs=kwargs)
class TaskProxy(glance.domain.proxy.Task): class TaskProxy(glance.domain.proxy.Task):
@ -354,3 +360,12 @@ class TaskProxy(glance.domain.proxy.Task):
self.notifier.info('task.failure', self.notifier.info('task.failure',
format_task_notification(self.task)) format_task_notification(self.task))
return super(TaskProxy, self).fail(message) return super(TaskProxy, self).fail(message)
class TaskDetailsProxy(glance.domain.proxy.TaskDetails):
def __init__(self, task_details, context, notifier):
self.task_details = task_details
self.context = context
self.notifier = notifier
super(TaskDetailsProxy, self).__init__(task_details)

View File

@ -1463,9 +1463,9 @@ class TaskTests(test_utils.BaseTestCase):
self.assertIsNone(task['deleted_at']) self.assertIsNone(task['deleted_at'])
self.assertEqual(task['created_at'], fixture['created_at']) self.assertEqual(task['created_at'], fixture['created_at'])
self.assertEqual(task['updated_at'], fixture['updated_at']) self.assertEqual(task['updated_at'], fixture['updated_at'])
self.assertEqual(task['input'], fixture['input']) task_details_keys = ['input', 'message', 'result']
self.assertEqual(task['result'], fixture['result']) for key in task_details_keys:
self.assertEqual(task['message'], fixture['message']) self.assertFalse(key in task)
def test_task_create(self): def test_task_create(self):
task_id = str(uuid.uuid4()) task_id = str(uuid.uuid4())

View File

@ -864,9 +864,8 @@ class TestImmutableTask(utils.BaseTestCase):
task_factory = glance.domain.TaskFactory() task_factory = glance.domain.TaskFactory()
self.context = glance.context.RequestContext(tenant=TENANT2) self.context = glance.context.RequestContext(tenant=TENANT2)
task_type = 'import' task_type = 'import'
task_input = '{"loc": "fake"}'
owner = TENANT2 owner = TENANT2
task = task_factory.new_task(task_type, task_input, owner) task = task_factory.new_task(task_type, owner)
self.task = authorization.ImmutableTaskProxy(task) self.task = authorization.ImmutableTaskProxy(task)
def _test_change(self, attr, value): def _test_change(self, attr, value):
@ -893,15 +892,9 @@ class TestImmutableTask(utils.BaseTestCase):
def test_change_status(self): def test_change_status(self):
self._test_change('status', 'success') self._test_change('status', 'success')
def test_change_input(self):
self._test_change('input', {'foo': 'bar'})
def test_change_owner(self): def test_change_owner(self):
self._test_change('owner', 'fake') self._test_change('owner', 'fake')
def test_change_message(self):
self._test_change('message', 'fake')
def test_change_expires_at(self): def test_change_expires_at(self):
self._test_change('expires_at', 'fake') self._test_change('expires_at', 'fake')
@ -952,7 +945,6 @@ class TestTaskFactoryProxy(utils.BaseTestCase):
def test_task_create_default_owner(self): def test_task_create_default_owner(self):
owner = self.request1.context.owner owner = self.request1.context.owner
task = self.task_factory.new_task(task_type=self.task_type, task = self.task_factory.new_task(task_type=self.task_type,
task_input=self.task_input,
owner=owner) owner=owner)
self.assertEqual(task.owner, TENANT1) self.assertEqual(task.owner, TENANT1)
@ -985,26 +977,25 @@ class TestTaskRepoProxy(utils.BaseTestCase):
def __init__(self, fixtures): def __init__(self, fixtures):
self.fixtures = fixtures self.fixtures = fixtures
def get(self, task_id): def get_task_and_details(self, task_id):
for f in self.fixtures: for f in self.fixtures:
if f.task_id == task_id: if f.task_id == task_id:
return f return f, None
else: else:
raise ValueError(task_id) raise ValueError(task_id)
def list(self, *args, **kwargs): def list_tasks(self, *args, **kwargs):
return self.fixtures return self.fixtures
def setUp(self): def setUp(self):
super(TestTaskRepoProxy, self).setUp() super(TestTaskRepoProxy, self).setUp()
task_factory = glance.domain.TaskFactory() task_factory = glance.domain.TaskFactory()
task_type = 'import' task_type = 'import'
task_input = '{"loc": "fake"}'
owner = None owner = None
self.fixtures = [ self.fixtures = [
task_factory.new_task(task_type, task_input, owner), task_factory.new_task(task_type, owner),
task_factory.new_task(task_type, task_input, owner), task_factory.new_task(task_type, owner),
task_factory.new_task(task_type, task_input, owner), task_factory.new_task(task_type, owner),
] ]
self.context = glance.context.RequestContext(tenant=TENANT1) self.context = glance.context.RequestContext(tenant=TENANT1)
task_repo = self.TaskRepoStub(self.fixtures) task_repo = self.TaskRepoStub(self.fixtures)
@ -1014,33 +1005,28 @@ class TestTaskRepoProxy(utils.BaseTestCase):
) )
def test_get_mutable_task(self): def test_get_mutable_task(self):
task = self.task_repo.get(self.fixtures[0].task_id) task, _ = self.task_repo.get_task_and_details(self.fixtures[0].task_id)
self.assertEqual(task.task_id, self.fixtures[0].task_id) self.assertEqual(task.task_id, self.fixtures[0].task_id)
def test_get_immutable_task(self): def test_get_immutable_task(self):
task = self.task_repo.get(self.fixtures[1].task_id) task_id = self.fixtures[1].task_id
self.assertRaises( task, task_details = self.task_repo.get_task_and_details(task_id)
exception.Forbidden, self.assertRaises(exception.Forbidden,
setattr, setattr,
task, task_details,
'input', 'input',
'foo' 'foo')
)
def test_list(self): def test_list(self):
tasks = self.task_repo.list() tasks = self.task_repo.list_tasks()
self.assertEqual(tasks[0].task_id, self.fixtures[0].task_id) self.assertEqual(tasks[0].task_id, self.fixtures[0].task_id)
self.assertRaises( self.assertRaises(exception.Forbidden,
exception.Forbidden, setattr,
setattr, tasks[1],
tasks[1], 'owner',
'input', 'foo')
'foo' self.assertRaises(exception.Forbidden,
) setattr,
self.assertRaises( tasks[2],
exception.Forbidden, 'owner',
setattr, 'foo')
tasks[2],
'input',
'foo'
)

View File

@ -562,87 +562,97 @@ class TestTaskRepo(test_utils.BaseTestCase):
[self.db.task_create(None, task) for task in self.tasks] [self.db.task_create(None, task) for task in self.tasks]
def test_get(self): def test_get(self):
task = self.task_repo.get(UUID1) task, task_details = self.task_repo.get_task_and_details(UUID1)
self.assertEqual(task.task_id, UUID1) self.assertEqual(task.task_id, UUID1)
self.assertEqual(task.type, 'import') self.assertEqual(task.type, 'import')
self.assertEqual(task.status, 'pending') self.assertEqual(task.status, 'pending')
self.assertEqual(task.input, self.fake_task_input) self.assertEqual(task.task_id, task_details.task_id)
self.assertEqual(task.result, '') self.assertEqual(task_details.input, self.fake_task_input)
self.assertEqual(task_details.result, '')
self.assertEqual(task.owner, TENANT1) self.assertEqual(task.owner, TENANT1)
def test_get_not_found(self): def test_get_not_found(self):
self.assertRaises(exception.NotFound, self.task_repo.get, self.assertRaises(exception.NotFound,
self.task_repo.get_task_and_details,
str(uuid.uuid4())) str(uuid.uuid4()))
def test_get_forbidden(self): def test_get_forbidden(self):
self.assertRaises(exception.NotFound, self.task_repo.get, UUID4) self.assertRaises(exception.NotFound,
self.task_repo.get_task_and_details,
UUID4)
def test_list(self): def test_list(self):
tasks = self.task_repo.list() tasks = self.task_repo.list_tasks()
task_ids = set([i.task_id for i in tasks]) task_ids = set([i.task_id for i in tasks])
self.assertEqual(set([UUID1, UUID2, UUID3]), task_ids) self.assertEqual(set([UUID1, UUID2, UUID3]), task_ids)
def test_list_with_type(self): def test_list_with_type(self):
filters = {'type': 'import'} filters = {'type': 'import'}
tasks = self.task_repo.list(filters=filters) tasks = self.task_repo.list_tasks(filters=filters)
task_ids = set([i.task_id for i in tasks]) task_ids = set([i.task_id for i in tasks])
self.assertEqual(set([UUID1, UUID2, UUID3]), task_ids) self.assertEqual(set([UUID1, UUID2, UUID3]), task_ids)
def test_list_with_status(self): def test_list_with_status(self):
filters = {'status': 'failure'} filters = {'status': 'failure'}
tasks = self.task_repo.list(filters=filters) tasks = self.task_repo.list_tasks(filters=filters)
task_ids = set([i.task_id for i in tasks]) task_ids = set([i.task_id for i in tasks])
self.assertEqual(set([UUID3]), task_ids) self.assertEqual(set([UUID3]), task_ids)
def test_list_with_marker(self): def test_list_with_marker(self):
full_tasks = self.task_repo.list() full_tasks = self.task_repo.list_tasks()
full_ids = [i.task_id for i in full_tasks] full_ids = [i.task_id for i in full_tasks]
marked_tasks = self.task_repo.list(marker=full_ids[0]) marked_tasks = self.task_repo.list_tasks(marker=full_ids[0])
actual_ids = [i.task_id for i in marked_tasks] actual_ids = [i.task_id for i in marked_tasks]
self.assertEqual(actual_ids, full_ids[1:]) self.assertEqual(actual_ids, full_ids[1:])
def test_list_with_last_marker(self): def test_list_with_last_marker(self):
tasks = self.task_repo.list() tasks = self.task_repo.list_tasks()
marked_tasks = self.task_repo.list(marker=tasks[-1].task_id) marked_tasks = self.task_repo.list_tasks(marker=tasks[-1].task_id)
self.assertEqual(len(marked_tasks), 0) self.assertEqual(len(marked_tasks), 0)
def test_limited_list(self): def test_limited_list(self):
limited_tasks = self.task_repo.list(limit=2) limited_tasks = self.task_repo.list_tasks(limit=2)
self.assertEqual(len(limited_tasks), 2) self.assertEqual(len(limited_tasks), 2)
def test_list_with_marker_and_limit(self): def test_list_with_marker_and_limit(self):
full_tasks = self.task_repo.list() full_tasks = self.task_repo.list_tasks()
full_ids = [i.task_id for i in full_tasks] full_ids = [i.task_id for i in full_tasks]
marked_tasks = self.task_repo.list(marker=full_ids[0], limit=1) marked_tasks = self.task_repo.list_tasks(marker=full_ids[0], limit=1)
actual_ids = [i.task_id for i in marked_tasks] actual_ids = [i.task_id for i in marked_tasks]
self.assertEqual(actual_ids, full_ids[1:2]) self.assertEqual(actual_ids, full_ids[1:2])
def test_sorted_list(self): def test_sorted_list(self):
tasks = self.task_repo.list(sort_key='status', sort_dir='desc') tasks = self.task_repo.list_tasks(sort_key='status', sort_dir='desc')
task_ids = [i.task_id for i in tasks] task_ids = [i.task_id for i in tasks]
self.assertEqual([UUID2, UUID1, UUID3], task_ids) self.assertEqual([UUID2, UUID1, UUID3], task_ids)
def test_add_task(self): def test_add_task(self):
task_type = 'import' task_type = 'import'
task = self.task_factory.new_task(task_type, self.fake_task_input, task = self.task_factory.new_task(task_type, None)
None)
self.assertEqual(task.updated_at, task.created_at) self.assertEqual(task.updated_at, task.created_at)
self.task_repo.add(task) task_details = self.task_factory.new_task_details(task.task_id,
retrieved_task = self.task_repo.get(task.task_id) self.fake_task_input)
self.task_repo.add(task, task_details)
retrieved_task, retrieved_task_details = \
self.task_repo.get_task_and_details(task.task_id)
self.assertEqual(retrieved_task.updated_at, task.updated_at) self.assertEqual(retrieved_task.updated_at, task.updated_at)
self.assertEqual(retrieved_task_details.task_id,
retrieved_task.task_id)
self.assertEqual(retrieved_task_details.input, task_details.input)
def test_save_task(self): def test_save_task(self):
task = self.task_repo.get(UUID1) task, task_details = self.task_repo.get_task_and_details(UUID1)
original_update_time = task.updated_at original_update_time = task.updated_at
self.task_repo.save(task) self.task_repo.save(task)
current_update_time = task.updated_at current_update_time = task.updated_at
self.assertTrue(current_update_time > original_update_time) self.assertTrue(current_update_time > original_update_time)
task = self.task_repo.get(UUID1) task, task_details = self.task_repo.get_task_and_details(UUID1)
self.assertEqual(task.updated_at, current_update_time) self.assertEqual(task.updated_at, current_update_time)
def test_remove_task(self): def test_remove_task(self):
task = self.task_repo.get(UUID1) task, task_details = self.task_repo.get_task_and_details(UUID1)
self.task_repo.remove(task) self.task_repo.remove(task)
self.assertRaises(exception.NotFound, self.assertRaises(exception.NotFound,
self.task_repo.get, self.task_repo.get_task_and_details,
task.task_id) task.task_id)

View File

@ -305,28 +305,38 @@ class TestTaskFactory(test_utils.BaseTestCase):
def test_new_task(self): def test_new_task(self):
task_type = 'import' task_type = 'import'
task_input = '{"import_from": "fake"}'
owner = TENANT1 owner = TENANT1
task = self.task_factory.new_task(task_type, task_input, owner) task = self.task_factory.new_task(task_type, owner)
self.assertTrue(task.task_id is not None) self.assertTrue(task.task_id is not None)
self.assertTrue(task.created_at is not None) self.assertTrue(task.created_at is not None)
self.assertEqual(task.created_at, task.updated_at) self.assertEqual(task.created_at, task.updated_at)
self.assertEqual(task.status, 'pending') self.assertEqual(task.status, 'pending')
self.assertEqual(task.owner, TENANT1) self.assertEqual(task.owner, TENANT1)
self.assertEqual(task.input, '{"import_from": "fake"}')
def test_new_task_invalid_type(self): def test_new_task_invalid_type(self):
task_type = 'blah' task_type = 'blah'
task_input = '{"import_from": "fake"}'
owner = TENANT1 owner = TENANT1
self.assertRaises( self.assertRaises(
exception.InvalidTaskType, exception.InvalidTaskType,
self.task_factory.new_task, self.task_factory.new_task,
task_type, task_type,
task_input,
owner, owner,
) )
def test_new_task_details(self):
task_id = 'fake_task_id'
task_input = '{"import_from": "fake"}'
result = '{"result": "success"}'
message = 'fake message'
task_details = self.task_factory.new_task_details(task_id,
task_input,
message,
result)
self.assertEqual(task_details.task_id, task_id)
self.assertEqual(task_details.input, task_input)
self.assertEqual(task_details.result, result)
self.assertEqual(task_details.message, message)
class TestTask(test_utils.BaseTestCase): class TestTask(test_utils.BaseTestCase):
@ -334,13 +344,10 @@ class TestTask(test_utils.BaseTestCase):
super(TestTask, self).setUp() super(TestTask, self).setUp()
self.task_factory = domain.TaskFactory() self.task_factory = domain.TaskFactory()
task_type = 'import' task_type = 'import'
task_input = ('{"import_from": "file:///home/a.img",'
' "import_from_format": "qcow2"}')
owner = TENANT1 owner = TENANT1
task_ttl = CONF.task.task_time_to_live task_ttl = CONF.task.task_time_to_live
self.gateway = unittest_utils.FakeGateway() self.gateway = unittest_utils.FakeGateway()
self.task = self.task_factory.new_task(task_type, self.task = self.task_factory.new_task(task_type,
task_input,
owner, owner,
task_time_to_live=task_ttl) task_time_to_live=task_ttl)
@ -351,12 +358,9 @@ class TestTask(test_utils.BaseTestCase):
exception.InvalidTaskStatus, exception.InvalidTaskStatus,
domain.Task, domain.Task,
task_id, task_id,
type='import', task_type='import',
status=status, status=status,
input=None,
result=None,
owner=None, owner=None,
message=None,
expires_at=None, expires_at=None,
created_at=timeutils.utcnow(), created_at=timeutils.utcnow(),
updated_at=timeutils.utcnow() updated_at=timeutils.utcnow()
@ -443,3 +447,28 @@ class TestTask(test_utils.BaseTestCase):
expected expected
) )
timeutils.clear_time_override() timeutils.clear_time_override()
class TestTaskDetails(test_utils.BaseTestCase):
def setUp(self):
super(TestTaskDetails, self).setUp()
self.task_input = ('{"import_from": "file:///home/a.img",'
' "import_from_format": "qcow2"}')
def test_task_details_init(self):
task_details_values = ['task_id_1',
self.task_input,
'result',
'None']
task_details = domain.TaskDetails(*task_details_values)
self.assertIsNotNone(task_details)
def test_task_details_with_no_task_id(self):
task_id = None
task_details_values = [task_id,
self.task_input,
'result',
'None']
self.assertRaises(exception.TaskException,
domain.TaskDetails,
*task_details_values)

View File

@ -290,7 +290,6 @@ class TestTaskFactory(test_utils.BaseTestCase):
super(TestTaskFactory, self).setUp() super(TestTaskFactory, self).setUp()
self.factory = mock.Mock() self.factory = mock.Mock()
self.fake_type = 'import' self.fake_type = 'import'
self.fake_input = "fake input"
self.fake_owner = "owner" self.fake_owner = "owner"
def test_proxy_plain(self): def test_proxy_plain(self):
@ -298,34 +297,52 @@ class TestTaskFactory(test_utils.BaseTestCase):
proxy_factory.new_task( proxy_factory.new_task(
type=self.fake_type, type=self.fake_type,
input=self.fake_input,
owner=self.fake_owner owner=self.fake_owner
) )
self.factory.new_task.assert_called_once_with( self.factory.new_task.assert_called_once_with(
type=self.fake_type, type=self.fake_type,
input=self.fake_input,
owner=self.fake_owner owner=self.fake_owner
) )
proxy_factory.new_task_details("task_01", "input")
self.factory.new_task_details.assert_called_once_with(
"task_01",
"input",
None, None
)
def test_proxy_wrapping(self): def test_proxy_wrapping(self):
proxy_factory = proxy.TaskFactory( proxy_factory = proxy.TaskFactory(
self.factory, self.factory,
proxy_class=FakeProxy, task_proxy_class=FakeProxy,
proxy_kwargs={'dog': 'bark'} task_proxy_kwargs={'dog': 'bark'},
) task_details_proxy_class=FakeProxy,
task_details_proxy_kwargs={'dog': 'bark'})
self.factory.new_task.return_value = 'fake_task' self.factory.new_task.return_value = 'fake_task'
self.factory.new_task_details.return_value = 'fake_task_detail'
task = proxy_factory.new_task( task = proxy_factory.new_task(
type=self.fake_type, type=self.fake_type,
input=self.fake_input,
owner=self.fake_owner owner=self.fake_owner
) )
self.factory.new_task.assert_called_once_with( self.factory.new_task.assert_called_once_with(
type=self.fake_type, type=self.fake_type,
input=self.fake_input,
owner=self.fake_owner owner=self.fake_owner
) )
self.assertIsInstance(task, FakeProxy) self.assertIsInstance(task, FakeProxy)
self.assertEqual(task.base, 'fake_task') self.assertEqual(task.base, 'fake_task')
task_details = proxy_factory.new_task_details('task_01', "input")
self.factory.new_task_details.assert_called_once_with(
'task_01',
"input",
None, None
)
self.assertIsInstance(task_details, FakeProxy)
self.assertEqual(task_details.base, 'fake_task_detail')

View File

@ -20,6 +20,7 @@ import webob
from glance.common import exception from glance.common import exception
import glance.context import glance.context
from glance import domain
from glance import notifier from glance import notifier
from glance.openstack.common import timeutils from glance.openstack.common import timeutils
import glance.tests.unit.utils as unit_test_utils import glance.tests.unit.utils as unit_test_utils
@ -401,16 +402,17 @@ class TestTaskNotifications(utils.BaseTestCase):
super(TestTaskNotifications, self).setUp() super(TestTaskNotifications, self).setUp()
self.task = TaskStub( self.task = TaskStub(
task_id='aaa', task_id='aaa',
type='import', task_type='import',
status='pending', status='pending',
input={"loc": "fake"},
result='',
owner=TENANT2, owner=TENANT2,
message='',
expires_at=None, expires_at=None,
created_at=DATETIME, created_at=DATETIME,
updated_at=DATETIME updated_at=DATETIME
) )
self.task_details = domain.TaskDetails(task_id=self.task.task_id,
task_input={"loc": "fake"},
result='',
message='')
self.context = glance.context.RequestContext( self.context = glance.context.RequestContext(
tenant=TENANT2, tenant=TENANT2,
user=USER1 user=USER1
@ -427,6 +429,9 @@ class TestTaskNotifications(utils.BaseTestCase):
self.context, self.context,
self.notifier self.notifier
) )
self.task_details_proxy = notifier.TaskDetailsProxy(self.task_details,
self.context,
self.notifier)
timeutils.set_time_override() timeutils.set_time_override()
def tearDown(self): def tearDown(self):
@ -434,7 +439,7 @@ class TestTaskNotifications(utils.BaseTestCase):
timeutils.clear_time_override() timeutils.clear_time_override()
def test_task_create_notification(self): def test_task_create_notification(self):
self.task_repo_proxy.add(self.task_proxy) self.task_repo_proxy.add(self.task_proxy, self.task_details_proxy)
output_logs = self.notifier.get_logs() output_logs = self.notifier.get_logs()
self.assertEqual(len(output_logs), 1) self.assertEqual(len(output_logs), 1)
output_log = output_logs[0] output_log = output_logs[0]

View File

@ -85,13 +85,13 @@ class ImageMembershipStub(object):
class TaskRepoStub(object): class TaskRepoStub(object):
def get(self, *args, **kwargs): def get_task_and_details(self, *args, **kwargs):
return 'task_from_get' return 'task_from_get', 'task_details_from_get'
def add(self, *args, **kwargs): def add(self, *args, **kwargs):
return 'task_from_add' return 'task_from_add'
def list(self, *args, **kwargs): def list_tasks(self, *args, **kwargs):
return ['task_from_list_0', 'task_from_list_1'] return ['task_from_list_0', 'task_from_list_1']
@ -385,7 +385,9 @@ class TestTaskPolicy(test_utils.BaseTestCase):
{}, {},
self.policy self.policy
) )
self.assertRaises(exception.Forbidden, task_repo.get, UUID1) self.assertRaises(exception.Forbidden,
task_repo.get_task_and_details,
UUID1)
def test_get_task_allowed(self): def test_get_task_allowed(self):
rules = {"get_task": True} rules = {"get_task": True}
@ -395,9 +397,9 @@ class TestTaskPolicy(test_utils.BaseTestCase):
{}, {},
self.policy self.policy
) )
output = task_repo.get(UUID1) task, task_details = task_repo.get_task_and_details(UUID1)
self.assertIsInstance(output, glance.api.policy.TaskProxy) self.assertIsInstance(task, glance.api.policy.TaskProxy)
self.assertEqual(output.task, 'task_from_get') self.assertEqual(task.task, 'task_from_get')
def test_get_tasks_not_allowed(self): def test_get_tasks_not_allowed(self):
rules = {"get_tasks": False} rules = {"get_tasks": False}
@ -407,7 +409,7 @@ class TestTaskPolicy(test_utils.BaseTestCase):
{}, {},
self.policy self.policy
) )
self.assertRaises(exception.Forbidden, task_repo.list) self.assertRaises(exception.Forbidden, task_repo.list_tasks)
def test_get_tasks_allowed(self): def test_get_tasks_allowed(self):
rules = {"get_task": True} rules = {"get_task": True}
@ -417,7 +419,7 @@ class TestTaskPolicy(test_utils.BaseTestCase):
{}, {},
self.policy self.policy
) )
tasks = task_repo.list() tasks = task_repo.list_tasks()
for i, task in enumerate(tasks): for i, task in enumerate(tasks):
self.assertIsInstance(task, glance.api.policy.TaskProxy) self.assertIsInstance(task, glance.api.policy.TaskProxy)
self.assertEqual(task.task, 'task_from_list_%d' % i) self.assertEqual(task.task, 'task_from_list_%d' % i)

View File

@ -41,10 +41,10 @@ DATETIME = datetime.datetime(2013, 9, 28, 15, 27, 36, 325355)
ISOTIME = '2013-09-28T15:27:36Z' ISOTIME = '2013-09-28T15:27:36Z'
def _db_fixture(id, **kwargs): def _db_fixture(task_id, **kwargs):
default_datetime = timeutils.utcnow() default_datetime = timeutils.utcnow()
obj = { obj = {
'id': id, 'id': task_id,
'status': 'pending', 'status': 'pending',
'type': 'import', 'type': 'import',
'input': {}, 'input': {},
@ -61,22 +61,23 @@ def _db_fixture(id, **kwargs):
return obj return obj
def _domain_fixture(id, **kwargs): def _domain_fixture(task_id, **kwargs):
default_datetime = timeutils.utcnow() default_datetime = timeutils.utcnow()
properties = { task_properties = {
'task_id': id, 'task_id': task_id,
'status': 'pending', 'status': kwargs.get('status', 'pending'),
'type': 'import', 'task_type': kwargs.get('type', 'import'),
'input': {}, 'owner': kwargs.get('owner', None),
'result': None, 'expires_at': kwargs.get('expires_at', None),
'owner': None, 'created_at': kwargs.get('created_at', default_datetime),
'message': None, 'updated_at': kwargs.get('updated_at', default_datetime),
'expires_at': None,
'created_at': default_datetime,
'updated_at': default_datetime,
} }
properties.update(kwargs) task = glance.domain.Task(**task_properties)
return glance.domain.Task(**properties) task_details = glance.domain.TaskDetails(task_id,
kwargs.get('input', {}),
kwargs.get('message', None),
kwargs.get('result', None))
return {'task': task, 'task_details': task_details}
class TestTasksController(test_utils.BaseTestCase): class TestTasksController(test_utils.BaseTestCase):
@ -267,8 +268,11 @@ class TestTasksController(test_utils.BaseTestCase):
def test_get(self): def test_get(self):
request = unit_test_utils.get_fake_request() request = unit_test_utils.get_fake_request()
output = self.controller.get(request, task_id=UUID1) output = self.controller.get(request, task_id=UUID1)
self.assertEqual(UUID1, output.task_id) task = output['task']
self.assertEqual('import', output.type) task_details = output['task_details']
self.assertEqual(UUID1, task.task_id)
self.assertEqual(UUID1, task_details.task_id)
self.assertEqual('import', task.type)
def test_get_non_existent(self): def test_get_non_existent(self):
request = unit_test_utils.get_fake_request() request = unit_test_utils.get_fake_request()
@ -289,10 +293,12 @@ class TestTasksController(test_utils.BaseTestCase):
"image_from_format": "qcow2"} "image_from_format": "qcow2"}
} }
output = self.controller.create(request, task=task) output = self.controller.create(request, task=task)
self.assertEqual('import', output.type) task = output['task']
task_details = output['task_details']
self.assertEqual('import', task.type)
self.assertEqual({ self.assertEqual({
"import_from": "swift://cloud.foo/myaccount/mycontainer/path", "import_from": "swift://cloud.foo/myaccount/mycontainer/path",
"image_from_format": "qcow2"}, output.input) "image_from_format": "qcow2"}, task_details.input)
output_logs = [nlog for nlog in self.notifier.get_logs() output_logs = [nlog for nlog in self.notifier.get_logs()
if nlog['event_type'] == 'task.create'] if nlog['event_type'] == 'task.create']
self.assertEqual(len(output_logs), 1) self.assertEqual(len(output_logs), 1)
@ -550,7 +556,8 @@ class TestTasksSerializer(test_utils.BaseTestCase):
} }
request = webob.Request.blank('/v2/tasks') request = webob.Request.blank('/v2/tasks')
response = webob.Response(request=request) response = webob.Response(request=request)
result = {'tasks': self.fixtures} task_fixtures = [f['task'] for f in self.fixtures]
result = {'tasks': task_fixtures}
self.serializer.index(response, result) self.serializer.index(response, result)
actual = jsonutils.loads(response.body) actual = jsonutils.loads(response.body)
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
@ -559,7 +566,8 @@ class TestTasksSerializer(test_utils.BaseTestCase):
def test_index_next_marker(self): def test_index_next_marker(self):
request = webob.Request.blank('/v2/tasks') request = webob.Request.blank('/v2/tasks')
response = webob.Response(request=request) response = webob.Response(request=request)
result = {'tasks': self.fixtures, 'next_marker': UUID2} task_fixtures = [f['task'] for f in self.fixtures]
result = {'tasks': task_fixtures, 'next_marker': UUID2}
self.serializer.index(response, result) self.serializer.index(response, result)
output = jsonutils.loads(response.body) output = jsonutils.loads(response.body)
self.assertEqual('/v2/tasks?marker=%s' % UUID2, output['next']) self.assertEqual('/v2/tasks?marker=%s' % UUID2, output['next'])
@ -568,7 +576,8 @@ class TestTasksSerializer(test_utils.BaseTestCase):
url = '/v2/tasks?limit=10&sort_key=id&sort_dir=asc' url = '/v2/tasks?limit=10&sort_key=id&sort_dir=asc'
request = webob.Request.blank(url) request = webob.Request.blank(url)
response = webob.Response(request=request) response = webob.Response(request=request)
result = {'tasks': self.fixtures, 'next_marker': UUID2} task_fixtures = [f['task'] for f in self.fixtures]
result = {'tasks': task_fixtures, 'next_marker': UUID2}
self.serializer.index(response, result) self.serializer.index(response, result)
output = jsonutils.loads(response.body) output = jsonutils.loads(response.body)
self.assertEqual('/v2/tasks?sort_key=id&sort_dir=asc&limit=10', self.assertEqual('/v2/tasks?sort_key=id&sort_dir=asc&limit=10',
@ -631,33 +640,56 @@ class TestTasksSerializer(test_utils.BaseTestCase):
'schema': '/v2/schemas/task', 'schema': '/v2/schemas/task',
} }
response = webob.Response() response = webob.Response()
self.serializer.get(response, self.fixtures[1]) self.serializer.get(response, self.fixtures[1])
actual = jsonutils.loads(response.body) actual = jsonutils.loads(response.body)
self.assertEqual(expected, actual) self.assertEqual(expected, actual)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
def test_create(self): def test_create(self):
response = webob.Response() response = webob.Response()
self.serializer.create(response, self.fixtures[3]) self.serializer.create(response, self.fixtures[3])
serialized_task = jsonutils.loads(response.body)
self.assertEqual(response.status_int, 201) self.assertEqual(response.status_int, 201)
self.assertEqual(self.fixtures[3].task_id, self.assertEqual(self.fixtures[3]['task'].task_id,
jsonutils.loads(response.body)['id']) serialized_task['id'])
self.assertTrue('expires_at' in jsonutils.loads(response.body)) self.assertEqual(self.fixtures[3]['task_details'].task_id,
serialized_task['id'])
self.assertEqual(self.fixtures[3]['task_details'].input,
serialized_task['input'])
self.assertTrue('expires_at' in serialized_task)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
def test_create_ensure_expires_at_is_not_returned(self): def test_create_ensure_expires_at_is_not_returned(self):
response = webob.Response() response = webob.Response()
self.serializer.create(response, self.fixtures[0]) self.serializer.create(response, self.fixtures[0])
serialized_task = jsonutils.loads(response.body)
self.assertEqual(response.status_int, 201) self.assertEqual(response.status_int, 201)
self.assertEqual(self.fixtures[0].task_id, self.assertEqual(self.fixtures[0]['task'].task_id,
jsonutils.loads(response.body)['id']) serialized_task['id'])
self.assertFalse('expires_at' in jsonutils.loads(response.body)) self.assertEqual(self.fixtures[0]['task_details'].task_id,
serialized_task['id'])
self.assertEqual(self.fixtures[0]['task_details'].input,
serialized_task['input'])
self.assertFalse('expires_at' in serialized_task)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
response = webob.Response() response = webob.Response()
self.serializer.create(response, self.fixtures[1]) self.serializer.create(response, self.fixtures[1])
serialized_task = jsonutils.loads(response.body)
self.assertEqual(response.status_int, 201) self.assertEqual(response.status_int, 201)
self.assertEqual(self.fixtures[1].task_id, self.assertEqual(self.fixtures[1]['task'].task_id,
jsonutils.loads(response.body)['id']) serialized_task['id'])
self.assertFalse('expires_at' in jsonutils.loads(response.body)) self.assertEqual(self.fixtures[1]['task_details'].task_id,
serialized_task['id'])
self.assertEqual(self.fixtures[1]['task_details'].input,
serialized_task['input'])
self.assertFalse('expires_at' in serialized_task)
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)