From 53e48b63a945885920b19a53c90731469d6151b7 Mon Sep 17 00:00:00 2001 From: bennojoy Date: Tue, 24 Sep 2013 13:59:38 +0530 Subject: [PATCH 1/5] dountil feature commit 1 --- lib/ansible/playbook/task.py | 16 +++++++++++++--- lib/ansible/runner/__init__.py | 28 +++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 4 deletions(-) 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: From 21529de82eb51ee0e335dabfe95c013f8afeaba5 Mon Sep 17 00:00:00 2001 From: bennojoy Date: Tue, 24 Sep 2013 15:23:01 +0530 Subject: [PATCH 2/5] dountil feature commit 2 --- lib/ansible/runner/__init__.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/ansible/runner/__init__.py b/lib/ansible/runner/__init__.py index 0cd921c9dd..0dc2fbf73e 100644 --- a/lib/ansible/runner/__init__.py +++ b/lib/ansible/runner/__init__.py @@ -654,7 +654,7 @@ class Runner(object): result = handler.run(conn, tmp, module_name, module_args, inject, complex_args) # Code for do until feature - until_result = 0 + until_result = 1 until = self.module_vars.get('until', None) if until is not None and result.comm_ok: inject[self.module_vars.get('register')] = result.result @@ -676,10 +676,9 @@ class Runner(object): 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 - + else: + until_result = 0 + result.result['until_result'] = until_result conn.close() if not result.comm_ok: From 0e749611ac81dc5270595cf0f87627e9e61b08d4 Mon Sep 17 00:00:00 2001 From: bennojoy Date: Wed, 25 Sep 2013 09:56:14 +0530 Subject: [PATCH 3/5] doc update and add attempts --- docsite/latest/rst/playbooks2.rst | 27 +++++++++++++++++++++++++++ lib/ansible/runner/__init__.py | 10 ++++------ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/docsite/latest/rst/playbooks2.rst b/docsite/latest/rst/playbooks2.rst index afb87e7604..8557e1cf53 100644 --- a/docsite/latest/rst/playbooks2.rst +++ b/docsite/latest/rst/playbooks2.rst @@ -461,6 +461,33 @@ from turning into arbitrary code with ugly nested ifs, conditionals, and so on - in more streamlined & auditable configuration rules -- especially because there are a minimum of decision points to track. +Do/Until +```````` + +Sometimes you would want to retry a task till a certain condition is met, In such conditions the Do/Until feature will help. +Here's an example which show's the syntax to be applied for the task. + + - action: shell /usr/bin/foo + register: result + until: register.stdout.find("all systems go") != -1 + retries: 5 + delay: 10 + +The above example run the shell module recursively till the module's result has "all systems go" in it's stdout or the task has +been retried for 5 times with a delay of 10 seconds. The default value for "retries" is 3 and "delay" is 5. + +The task returns the results returned by the last task run. The results of individual retries can be viewed by -vv option. +The results will have a new key "attempts" which will have the number of the retries for the task. + +.. note:: + The Do/Until does not take decision on whether to fail or pass the play when the maximum retries are completed, the user can + can do that in the next task as follows: + + - name: fail the play + fail: msg=" This play fails as the foo exceeded maximum retries" + fail_when: register.attempts >= 5 + + Loops ````` diff --git a/lib/ansible/runner/__init__.py b/lib/ansible/runner/__init__.py index 0dc2fbf73e..396dfeee08 100644 --- a/lib/ansible/runner/__init__.py +++ b/lib/ansible/runner/__init__.py @@ -654,7 +654,6 @@ class Runner(object): result = handler.run(conn, tmp, module_name, module_args, inject, complex_args) # Code for do until feature - until_result = 1 until = self.module_vars.get('until', None) if until is not None and result.comm_ok: inject[self.module_vars.get('register')] = result.result @@ -662,23 +661,22 @@ class Runner(object): 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): + for x in range(1, retries + 1): 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) + result.result['attempts'] = x 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; - else: - until_result = 0 - result.result['until_result'] = until_result + else: + result.result['attempts'] = 0 conn.close() if not result.comm_ok: From daf2f49116dee61a6478fbee5254d0c6c6911600 Mon Sep 17 00:00:00 2001 From: bennojoy Date: Wed, 25 Sep 2013 10:22:51 +0530 Subject: [PATCH 4/5] doc update --- docsite/latest/rst/playbooks2.rst | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/docsite/latest/rst/playbooks2.rst b/docsite/latest/rst/playbooks2.rst index 8557e1cf53..37e2c613ee 100644 --- a/docsite/latest/rst/playbooks2.rst +++ b/docsite/latest/rst/playbooks2.rst @@ -467,11 +467,11 @@ Do/Until Sometimes you would want to retry a task till a certain condition is met, In such conditions the Do/Until feature will help. Here's an example which show's the syntax to be applied for the task. - - action: shell /usr/bin/foo - register: result - until: register.stdout.find("all systems go") != -1 - retries: 5 - delay: 10 + - action: shell /usr/bin/foo + register: result + until: register.stdout.find("all systems go") != -1 + retries: 5 + delay: 10 The above example run the shell module recursively till the module's result has "all systems go" in it's stdout or the task has been retried for 5 times with a delay of 10 seconds. The default value for "retries" is 3 and "delay" is 5. @@ -480,12 +480,15 @@ The task returns the results returned by the last task run. The results of indiv The results will have a new key "attempts" which will have the number of the retries for the task. .. note:: - The Do/Until does not take decision on whether to fail or pass the play when the maximum retries are completed, the user can - can do that in the next task as follows: + The Do/Until does not take decision on whether to fail or pass the play when the maximum retries are completed, the user can + can do that in the next task as follows: - - name: fail the play - fail: msg=" This play fails as the foo exceeded maximum retries" - fail_when: register.attempts >= 5 + - action: shell /usr/bin/foo + register: result + until: register.stdout.find("all systems go") != -1 + retries: 5 + delay: 10 + failed_when: result.attempts == 5 Loops From 16d03204089ed40feee8deaa08799c79b29742c2 Mon Sep 17 00:00:00 2001 From: Benno Joy Date: Wed, 25 Sep 2013 10:48:43 +0530 Subject: [PATCH 5/5] Update playbooks2.rst --- docsite/latest/rst/playbooks2.rst | 37 +++++++++++++++++-------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/docsite/latest/rst/playbooks2.rst b/docsite/latest/rst/playbooks2.rst index 37e2c613ee..8d3777bdbd 100644 --- a/docsite/latest/rst/playbooks2.rst +++ b/docsite/latest/rst/playbooks2.rst @@ -461,17 +461,17 @@ from turning into arbitrary code with ugly nested ifs, conditionals, and so on - in more streamlined & auditable configuration rules -- especially because there are a minimum of decision points to track. -Do/Until +Do-Until ```````` Sometimes you would want to retry a task till a certain condition is met, In such conditions the Do/Until feature will help. -Here's an example which show's the syntax to be applied for the task. - - - action: shell /usr/bin/foo - register: result - until: register.stdout.find("all systems go") != -1 - retries: 5 - delay: 10 +Here's an example which show's the syntax to be applied for the task.:: + + - action: shell /usr/bin/foo + register: result + until: register.stdout.find("all systems go") != -1 + retries: 5 + delay: 10 The above example run the shell module recursively till the module's result has "all systems go" in it's stdout or the task has been retried for 5 times with a delay of 10 seconds. The default value for "retries" is 3 and "delay" is 5. @@ -479,16 +479,19 @@ been retried for 5 times with a delay of 10 seconds. The default value for "retr The task returns the results returned by the last task run. The results of individual retries can be viewed by -vv option. The results will have a new key "attempts" which will have the number of the retries for the task. -.. note:: - The Do/Until does not take decision on whether to fail or pass the play when the maximum retries are completed, the user can - can do that in the next task as follows: +.. Note:: + + The Do/Until does not take decision on whether to fail or pass the play when the maximum retries are completed, the user can + can do that in the next task as follows. + +Example:: - - action: shell /usr/bin/foo - register: result - until: register.stdout.find("all systems go") != -1 - retries: 5 - delay: 10 - failed_when: result.attempts == 5 + - action: shell /usr/bin/foo + register: result + until: register.stdout.find("all systems go") != -1 + retries: 5 + delay: 10 + failed_when: result.attempts == 5 Loops