get ansible groups by looping with_items - ansible

I'm trying to get the inventory host group names by below process which is not working
- debug:
msg: "{{ groups['{{ item }}'] }}"
with_items: "{{ vm.stdout_lines }}"
this is what actually I'm trying to do
I will get a list of servers by a shell script
- name: Getting the servers list
shell: |
sh getServers.sh
register: vm
Then adding them into inventory by add_host
- name: Creating Logical host_group for each server
add_host:
name: "{{ item }}"
groups: ["{{item }}"]
with_items: "{{ vm.stdout_lines }}"
register: inv
Here I'm trying to get the only groups I've added in above step instead of all groups
- debug:
msg: "{{ groups['{{ item }}'] }}"
with_items: "{{ vm.stdout_lines }}"
Error is
{"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute '{{ item }}'
Appreciate help on this!

Fix the syntax
msg: "{{ groups[item] }}"

Related

Ansible nested braces or nested quotes

Using ansible 2.9 I set a variable like this to store part of a group name
- name: set group
set_fact:
ansible_group: aaaa
I then want to use this variable in the following with_items clause:
- name: get
uri:
url: "http://{{ item }}:5324/kjhfg"
with_items: "{{ groups['thisgroup_{{ ansible_group }}'] }}"
However, using nested curly braces gives me the following error:
FAILED! => {"msg": "'dict object' has no attribute 'thisgroup_{{ ansible_group }}'"}
I also tried the following syntax variations
with_items: "{{ groups['thisgroup_ansible_group'] }}"
with_items: "groups['thisgroup_{{ ansible_group }}']"
with_items: "{{ groups['thisgroup_hostvars['localhost']['ansible_group']'] }}"
with_items: "{{ groups['thisgroup_hostvars[''localhost''][''ansible_group'']'] }}"
with_items: "{{ groups['thisgroup_hostvars[`localhost`][`ansible_group`]'] }}"
and probably one hundred other variations which all of them produced various errors
Can someone help me figure out the right syntax?
Simply concatenate the name of the group, e.g. given the inventory
shell> cat hosts
[thisgroup_aaaa]
host1
host2
host3
the playbook
- hosts: all
gather_facts: false
vars:
ansible_group: aaaa
_group: "{{ groups['thisgroup_' ~ ansible_group] }}"
tasks:
- debug:
var: item
loop: "{{ _group }}"
run_once: true
gives
item: host1
item: host2
item: host3

Ansible "item is undefined" when using {{ item }} in "vars" section

I have some codes like below, I want to iterate each host in groups['A'] and groups['B'] to create the group.
- name: Create a group
group:
name: "test_group"
state: "present"
delegate_to: "{{ item }}"
vars:
ansible_ssh_user: "{{ lookup('env', 'USER') }}#user#{{ item }}"
with_items:
- "{{ groups['A'] }}"
- "{{ groups['B'] }}"
Because I want to modify the ansible ssh connection user to connect to the "delegate_to" host, I override the ansible_ssh_user in this task, but it won't work and give me the error message like
FAILED! => {"msg": "'item' is undefined"}
But if I comment out the lines of
vars:
ansible_ssh_user: "{{ lookup('env', 'USER') }}#user#{{ item }}"
It gives no errors.
try changing the var to:
ansible_ssh_user: "{{ lookup('env', 'USER') }}#user#{{ ansible_hostname }}
this works fine for me:
- name: 'install public key on every server'
authorized_key:
user: '{{ myuser}}'
key: "{{ myuser.ssh_public_key }}"
delegate_to: '{{ item }}'
with_items:
- '{{ groups["A"] }}'
- '{{ groups["B"] }}'
- '{{ groups["C"] }}'
maybe you could try
but before I delegated a set_fact and recovered it locally...
Finally, I got a workaround, it involves all groups I need to use in my playbook.
And use "when" condition like
delegate_to: "{{ item }}"
with_items:
- "{{ groups['A'] }}"
- "{{ groups['B'] }}"
when: "inventory_hostname == item"
to let the task only run on the hosts mentioned in the "with_items" section.
It's not a very cool workaround but works for me...
Thank you for looking at this problem!

Sync files between 2 hosts using ansible

I'm looking for a way to sync files between 2 hosts in ansible. The scenario is as follows. I have a CSV file which contains 3 columns indicating directories which needs to be synced between 2 servers. the first 2 columns indicate the source and target servers and the third column indicates the directory
source, target, directory
src01, tgt02, dir0003
src02, tgt05, dir0004
src10, tgt68, dir1022
I found this answer for syncing files between 2 hosts - How to copy files between two nodes using ansible
Is there any way to parameterize this using a csv config file?
Yes. It's possible. In the first play read the CSV file and create group of targets. Use the new group in the second play and loop the synchronize module. For example the playbook
- hosts: localhost
tasks:
- read_csv:
path: db.csv
register: my_db
- add_host:
hostname: "{{ item.target }}"
groups: my_targets
my_list: "{{ my_db.list }}"
loop: "{{ my_db.list }}"
- hosts: my_targets
tasks:
- debug:
msg: "Copy {{ item.directory }} from {{ item.source }} to {{ inventory_hostname }}"
loop: "{{ my_list|json_query(query) }}"
vars:
query: "[?target == '{{ inventory_hostname }}']"
- name: Copy
synchronize:
src: "{{ item.directory }}"
dest: "{{ item.directory }}"
delegate_to: "{{ item.source }}"
loop: "{{ my_list|json_query(query) }}"
vars:
query: "[?target == '{{ inventory_hostname }}']"
(not tested)
gives
"msg": "Copy dir0004 from src02 to tgt05"
"msg": "Copy dir0003 from src01 to tgt02"
"msg": "Copy dir1022 from src10 to tgt68"

printing the host name from group in inventory

I have below inventory file:
[web]
10.0.1.0
[db]
10.0.3.0
[frontend]
10.0.5.0
[X_all:children]
web
db
frontend
Now in my playbook: I'm trying to print the hostname under X_all group in the name line.
- name: "Copying the output of Registry run to local machine from {{ hostvars[item]['inventory_hostname'] }}"
become: true
become_user: "{{ login }}"
fetch:
src: /tmp/DeploymentRegistry.txt
dest: /tmp/DeploymentRegistry-{{ inventory_hostname }}.txt
flat: yes
with_items:
- "{{ groups['X_all'] }}"
Is it even possible to add the hostname in the name line?
I tried replacing {{ hostvars[item]['inventory_hostname'] }} with inventory_hostname but it's also not working.
Regarding your requirement
I'm trying to print the hostname under test group in the name line.
take note that the group has more than one member and therefore more than one hostname, but a list of hostnames.
- name: Show hosts {{ groups['test'] }}
delegate_to: localhost
debug:
msg: "{{ item }}" # will show the group member hostname(s)
with_items:
- "{{ groups['test'] }}"
Is it even possible to add the hostname in the name line? I tried ... with inventory_hostname but it's also not working.
Yes, it is.
- name: Show host {{ inventory_hostname }}
debug:
msg: "{{ item }}"
with_items:
- "{{ groups['test'] }}"
But it will print the first hostname from list only.

Variable with_items and hostvars

I need to pass a dynamic group name info with_items so that i can access a specific fact that is ran from another host. I cannot hard code the group name
I tried to set a generic variable that is passed as 'GroupName' a few different ways. Including
with_items: "{{ groups['{{GROUPNAME}}'] }}"
- name: Name of task
debug:
msg: "{{ hostvars[item]['ansible_check_mode'] }}"
with_items: "{{ groups['GROUPNAME'] }}"
fatal: [localhost]: FAILED! => {"msg": "'dict object' has no attribute '{{ GROUPNAME }}'"}
Get the list of the hosts in the group and loop them
vars:
my_group: GROUPNAME
tasks:
- set_fact:
my_hosts: "{{ groups|
dict2items|
selectattr('key', 'match', my_group)|
map(attribute='value')|
list|
flatten }}"
- debug:
msg: "{{ hostvars[item]['ansible_check_mode'] }}"
loop: "{{ my_hosts }}"
(not tested)

Resources