[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