diff options
author | James Cammarata <jimi@sngx.net> | 2016-07-08 16:08:38 -0500 |
---|---|---|
committer | James Cammarata <jimi@sngx.net> | 2016-07-08 16:08:38 -0500 |
commit | 5d1cee3c843d0daed126782cb317eb90aa6e489a (patch) | |
tree | 7414f3c5c4fa7382b142d385ffe8333640048e14 | |
parent | 3d7a7c16124952a38158c8d6f546534867135f74 (diff) | |
download | ansible-feature_1476.tar.gz |
New feature: add new meta action `end_play`feature_1476
This feature also cleans up and extends the meta subsystem:
* Allows for some meta actions (noop, clear_facts, clear_host_errors,
and end_play) to operate on a per-host basis, meaning they can work
with the free strategy as expected.
* Allows for conditionals on meta tasks.
* Fixes a bug where (for the linear strategy) metas were not treated
as a run_once task, meaning every host in inventory would run the
meta task.
Fixes #1476
-rw-r--r-- | lib/ansible/plugins/strategy/__init__.py | 73 | ||||
-rw-r--r-- | lib/ansible/plugins/strategy/free.py | 2 | ||||
-rw-r--r-- | lib/ansible/plugins/strategy/linear.py | 5 |
3 files changed, 59 insertions, 21 deletions
diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py index d7441b0908..f4f1d41bd2 100644 --- a/lib/ansible/plugins/strategy/__init__.py +++ b/lib/ansible/plugins/strategy/__init__.py @@ -727,28 +727,63 @@ class StrategyBase: return ret - def _execute_meta(self, task, play_context, iterator): + def _execute_meta(self, task, play_context, iterator, target_host=None): # meta tasks store their args in the _raw_params field of args, # since they do not use k=v pairs, so get that meta_action = task.args.get('_raw_params') - if meta_action == 'noop': - # FIXME: issue a callback for the noop here? - pass - elif meta_action == 'flush_handlers': - self.run_handlers(iterator, play_context) - elif meta_action == 'refresh_inventory': - self._inventory.refresh_inventory() - elif meta_action == 'clear_facts': - for host in iterator._host_states: - self._variable_manager.clear_facts(host) - #elif meta_action == 'reset_connection': - # connection_info.connection.close() - elif meta_action == 'clear_host_errors': - self._tqm._failed_hosts = dict() - self._tqm._unreachable_hosts = dict() - for host in iterator._host_states: - iterator._host_states[host].fail_state = iterator.FAILED_NONE + # FIXME(s): + # * raise an error or show a warning when a conditional is used + # on a meta task that doesn't support them + + def _evaluate_conditional(h): + all_vars = self._variable_manager.get_vars(loader=self._loader, play=iterator._play, host=host, task=task) + templar = Templar(loader=self._loader, variables=all_vars) + return task.evaluate_conditional(templar, all_vars) + + if target_host: + host_list = [target_host] else: - raise AnsibleError("invalid meta action requested: %s" % meta_action, obj=task._ds) + host_list = [host for host in self._inventory.get_hosts(iterator._play.hosts) if host.name not in self._tqm._unreachable_hosts] + + results = [] + for host in host_list: + result = None + if meta_action == 'noop': + # FIXME: issue a callback for the noop here? + result = TaskResult(host, task, dict(changed=False, msg="noop")) + elif meta_action == 'flush_handlers': + self.run_handlers(iterator, play_context) + elif meta_action == 'refresh_inventory': + self._inventory.refresh_inventory() + result = TaskResult(host, task, dict(changed=False, msg="inventory successfully refreshed")) + elif meta_action == 'clear_facts': + if _evaluate_conditional(host): + self._variable_manager.clear_facts(target_host) + result = TaskResult(host, task, dict(changed=True, msg="inventory successfully refreshed")) + else: + result = TaskResult(host, task, dict(changed=False, skipped=True)) + elif meta_action == 'clear_host_errors': + if _evaluate_conditional(host): + self._tqm._failed_hosts.pop(host.name, False) + self._tqm._unreachable_hosts.pop(host.name, False) + iterator._host_states[host.name].fail_state = iterator.FAILED_NONE + result = TaskResult(host, task, dict(changed=True, msg="successfully cleared host errors")) + else: + result = TaskResult(host, task, dict(changed=False, skipped=True)) + elif meta_action == 'end_play': + if _evaluate_conditional(host): + iterator._host_states[host.name].run_state = iterator.ITERATING_COMPLETE + result = TaskResult(host, task, dict(changed=True, msg="ending play")) + else: + result = TaskResult(host, task, dict(changed=False, skipped=True)) + #elif meta_action == 'reset_connection': + # connection_info.connection.close() + else: + raise AnsibleError("invalid meta action requested: %s" % meta_action, obj=task._ds) + + if result is not None: + results.append(result) + + return results diff --git a/lib/ansible/plugins/strategy/free.py b/lib/ansible/plugins/strategy/free.py index 89287c49ab..52dfc642f2 100644 --- a/lib/ansible/plugins/strategy/free.py +++ b/lib/ansible/plugins/strategy/free.py @@ -137,7 +137,7 @@ class StrategyModule(StrategyBase): continue if task.action == 'meta': - self._execute_meta(task, play_context, iterator) + self._execute_meta(task, play_context, iterator, target_host=host) self._blocked_hosts[host_name] = False else: # handle step if needed, skip meta actions as they are used internally diff --git a/lib/ansible/plugins/strategy/linear.py b/lib/ansible/plugins/strategy/linear.py index b0ba34cae1..644fddead4 100644 --- a/lib/ansible/plugins/strategy/linear.py +++ b/lib/ansible/plugins/strategy/linear.py @@ -212,7 +212,10 @@ class StrategyModule(StrategyBase): continue if task.action == 'meta': - self._execute_meta(task, play_context, iterator) + # for the linear strategy, we run meta tasks just once and for + # all hosts currently being iterated over rather than one host + results.extend(self._execute_meta(task, play_context, iterator)) + run_once = True else: # handle step if needed, skip meta actions as they are used internally if self._step and choose_step: |