summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Krizek <martin.krizek@gmail.com>2018-11-14 15:46:25 +0100
committerBrian Coca <bcoca@users.noreply.github.com>2018-11-14 09:46:25 -0500
commit907ff2f26c7cb9d3ec2c8110b651440b13e47277 (patch)
tree3d91e1fcf5498895020f26b70425fdbb039cb90f
parent24593f2ffbd589c1e88a73423a1e2955f6bc6f37 (diff)
downloadansible-907ff2f26c7cb9d3ec2c8110b651440b13e47277.tar.gz
Add new meta task end_host (#47194)
* Add new meta task end_host
-rw-r--r--changelogs/fragments/end-host-meta-task.yaml2
-rw-r--r--lib/ansible/modules/utilities/helper/meta.py9
-rw-r--r--lib/ansible/plugins/strategy/__init__.py7
-rw-r--r--lib/ansible/plugins/strategy/linear.py2
-rw-r--r--test/integration/targets/meta_tasks/aliases1
-rwxr-xr-xtest/integration/targets/meta_tasks/runme.sh23
-rw-r--r--test/integration/targets/meta_tasks/test_end_host.yml14
-rw-r--r--test/integration/targets/meta_tasks/test_end_host_all.yml13
8 files changed, 69 insertions, 2 deletions
diff --git a/changelogs/fragments/end-host-meta-task.yaml b/changelogs/fragments/end-host-meta-task.yaml
new file mode 100644
index 0000000000..83cbe81b5e
--- /dev/null
+++ b/changelogs/fragments/end-host-meta-task.yaml
@@ -0,0 +1,2 @@
+minor_changes:
+ - Add new meta task end_host - https://github.com/ansible/ansible/issues/40904
diff --git a/lib/ansible/modules/utilities/helper/meta.py b/lib/ansible/modules/utilities/helper/meta.py
index 3de3f6bf8a..150c61e5aa 100644
--- a/lib/ansible/modules/utilities/helper/meta.py
+++ b/lib/ansible/modules/utilities/helper/meta.py
@@ -39,7 +39,8 @@ options:
- "C(clear_host_errors) (added in 2.1) clears the failed state (if any) from hosts specified in the play's list of hosts."
- "C(end_play) (added in 2.2) causes the play to end without failing the host(s). Note that this affects all hosts."
- "C(reset_connection) (added in 2.3) interrupts a persistent connection (i.e. ssh + control persist)"
- choices: ['flush_handlers', 'refresh_inventory', 'noop', 'clear_facts', 'clear_host_errors', 'end_play', 'reset_connection']
+ - "C(end_host) (added in 2.8) is a per-host variation of C(end_play). Causes the play to end for the current host without failing it."
+ choices: ['flush_handlers', 'refresh_inventory', 'noop', 'clear_facts', 'clear_host_errors', 'end_play', 'reset_connection', 'end_host']
required: true
notes:
- C(meta) is not really a module nor action_plugin as such it cannot be overwritten.
@@ -77,4 +78,10 @@ EXAMPLES = '''
- user: name={{ansible_user}} groups=input
- name: reset ssh connection to allow user changes to affect 'current login user'
meta: reset_connection
+
+- name: End the play for hosts that run CentOS 6
+ meta: end_host
+ when:
+ - ansible_distribution == 'CentOS'
+ - ansible_distribution_major_version == '6'
'''
diff --git a/lib/ansible/plugins/strategy/__init__.py b/lib/ansible/plugins/strategy/__init__.py
index 6a5d86e69a..26f359f0a9 100644
--- a/lib/ansible/plugins/strategy/__init__.py
+++ b/lib/ansible/plugins/strategy/__init__.py
@@ -1067,6 +1067,13 @@ class StrategyBase:
if host.name not in self._tqm._unreachable_hosts:
iterator._host_states[host.name].run_state = iterator.ITERATING_COMPLETE
msg = "ending play"
+ elif meta_action == 'end_host':
+ if _evaluate_conditional(target_host):
+ iterator._host_states[target_host.name].run_state = iterator.ITERATING_COMPLETE
+ msg = "ending play for %s" % target_host.name
+ else:
+ skipped = True
+ msg = "end_host conditional evaluated to false, continuing execution for %s" % target_host.name
elif meta_action == 'reset_connection':
all_vars = self._variable_manager.get_vars(play=iterator._play, host=target_host, task=task)
templar = Templar(loader=self._loader, variables=all_vars)
diff --git a/lib/ansible/plugins/strategy/linear.py b/lib/ansible/plugins/strategy/linear.py
index 203e019a11..6db63dc558 100644
--- a/lib/ansible/plugins/strategy/linear.py
+++ b/lib/ansible/plugins/strategy/linear.py
@@ -265,7 +265,7 @@ class StrategyModule(StrategyBase):
# 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, host))
- if task.args.get('_raw_params', None) not in ('noop', 'reset_connection'):
+ if task.args.get('_raw_params', None) not in ('noop', 'reset_connection', 'end_host'):
run_once = True
if (task.any_errors_fatal or run_once) and not task.ignore_errors:
any_errors_fatal = True
diff --git a/test/integration/targets/meta_tasks/aliases b/test/integration/targets/meta_tasks/aliases
new file mode 100644
index 0000000000..b59832142f
--- /dev/null
+++ b/test/integration/targets/meta_tasks/aliases
@@ -0,0 +1 @@
+shippable/posix/group3
diff --git a/test/integration/targets/meta_tasks/runme.sh b/test/integration/targets/meta_tasks/runme.sh
new file mode 100755
index 0000000000..1549b4c578
--- /dev/null
+++ b/test/integration/targets/meta_tasks/runme.sh
@@ -0,0 +1,23 @@
+#!/usr/bin/env bash
+
+set -eux
+
+# test end_host meta task, with when conditional
+for test_strategy in linear free; do
+ out="$(ansible-playbook test_end_host.yml -i ../../inventory -e test_strategy=$test_strategy -vv "$@")"
+
+ grep -q "META: end_host conditional evaluated to false, continuing execution for testhost" <<< "$out"
+ grep -q "META: ending play for testhost2" <<< "$out"
+ grep -q "play not ended for testhost" <<< "$out"
+ grep -qv "play not ended for testhost2" <<< "$out"
+done
+
+# test end_host meta task, on all hosts
+for test_strategy in linear free; do
+ out="$(ansible-playbook test_end_host_all.yml -i ../../inventory -e test_strategy=$test_strategy -vv "$@")"
+
+ grep -q "META: ending play for testhost" <<< "$out"
+ grep -q "META: ending play for testhost2" <<< "$out"
+ grep -qv "play not ended for testhost" <<< "$out"
+ grep -qv "play not ended for testhost2" <<< "$out"
+done
diff --git a/test/integration/targets/meta_tasks/test_end_host.yml b/test/integration/targets/meta_tasks/test_end_host.yml
new file mode 100644
index 0000000000..131d4d4e26
--- /dev/null
+++ b/test/integration/targets/meta_tasks/test_end_host.yml
@@ -0,0 +1,14 @@
+- name: "Testing end_host with strategy={{ test_strategy | default('linear') }}"
+ hosts:
+ - testhost
+ - testhost2
+ gather_facts: no
+ strategy: "{{ test_strategy | default('linear') }}"
+ tasks:
+ - debug:
+
+ - meta: end_host
+ when: "host_var_role_name == 'role2'" # end play for testhost2, see test/integration/inventory
+
+ - debug:
+ msg: "play not ended for {{ inventory_hostname }}"
diff --git a/test/integration/targets/meta_tasks/test_end_host_all.yml b/test/integration/targets/meta_tasks/test_end_host_all.yml
new file mode 100644
index 0000000000..dab5e881fa
--- /dev/null
+++ b/test/integration/targets/meta_tasks/test_end_host_all.yml
@@ -0,0 +1,13 @@
+- name: "Testing end_host all hosts with strategy={{ test_strategy | default('linear') }}"
+ hosts:
+ - testhost
+ - testhost2
+ gather_facts: no
+ strategy: "{{ test_strategy | default('linear') }}"
+ tasks:
+ - debug:
+
+ - meta: end_host
+
+ - debug:
+ msg: "play not ended {{ inventory_hostname }}"