Nested loop in ansible. product undefined - ansible

I have this simple playbook:
---
- hosts: all
become: yes
vars:
my_hosts:
- 192.168.0.1
- 192.168.0.2
- 192.168.0.3
tasks:
- name: Check ports
wait_for:
port: "{{ item.1 }}"
host: "{{ item.0 }}"
timeout: 10
loop: "{{ product(my_hosts) | product([443, 80443]) | list }}"
When I run it like so ...
$ ansible-playbook -i,192.168.2.2 run_wait_for.yml
... I get this error ...
fatal: [192.168.2.2]: FAILED! => {"msg": "'product' is undefined"}
What am I doing wrong?

Fix the syntax
loop: "{{ my_hosts | product([443, 80443]) }}"
For example
- debug:
msg: "Check host: {{ item.0 }} port: {{ item.1 }}"
loop: "{{ my_hosts|product([443, 80443]) }}"
gives (abridged)
msg: 'Check host: 192.168.0.1 port: 443'
msg: 'Check host: 192.168.0.1 port: 80443'
msg: 'Check host: 192.168.0.2 port: 443'
msg: 'Check host: 192.168.0.2 port: 80443'
msg: 'Check host: 192.168.0.3 port: 443'
msg: 'Check host: 192.168.0.3 port: 80443'

I've Ansible 2.9 and this worked to me:
---
- name: Playbook for Check Ports
hosts: localhost
connection: local
gather_facts: no
vars:
my_hosts:
- 192.168.0.1
- 192.168.0.2
- 192.168.0.3
ports:
- 443
- 80443
tasks:
- name: Check Ports.
debug:
msg: "Check host: {{ item[0] }} port: {{ item[1] }}"
loop: "{{ my_hosts | product(ports) | list }}"
...

Related

how to make a list from ansible_facts with multiple hosts

I'm trying to make a list with IP addresses of various hosts and then use this list in another task. My question is, how can I pick an IP (I need the public IP) from the output of each host and add it to a list? I need the IPs that do not start with 10..
Later, I need to use this list in another task.
I extract this information by running this playbook:
- hosts: facts
become: true
gather_facts: True
tasks:
- debug:
msg: "The ip: {{ item }}"
with_items: "{{ ansible_all_ipv4_addresses }}"
Later, I need to use this list in another task:
- wait_for:
host: "{{ item[0] }}"
port: "{{ item[1] }}"
state: started
delay: 0
timeout: 2
delegate_to: localhost
become: false
ignore_errors: no
ignore_unreachable: yes
register: result
failed_when: not result.failed
with_nested:
- [ IP LIST HERE]
- [443,80,9200,9300,22,5432,6432]
You can access those values from the hostvars right away, then use a reject filter with a match test in order to reject what you don't want to test for.
Which, in a debug task would gives:
# note: ports list reduced for brevity
- debug:
msg: "I should wait for interface {{ item.0 }}:{{ item.1 }}"
loop: >-
{{
hostvars
| dict2items
| selectattr('key', 'in', ansible_play_hosts)
| map(attribute='value.ansible_all_ipv4_addresses', default=[])
| flatten
| reject('match', '10\..*')
| product(_ports)
}}
loop_control:
label: "{{ item.0 }}"
run_once: true
delegate_to: localhost
vars:
_ports:
- 22
- 80
In my lab, this give:
ok: [ansible-node-1 -> localhost] => (item=172.18.0.3) =>
msg: I should wait for interface 172.18.0.3:22
ok: [ansible-node-1 -> localhost] => (item=172.18.0.3) =>
msg: I should wait for interface 172.18.0.3:80
ok: [ansible-node-1 -> localhost] => (item=172.18.0.4) =>
msg: I should wait for interface 172.18.0.4:22
ok: [ansible-node-1 -> localhost] => (item=172.18.0.4) =>
msg: I should wait for interface 172.18.0.4:80
Try the example below
shell> cat pb.yml
- hosts: all
vars:
ip_list: "{{ ansible_play_hosts|
map('extract', hostvars, 'ansible_all_ipv4_addresses')|
map('first')|list }}"
ip_list_reject: "{{ ip_list|reject('match', '10\\.')|list }}"
tasks:
- setup:
gather_subset: network
- block:
- debug:
var: ip_list
- debug:
var: ip_list_reject
- wait_for:
host: "{{ item.0 }}"
port: "{{ item.1 }}"
state: started
delay: 0
timeout: 2
delegate_to: localhost
register: result
with_nested:
- "{{ ip_list_reject }}"
- [443, 80, 9200, 9300, 22, 5432, 6432]
run_once: true

Ansible variables question from output and filtered with json_query

I am trying to get the pertinent fields from a vmware module output, I am filtering with json, but the says my variable target_vm_name is undefined. how do I get a variable with only the matching criteria which is filtered by the ip address of the list of hosts I want to iterate through?
code is below:
- name: Loop thru hosts and get IPs
hosts: rpa_test
vars:
ip_addr:
"{{ lookup('dig', ansible_host) }}"
tasks:
- debug:
msg: "System {{ inventory_hostname }} has ip address of {{ ip_addr }}"
- name: get vm info based on ip
community.vmware.vmware_vm_info:
hostname: "{{ vcenter_hostname }}"
username: "{{ vault_vcenter_admin_name }}"
password: "{{ vault_vcenter_admin_password }}"
validate_certs: False
delegate_to: localhost
register: vm_info
vars:
target_vm_name: "{{ vm_info.virtual_machines | json_query(query) }}"
query: "[?ip_address=={{ ip_addr }}]"
- debug:
msg: "{{ target_vm_name.virtual_machines.guest_name }}"
vars is not at the right place inside the community.vmware.vmware_vm_info task ,
you should put it in the debug task:
tasks:
- debug:
msg: "System {{ inventory_hostname }} has ip address of {{ ip_addr }}"
- name: get vm info based on ip
community.vmware.vmware_vm_info:
hostname: "{{ vcenter_hostname }}"
username: "{{ vault_vcenter_admin_name }}"
password: "{{ vault_vcenter_admin_password }}"
validate_certs: False
delegate_to: localhost
register: vm_info
- debug:
msg: "{{ target_vm_name.virtual_machines.guest_name }}"
vars:
target_vm_name: "{{ vm_info.virtual_machines | json_query(query) }}"
query: "[?ip_address=={{ ip_addr }}]"

Ansible playbook to check connectivity to windows host and report status

I am trying to put together a playbook that will connect to hosts and report back if the connection was successful or not. The result of the connection check should be stored in a variable. I had a crack at this by using the ansible facts, however I cannot workout how to handle unsuccessful connections to hosts.
---
- name: Set Facts variables
set_fact:
server_domain: "{{ ansible_domain}}"
server_ip: "{{ ansible_ip_addresses[1] }}"
- name: Set PowerShell parameters
set_fact:
ps_params: '-server_ip "{{ ansible_ip_addresses[1] }}" -server_domain "{{ ansible_domain }}"'
- name: Execute Script
win_shell: "powershell.exe -file \\PSfile.ps1 {{ps_params}}"
Try this:
---
- hosts: all
gather_facts: yes
ignore_errors: true
ignore_unreachable: true
vars:
# email_file The filename to attach to the email
# email_recipient email address to send the email to
# email_subject text to appear in the subject line
email_subject: "Windows Server Connection Report for {{ awx_inventory_name }}"
email_file: ./failed_connect_report.csv
ansible_port: 5985
tasks:
- name: Write header and ensure the email file exists
lineinfile:
path: "{{ email_file }}"
line: 'VM Name,IP Address,Distribution,Port,Note,Port,Note'
state: present
mode: '0774'
create: yes
insertafter: EOF
become: no
delegate_to: localhost
run_once: True
when: email_recipient != ''
- name: Test connectivity to port {{ ansible_port }}
win_ping:
register: result
- name: Did we fail to talk to this host?
block:
- set_fact:
ip_addresses: "unknown"
- set_fact:
distribution: "unknown"
- name: Did we fail to talk to this host?
set_fact:
line1: "{{ inventory_hostname }},{{ ip_addresses }},{{ distribution }},{{ ansible_port }},FAILED - {{ result.msg | replace(',',' ') }}"
delegate_to: localhost
- set_fact:
failed1: "True"
when: ((result.unreachable is defined and
result.unreachable == True) or
(result.failed is defined and
result.failed == True)) and
email_recipient != ''
- name: Log the success
set_fact:
line1: "{{ inventory_hostname }},{{ ansible_facts.ip_addresses.0 }},{{ ansible_facts.distribution }},{{ ansible_port }},SUCCESS"
delegate_to: localhost
when: (failed1 is not defined) and
email_recipient != ''

when condition does not match with "ansible_host" Ansible 2.10?

I try something very simple but it does not work:
I want to execute a task only, if two strings are the same:
hostname=1-Europe-ECV-Site2
ansible_host=1-Europe-ECV-Site2
This is the playbook:
- debug: var=hostname
- debug: var=ansible_host
- name: Gather a virtual machine info
vmware_guest_info:
hostname: '{{ vsphere_host }}'
username: '{{ vsphere_user }}'
password: '{{ vsphere_password }}'
validate_certs: false
datacenter: "{{ vsphere_datacenter }}"
name: "{{ hostname }}"
schema: vsphere
properties:
- guest.ipAddress
retries: 60
delay: 10
until: gather_vm_info.instance.guest.ipAddress is not none
register: gather_vm_info
delegate_to: localhost
when: ansible_host == hostname
I got this result, even if I can see by debugging, that both values are equal:
PLAY [Configure vyOS BGP LAN Router] *****************************************************************************************************************************************************
TASK [get_ip_vsphere : debug] ************************************************************************************************************************************************************
ok: [1-Europe-ECV-Site2] =>
hostname: 1-Europe-ECV-Site2
ok: [1-Europe-ECV-Site3] =>
hostname: 1-Europe-ECV-Site3
ok: [1-Europe-ECV-Site1-1] =>
hostname: 1-Europe-ECV-Site1-1
ok: [1-Europe-ECV-Site1-2] =>
hostname: 1-Europe-ECV-Site1-2
TASK [get_ip_vsphere : debug] ************************************************************************************************************************************************************
ok: [1-Europe-ECV-Site2] =>
ansible_host: 1-Europe-ECV-Site2
ok: [1-Europe-ECV-Site3] =>
ansible_host: 1-Europe-ECV-Site3
ok: [1-Europe-ECV-Site1-1] =>
ansible_host: 1-Europe-ECV-Site1-1
ok: [1-Europe-ECV-Site1-2] =>
ansible_host: 1-Europe-ECV-Site1-2
TASK [get_ip_vsphere : Gather a virtual machine info] ************************************************************************************************************************************
skipping: [1-Europe-ECV-Site2]
skipping: [1-Europe-ECV-Site3]
skipping: [1-Europe-ECV-Site1-1]
skipping: [1-Europe-ECV-Site1-2]
TASK [get_ip_vsphere : Gather a virtual machine info] ************************************************************************************************************************************
skipping: [1-Europe-ECV-Site2]
skipping: [1-Europe-ECV-Site3]
skipping: [1-Europe-ECV-Site1-1]
skipping: [1-Europe-ECV-Site1-2]
Question:
Why this condition does not match? Do I need to do something special if I want to use the build in variable ansible_host I use Ansible 2.10
EDIT:
The purpose of this playbook is to write only the discovered IP address into the inventory YAML file under host_vars, if it is not already defined. As you can see in my example, the ansible_host is equal to the hostname of the VM, if no IP address was detected.
For this I have to check if ansible_host == hostname and only then IP must be fetched and written into the YAML inventory file.
Another solution is to check if 192.168. is not included in "ansbile_host" and then execute the task:
when: "'192.168' in ansible_host"
But this also does not work!
What do I miss?
I don't think issue is with the ansible_host variable. It is because you are trying to match hostname with ansible_host, which should ideally match every time (looking at the debug output).
For example, when the task vmware_guest_info runs on 1-Europe-ECV-Site3:
hostname == ansible_host
Will be:
"1-Europe-ECV-Site3" == "1-Europe-ECV-Site3"
#=> True
Which is not what you want, even if it runs. If you want the task to run only when ansible_hostname matches 1-Europe-ECV-Site2, then the condition should be:
- name: Gather a virtual machine info
vmware_guest_info:
hostname: '{{ vsphere_host }}'
username: '{{ vsphere_user }}'
password: '{{ vsphere_password }}'
validate_certs: false
datacenter: "{{ vsphere_datacenter }}"
name: "{{ hostname }}"
schema: vsphere
properties:
- guest.ipAddress
retries: 60
delay: 10
until: gather_vm_info.instance.guest.ipAddress is not none
register: gather_vm_info
delegate_to: localhost
when: ansible_hostname == "1-Europe-ECV-Site2"
This solution works, I don't know why the other conditions does not fit:
---
- name: Gather a virtual machine info
vmware_guest_info:
hostname: '{{ vsphere_host }}'
username: '{{ vsphere_user }}'
password: '{{ vsphere_password }}'
validate_certs: false
datacenter: "{{ vsphere_datacenter }}"
name: "{{ hostname }}"
schema: vsphere
properties:
- guest.ipAddress
retries: 60
delay: 10
until: gather_vm_info.instance.guest.ipAddress is not none
register: gather_vm_info
delegate_to: localhost
when: "'192.168' not in ansible_host"
- name: Gather a virtual machine info
vmware_guest_info:
hostname: '{{ vsphere_host }}'
username: '{{ vsphere_user }}'
password: '{{ vsphere_password }}'
validate_certs: false
datacenter: "{{ vsphere_datacenter }}"
name: "{{ hostname }}"
schema: vsphere
properties:
- guest.ipAddress
retries: 60
delay: 10
until: gather_vm_info.instance.guest.ipAddress != "0.0.0.0"
register: gather_vm_info
delegate_to: localhost
when: "'192.168' not in ansible_host"
- debug: var=gather_vm_info.instance.guest.ipAddress
- name: Update IP
block:
- name: Add ansible_host IP to the YAML inventory file
delegate_to: localhost
lineinfile:
path: host_vars/{{ hostname }}.yml
line: " ansible_host: {{ gather_vm_info.instance.guest.ipAddress }}"
- name: Update dynamic ansible_host with new IP Address
set_fact:
ansible_host: "{{ gather_vm_info.instance.guest.ipAddress }}"
ansible_hostname: "{{ hostname }}"
when: "'192.168' not in ansible_host"
If you use IP address in when condition, it works. Hostname resolution did not happen in my case.
when: ansible_host == "xx.xx.xx.xx"

item from list of nodes depend on current index of host from hostgroup

I am having below setup,
groups_var/all.yml
---
cassandra_restore:
nodes:
- 192.168.0.1
- 192.168.0.2
- 192.168.0.3
inventory contains,
[just_created]
192.168.0.4
192.168.0.5
192.168.0.6
main.yml
---
# playbook
- name: setup
hosts: just_created
remote_user: ubuntu
become: true
become_method: sudo
gather_facts: yes
vars:
current_index: "{{ ansible_play_batch.index(inventory_hostname) }}"
tasks:
- debug:
msg: "current host index: {{ ansible_play_batch.index(inventory_hostname) }} : {{ current_index }}"
- debug:
msg: "first target host: {{ cassandra_restore.nodes.0 }}"
- name: get mapped value
debug:
msg: "current target host: {{ cassandra_restore.nodes.current_index }} "
I want to access item from list of nodes depend on current index of host from hostgroup just_created.
So when the host is 192.168.0.4 it should print 192.168.0.1 and when host is 192.168.0.5 it should print 192.168.0.2 and so on.
How can I achieve this?
You have to use the map form to access with a dynamic index or key:
- name: get mapped value
debug:
msg: "current target host: {{ cassandra_restore.nodes[current_index] }} "
But I'm not sure the order of the hosts is deterministic.
---
# playbook for creating cassandra setup
- name: setup cassnadra
hosts: just_created
remote_user: ubuntu
become: true
become_method: sudo
gather_facts: yes
vars:
current_index: "{{ ansible_play_batch.index(inventory_hostname) }}"
tasks:
- name: get mapped value
debug:
msg: "current_index current target host: {{ item.index }} : {{ item.host }} : {{ current_index }} "
when: current_index == item.index
with_items:
- "{{ cassandra_restore }}"
I got this working with following variables,
cassandra_restore:
- { index: "0", host: 192.168.0.1 }
- { index: "1", host: 192.168.0.2 }
- { index: "2", host: 192.168.0.3 }

Resources