How can I call a playbook multiple times? - ansible

I have a main login that is as bellow:
- name: Register
hosts: "{{ host }}"
tasks:
- include_role:
name: ROLE_NAME
vars:
service: "{{ service }}"
I want to call my main login multiple time something like bellow:
- name: call main logic
tasks:
- import_playbook:
name: main-logic.yml
loop:
- host: "1"
service: "s1"
- host: "2"
service: "s2"
I didn't find any solution for that, is it possible? HOW?

If you for whatever reason have to run the playbook(s) sequentially create a batch. However, if you want to execute the playbook on all hosts sequentially one after another, use serial. See Setting the batch size with serial. The difference is that you'll see PLAY RECAP once. In the first case, you'll see PLAY RECAP three times.
Create batch
For example,
shell> cat create_batch.yml
- hosts: localhost
vars:
my_batch:
- {host: host1, service: s1}
- {host: host2, service: s2}
- {host: host3, service: s3}
tasks:
- command: which bash
register: which_bash
- copy:
dest: "{{ playbook_dir }}/batch.sh"
mode: "a+x"
content: |
{{ '#!' }}{{ which_bash.stdout }}
{% for i in my_batch %}
ansible-playbook main-logic.yml -e "host={{ i.host }}" -e "service={{ i.service }}"
{% endfor %}
gives
shell> cat batch.sh
#!/usr/bin/bash
ansible-playbook main-logic.yml -e "host=host1" -e "service=s1"
ansible-playbook main-logic.yml -e "host=host2" -e "service=s2"
ansible-playbook main-logic.yml -e "host=host3" -e "service=s3"
Given the project tree for testing
shell> tree .
.
├── ansible.cfg
├── batch.sh
├── create_batch.yml
├── hosts
└── main-logic.yml
0 directories, 5 files
shell> cat ansible.cfg
[defaults]
gathering = explicit
inventory = $PWD/hosts
roles_path = $PWD/roles
remote_tmp = ~/.ansible/tmp
retry_files_enabled = false
stdout_callback = yaml
shell> cat hosts
host1
host2
host3
shell> cat main-logic.yml
- hosts: "{{ host }}"
tasks:
- debug:
msg: "{{ inventory_hostname }} {{ service }}"
The batch gives
shell> ./batch.sh
PLAY [host1] **************************************************************************************
TASK [debug] **************************************************************************************
ok: [host1] =>
msg: host1 s1
PLAY RECAP ****************************************************************************************
host1: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
PLAY [host2] **************************************************************************************
TASK [debug] **************************************************************************************
ok: [host2] =>
msg: host2 s2
PLAY RECAP ****************************************************************************************
host2: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
PLAY [host3] **************************************************************************************
TASK [debug] **************************************************************************************
ok: [host3] =>
msg: host3 s3
PLAY RECAP ****************************************************************************************
host3: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Setting the batch size with serial
Declare the below variables. For example, in group_vars/all
shell> cat group_vars/all/my_batch.yml
my_batch:
- {host: host1, service: s1}
- {host: host2, service: s2}
- {host: host3, service: s3}
my_batch_host_sevice: "{{ my_batch|
items2dict(key_name='host',
value_name='service') }}"
service: "{{ my_batch_host_sevice[inventory_hostname] }}"
Set serial: 1. The playbook will serve the remote hosts one after another
shell> cat main-logic.yml
- hosts: "{{ host }}"
serial: 1
tasks:
- debug:
var: ansible_play_batch
- debug:
msg: "{{ inventory_hostname }} {{ service }}"
gives
shell> ansible-playbook main-logic.yml -e host='host1:host2:host3'
PLAY [host1:host2:host3] **************************************************************************
TASK [debug] **************************************************************************************
ok: [host1] =>
ansible_play_batch:
- host1
TASK [debug] **************************************************************************************
ok: [host1] =>
msg: host1 s1
PLAY [host1:host2:host3] **************************************************************************
TASK [debug] **************************************************************************************
ok: [host2] =>
ansible_play_batch:
- host2
TASK [debug] **************************************************************************************
ok: [host2] =>
msg: host2 s2
PLAY [host1:host2:host3] **************************************************************************
TASK [debug] **************************************************************************************
ok: [host3] =>
ansible_play_batch:
- host3
TASK [debug] **************************************************************************************
ok: [host3] =>
msg: host3 s3
PLAY RECAP ****************************************************************************************
host1: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host2: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host3: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Related

How Do I Make An Ansible Playbook Skip A Role?

I am trying to skip the upgrade part of my playbook. The key part looks like this:
hosts: linux_group
name: Upgrade the third-party application
roles:
- role: "upgradeEnv"
when: ENV == inventory_hostname
vars:
logdir: "/home/appuser/external/logs"
become_user: "{{ sudoUser }}"
become_method: sudo
become: yes
tags:
- upgrade
And the key part of the role looks like this:
- name: Upgrade database
shell: "upgradeDB.sh {{ env }}"
vars:
DBURL: "{{ user }}#{{ host }}"
no_log: True
register: register_appupgrade
tags:
- upgrade
- fail:
msg: "Upgrade errors:"
when: register_appupgrade.stderr !=""
tags:
- upgrade
I run the playbook with --skip-tags=upgrade but ansible still goes into the role and runs the tasks so I end up with tags: upgrade specified on each task.
The Upgrade database gets skipped but the fail ends the run due to the when condition.
Why is the role being run from the playbook even when the tags are supposed to be skipped?
Why is the fail task not being skipped?
Given the project for testing
shell> tree .
.
├── ansible.cfg
├── hosts
├── pb.yml
└── roles
└── upgradeEnv
└── tasks
└── main.yml
3 directories, 4 files
shell> cat ansible.cfg
[defaults]
inventory = $PWD/hosts
roles_path = $PWD/roles
remote_tmp = ~/.ansible/tmp
retry_files_enabled = false
stdout_callback = yaml
shell> cat hosts
[linux_group]
test_11
test_13
ansible [core 2.14.1]
The tags keyword means the tags are applied to all tasks at the indentation level.
If you apply tags at the play level
shell> cat pb.yml
- hosts: linux_group
roles:
- role: upgradeEnv
when: ENV == inventory_hostname
tags: upgrade
everything will be skipped
shell> ansible-playbook pb.yml --skip-tags=upgrade
PLAY [linux_group] ***************************************************************************
PLAY RECAP ***********************************************************************************
If you apply tags at the role level
shell> cat pb.yml
- hosts: linux_group
roles:
- role: upgradeEnv
when: ENV == inventory_hostname
tags: upgrade
the role will be skipped
shell> ansible-playbook pb.yml --skip-tags=upgrade
PLAY [linux_group] ***************************************************************************
TASK [Gathering Facts] ***********************************************************************
ok: [test_13]
ok: [test_11]
PLAY RECAP ***********************************************************************************
test_11: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
test_13: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=
You'll see the same result if you omit tags at role level and apply tags at each task in the role
shell> cat pb.yml
- hosts: linux_group
roles:
- role: upgradeEnv
when: ENV == inventory_hostname
shell> cat roles/upgradeEnv/tasks/main.yml
- name: Upgrade database
command: "echo {{ env }}"
register: register_appupgrade
tags: upgrade
- debug:
msg: |
register_appupgrade.stdout: {{ register_appupgrade.stdout }}
register_appupgrade.stderr: {{ register_appupgrade.stderr }}
tags: upgrade
- fail:
msg: Upgrade errors
when: register_appupgrade.stderr != ""
tags: upgrade
If you don't skip tags the play works as expected
shell> ansible-playbook pb.yml -e ENV=test_11 -e env=test
PLAY [linux_group] ***************************************************************************
TASK [Gathering Facts] ***********************************************************************
ok: [test_11]
ok: [test_13]
TASK [upgradeEnv : Upgrade database] *********************************************************
skipping: [test_13]
changed: [test_11]
TASK [upgradeEnv : debug] ********************************************************************
skipping: [test_13]
ok: [test_11] =>
msg: |-
register_appupgrade.stdout: test
register_appupgrade.stderr:
TASK [upgradeEnv : fail] *********************************************************************
skipping: [test_11]
skipping: [test_13]
PLAY RECAP ***********************************************************************************
test_11: ok=3 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
test_13: ok=1 changed=0 unreachable=0 failed=0 skipped=3 rescued=0 ignored=0

get the value from a dict using filter

