Ansible - Iterate over inventory groups - ansible

I'm trying to iterate over an ansible inventory file base on host group from that file which are define between [].
I tried to add hosts: "{{ item }}" and with_items(I defined in different file all the hostgroup without [])in the playbook, but is not working.
[group1]
host1
host2
[group2]
test1
test2
Basically what I want to do is to iterate over each ansible hostgroup from inventory file, the same task with different parameter.
Thanks for help

Can you try as below
---
- hosts: localhost
tasks:
- name: Run command
command: "some command {{item}}"
loop: "{{ groups['all'] }}"

Related

Ansible assign hostname using inventory items

I'm trying to assign hostname to a few hosts, gathering it from inventory.
My inventory is:
[masters]
master.domain.tld
[workers]
worker1.domain.tld
worker2.domain.tld
[all:vars]
ansible_user=root
ansible_ssh_private_key_file=~/.ssh/id_rsa
The code I'm using is:
- name: Set hostname
shell: hostnamectl set-hostname {{ item }}
with_items: "{{ groups['all'] }}"
Unfortunately, code iterate all items (both IPs and hostnames) and assigns to all 3 hosts the last item...
Any help would be much appreciated.
Don't loop: this is going through all your hosts on each target. Use only the natural inventory loop and the inventory_hostname special var.
Moreover, don't use shell when there is a dedicated module
- name: Assign hostname
hosts: all
gather_facts: false
tasks:
- name: Set hostname for target
hostname:
name: "{{ inventory_hostname }}"

Run ansible task only once per each unique fact value

I have a dynamic inventory that assigns a "fact" to each host, called a 'cluster_number'.
The cluster numbers are not known in advance, but there is one or more hosts that are assigned the same number. The inventory has hundreds of hosts and 2-3 dozen unique cluster numbers.
I want to run a task for all hosts in the inventory, however I want to execute it only once per each group of hosts sharing the same 'cluster_number' value. It does not matter which specific host is selected for each group.
I feel like there should be a relatively straight forward way to do this with ansible, but can't figure out how. I've looked at group_by, when, loop, delegate_to etc. But no success yet.
An option would be to
group_by the cluster_number
run_once a loop over cluster numbers
and pick the first host from each group.
For example given the hosts
[test]
test01 cluster_number='1'
test02 cluster_number='1'
test03 cluster_number='1'
test04 cluster_number='1'
test05 cluster_number='1'
test06 cluster_number='2'
test07 cluster_number='2'
test08 cluster_number='2'
test09 cluster_number='3'
test10 cluster_number='3'
[test:vars]
cluster_numbers=['1','2','3']
the following playbook
- hosts: all
gather_facts: no
tasks:
- group_by: key=cluster_{{ cluster_number }}
- debug: var=groups['cluster_{{ item }}'][0]
loop: "{{ cluster_numbers }}"
run_once: true
gives
> ansible-playbook test.yml | grep groups
"groups['cluster_1'][0]": "test01",
"groups['cluster_2'][0]": "test06",
"groups['cluster_3'][0]": "test09",
To execute tasks at the targets include_tasks (instead of debug in the loop above) and delegate_to the target
- set_fact:
my_group: "cluster_{{ item }}"
- command: hostname
delegate_to: "{{ groups[my_group][0] }}"
Note: Collect the list cluster_numbers from the inventory
cluster_numbers: "{{ hostvars|json_query('*.cluster_number')|unique }}"
If you don't mind play logs cluttering, here's a way:
- hosts: all
gather_facts: no
serial: 1
tasks:
- group_by:
key: "single_{{ cluster_number }}"
when: groups['single_'+cluster_number] | default([]) | count == 0
- hosts: single_*
gather_facts: no
tasks:
- debug:
msg: "{{ inventory_hostname }}"
serial: 1 is crucial in the first play to reevaluate when statement on for every host.
After first play you'll have N groups for each cluster with only single host in them.

Can ansible variables be used to declare hosts in a playbook?

