diff --git a/lib/ansible/playbook/task.py b/lib/ansible/playbook/task.py index 9c29593f6f..7abfea95da 100644 --- a/lib/ansible/playbook/task.py +++ b/lib/ansible/playbook/task.py @@ -29,7 +29,7 @@ class Task(object): 'delegate_to', 'first_available_file', 'ignore_errors', 'local_action', 'transport', 'sudo', 'sudo_user', 'sudo_pass', 'items_lookup_plugin', 'items_lookup_terms', 'environment', 'args', - 'any_errors_fatal', 'changed_when', 'failed_when', 'always_run' + 'any_errors_fatal', 'changed_when', 'failed_when', 'always_run', 'delay', 'retries', 'until' ] # to prevent typos and such @@ -38,9 +38,9 @@ class Task(object): 'first_available_file', 'include', 'tags', 'register', 'ignore_errors', 'delegate_to', 'local_action', 'transport', 'sudo', 'sudo_user', 'sudo_pass', 'when', 'connection', 'environment', 'args', - 'any_errors_fatal', 'changed_when', 'failed_when', 'always_run' + 'any_errors_fatal', 'changed_when', 'failed_when', 'always_run', 'delay', 'retries', 'until' ] - + def __init__(self, play, ds, module_vars=None, default_vars=None, additional_conditions=None, role_name=None): ''' constructor loads from a task or handler datastructure ''' @@ -111,6 +111,16 @@ class Task(object): self.sudo = utils.boolean(ds.get('sudo', play.sudo)) self.environment = ds.get('environment', {}) self.role_name = role_name + + #Code to allow do until feature in a Task + if 'until' in ds: + if not ds.get('register'): + raise errors.AnsibleError("register keyword is mandatory when using do until feature") + self.module_vars['delay'] = ds.get('delay', 5) + self.module_vars['retries'] = ds.get('retries', 3) + self.module_vars['register'] = ds.get('register', None) + self.until = "jinja2_compare %s" % (ds.get('until')) + self.module_vars['until'] = utils.compile_when_to_only_if(self.until) # rather than simple key=value args on the options line, these represent structured data and the values # can be hashes and lists, not just scalars diff --git a/lib/ansible/runner/__init__.py b/lib/ansible/runner/__init__.py index f64a9f2017..0cd921c9dd 100644 --- a/lib/ansible/runner/__init__.py +++ b/lib/ansible/runner/__init__.py @@ -653,7 +653,33 @@ class Runner(object): result = handler.run(conn, tmp, module_name, module_args, inject, complex_args) - + # Code for do until feature + until_result = 0 + until = self.module_vars.get('until', None) + if until is not None and result.comm_ok: + inject[self.module_vars.get('register')] = result.result + cond = template.template(self.basedir, until, inject, expand_lists=False) + if not utils.check_conditional(cond, self.basedir, inject, fail_on_undefined=self.error_on_undefined_vars): + retries = self.module_vars.get('retries') + delay = self.module_vars.get('delay') + for x in range(0, retries): + time.sleep(delay) + tmp = '' + if getattr(handler, 'NEEDS_TMPPATH', True): + tmp = self._make_tmp_path(conn) + result = handler.run(conn, tmp, module_name, module_args, inject, complex_args) + vv("Result from run %i is: %s" % (x, result.result)) + if not result.comm_ok: + break; + inject[self.module_vars.get('register')] = result.result + cond = template.template(self.basedir, until, inject, expand_lists=False) + if utils.check_conditional(cond, self.basedir, inject, fail_on_undefined=self.error_on_undefined_vars): + until_result = 1 + break; + if utils.check_conditional(cond, self.basedir, inject, fail_on_undefined=self.error_on_undefined_vars): + until_result = 1 + result.result['until_result'] = until_result + conn.close() if not result.comm_ok: