ansible set variables conditionally in group_vars/all - ansible

i am trying to set global variables that will be valid to all playbooks
i am trying to set this global variable in group_vars/all file
i want to set one variable which can have multiple values depending to the conditions
i have tried to use when conditions:
kdump_nfs: 'nfs1'
when: ansible_local.default_gateway.site == "site1"
kdump_nfs: 'nfs2'
when: ansible_local.default_gateway.site == "site2"
but getting :
[WARNING]: While constructing a mapping from /group_vars/all, line 1, column 1, found a duplicate dict key (kdump_nfs). Using last defined value only.
how can i set the variable "kdump_nfs" to get a deferent value depending of the condition

Setting a changing variable at group vars will not be a good option. You can use the extra vars to pass the variable value that will be more dynamic.
For eg.
--extra-vars "var_name=${var_value}"

$ cat group_vars/all/main.yml
my_variable: "{% if condition1 %}foo{% else %}bar{% endif %}"
$ cat site.yml
- hosts: all
gather_facts: false
tasks:
- name: site.yml --> Print debug variable
debug:
msg: "{{ my_variable }}"
$ ansible-playbook --connection=local --inventory 127.0.0.1, site.yml --extra-vars "condition1=True"
PLAY [all] ********************************************************************************************************************************************************************************************************
TASK [site.yml --> Print debug variable] **************************************************************************************************************************************************************************
ok: [127.0.0.1] => {
"msg": "foo"
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
127.0.0.1 : ok=2 changed=0 unreachable=0 failed=0

Related

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.

How to pass URLs as a variable to an ansible playbook

I created a playbook which clears cache, I'm trying to pass a url to a variable, and when I execute the playbook I get an empty array for that parameter.
In my playbook I have a vars module with this variable (environment), it gets defined when you pass in a variable to the ansible-playbook command
vars:
environment: "{{testenv}}"
-e testenv=https://www.test1.com
When I execute the playbook I get this error.
Do I need to format the url in someway?
fatal: [localhost]: FAILED! => {"changed": false, "msg": "unknown url type: '[]/content/clear_cache?
Your issue is coming from the fact that environment is a reserved variable, as pointed in the second row of this table in the documentation:
Valid variable names
 Not valid
 foo
 *foo, Python keywords such as async and lambda
 foo_env
 playbook keywords such as environment
 foo_port
 foo-port, foo port, foo.port
 foo5, _foo
 5foo, 12
Source: https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#creating-valid-variable-names
So, you just need to change your variable name to something else and it will work.
Given the playbook:
- hosts: all
gather_facts: no
tasks:
- debug:
msg: "{{ _environment }}"
vars:
_environment: "{{ testenv }}"
When run:
$ ansible-playbook play.yml -e testenv=https://www.test1.com
PLAY [all] **********************************************************************************************************
TASK [debug] ********************************************************************************************************
ok: [localhost] => {
"msg": "https://www.test1.com"
}
PLAY RECAP **********************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Avoid unused and undefined variable in playbook

I have following data in a variable file
data: [
{
service: "ServiceName",
var2: "file/path/value",
var3: "{{ check_var }}",
}, {
service: "ServiceName",
var2: "file/path/value",
var3: "{{ check_var }}",
}
]
I have two playbooks which require the same data. However one playbook does not require var3.
- debug: msg="{{ item['service'] }} uses - {{ item['var2'] }}"
with_items: "{{ data }}"
This gives error - "'check_var' is undefined".
TRIED:
I don't want to populate the playbook with bad standards and use
when: check_var is undefined
Or use false dummy data in playbook's vars atrribute. Is there any way around this while maintaining standards. Also the actual data is quite huge so I don't want to repeat it twice for each playbook.
In Ansible data has to be assigned to hosts not to playbooks.
You have to create two host groups. Those hosts, who needs just two variables go into the first group. And those hosts which need 3 variables go into both groups. You can include the hosts of the first group in the second group.
Then you create two group var files. In the first you put 2 variables and in the second the 3rd variable.
By this each host gets the right amount of information. Playbook 1 uses 3 variables and playbook 2 uses just 2 variables.
Update: Minimal example
$ diff -N -r none .
diff -N -r none/check_var.yaml ./check_var.yaml
0a1,4
> ---
> - hosts: localhost
> tasks:
> - debug: var=check_var
diff -N -r none/group_vars/myhosts.yaml ./group_vars/myhosts.yaml
0a1
> check_var: "Hello World!"
diff -N -r none/inventory ./inventory
0a1,2
> [myhosts]
> localhost
$ ansible-playbook -i inventory check_var.yaml
PLAY [localhost] ***************************************************************************
TASK [Gathering Facts] *********************************************************************
ok: [localhost]
TASK [debug] *******************************************************************************
ok: [localhost] => {
"check_var": "Hello World!"
}
PLAY RECAP *********************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0

How to read multiline argument in Ansible

I pass a multiline variable called host_list from Jenkins to ansible which contains the list of hosts.
I need to read each host line by line and add it to ansible's add_host module.
Below is how my multiline argument looks like.
ansible-playbook /app/upgrade_tomcat.yml -i /tmp/inventory1775725953939119720.ini -t validate -f 5 -e tomcat_home=/app/tomcat -e host_list='10.9.9.19
10.9.55.16
10.9.44.26
' -e USER=user1
I tried the below but it does not work.
---
- name: "Find the details here"
hosts: localhost
tasks:
- add_host: name={{ item }}
groups=dest_nodes
ansible_user={{ USER }}
with_items: "{{ host_list.split('\n') }}"
I even tried the following:
host_list.splitlines()
host_list.split( )
But none of them works.
Requesting suggestions.
Warning: this is absolutely ugly and should be replaced by any other correct way to acheive your result (non exhaustively including: defining your host list in a group in your inventory, including a file containing a definition of your list in yaml/json, passing var as extra var directly in yaml/json....)
After this warning, here is a working solution with your current situation. Simply quote values correctly.
The command
ansible-playbook playbook.yml -e 'my_list="toto
pipo
bingo"'
The playbook
---
- name: Passing abolutely ugly vars on command line
hosts: localhost
gather_facts: false
tasks:
- name: Split ugly extra var
debug:
msg: "{{ my_list.splitlines() }}"
The result:
PLAY [Passing abolutely ugly vars on command line] ***********************************************************
TASK [Split ugly extra var] **************************************************************************************
ok: [localhost] => {
"msg": [
"toto",
"pipo",
"bingo"
]
}
PLAY RECAP ***************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can pass as an array in extra-vars as below
-e '{"host_list": [10.9.9.19,10.9.55.16,10.9.44.26]}'
But it is always good to add them in the inventory as a group and use the group name in playbook
Inventory:
[host_list]
10.9.9.19
10.9.55.16
10.9.44.26
Use below to loop through each host
with_items: "{{ groups['host_list'] }}"

Add object to a dictionary in variables

I'd like to add objects to a list in variables like this
system_user:
- user1
system_users: "{{ system_users | union(system_user) }}"
It fails with a recursion error:
AnsibleError: recursive loop detected in template string
Is there any way to solve this? I want to create a definition file for each user in group_vars/all/ and then loop through them in a playbook. I don't want to redefine the list for every new user.
PS: There's a workaround: create variables with user names, like system_user_otto20 but it's not elegant at all.
There is a similar opened issue: https://github.com/ansible/ansible/issues/17906
I suggest you not to use undefined variables in template strings to define them.
As another workaround you could use hash_behaviour=merge with following definitions:
group_vars/all.yml
system_users:
user1:
user2:
book1.yml
- hosts: localhost
gather_facts: false
vars:
system_users:
user3:
user4:
tasks:
- debug: msg="{{ system_users | unique }}"
Running a playbook:
$ ansible-playbook book1.yml
[WARNING]: Host file not found: /etc/ansible/hosts
[WARNING]: provided hosts list is empty, only localhost is available
PLAY [localhost] ***************************************************************
TASK [debug] *******************************************************************
ok: [localhost] => {
"msg": [
"user4",
"user2",
"user3",
"user1"
]
}
PLAY RECAP *********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0
unique is used to convert dictionary to unsorted list.

Resources