I have a playbook in the format below:
---
- hosts: myIP
tasks:
- name: Install a yum package in Ansible example
yum:
name: ThePackageIWantToInstall
state: present
where myIP and ThePackageIWantToInstall are variables.
When the job template runs, I would like the user in the extra variables popup to be able to go with:
myIP = 192.168.1.1
ThePackageIWantToInstall = nano
As the documentation doesn't provide an example of supplying a variable via a job template, is this possible?
Yes.
- name: Do The Thing
hosts: "{{ foo }}"
roles:
- "{{ role }}"
Need mustaches and quotes.
to run from popup
(I don't use this, but it was suggested as an edit, thanks...)
foo: value
I have achieved similar thing with add_hosts. Here iam not installing package but creating file with name passed from command line. Any number of hosts (separated by commas can be passed from command line).
# cat addhost2.yml
- hosts: localhost
gather_facts: no
tasks:
- add_host:
name: "{{ item }}"
groups: hosts_from_commandline
with_items: "{{ new_hosts_passed.split(',') }}"
- hosts: hosts_from_commandline
tasks:
- name: Ansible create file with name passed from commandline
file:
path: "/tmp/{{ filename_from_commandline }}"
state: touch
# ansible-playbook -i hosts addhost2.yml --extra-vars='new_hosts_passed=192.168.3.104,192.168.3.113 filename_from_commandline=lathamdkv'
Hope this helps

How to make Ansible playbook run on first host in the group?

How can I run a playbook only on first host in the group?
I am expecting something like this:
---
- name: playbook that only run on first host in the group
hosts: "{{ groups[group_name] | first }}"
tasks:
- debug:
msg: "on {{ inventory_hostname }}"
But this doesn't work, gives error:
'groups' is undefined
How can I make it work?
You can use:
hosts: group_name[0]
Inventory hosts values (specified in the hosts directive) are processed with a custom parser, which does not allow Jinja2 expressions like the regular template engine does.
Read about Patterns.

Ansible, how to define a list in host inventory?

I have a playbook and I want to define a list of strings in my hosts file.
Here's my host file:
[dashboard]
1.2.3.4 dashboard_domain=test site_domain=['one','two','foo', 'bar']
Here's my playbook that I attempted to write using the list documentation:
---
- hosts: dashboard
gather_facts: False
remote_user: ubuntu
become: yes
tasks:
- name: ping
ping:
- debug:
msg: "Domain: {{dashboard_domain}}"
- debug:
msg: "Site: {{ item }}"
with_items: "{{site_domain}}"
However running this playbook with ansible-playbook -i hosts ping.yml causes this error:
TASK: [debug ] ****************************************************************
fatal: [1.2.3.4] => with_items expects a list or a set
This seems to be an issue of transferring the defined list from the host file to the playbook because defining the list directly in the playbook works:
---
- hosts: dashboard
gather_facts: False
remote_user: ubuntu
become: yes
vars:
site_domain: ['one','two','foo', 'bar']
tasks:
#### APPLY HTTP-AUTH ####
- name: ping
ping:
- debug:
msg: "Domain: {{dashboard_domain}}"
- debug:
msg: "Site: {{ item }}"
with_items: "{{site_domain}}"
Just quote the variable value:
[dashboard]
1.2.3.4 dashboard_domain=test site_domain="['one','two','foo', 'bar']"
It seems in case of INI-formatted inventory files, Ansible does not parse the variable value if it starts with an unquoted [ and passes it as a string.
Regarding your example: I'm not sure why you're not getting an expected key=value error on reading the inventory file, if you really have a space inside.
#techraf does answer your question and their solution is perfect if every host in the dashboard group has a site_domain list with different values.
Looking at your playbook, though, it seems that site_domain is constant across the whole dashboard group. If you had 10 hosts in dashboard, you would have to copy the list into each host's line. To avoid the repetition, you could have a dashboard:vars section in your inventory, where you can define variables that have the same value for all the hosts in the group:
[dashboard:vars]
site_domain="['one','two','foo', 'bar']"
[dashboard]
1.2.3.4 dashboard_domain=test
1.2.3.5 dashboard_domain=uat
1.2.3.6 dashboard_domain=integ
https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#assigning-a-variable-to-many-machines-group-variables
If your inventory folder is more structured, you could also define variables for the dashboard group in a separate file, in YAML. Your inventory folder tree could be:
inventories
|
+-- group_vars
| \-- dashboard.yml
|
+-- hosts.ini
In that configuration, dashboard.yml could simply be:
site_domain: ['one', 'two', 'foo', 'bar']
...or:
site_domain:
- one
- two
- foo
- bar
https://docs.ansible.com/ansible/latest/user_guide/intro_inventory.html#organizing-host-and-group-variables

Resources