[Kimchi-devel] [PATCH 4/8] Add model function to wait for task
Aline Manera
alinefm at linux.vnet.ibm.com
Mon Nov 3 16:12:37 UTC 2014
On 11/02/2014 11:05 PM, Crístian Viana wrote:
> Sometimes we need to wait for a task to finish. Instead of writing the
> waiting loop everytime, we can now use the function "wait".
>
> Add the function "TaskModel.wait" which waits for a task to finish
> for a maximum ammount of time (in seconds). If the task finishes before
> the timeout expires, the function returns successfully; otherwise, an
> exception is raised.
> Also, update calls to an already existing function which does the same thing
> in the test code, and replace its usages with this new function.
>
> Signed-off-by: Crístian Viana <vianac at linux.vnet.ibm.com>
> ---
> src/kimchi/i18n.py | 1 +
> src/kimchi/model/tasks.py | 28 ++++++++++++++++++++++++++++
> tests/test_model.py | 19 +++++++++----------
> 3 files changed, 38 insertions(+), 10 deletions(-)
>
> diff --git a/src/kimchi/i18n.py b/src/kimchi/i18n.py
> index f789259..10408bf 100644
> --- a/src/kimchi/i18n.py
> +++ b/src/kimchi/i18n.py
> @@ -35,6 +35,7 @@ messages = {
>
> "KCHASYNC0001E": _("Datastore is not initiated in the model object."),
> "KCHASYNC0002E": _("Unable to start task due error: %(err)s"),
> + "KCHASYNC0003E": _("Timeout of %(seconds)s seconds expired while running task '%(task)s."),
>
> "KCHAUTH0001E": _("Authentication failed for user '%(username)s'. [Error code: %(code)s]"),
> "KCHAUTH0002E": _("You are not authorized to access Kimchi"),
> diff --git a/src/kimchi/model/tasks.py b/src/kimchi/model/tasks.py
> index f25bcbf..61bc2f3 100644
> --- a/src/kimchi/model/tasks.py
> +++ b/src/kimchi/model/tasks.py
> @@ -18,6 +18,11 @@
> # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
>
>
> +import time
> +
> +from kimchi.exception import TimeoutExpired
> +
> +
> class TasksModel(object):
> def __init__(self, **kargs):
> self.objstore = kargs['objstore']
> @@ -34,3 +39,26 @@ class TaskModel(object):
> def lookup(self, id):
> with self.objstore as session:
> return session.get('task', str(id))
> +
> + def wait(self, id, timeout=10):
> + """Wait for a task until it stops running (successfully or due to
> + an error). If the Task finishes its execution before <timeout>, this
> + function returns normally; otherwise an exception is raised.
> +
> + Parameters:
> + id -- The Task ID.
> + timeout -- The maximum time, in seconds, that this function should wait
> + for the Task. If the Task runs for more than <timeout>,
> + "TimeoutExpired" is raised.
> + """
> + for i in range(0, timeout):
> + with self.objstore as session:
> + task = session.get('task', str(id))
> +
> + if task['status'] != 'running':
> + return
> +
> + time.sleep(1)
> +
> + raise TimeoutExpired('KCHASYNC0003E', {'seconds': timeout,
> + 'task': task['target_uri']})
> diff --git a/tests/test_model.py b/tests/test_model.py
> index de2e49a..7f33540 100644
> --- a/tests/test_model.py
> +++ b/tests/test_model.py
> @@ -45,7 +45,6 @@ from kimchi.iscsi import TargetClient
> from kimchi.model import model
> from kimchi.rollbackcontext import RollbackContext
> from kimchi.utils import add_task
> -from utils import wait_task
>
>
If you will use the new TaskModel.wait() function in all wait_task
occurrences you should also remove the wait_task implementation from
utils.py
> invalid_repository_urls = ['www.fedora.org', # missing protocol
> @@ -130,7 +129,7 @@ class ModelTests(unittest.TestCase):
> 'format': 'qcow2'}
> task_id = inst.storagevolumes_create('default', params)['id']
> rollback.prependDefer(inst.storagevolume_delete, 'default', vol)
> - wait_task(inst.task_lookup, task_id)
> + inst.task_wait(task_id)
> self.assertEquals('finished', inst.task_lookup(task_id)['status'])
> vol_path = inst.storagevolume_lookup('default', vol)['path']
>
> @@ -290,7 +289,7 @@ class ModelTests(unittest.TestCase):
> 'format': 'qcow2'}
> task_id = inst.storagevolumes_create(pool, params)['id']
> rollback.prependDefer(inst.storagevolume_delete, pool, vol)
> - wait_task(inst.task_lookup, task_id)
> + inst.task_wait(task_id)
>
> vm_name = 'kimchi-cdrom'
> params = {'name': 'test', 'disks': [], 'cdrom': self.kimchi_iso}
> @@ -569,7 +568,7 @@ class ModelTests(unittest.TestCase):
> params['name'] = vol
> task_id = inst.storagevolumes_create(pool, params)['id']
> rollback.prependDefer(inst.storagevolume_delete, pool, vol)
> - wait_task(inst.task_lookup, task_id)
> + inst.task_wait(task_id)
> self.assertEquals('finished', inst.task_lookup(task_id)['status'])
>
> fd, path = tempfile.mkstemp(dir=path)
> @@ -610,7 +609,7 @@ class ModelTests(unittest.TestCase):
> taskid = task_response['id']
> vol_name = task_response['target_uri'].split('/')[-1]
> self.assertEquals('COPYING', vol_name)
> - wait_task(inst.task_lookup, taskid, timeout=60)
> + inst.task_wait(taskid, timeout=60)
> self.assertEquals('finished', inst.task_lookup(taskid)['status'])
> vol_path = os.path.join(args['path'], vol_name)
> self.assertTrue(os.path.isfile(vol_path))
> @@ -1155,7 +1154,7 @@ class ModelTests(unittest.TestCase):
> inst = model.Model('test:///default',
> objstore_loc=self.tmp_store)
> taskid = add_task('', quick_op, inst.objstore, 'Hello')
> - wait_task(inst.task_lookup, taskid)
> + inst.task_wait(taskid)
> self.assertEquals(1, taskid)
> self.assertEquals('finished', inst.task_lookup(taskid)['status'])
> self.assertEquals('Hello', inst.task_lookup(taskid)['message'])
> @@ -1166,12 +1165,12 @@ class ModelTests(unittest.TestCase):
> self.assertEquals(2, taskid)
> self.assertEquals('running', inst.task_lookup(taskid)['status'])
> self.assertEquals('OK', inst.task_lookup(taskid)['message'])
> - wait_task(inst.task_lookup, taskid)
> + inst.task_wait(taskid)
> self.assertEquals('failed', inst.task_lookup(taskid)['status'])
> self.assertEquals('It was not meant to be',
> inst.task_lookup(taskid)['message'])
> taskid = add_task('', abnormal_op, inst.objstore, {})
> - wait_task(inst.task_lookup, taskid)
> + inst.task_wait(taskid)
> self.assertEquals('Exception raised',
> inst.task_lookup(taskid)['message'])
> self.assertEquals('failed', inst.task_lookup(taskid)['status'])
> @@ -1179,7 +1178,7 @@ class ModelTests(unittest.TestCase):
> taskid = add_task('', continuous_ops, inst.objstore,
> {'result': True})
> self.assertEquals('running', inst.task_lookup(taskid)['status'])
> - wait_task(inst.task_lookup, taskid, timeout=10)
> + inst.task_wait(taskid, timeout=10)
> self.assertEquals('finished', inst.task_lookup(taskid)['status'])
>
> # This wrapper function is needed due to the new backend messaging in
> @@ -1285,7 +1284,7 @@ class ModelTests(unittest.TestCase):
> task = inst.debugreports_create({'name': reportName})
> rollback.prependDefer(inst.debugreport_delete, tmp_name)
> taskid = task['id']
> - wait_task(inst.task_lookup, taskid, timeout)
> + inst.task_wait(taskid, timeout)
> self.assertEquals('finished',
> inst.task_lookup(taskid)['status'],
> "It is not necessary an error. "
More information about the Kimchi-devel
mailing list