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

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"

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 Tower how to pass inventory to my playbook variables

I am setting up a vmware job in Ansible Tower to snapshot a list of VM's, ideally, this list should be generated by AWX/Tower from the vSphere dynamic inventory. Inventory is named "lab_vm" in AWX and use either the hostname or the UUID of the VM.
How do I pass this through in my playbook variables file?
---
vars:
vmware:
host: '{{ lookup("env", "VMWARE_HOST") }}'
username: '{{ lookup("env", "VMWARE_USER") }}'
password: '{{ lookup("env", "VMWARE_PASSWORD") }}'
vcenter_datacenter: "dc1"
vcenter_validate_certs: false
vm_name: "EVE-NG"
vm_template: "Win2019-Template"
vm_folder: "Network Labs"
my playbook
---
- name: vm snapshot
hosts: localhost
become: false
gather_facts: false
collections:
- community.vmware
pre_tasks:
- include_vars: vars.yml
tasks:
- name: create snapshot
vmware_guest_snapshot:
# hostname: "{{ host }}"
# username: "{{ user }}"
# password: "{{ password }}"
datacenter: "{{ vcenter_datacenter }}"
validate_certs: False
name: "{{ vm_name }}"
state: present
snapshot_name: "Ansible Managed Snapshot"
folder: "{{ vm_folder }}"
description: "This snapshot is created by Ansible Playbook"
You're going about it backward. Ansible loops through the inventory for you. Use that feature, and delegate the task to localhost:
---
- name: vm snapshot
hosts: all
become: false
gather_facts: false
collections:
- community.vmware
pre_tasks:
- include_vars: vars.yml
tasks:
- name: create snapshot
vmware_guest_snapshot:
datacenter: "{{ vcenter_datacenter }}"
validate_certs: False
name: "{{ inventory_hostname }}"
state: present
snapshot_name: "Ansible Managed Snapshot"
folder: "{{ vm_folder }}"
description: "This snapshot is created by Ansible Playbook"
delegate_to: localhost
I've not used this particular module before, but don't your want snapshot_name to be unique for each guest?

YAML: “Unsupported parameters for ansible module"

i get the below error when try this as below:
"msg": "Unsupported parameters for (vmware_vm_vm_drs_rule) module: delegate_to Supported parameters include: affinity_rule, cluster_name, drs_rule_name, enabled, hostname, mandatory, password, port, proxy_host, proxy_port, state, username, validate_certs, vms".
I dont want my module to execute when the final_list is empty or less than one object. Only if its more than 2 object in final_list i would want it to execute. Could someone help me with the correct condition
"ansible_facts": {"final_list": [ "NPSY7ADFS01"]}
"ansible_facts": {"final_list": []}
- name: Create DRS Anti Affinity Rule for VM-VM
vmware_vm_vm_drs_rule:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
cluster_name: "{{ datacenter_name }}-{{ cluster_name }}"
validate_certs: no
vms: "{{ final_list }}"
drs_rule_name: "{{ rule_name }}"
enabled: True
mandatory: True
affinity_rule: "{{ action_type }}"
delegate_to: localhost
register: rule_creation
when: final_list is defined
Q: "Unsupported parameters for (vmware_vm_vm_drs_rule) module: delegate_to ... "
A: The error message is clear: "delegate_to is not a parameter of vmware_vm_vm_drs_rule". The indentation of delegate_to is wrong. This is the reason why delegate_to has been considered a parameter of the module. Fix the indentation of delegate_to
- name: Create DRS Anti Affinity Rule for VM-VM
vmware_vm_vm_drs_rule:
hostname: "{{ vcenter_hostname }}"
username: "{{ vcenter_username }}"
password: "{{ vcenter_password }}"
cluster_name: "{{ datacenter_name }}-{{ cluster_name }}"
validate_certs: no
vms: "{{ final_list }}"
drs_rule_name: "{{ rule_name }}"
enabled: True
mandatory: True
affinity_rule: "{{ action_type }}"
delegate_to: localhost
register: rule_creation
when: final_list is defined
FWIW. Use ansible-lint to validate the syntax.
Q: "I don't want the module to execute when the final_list is empty."
A: Try this
when: final_list|default([])|length > 0

Whan can I wait for after rebooting a VmWare VM in Ansible vsphere to ensure the state is booted?

I deploy some low supported OS like Debian 9, Debian 8, Rehhat 6,7, Centos 7.
The IP configuration is unsupported at boot time, so I add only the VLAN/virtual network interface, then I use vmware_vm_shell to configure the OS step by step.
What I'm looking for is a trick to wait for an event like /proc/net/dev exists on remote VM to continue other steps
What I tried so far :
- hosts: localhost
tasks:
- name: Create a virtual machine "{{ vm_name }}"
vmware_guest:
datacenter: '{{ datacenter }}'
hostname: '{{ vcenter }}'
username: "{{ login }}"
password: "{{ passwd }}"
folder: "{{ folder }}"
name: "{{ vm_name }}"
template: '{{ template }}'
cluster: "{{ cluster }}"
state: poweredon
disk:
- size_gb: "{{ disksizeGB }}"
datastore: '{{ datastore }}'
hardware:
memory_mb: '{{ ramsizeMB }}'
num_cpus: '{{ vcpu_num }}'
hotadd_cpu: True
hotremove_cpu: True
hotadd_memory: True
networks: '{{ vlans }}'
#wait_for_ip_address: yes # ERR there's ifaces, but not ip at this time
register: deploy
- name: Wait for server to start
local_action:
module: wait_for
timeout=15
when: deploy.changed
The last wait code block sucks (waiting N seconds) , I would like something smarter.
Any idea ?
If I don't wait, I sometimes get error : fatal: [localhost]: FAILED! => {"changed": false, "msg": "VMWareTools is not installed or is not running in the guest. VMware Tools are necessary to run this module."}
because the VM is not booted. The template have vmware-tools.
https://docs.ansible.com/ansible/2.6/modules/vmware_guest_module.html#vmware-guest-module
https://docs.ansible.com/ansible/latest/modules/vmware_vm_shell_module.html
Ok, found myself :)
- name: wait for server to boot
vmware_vm_shell:
datacenter: '{{ datacenter }}'
hostname: 'vcenter{{ vcenter }}'
username: "{{ login }}"
password: "{{ passwd }}"
validate_certs: False
folder: "{{ folder }}"
vm_id: "{{ vm_name }}"
cluster: "{{ cluster }}"
vm_password: '{{ passwd }}'
vm_username: root
vm_shell: '/bin/sleep'
vm_shell_args: 0
when: deploy.changed and 'debian' in distro
register: has_reboot
until: has_reboot.failed != 'true'
delay: 2
retries: 150

Getting UUID of a VMware Virtual Machine using Ansible

We are working on Ansible Environemt. We wanted to connect to a Newly Deployed VM using its UUUID.
How to Get the UUID of a VMware Virtual Machine using Ansible so that i can establish the connection.
Did you check this link: The UUID Location and Format
It can be accessed by standard SMBIOS scanning software — for example
SiSoftware Sandra or the IBM utility smbios2 [...]
You must use the vmware_guest_facts module first, and retrieve the UUID. However, there are two identified as uuid, so I listed them both. I am assuming that the uuid you want is the instance_uuid.
tasks:
- name: get list of facts
vmware_guest_facts:
hostname: '{{ vc_name }}'
username: '{{ vc_user }}'
password: '{{ vc_pwd }}'
datacenter: "{{ dc_name }}"
name: "{{ vm_name }}"
folder: "{{ dc_folder }}"
validate_certs: False
register: vm_facts
- set_fact:
vm_uuid: "{{ vm_facts.instance.instance_uuid }}"
- debug:
msg: "product uuid hw : {{ vm_facts.instance.hw_product_uuid }}\n instance: {{ vm_facts.instance.instance_uuid }}"
Now continue on in your script and use {{ vm_uuid }} where you need the uuid to the VM.
Ansible module vmware_guest_facts has been deprecated. This will not run in Ansible 2.9. You need to use the vmware_guest_info module instead.
- name: Getting VMWARE UUID
hosts: localhost
gather_facts: false
connection: local
tasks:
- name: Get Virtual Machine info
vmware_guest_info:
validate_certs: no
hostname: "{{ vcenter_hostname }}"
username: "{{ Password }}"
password: "{{ pass }}"
validate_certs: no
datacenter: "{{ datacenter_name }}"
name: "{{ VM_Name }}"
schema: "vsphere"
properties:
delegate_to: localhost
register: vminfo
- debug:
var: vminfo.instance.config.uuid
The above code assumes you know the datacenter the VM is sitting on. If unsure of such you can also run the following code:
- name: Get UUID from given VM Name
block:
- name: Get virtual machine info
vmware_vm_info:
hostname: '{{ vcenter_hostname }}'
username: '{{ vcenter_username }}'
password: '{{ vcenter_password }}'
folder: "/datacenter/vm/folder"
delegate_to: localhost
register: vm_info
- debug:
msg: "{{ item.uuid }}"
with_items:
- "{{ vm_info.virtual_machines | json_query(query) }}"
vars:
query: "[?guest_name=='DC0_H0_VM0']"

Resources