Ansible, Issue while using variable content in playbook - ansible

I need to use variable defined for some hosts (in inventory), on another host.
Here i define it in my inventory
[mygroup:vars]
service_url=my_front_url
Where mygroup contain other groups, containing my hosts.
Then my playbook :
- name: Get variable
hosts: 127.0.0.1
tasks:
- debug:
var: hostvars[groups['{{ platform }}'][0]]['service_url']
- debug:
msg: "{{ hostvars[groups['\"{{ platform }}\"'][0]]['service_url'] }}"
Where platform is an extra-var (setting which "mygroup" to use)
and where 127.0.0.1 is my ansible host, distinct from my target hosts.
ex:
ansible-playbook test.yaml --extra-vars='platform=my-group'
TASK [debug] ********************************************************************************************************************************************************************
ok: [127.0.0.1] => {
"hostvars[groups['idi_se_prod'][0]]['service_url']": "my-front-url"
}
TASK [debug] ********************************************************************************************************************************************************************
fatal: [127.0.0.1]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dict object' has no attribute '\"{{ platform }}\"'\n\nThe error appears to have been in 'XXXX/ansible/test.yaml': line 6, column 5, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n var: hostvars[groups['{{ platform }}'][0]]['service_url']\n - debug:\n ^ here\n"}
If i set static group name in yaml, this work fine.
- name: Get variable
hosts: 127.0.0.1
tasks:
- debug:
var: hostvars[groups['{{ platform }}'][0]]['service_url']
- debug:
msg: "{{ hostvars[groups['mygroup'][0]]['service_url'] }}"
TASK [debug] ********************************************************************************************************************************************************************
ok: [127.0.0.1] => {
"hostvars[groups['my-group'][0]]['service_url']": "my-front-url"
}
TASK [debug] ********************************************************************************************************************************************************************
ok: [127.0.0.1] => {
"msg": "my_front_url"
}
It look like a syntax probleme but i tried so many ways that i think i could use some help.
Thank you
Nicolas

Everything inside {{ and }} is more or less just python, so don't use recursive templates like you have:
msg: "{{ hostvars[groups['\"{{ platform }}\"'][0]]['service_url'] }}"
instead just reference the variable like it is, a variable:
msg: "{{ hostvars[groups[platform][0]]['service_url'] }}"

Related

Why is my fail msg not being displayed when lookup('vars', item) fails?

I need to modify a playbook that expects to have a yaml file loaded via --extra-vars because the extra vars file needs to be generated with user input every time it's used.
This playbook currently overwrites a file and then modifies it, replacing placeholders with the values in my-extra-vars.yml. This is a destructive step; if a variable is not defined then the placeholder is left untouched.
This is working, sort of, but the error message is not what I expect or want.
vars:
- required_vars:
- 'varname1'
- 'varname2'
tasks:
- name: Check for required variables
fail:
msg: "variable '{{item}}' is not defined"
when: lookup('vars', item) is undefined
with_items: "{{required_vars}}"
Running the playbook as ansible playbook -K --extra-vars '#test-vars.yml' test.yml with only varname1 defined gives me the following output.
TASK [Check for required variables] **************************************************************************************
skipping: [127.0.0.1] => (item=varname1)
fatal: [127.0.0.1]: FAILED! => {"msg": "The conditional check 'lookup('vars', item) is undefined' failed. The error was: error while evaluating conditional (lookup('vars', item) is undefined): No variable found with this name: varname2\n\nThe error appears to be in '/home/me/projects/test/test.yml': line 21, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n tasks:\n - name: Check for required variables\n ^ here\n"}
If all variables are defined, then there is no syntax error. Otherwise, it is dying, so at least that aspect of the problem is managed.
Because the lookup, itself is failing, so the when condition fails and your tasks is not failing as it normally should.
A way around this failure would be to use the default of the vars lookup, but from there it all depends what are your acceptable values for those variables.
An example, considering I do not want blank string in them would be:
- name: Check for required variables
fail:
msg: "variable '{{item}}' is not defined"
when: lookup('vars', item, default='') == ''
loop: "{{ required_vars }}"
vars:
required_vars:
- 'varname1'
- 'varname2'
Which would yield your expected:
TASK [Check for required variables] **************************************
failed: [localhost] (item=varname1) => changed=false
ansible_loop_var: item
item: varname1
msg: variable 'varname1' is not defined
failed: [localhost] (item=varname2) => changed=false
ansible_loop_var: item
item: varname2
msg: variable 'varname2' is not defined
A better way, though, is to use the undef keyword, this way, if you do template the variable, they will automatically raise the undefined hint provided.
Given the playbook
- hosts: localhost
gather_facts: no
vars:
varname1: "{{ undef(hint='Please provide a value for `varname1`') }}"
tasks:
- debug:
msg: "{{ varname1 }}"
It yields:
atal: [localhost]: FAILED! =>
msg: |-
The task includes an option with an undefined variable.
The error was: {{ undef(hint='Please provide a value for `varname1`') }}:
Please provide a value for `varname1`

How to use custom fact in Ansible dynamically to evaluate conditional statement

I'm trying to evaluate the condition
hostvars[inventory_hostname].external_ip == ansible_facts['ipify_ip']
The external_ip is set on the host_variable . I have set the ipify_ip on the custom facts and trying to evaluate this condition
when: hostvars[inventory_hostname].external_ip == ansible_facts['ipify_ip']
I have tried this option also but it failed there too
when: hostvars[inventory_hostname].external_ip == {{ ipify_ip }}
Here is the complete playbook file
- name: Get public ip for the host
ipify_facts:
api_url: https://api.ipify.org/
timeout: 20
tags: always
- name: Set fact
set_fact:
ipify_ip: "{{ ipify_public_ip }}"
tags: always
- name: ipify_ip External IP
debug:
var: ipify_ip
tags: always
- name: is extrnal_ip in hostvars is same with ipify_ip
debug:
var=hostvars[inventory_hostname].external_ip
when: hostvars[inventory_hostname].external_ip == ansible_facts['ipify_ip']
tags: always
The error
fatal: [localhost]: FAILED! => {"msg": "The conditional check 'hostvars[inventory_hostname].external_ip == ansible_facts['ipify_ip']' failed. The error was: error while evaluating conditional (hostvars[inventory_hostname].external_ip == ansible_facts['ipify_ip']): 'dict object' has no attribute 'ipify_ip'\n\nThe error appears to be in '/home/anish/playbook/prereqs.yml': line 29, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n - name: extrnal_ip on hostvars\n ^ here\n"}
What is the right way to do this ??
Simply use the variables. For example, given the inventory
shell> cat hosts
host01 external_ip=1.2.3.4
and the playbook
shell> cat playbook.yml
- hosts: host01
tasks:
- set_fact:
ipify_ip: 1.2.3.4
- debug:
var: ipify_ip
- debug:
var: external_ip
- debug:
msg: "{{ external_ip }} is equal to {{ ipify_ip }}"
when: external_ip == ipify_ip
gives
shell> ansible-playbook -i hosts playbook.yml
PLAY [host01] *******************************
TASK [set_fact] *****************************
ok: [host01]
TASK [debug] ********************************
ok: [host01] =>
ipify_ip: 1.2.3.4
TASK [debug] ********************************
ok: [host01] =>
external_ip: 1.2.3.4
TASK [debug] ********************************
ok: [host01] =>
msg: 1.2.3.4 is equal to 1.2.3.4
PLAY RECAP **********************************
host01: ok=4 changed=0 unreachable=0 failed=0 ...

ansible-playbook command raising undefined variable error while variable is set in inventory file

I'm facing a mysterious ansible behaviour.
I've set groups, hosts and groups vars in my inventory file, but the ansible-playbook command is raising Undefined Variable for all my group vars, while printing them with the ansible debug module show the variable well.
Here is my inventory.ini file:
[windows]
ad_server ansible_host=mrspw00550.mydomain.com
[windows:vars]
ansible_connection=winrm
ansible_winrm_transport=ntlm
ansible_port=5985
ansible_become_method=runas
dns_zone=mydomain.com
ptr_zone=10.in-addr.arpa
dns_server=10.0.100.100
[linux]
web_server ansible_host=10.0.101.129
[linux:vars]
ansible_connection=ssh
ansible_become=yes
ansible_become_method=sudo
dns_zone=mydomain.com
ptr_zone=10.in-addr.arpa
dns_server=10.0.100.100
linux_home_dir=/home/ldaphome
the playbook file (set-hostname-and-dns.yml):
- name: Debug vars
debug: var=hostvars[inventory_hostname]['dns_zone']
delegate_to: ad_server
- name: Set hostname and make DNS registrations
block:
- name: Set hostname
hostname:
name: "web.{{ dns_zone }}"
delegate_to: web_server
- name: Create a DNS registration of type A
win_dns_record:
name: "web"
type: "A"
value: "{{ inventory_hostname }}"
zone: "{{ dns_zone }}"
computer_name: "{{ dns_server }}"
delegate_to: "{{ ad_server }}"
- name: Create a DNS registration of type PTR
win_dns_record:
name: "{{ inventory_hostname }}"
type: "PTR"
value: "web"
zone: "{{ ptr_zone }}"
computer_name: "{{ dns_server }}"
delegate_to: "{{ ad_server }}"
Running the ansible-playbook command gives :
$ ansible-playbook playbook.yml -i inventory-files/inventory.ini
PLAY [localhost] *********************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************************************************************
ok: [localhost]
TASK [create-linux-vm : Debug vars] **************************************************************************************************************************************************************************
ok: [localhost -> mrspw00550.mydomain.com] => {
"hostvars[inventory_hostname]['dns_zone']": "VARIABLE IS NOT DEFINED!"
}
TASK [create-linux-vm : Set web_server hostname] **************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'dns_zone' is undefined\n\nThe error appears to be in 'set-hostname-and-dns.yml': line 14, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n block:\n - name: Set {{ vm_name }} hostname\n ^ here\nWe could be wrong, but this one looks like it might be an issue with\nmissing quotes. Always quote template expression brackets when they\nstart a value. For instance:\n\n with_items:\n - {{ foo }}\n\nShould be written as:\n\n with_items:\n - \"{{ foo }}\"\n"}
PLAY RECAP ***************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Running debug module:
$ ansible -m debug -i inventory-files/inventory.ini -a "var=hostvars[inventory_hostname]['dns_zone']" all
ad_server | SUCCESS => {
"hostvars[inventory_hostname]['dns_zone']": "mydomain.com"
}
web_server | SUCCESS => {
"hostvars[inventory_hostname]['dns_zone']": "mydomain.com"
}
$
So as you can see, ansible-playbook command is unable to retrieve my host vars, while ansible debug module does.
The result is the same even if I define those variables in inventory-files/group_vars/linux.yml or inventory-files/group_vars/windows.yml, the variable is still as undefined by ansible. The problem is the same if try to access any other variable than special variables from inventory running ansible-playbook
What could be wrong there?
I tried with delegate_facts set to true, it didn't work.
Then defined a local group in the inventory containing localhost and defined my local group vars there like this :
[local]
localhost
[local:vars]
ansible_connection=local
dns_zone=mydomain.com
ptr_zone=10.in-addr.arpa
dns_server=10.0.100.100
linux_home_dir=/home/ldaphome
and remove those var from remote hosts facts, as I don't really those variables there. All my tasks are executed on the localhost and delegated to the remote hosts depending to the action.
I'd also like to precise that specifically ask for var/fact like #Zeitounator mentioned above ({{ hostvars['ad_server'].ptr_zone }}) in his comment works too.

Syntax for retrieving variable using another variable

I'm trying to find the UUID of a VM based on it's hostname. I'm not sure what is missing in my syntax here, but I've tried several different methods. Here is the sample playbook I'm working with currently:
---
- name: Test taking snapshot by UUID
hosts: tst000.company.com
vars_files:
- vars/credentials.yml
tasks:
- name: Gather all registered virtual machines
vmware_vm_facts:
hostname: 'vcenter.company.com'
username: '{{ vcenter.username }}'
password: '{{ vcenter.password }}'
validate_certs: False
delegate_to: localhost
register: vmfacts
- debug:
var: vmfacts.virtual_machines.{{ ansible_facts['hostname'] }}.uuid
- set_fact:
vm_uuid: "{{ lookup('vars', 'vmfacts.virtual_machines.' + ansible_facts['hostname'] + '.uuid') }}"
Results are as follows:
Identity added: /opt/tmp/awx_2507_ithHYD/credential_3
(/opt/tmp/awx_2507_ithHYD/credential_3) Vault password:
PLAY [Test taking snapshot by UUID]
********************************************
TASK [Gathering Facts]
********************************************************* ok: [tst000.company.com]
TASK [Gather all registered virtual machines]
********************************** ok: [tst000.company.com -> localhost]
TASK [debug]
******************************************************************* ok: [tst000.company.com] => {
"vmfacts.virtual_machines.tst000.uuid": "421d2491-8896-e52f-e4f5-5118687ce0e9" }
TASK [set_fact]
**************************************************************** fatal: [tst000.company.com]: FAILED! => {"msg": "The task
includes an option with an undefined variable. The error was: No
variable found with this name:
vmfacts.virtual_machines.tst000.uuid\\n\\nThe error appears to
have been in '/var/lib/awx/projects/quick-stuff/test_snapshot.yml':
line 21, column 7, but may\\nbe elsewhere in the file depending on the
exact syntax problem.\\n\\nThe offending line appears to be:\\n\\n\\n
- set_fact:\\n ^ here\\n"}
PLAY RECAP
********************************************************************* tst000.company.com : ok=3 changed=0 unreachable=0
failed=1
In the debug and set_fact modules, you can see that the ansible_facts['hostname]' properly places the hostname as needed, however, it returns the proper value in the debug module, but is claiming there is no variable found by that name in the set_fact module. I'm not sure what is wrong with my syntax here.
There's no need to use the lookup in that way, since vars and its hostvars friend are effectively dicts:
- set_fact:
vm_uuid: "{{ vmfacts.virtual_machines[ansible_facts['hostname']].uuid }}"

Ansible v2.2 error when using with_subelements which worked fine in 1.7

I am getting the following error while running my ansible playbook.
TASK [base : Rsyslog yapilandiriliyor.]
**************************************** fatal: [gkts.ahtapot]: FAILED! => {"failed": true, "msg": "The conditional check
'ansible_fqdn == {{item.1}}' failed. The error was: error while
evaluating conditional (ansible_fqdn == {{item.1}}): 'item' is
undefined\n\nThe error appears to have been in
'/etc/ansible/roles/base/tasks/rsyslog.yml': line 2, column 3, but
may\nbe elsewhere in the file depending on the exact syntax
problem.\n\nThe offending line appears to be:\n\n---\n- name: Rsyslog
yapilandiriliyor.\n ^ here\n"}
This worked fine in ansible 1.7 but doesn't work in ansible 2.2.1
- name: Rsyslog yapilandiriliyor.
template:
src: "{{ rsyslog['conf']['source'] }}"
dest: "{{ rsyslog['conf']['destination'] }}"
owner: "{{ rsyslog['conf']['owner'] }}"
group: "{{ rsyslog['conf']['group'] }}"
mode: "{{ rsyslog['conf']['mode'] }}"
# when: "ansible_fqdn == item.1"
when: "ansible_fqdn == {{item.1}}"
with_subelements:
- "{{ossimciks}}"
- "{{clients}}"
notify:
- rsyslog servisini yeniden baslat
sudo: yes
tags: rsyslog
ossimciks and clients are defined in my vars file:
ossimciks:
server01:
fqdn: "OSSIMCIK_FQDN"
port: "20514"
clients:
- "LOG_KAYNAGI_FQDN"
- "LOG_KAYNAGI_FQDN"
What am I missing?
with_subelements:
- "{{ossimciks}}"
- "{{clients}}"
Syntax
I don't know how where/how/when this might have changed in Ansible, but I think that
the first element in with_subelements is a variable, and
the second element in with_subelements is a key.
This works in playbooks I've written, and matches the relevant docs (since 2.5, there are no with_* loops [1] in the docs since they were always lookups anyhow [2]):
with_subelements:
- "{{ ossimciks }}"
- clients
Data
It's not clear to me which item you're attempting to target with {{ item.1 }} in your playbook, but if making a minor change to your data is permissible, you can structure it so that any of the information shown is accessible within a with_subelements loop (I've also expanded and restructured the data a bit to clarify what the loop is doing):
---
- hosts: localhost
gather_facts: false
vars:
fqdn_var: "OSSIMCIK_FQDN_2"
ossimciks:
- server: "server01"
fqdn: "OSSIMCIK_FQDN_1"
port: "20514"
clients:
- "LOG_KAYNAGI_FQDN_1"
- "LOG_KAYNAGI_FQDN_2"
- server: "server02"
fqdn: "OSSIMCIK_FQDN_2"
port: "20514"
clients:
- "LOG_KAYNAGI_FQDN_1"
- "LOG_KAYNAGI_FQDN_2"
tasks:
- name: Output ossimciks contents.
debug:
msg: "{{ item.0.server }} client: {{ item.1 }}"
with_subelements:
- "{{ ossimciks }}"
- clients
when: item.0.fqdn == fqdn_var
This outputs:
skipping: [localhost] => (item=None) => {"skip_reason": "Conditional result was False"}
skipping: [localhost] => (item=None) => {"skip_reason": "Conditional result was False"}
ok: [localhost] => (item=None) => {
"msg": "server02 client: LOG_KAYNAGI_FQDN_1"
}
ok: [localhost] => (item=None) => {
"msg": "server02 client: LOG_KAYNAGI_FQDN_2"
}
[1] http://docs.ansible.com/ansible/latest/user_guide/playbooks_loops.html
[2] Loops are actually a combination of things with_ + lookup(), so any lookup plugin can be used as a source for a loop, ‘items’ is lookup.
Edited to add: the playbooks where I've used the syntax above were definitely in the 2.x release series--I think ~2.1.

Resources