I have a dictionary, not a dict list, let's say I read a dict from JSON file something.json has content {"a": "b"}
I would like to extract the value using a filter, so I could process that with more filters
# Expecting 'lookup('file', 'something.json') | from_json | ???' gives the value 'b'
- debug:
msg: "{{ lookup('file', 'something.json') | from_json | ??? | urlencode() }}"
I searched that all other examples are for dict list, but I only have a dict here
Given the file below
shell> cat something.json
{"a": "b"}
Q: "Get the value from a dict using a filter."
A: I read your question: "Get the value from a hash without knowing the key." There are many options:
Include the variable from the file to a dictionary, e.g. d1, and display the first value
- hosts: localhost
tasks:
- include_vars:
file: something.json
name: d1
- debug:
msg: "{{ d1.values()|first }}"
gives
shell> ansible-playbook pb.yml
PLAY [localhost] *****************************************************************************
TASK [include_vars] **************************************************************************
ok: [localhost]
TASK [debug] *********************************************************************************
ok: [localhost] =>
msg: b
PLAY RECAP ***********************************************************************************
localhost: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can put the declarations into the vars
- hosts: localhost
vars:
d1: "{{ lookup('file', 'something.json') }}"
v1: "{{ d1.values()|first }}"
tasks:
- debug:
var: v1
- debug:
var: d1|type_debug
- debug:
var: d1
gives
PLAY [localhost] *****************************************************************************
TASK [debug] *********************************************************************************
ok: [localhost] =>
v1: b
TASK [debug] *********************************************************************************
ok: [localhost] =>
d1|type_debug: dict
TASK [debug] *********************************************************************************
ok: [localhost] =>
d1:
a: b
PLAY RECAP ***********************************************************************************
localhost: ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Use json_query
- hosts: localhost
vars:
d1: "{{ lookup('file', 'something.json') }}"
v1: "{{ d1|json_query('values(#)')|first }}"
tasks:
- debug:
var: v1
gives
PLAY [localhost] *****************************************************************************
TASK [debug] *********************************************************************************
ok: [localhost] =>
v1: b
PLAY RECAP ***********************************************************************************
localhost: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
All the above options assume the file is available at the controller. If the file is at the remote host:
Use slurp
- hosts: localhost
vars:
d1: "{{ out.content|b64decode }}"
v1: "{{ d1.values()|first }}"
tasks:
- slurp:
src: "{{ playbook_dir }}/something.json"
register: out
- debug:
var: v1
gives
PLAY [localhost] *****************************************************************************
TASK [slurp] *********************************************************************************
ok: [localhost]
TASK [debug] *********************************************************************************
ok: [localhost] =>
v1: b
PLAY RECAP ***********************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can also simply register the output of cat
- hosts: localhost
vars:
d1: "{{ out.stdout }}"
v1: "{{ d1.values()|first }}"
tasks:
- command:
cmd: "cat something.json"
chdir: "{{ playbook_dir }}"
register: out
- debug:
var: v1
gives
PLAY [localhost] *****************************************************************************
TASK [command] *******************************************************************************
changed: [localhost]
TASK [debug] *********************************************************************************
ok: [localhost] =>
v1: b
PLAY RECAP ***********************************************************************************
localhost: ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Thanks, Zeitounator, I sorted out using
- debug:
msg: "{{ lookup('file', 'something.json') | from_json | dict2items | map(attribute='value') | urlencode() }}"

Ansible - unable to append correctly using the file plugin

I'm trying to use the Ansible file plugin to append data to a txt file.
This is my playbook:
- name: Setting some variables.
hosts: "{{ target }}"
gather_facts: no
connection: local
tasks:
- name: Delete newDevices file.
file:
path: newDevices.txt
state: absent
run_once: true
- name: Create newDevices file.
file:
path: newDevices.txt
state: touch
run_once: true
- name: Add new devices to file.
delegate_to: 127.0.0.1
lineinfile:
insertafter: EOF
path: newDevices.txt
line: "{{ inventory_hostname }}"
This is my host file:
[lab]
routerA01.mgt.net
routerA02.mgt.net
routerB01.mgt.net
routerB02.mgt.net
This is how I'm running the playbook:
ansible-playbook myplaybook.yml -i hosts --limit "lab[0-1]" -e target=lab
The newDevices.txt file gets deleted and recreated but the contents of the file vary from having 1 hostname or 2 hostnames. If I change the limit in the run command to --limit "lab[0-2]" then the same thing happens. Sometimes 2 hostnames will print and other times all 3 will print. Seems like there will always be a time when the newDevices.txt file will contain one less hostname in it.
Not sure why this is happening. Tried adding a pause after the file is created to maybe give the processing a little extra time, but that didn't help either.
There is a couple of improvements
Put all tasks into a block delegated to localhost. All of them should run only once on the localhost anyway.
Then, there is no point to declare global connection: local
Set hosts: all if you plan to limit the inventory on the command line. In this case, there is no point to put the group into a variable.
Write the file in a loop. This avoids concurrent writing from multiple instances. (What is probably the main reason for your troubles.)
Given the (simplified) inventory
shell> cat hosts
[lab]
A01
A02
B01
B02
The playbook
shell> cat pb.yml
- hosts: all
gather_facts: false
tasks:
- block:
- file:
path: newDevices.txt
state: absent
- file:
path: newDevices.txt
state: touch
- lineinfile:
insertafter: EOF
path: newDevices.txt
line: "{{ item }}"
loop: "{{ ansible_play_hosts }}"
delegate_to: localhost
run_once: true
gives
shell> ansible-playbook pb.yml --limit lab[0:1]
PLAY [all] **************************************************************************************
TASK [file] *************************************************************************************
changed: [A01 -> localhost]
TASK [file] *************************************************************************************
changed: [A01 -> localhost]
TASK [lineinfile] *******************************************************************************
changed: [A01 -> localhost] => (item=A01)
changed: [A01 -> localhost] => (item=A02)
PLAY RECAP **************************************************************************************
A01: ok=3 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
shell> cat newDevices.txt
A01
A02
The above playbook is not idempotent. The file is always recreated. The result is that the files will always keep the hosts from the last play only.
The simplified playbook below is idempotent. The list of the hosts in the file, however, will be cumulative
shell> cat pb.yml
- hosts: all
gather_facts: false
tasks:
- lineinfile:
create: true
insertafter: EOF
path: newDevices.txt
line: "{{ item }}"
loop: "{{ ansible_play_hosts }}"
delegate_to: localhost
run_once: true
gives
shell> ansible-playbook pb.yml --limit lab[0:1]
PLAY [all] **************************************************************************************
TASK [lineinfile] *******************************************************************************
changed: [A01 -> localhost] => (item=A01)
changed: [A01 -> localhost] => (item=A02)
PLAY RECAP **************************************************************************************
A01: ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
shell> cat newDevices.txt
A01
A02
shell> ansible-playbook pb.yml --limit lab[0:1]
PLAY [all] **************************************************************************************
TASK [lineinfile] *******************************************************************************
ok: [A01 -> localhost] => (item=A01)
ok: [A01 -> localhost] => (item=A02)
PLAY RECAP **************************************************************************************
A01: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
shell> ansible-playbook pb.yml --limit lab[0:2]
PLAY [all] **************************************************************************************
TASK [lineinfile] *******************************************************************************
ok: [A01 -> localhost] => (item=A01)
ok: [A01 -> localhost] => (item=A02)
changed: [A01 -> localhost] => (item=B01)
PLAY RECAP **************************************************************************************
A01: ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
shell> cat newDevices.txt
A01
A02
B01
shell> ansible-playbook pb.yml --limit lab[0]
PLAY [all] **************************************************************************************
TASK [lineinfile] *******************************************************************************
ok: [A01 -> localhost] => (item=A01)
PLAY RECAP **************************************************************************************
A01: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
shell> cat newDevices.txt
A01
A02
B01
The playbook below is idempotent and the file will keep the list of hosts from the last play only
shell> cat pb.yml
- hosts: all
gather_facts: false
tasks:
- copy:
dest: newDevices.txt
content: |-
{% for host in ansible_play_hosts %}
{{ host }}
{% endfor %}
delegate_to: localhost
run_once: true
Another way to do this would be to have a play targeting localhost itself since the file is to be created on the controller anyway. The file can be created using the "items" of lab inventory group.
Something like below:
- hosts: localhost
connection: local
tasks:
- file:
path: newDevices.txt
state: absent
- lineinfile:
path: newDevices.txt
create: yes
insertafter: EOF
line: "{{ item }}"
loop: "{{ groups['lab'][0:2] }}"
In the above example, the file gets created by lineinfile task itself. You can also remove/change the list slice of [0:2] as per your requirement.
Then run it with:
ansible-playbook myplaybook.yml -i hosts

Fetch hosts without domain from inventory file

I have following inventory file
$ cat hosts
[web]
server1.example.com
server2.example.com
I would like to fetch the hostname, without the part of domain (.example.com).
I tried with the following playbook, however, it is still fetching with the entire hostname..
$ playbook.yaml
- hosts: localhost
tasks:
- debug:
msg: "{{ groups['web'] }}"
Output
PLAY [localhost] *************************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************************
ok: [localhost]
TASK [debug] *****************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"server1.example.com"
"server2.example.com"
]
}
PLAY RECAP *******************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Expected output
PLAY [localhost] *************************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************************
ok: [localhost]
TASK [debug] *****************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"server1"
"server2"
]
}
PLAY RECAP *******************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can get what you want from a magic variable called inventory_hostname_short which basically returns anything before the first . found in the inventory_hostname.
To get this in a normal play host loop, it's as easy as:
- hosts: all
tasks:
- name: show target short name
debug:
var: inventory_hostname_short
If you need to get that for hosts not in the host loop, you will have to go through hostvars. Here is an example to get all those names in a list for a given group running from localhost:
- hosts: localhost
gather_facts: false
tasks:
- name: show list of shortnames for group 'toto'
debug:
msg: "{{ groups['toto'] | map('extract', hostvars, 'inventory_hostname_short') }}"
An other example to get that name only for the first server in group 'toto'
- hosts: localhost
gather_facts: false
tasks:
- name: show shortnames for first server in group 'toto'
vars:
server_name: "{{ groups['toto'][0] }}"
debug:
msg: "{{ hostvars[server_name].inventory_hostname_short }}"

Ansible how to select hosts based on certain attributes and use their ip addresses to create a list at runtime

I have a specific question about data manipulation in ansible.
In my inventory file, I have a group called postgresql as below:
[postgresql]
host1 ansible_host=1.1.1.1 postgresql_cluster_port=5432 postgresql_harole=master
host2 ansible_host=2.2.2.2 postgresql_cluster_port=5432 postgresql_harole=slave postgresql_master_ip=1.1.1.1
host3 ansible_host=3.3.3.3 postgresql_cluster_port=5432 postgresql_harole=slave postgresql_master_ip=1.1.1.1
host4 ansible_host=4.4.4.4 postgresql_cluster_port=5432 postgresql_harole=slave postgresql_master_ip=1.1.1.1
Somewhere in my playbook I will need to manipulate and use filters to make a list of ip addresses of all hosts whose postgresql_harole=slave as below:
- hosts: postgresql
gather_facts: True
remote_user: root
tasks:
- set_facts:
slave_ip_list: "{{ expressions }}"
I am pulling my hairs to have the correct expressions... any help is highly appreciated!!!!
Q: "List of ip addresses of all hosts whose postgresql_harole=slave"
A: Select the attribute from hostvars, e.g.
- set_fact:
slave_ip_list: "{{ hostvars|dict2items|
selectattr('value.postgresql_harole', 'eq', 'slave')|
map(attribute='value.ansible_host')|
list }}"
run_once: true
gives
slave_ip_list:
- 2.2.2.2
- 3.3.3.3
- 4.4.4.4
Select the hostvars for the group postgresql first if there are hostvars for other hosts, e.g. as a result of - hosts: all. The task below gives the same result
- set_fact:
slave_ip_list: "{{ groups.postgresql|
map('extract', hostvars)|
selectattr('postgresql_harole', 'eq', 'slave')|
map(attribute='ansible_host')|
list }}"
run_once: true
Update
You can simplify both the code and inventory. Put the declarations into the group_vars. For example,
shell> cat group_vars/postgresql
postgresql_cluster_port: 5432
postgresql_master_ip: "{{ groups.postgresql|
map('extract', hostvars)|
selectattr('postgresql_harole', 'eq', 'master')|
map(attribute='ansible_host')|first }}"
postgresql_slave_ip: "{{ groups.postgresql|
map('extract', hostvars)|
selectattr('postgresql_harole', 'eq', 'slave')|
map(attribute='ansible_host')|list }}"
Then, you can remove postgresql_master_ip and postgresql_cluster_port from the inventory
shell> cat hosts
[postgresql]
host1 ansible_host=1.1.1.1 postgresql_harole=master
host2 ansible_host=2.2.2.2 postgresql_harole=slave
host3 ansible_host=3.3.3.3 postgresql_harole=slave
host4 ansible_host=4.4.4.4 postgresql_harole=slave
The playbook
- hosts: postgresql
gather_facts: false
tasks:
- debug:
msg: |
ansible_host: {{ ansible_host }}
postgresql_harole: {{ postgresql_harole }}
postgresql_master_ip: {{ postgresql_master_ip }}
postgresql_cluster_port: {{ postgresql_cluster_port }}
postgresql_slave_ip: {{ postgresql_slave_ip }}
gives
shell> ansible-playbook pb.yml
PLAY [postgresql] ****************************************************************************
TASK [debug] *********************************************************************************
ok: [host1] =>
msg: |-
ansible_host: 1.1.1.1
postgresql_harole: master
postgresql_master_ip: 1.1.1.1
postgresql_cluster_port: 5432
postgresql_slave_ip: ['2.2.2.2', '3.3.3.3', '4.4.4.4']
ok: [host2] =>
msg: |-
ansible_host: 2.2.2.2
postgresql_harole: slave
postgresql_master_ip: 1.1.1.1
postgresql_cluster_port: 5432
postgresql_slave_ip: ['2.2.2.2', '3.3.3.3', '4.4.4.4']
ok: [host4] =>
msg: |-
ansible_host: 4.4.4.4
postgresql_harole: slave
postgresql_master_ip: 1.1.1.1
postgresql_cluster_port: 5432
postgresql_slave_ip: ['2.2.2.2', '3.3.3.3', '4.4.4.4']
ok: [host3] =>
msg: |-
ansible_host: 3.3.3.3
postgresql_harole: slave
postgresql_master_ip: 1.1.1.1
postgresql_cluster_port: 5432
postgresql_slave_ip: ['2.2.2.2', '3.3.3.3', '4.4.4.4']
PLAY RECAP ***********************************************************************************
host1: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host2: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host3: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host4: ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The easiest solution is probably to use Ansible's group_by module, which allows you to create groups dynamically based on the values of host variables. For example, given this inventory:
[postgresql]
host1 ansible_host=1.1.1.1 postgresql_cluster_port=5432 postgresql_harole=master
host2 ansible_host=2.2.2.2 postgresql_cluster_port=5432 postgresql_harole=worker postgresql_master_ip=1.1.1.1
host3 ansible_host=3.3.3.3 postgresql_cluster_port=5432 postgresql_harole=worker postgresql_master_ip=1.1.1.1
host4 ansible_host=4.4.4.4 postgresql_cluster_port=5432 postgresql_harole=worker postgresql_master_ip=1.1.1.1
We can group hosts using the postgresql_harole variable like this:
- hosts: all
gather_facts: false
tasks:
- name: create group of postgresql workers
group_by:
key: "pg_role_{{ postgresql_harole|default('none') }}"
- hosts: pg_role_worker
gather_facts: false
tasks:
- run_once: true
debug:
var: groups.pg_role_worker
- debug:
msg: "Hello world"
Running the above playbook would generate output similar to:
PLAY [all] ***********************************************************************************
TASK [create group of postgresql workers] ****************************************************
changed: [host1]
changed: [host2]
changed: [host3]
changed: [host4]
PLAY [pg_role_worker] ************************************************************************
TASK [debug] *********************************************************************************
ok: [host2] => {
"groups.pg_role_worker": [
"host2",
"host3",
"host4"
]
}
TASK [debug] *********************************************************************************
ok: [host2] => {
"msg": "Hello world"
}
ok: [host3] => {
"msg": "Hello world"
}
ok: [host4] => {
"msg": "Hello world"
}
PLAY RECAP ***********************************************************************************
host1 : ok=1 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host2 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host3 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host4 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can see that (a) there now exists a group pg_role_worker containing hosts host2, host3, and host4 and that (b) the final debug task runs only on those hosts.

Resources