From a6d6a89ad1d460f8d29589128549e2bac1e54db8 Mon Sep 17 00:00:00 2001 From: James Cammarata Date: Thu, 15 Jan 2015 16:56:54 -0600 Subject: [PATCH] More work on v2, fixing bugs and getting integration tests running --- v2/ansible/executor/task_executor.py | 35 +++++++++++++++++++++------ v2/ansible/playbook/base.py | 8 +++--- v2/ansible/playbook/conditional.py | 19 +++++++++------ v2/ansible/plugins/action/__init__.py | 6 +++++ v2/ansible/plugins/action/set_fact.py | 3 +++ v2/ansible/template/__init__.py | 2 ++ 6 files changed, 53 insertions(+), 20 deletions(-) diff --git a/v2/ansible/executor/task_executor.py b/v2/ansible/executor/task_executor.py index d82060a5107..b3080ea9307 100644 --- a/v2/ansible/executor/task_executor.py +++ b/v2/ansible/executor/task_executor.py @@ -79,6 +79,10 @@ class TaskExecutor: res = self._execute() debug("_execute() done") + # make sure changed is set in the result, if it's not present + if 'changed' not in res: + res['changed'] = False + debug("dumping result to json") result = json.dumps(res) debug("done dumping result, returning") @@ -154,7 +158,7 @@ class TaskExecutor: if not self._task.evaluate_conditional(variables): debug("when evaulation failed, skipping this task") - return dict(skipped=True, skip_reason='Conditional check failed') + return dict(changed=False, skipped=True, skip_reason='Conditional check failed') self._task.post_validate(variables) @@ -166,6 +170,10 @@ class TaskExecutor: if delay < 0: delay = 1 + # make a copy of the job vars here, in case we need to update them + # with the registered variable value later on when testing conditions + vars_copy = variables.copy() + debug("starting attempt loop") result = None for attempt in range(retries): @@ -189,17 +197,28 @@ class TaskExecutor: if self._task.poll > 0: result = self._poll_async_result(result=result) + # update the local copy of vars with the registered value, if specified + if self._task.register: + vars_copy[self._task.register] = result + + # create a conditional object to evaluate task conditions + cond = Conditional(loader=self._loader) + + # FIXME: make sure until is mutually exclusive with changed_when/failed_when if self._task.until: - # make a copy of the job vars here, in case we need to update them - vars_copy = variables.copy() - # now update them with the registered value, if it is set - if self._task.register: - vars_copy[self._task.register] = result - # create a conditional object to evaluate the until condition - cond = Conditional(loader=self._loader) cond.when = self._task.until if cond.evaluate_conditional(vars_copy): break + elif (self._task.changed_when or self._task.failed_when) and 'skipped' not in result: + if self._task.changed_when: + cond.when = [ self._task.changed_when ] + result['changed'] = cond.evaluate_conditional(vars_copy) + if self._task.failed_when: + cond.when = [ self._task.failed_when ] + failed_when_result = cond.evaluate_conditional(vars_copy) + result['failed_when_result'] = result['failed'] = failed_when_result + if failed_when_result: + break elif 'failed' not in result and result.get('rc', 0) == 0: # if the result is not failed, stop trying break diff --git a/v2/ansible/playbook/base.py b/v2/ansible/playbook/base.py index 43d89e0299f..dffdabd4afa 100644 --- a/v2/ansible/playbook/base.py +++ b/v2/ansible/playbook/base.py @@ -231,13 +231,13 @@ class Base: as field attributes. ''' - debug("starting serialization of %s" % self.__class__.__name__) + #debug("starting serialization of %s" % self.__class__.__name__) repr = dict() for (name, attribute) in iteritems(self._get_base_attributes()): repr[name] = getattr(self, name) - debug("done serializing %s" % self.__class__.__name__) + #debug("done serializing %s" % self.__class__.__name__) return repr def deserialize(self, data): @@ -248,7 +248,7 @@ class Base: and extended. ''' - debug("starting deserialization of %s" % self.__class__.__name__) + #debug("starting deserialization of %s" % self.__class__.__name__) assert isinstance(data, dict) for (name, attribute) in iteritems(self._get_base_attributes()): @@ -256,7 +256,7 @@ class Base: setattr(self, name, data[name]) else: setattr(self, name, attribute.default) - debug("done deserializing %s" % self.__class__.__name__) + #debug("done deserializing %s" % self.__class__.__name__) def __getattr__(self, needle): diff --git a/v2/ansible/playbook/conditional.py b/v2/ansible/playbook/conditional.py index 65ed7c4b540..1e20f3ffc63 100644 --- a/v2/ansible/playbook/conditional.py +++ b/v2/ansible/playbook/conditional.py @@ -55,11 +55,11 @@ class Conditional: templar = Templar(loader=self._loader, variables=all_vars) for conditional in self.when: - if not self._check_conditional(conditional, templar): + if not self._check_conditional(conditional, templar, all_vars): return False return True - def _check_conditional(self, conditional, templar): + def _check_conditional(self, conditional, templar, all_vars): ''' This method does the low-level evaluation of each conditional set on this object, using jinja2 to wrap the conditionals for @@ -68,17 +68,20 @@ class Conditional: if conditional is None or conditional == '': return True - elif not isinstance(conditional, basestring): - return conditional - conditional = conditional.replace("jinja2_compare ","") + # FIXME: is this required? there is no indication what it does + #conditional = conditional.replace("jinja2_compare ","") # allow variable names - #if conditional in inject and '-' not in str(inject[conditional]): - # conditional = inject[conditional] + #if conditional in all_vars and '-' not in str(all_vars[conditional]): + # conditional = all_vars[conditional] conditional = templar.template(conditional, convert_bare=True) - original = str(conditional).replace("jinja2_compare ","") + if not isinstance(conditional, basestring): + return conditional + + # FIXME: same as above + #original = str(conditional).replace("jinja2_compare ","") # a Jinja2 evaluation that results in something Python can eval! presented = "{%% if %s %%} True {%% else %%} False {%% endif %%}" % conditional diff --git a/v2/ansible/plugins/action/__init__.py b/v2/ansible/plugins/action/__init__.py index e8f3507b399..4ca179a104d 100644 --- a/v2/ansible/plugins/action/__init__.py +++ b/v2/ansible/plugins/action/__init__.py @@ -399,6 +399,12 @@ class ActionBase: else: data = dict() + # store the module invocation details back into the result + data['invocation'] = dict( + module_args = module_args, + module_name = module_name, + ) + debug("done with _execute_module (%s, %s)" % (module_name, module_args)) return data diff --git a/v2/ansible/plugins/action/set_fact.py b/v2/ansible/plugins/action/set_fact.py index c380cadca91..bf89e7ec517 100644 --- a/v2/ansible/plugins/action/set_fact.py +++ b/v2/ansible/plugins/action/set_fact.py @@ -18,6 +18,7 @@ from ansible.errors import AnsibleError from ansible.plugins.action import ActionBase from ansible.template import Templar +from ansible.utils.boolean import boolean class ActionModule(ActionBase): @@ -29,5 +30,7 @@ class ActionModule(ActionBase): if self._task.args: for (k, v) in self._task.args.iteritems(): k = templar.template(k) + if isinstance(v, basestring) and v.lower() in ('true', 'false', 'yes', 'no'): + v = boolean(v) facts[k] = v return dict(changed=True, ansible_facts=facts) diff --git a/v2/ansible/template/__init__.py b/v2/ansible/template/__init__.py index 30696d47010..6571dca2581 100644 --- a/v2/ansible/template/__init__.py +++ b/v2/ansible/template/__init__.py @@ -30,6 +30,7 @@ from ansible.plugins import filter_loader, lookup_loader from ansible.template.safe_eval import safe_eval from ansible.template.template import AnsibleJ2Template from ansible.template.vars import AnsibleJ2Vars +from ansible.utils.debug import debug __all__ = ['Templar'] @@ -253,6 +254,7 @@ class Templar: "Make sure your variable name does not contain invalid characters like '-'." ) else: + debug("failing because of a type error, template data is: %s" % data) raise AnsibleError("an unexpected type error occurred. Error was %s" % te) if preserve_trailing_newlines: