How to remove a host from a group in Ansible
You can’t. But it’s possible to work around.
There is an unsolved issue of remove_host
module for Ansible. There is add_host
module, which allows you to add host into a group dynamically (or even create a host object in runtime), but remove_host
module is a dream (as per ansible-core 2.11). The general answer is that if you don’t need host in your play, just use ‘!
’ in a hosts
directive for a play:
---
- hosts: target,!unwanted
tasks:
....
But it’s not always the solution.
Why you may need to remove host?
The main reason is ‘do not touch playbooks text’. The most likely scenario is testing. Let’s say you have a huge project with few dozens of plays in a few playbooks, all joined into ‘site.yaml
’
You need to test following scenario:
- Run full suite for all hosts. (run 1)
- Kill one host
- Replace it with a new one.
- Run recovery playbook.
- Check if you can run full suite again for a new (updated) recovery. (run 2)
For the sake of example will assume following:
- there is a
target
group (we run our production against it). - there is a
kill
group (a hosts which are killed during test). Hosts fromkill
group must participate in run 1. - there is a
recovery
group (a hosts to replace killed hosts). They must participate in run 2.
Solution
- Put in
target
group only host which need to be present on both runs (run 1 and run 2). - Put kill hosts into kill group.
- Put recovery hosts into recovery group.
converging playbook:
---
- name: Interesting play #1
hosts: kill
tasks:
- add_host:
name: '{{ inventory_hostname }}'
groups: [target]- import_playbook: site.yaml # run 1- import_playbook: kill.yaml
- import_playbook: recovery.yaml- name: Interesting play #2
hosts: localhost
tasks:
- meta: refresh_inventory- name: Interesting play #3
hosts: recovery
tasks:
- add_host:
name: '{{ inventory_hostname }}'
groups: [target]- import_playbook: site.yaml # run 1
The magic happens in ‘interesting plays’ #1–3.
Play #1 adds hosts from ‘kill
’ group into ‘target
’ group. After that run 1 sees them all as ‘target’ group.
Play #2 reloads inventory, therefore instantly removing hosts added in play #1.
Play #3 adds hosts from recovery
group into target
group allowing site.yaml
to operate on both of them.
Basically, combination of play #1 and play #2 is the mythical remove_host
module for Ansible.
A simple playbook to show it all together (for groups foo
and bar
)
---
- hosts: bar
gather_facts: false
tasks:
- add_host:
name: '{{ inventory_hostname }}'
groups: [foo]- hosts: foo
gather_facts: false
tasks:
- debug:- hosts: localhost
gather_facts: false
tasks:
- meta: refresh_inventory- hosts: foo
gather_facts: false
tasks:
- debug: