How to remove a host from a group in Ansible

You can’t. But it’s possible to work around.

George Shuklin
OpsOps
2 min readApr 12, 2021

--

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 from kill group must participate in run 1.
  • there is a recovery group (a hosts to replace killed hosts). They must participate in run 2.

Solution

  1. Put in target group only host which need to be present on both runs (run 1 and run 2).
  2. Put kill hosts into kill group.
  3. 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:

--

--

George Shuklin
OpsOps

I work at Servers.com, most of my stories are about Ansible, Ceph, Python, Openstack and Linux. My hobby is Rust.