How to initilize a dictonary to some value in ansible - ansible

I am trying to set a default value to element of the dictornary, following is my playbook showing incorrect way to set the value. Can someone tell to set dictname.key.value to default. ?
-->cat initilize_dict.yml
---
- hosts: localhost
vars:
dictname:
key: 'default'
value: 'default'
tasks:
- debug: var=dictname.key.value
- debug: var=dictname.key.['value']
Current output
-->ansible-playbook initilize_dict.yml
[WARNING]: Unable to parse /etc/ansible/hosts as an inventory source
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [localhost] *************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [debug] *****************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
"dictname.key.value": "VARIABLE IS NOT DEFINED!"
}
TASK [debug] *****************************************************************************************************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "template error while templating string: expected name or number. String: {{dictname.key.['value']}}"}
to retry, use: --limit #/home/monk/samples/initilize_dict.retry
PLAY RECAP *******************************************************************************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=1

You would have to use following syntax:
- set_fact:
dictname:
key:
{ 'value': 'default' }
To validate:
- debug: var=dictname.key.value

Related

Using ansible variable inside gathered fact list

I'm stuck to get data from gathered fact, using calculated data as part of query.
I am using 2.9 ansible and here is my task
---
- hosts: ios
connection: network_cli
gather_facts: true
tasks:
- name: CEF OUTPUT
ios_command:
commands: sh ip cef 0.0.0.0 0.0.0.0 | i nexthop
register: cef
- set_fact:
reg_result: "{{ cef.stdout |string| regex_search('Tunnel[0-9]+')}}"
- name: IT WORKS!
debug:
msg: "{{ reg_result }}"
- name: MANUAL LIST
debug:
var: ansible_facts.net_interfaces.Tunnel3.description
- name: AUTO LIST
debug:
var: ansible_facts.net_interfaces.[reg_result].description
and here is output
PLAY [ios] **********************************************
TASK [Gathering Facts] **********************************
ok: [10.77.3.1]
TASK [CEF OUTPUT] ***************************************
ok: [10.77.3.1]
TASK [set_fact] *****************************************
ok: [10.77.3.1]
TASK [IT WORKS!] ****************************************
ok: [10.77.3.1] => {
"msg": "Tunnel3"
}
TASK [MANUAL LIST] **************************************
ok: [10.77.3.1] => {
"ansible_facts.net_interfaces.Tunnel3.description": "DMVPN via MTS"
}
TASK [AUTO LIST] ****************************************
fatal: [10.77.3.1]: FAILED! => {"msg": "template error while templating string: expected name or number. String: {{ansible_facts.net_interfaces.[reg_result].description}}"}
to retry, use: --limit #/home/user/ansible/retry/ios_find_gw_int.retry
PLAY RECAP **********************************************
10.77.3.1 : ok=5 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
You see. Now I know that my default gateway is pointing to "Tunnel3", and it is possible to get some data placing this "Tunnel3" in {{ ansible_facts.net_interfaces.Tunnel3.description }} but how to get this automatically? And I feel such nested variable in the list is a very handy tool.
Remove the dot if you use the indirect addressing
- name: AUTO LIST
debug:
var: ansible_facts.net_interfaces[reg_result].description
See Referencing key:value dictionary variables.

Ansible not setting environment variable correctly

I trying to set an environment variable for an ansible play.
Based on this, I should be able to do something like:
---
- hosts: localhost
connection: local
environment:
test_var: "a vault here"
tasks:
- debug:
msg: "Test var is: {{lookup('env', 'test_var')}}"
- debug:
msg: "Home is here {{lookup('env', 'HOME')}}"
But I am clearly missing something or encountered a bug?
osboxes#osboxes:~$ ansible-playbook --version
ansible-playbook 2.9.6
<snip...>
osboxes#osboxes:~$ ansible-playbook test.yaml
<snip...>
TASK [debug] ****************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Test var is: " # where is the env variable?
}
TASK [debug] ****************************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Home is here /home/osboxes"
}
When you set env using environment plugin, you do not affect the ansible session which is already running.
You would have to do as follow:
---
- hosts: localhost
connection: local
environment:
test_var: "a vault here"
tasks:
- shell: echo $test_var
register: test_var
- debug:
msg: "Test var is: {{ test_var.stdout }}"
- debug:
msg: "Home is here {{lookup('env', 'HOME')}}"
The above playbook would return the following output:
PLAY [localhost] ****************************************************************************************************************************************************
TASK [Gathering Facts] **********************************************************************************************************************************************
ok: [localhost]
TASK [shell] ********************************************************************************************************************************************************
changed: [localhost]
TASK [debug] ********************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Test var is: a vault here"
}
TASK [debug] ********************************************************************************************************************************************************
ok: [localhost] => {
"msg": "Home is here /home/ps"
}
PLAY RECAP **********************************************************************************************************************************************************
localhost : ok=4 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Note: See this link to official documents.
When you set a value with environment: at the play or block level, it
is available only to tasks within the play or block that are executed
by the same user. The environment: keyword does not affect Ansible
itself, Ansible configuration settings, the environment for other
users, or the execution of other plugins like lookups and filters.
Variables set with environment: do not automatically become Ansible
facts, even when you set them at the play level. You must include an
explicit gather_facts task in your playbook and set the environment
keyword on that task to turn these values into Ansible facts.
Important points to highlight in the above text:
The environment: keyword does not affect Ansible itself, Ansible
configuration settings, the environment for other users, or the
execution of other plugins like lookups and filters

Checking whether nested variable is defined in the when statement

Nested data structures can be accessed either by indexing using the key name or dot syntax with the key name - https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#accessing-complex-variable-data
But I'm not able to access nested data structure from variables in the when statement. Here is a minimal sample to demonstrate the issue
# cat play.yml
- hosts: localhost
vars:
parent:
child1: true tasks:
- name: "Check if variable is defined"
fail:
msg: "mandatory variable {{ item }} not passed as extra args when invoking playbook"
when: item not in vars
loop:
- parent
- parent.child1
- parent.child2
Here is the sample output
ansible-playbook play.yml (livingstone-dev/monitoring)
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [localhost] *********************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************
ok: [localhost]
TASK [Check if variable is defined] **************************************************************************************************************************
skipping: [localhost] => (item=parent)
failed: [localhost] (item=parent.child1) => {"ansible_loop_var": "item", "changed": false, "item": "parent.child1", "msg": "mandatory variable parent.child1 not passed as extra args when invoking playbook"}
failed: [localhost] (item=parent.child2) => {"ansible_loop_var": "item", "changed": false, "item": "parent.child2", "msg": "mandatory variable parent.child2 not passed as extra args when invoking playbook"}
PLAY RECAP ***************************************************************************************************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
Any idea how I can have nested variables in ansible when statements. Here are some things which I've already tried and didn't work:
Using dotted notation for accessing variable
Changing the when statement to "item is not defined" without the quotes
Below code worked for me. You have to provide the values in loop within "{{}}"
- name: "Check if variable is defined"
fail:
msg: "mandatory variable {{ item }} not passed as extra args when invoking playbook"
loop:
- "{{parent.child1}}"
- "{{parent}}"
- "{{parent.child2}}"
when: item is not defined
To get the same result without warning change
when: "{{item}} is not defined"
to
when: not vars|json_query(item)
Here is the working playbook. Thanks to #smily for pointing me in the right direction. Since the loop variable item needs to be evaluated before the when condition is evaluated, I had to expand the variable item. I've done it by encompassing the entire when condition in double quotes and just expanding the item loop variable.
$ cat play.yml (livingstone-dev/monitoring)
- hosts: localhost
vars:
parent:
child1: true
tasks:
- name: show variable
debug:
var: parent
- name: "Check if variable is defined"
fail:
msg: "mandatory variable item not passed as extra args when invoking playbook"
when: "{{item}} is not defined"
loop:
- parent
- parent.child1
- parent.child2
Here is the playbook output.
$ ansible-playbook play.yml (livingstone-dev/monitoring)
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [localhost] *********************************************************************************************************************************************
TASK [Gathering Facts] ***************************************************************************************************************************************
ok: [localhost]
TASK [show variable] *****************************************************************************************************************************************
ok: [localhost] => {
"parent": {
"child1": true
}
}
TASK [Check if variable is defined] **************************************************************************************************************************
[WARNING]: conditional statements should not include jinja2 templating delimiters such as {{ }} or {% %}. Found: {{item}} is not defined
skipping: [localhost] => (item=parent)
skipping: [localhost] => (item=parent.child1)
failed: [localhost] (item=parent.child2) => {"ansible_loop_var": "item", "changed": false, "item": "parent.child2", "msg": "mandatory variable item not passed as extra args when invoking playbook"}
PLAY RECAP ***************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0

include_vars and unknown variable

I want to use Custom variable files but I have an error. please explain me How can I have a custom variable file?
my vars/var1.yml is :
---
ip_ssh_srv1: 192.168.10.10
and vars/var2.yml is :
---
ip_ssh_srv2: 192.168.10.20
my task.yml is :
---
- include_vars:
file: var1.yml
file: var2.yml
- name: -- my task --
template: src=db_info.j2 dest=/root/db_info.cnf
and my output is :
[root#anisble ansible]# ansible-playbook playbooks/get_ip_ssh.yml
TASK [Gathering Facts]
*********************************************************************
ok: [db1]
ok: [db3]
TASK [ssh : include_vars] ***************************************************************
ok: [db1]
ok: [db2]
TASK [ssh : -- my task --] *******************************************************************
fatal: [db1]: FAILED! => {"changed": false, "msg": "AnsibleUndefinedVariable: 'ip_ssh_srv1' is undefined"}
fatal: [db2]: FAILED! => {"changed": false, "msg": "AnsibleUndefinedVariable: 'ip_ssh_srv2' is undefined"}
PLAY RECAP ****************************************************************
db1 : ok=2 changed=0 unreachable=0 failed=1
db2 : ok=2 changed=0 unreachable=0 failed=1
why unknown variable?
Mistake 1
You seem to including an unspecified vars file.
Mistake 2
You should not define the same keys multiple times.
This is a YAML dictionary:
- include_vars:
file: var1.yml
file: var2.yml
It is syntactically correct, but you defined the same key file twice.
When Ansible queries it, it can get only a single value for the file key value (var2.yml).
If you look at the include_vars module docs, you'll find a few ways to include multiple files (but none through defining the same key), for example:
- include_vars:
dir: vars
files_matching: var

ansible: accessing register variables from other plays within same playbook

I'm trying to access the variable called "count" from the first "play" in my playbook in the second playbook. I found some other posts here about the same issue and I thought I was following the right steps, but the code below is still failing.
The Code
- hosts: group1
tasks:
- name: count registrations on primary node
shell: psql -U widgets widgets -c 'SELECT COUNT(*) FROM location' -t
register: count
- debug: var=count.stdout
- hosts: group2
tasks:
#the line below works...
# - debug: msg={{ hostvars['myserver1.mydomain.com']['count']['stdout'] }}
# but this one fails
- debug: msg={{ hostvars['group1']['count']['stdout'] }}
This produces the following output:
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [myserver1.mydomain.com]
TASK [count registrations on node] **************************************
changed: [myserver1.mydomain.com]
TASK [debug] *******************************************************************
ok: [myserver1.mydomain.com] => {
"count.stdout": " 2"
}
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [myserver2.mydomain.com]
TASK [debug] *******************************************************************
fatal: [myserver1.mydomain.com]: FAILED! => {"failed": true, "msg": "'ansible.vars.hostvars.HostVars object' has no attribute 'can_sip1'"}
NO MORE HOSTS LEFT *************************************************************
[ERROR]: Could not create retry file 'playbooks/test.retry'. The error was: [Errno 13] Permission denied: 'playbooks/test.retry'
PLAY RECAP *********************************************************************
myserver1.mydomain.com : ok=3 changed=1 unreachable=0 failed=0
myserver2.mydomain.com : ok=1 changed=0 unreachable=0 failed=1
The other post that I referring to is found here:
How do I set register a variable to persist between plays in ansible?
It's probably something simple, but I can't see where the bug lies.
Thanks.
EDIT 1
I've also tried to use set_fact like this:
- hosts: group1
tasks:
- name: count registrations on primary node
shell: psql -U widget widget -c 'SELECT COUNT(*) FROM location' -t
register: result
- debug: var=result.stdout
- set_fact: the_count=result.stdout
- debug: var={{the_count}}
- hosts: group2
tasks:
- name: retrieve variable from previous play
shell: echo hello
- debug: var={{hostvars}}
The results I get are:
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [myserver1.mydomain.com]
TASK [count reg on primary] ****************************************************
changed: [myserver1.mydomain.com]
TASK [debug] *******************************************************************
ok: [myserver1.mydomain.com] => {
"result.stdout": " 2"
}
TASK [set_fact] ****************************************************************
ok: [myserver1.mydomain.com]
TASK [debug] *******************************************************************
ok: [myserver1.mydomain.com] => {
"result.stdout": " 2"
}
PLAY ***************************************************************************
TASK [setup] *******************************************************************
ok: [myserver2.mydomain.com]
TASK [retrieve variable from previous play] ************************************
changed: [myserver2.mydomain.com]
TASK [debug] *******************************************************************
ok: [myserver2.mydomain.com] => {
"<ansible.vars.hostvars.HostVars object at 0x7f3b6602b290>": "VARIABLE IS NOT DEFINED!"
}
PLAY RECAP *********************************************************************
myserver1.mydomain.com : ok=5 changed=1 unreachable=0 failed=0
myserver2.mydomain.com : ok=3 changed=1 unreachable=0 failed=0
So It looks like there are no objects in the hostvars...
EDIT 3
This is what the playbook looks like this morning.
- hosts: group1
tasks:
- name: count reg on primary
shell: psql -U widgets widgets -c 'SELECT COUNT(*) FROM location' -t
register: result
- debug: var=result.stdout
- set_fact: the_count={{result.stdout}}
- debug: var={{the_count}}
- hosts: group2
tasks:
- name: retrieve variable from previous play
shell: echo hello
- debug: var={{hostvars}}
The "debug: var={{the_count}}" line from the first play prints out the correct value for the count but it also says the VARIABLE IS NOT DEFINED... like so:
TASK [set_fact] ****************************************************************
task path: /etc/ansible/playbooks/test.yml:8
ok: [myserver1.mydomain.com] => {"ansible_facts": {"the_count": " 2"}, "changed": false, "invocation": {"module_args": {"the_count": " 2"}, "module_name": "set_fact"}}
TASK [debug] *******************************************************************
task path: /etc/ansible/playbooks/test.yml:10
ok: [myserver1.mydomain.com] => {
" 2": "VARIABLE IS NOT DEFINED!"
}
And then once I hit the second play, I still get the message
TASK [debug] *******************************************************************
task path: /etc/ansible/playbooks/test.yml:16
ok: [myserver2.mydomain.com] => {
"<ansible.vars.hostvars.HostVars object at 0x7fb077fdc310>": "VARIABLE IS NOT DEFINED!"
}
In your example, you are suggestion that I use "debug: var={{hostlers}}". If you can clarify that for me please. It looks like it's a typo.
EDIT 4:
If you take a look at Edit 3 carefully, you will see that I have implemented "debug:var={{hostvars}}" as you suggest in your answer. But it gives me the same error that the variable is not defined.
I'm not just trying to pass variables from one play to another.. but from one set of hosts to another. Notice how play 1 uses group1 and play two applies only to group2.
Register variables, like facts, are per host. The values can differ depending on the machine. So you can only use host/ip defined in the inventory as key, not the group name. I think you have already knowed this, as you marked this in code snippet 1.
In the code snippet 2, the set_fact line (- set_fact: the_count=result.stdout) actually set the key the_count to the text value result.stdout, since result.stdout is treated as plain text, not a variable. If you want to treat it as a variable, you'd better use {{ result.stdout }}. You can verify this via running the playbook with -v option.
Tasks:
set_fact: the_content1=content.stdout
set_fact: the_content2={{ content.stdout }}
Output:
TASK [set_fact] ****************************************************************
ok: [192.168.1.58] => {"ansible_facts": {"the_content1": "content.stdout"}, "changed": false}
TASK [set_fact] ****************************************************************
ok: [192.168.1.58] => {"ansible_facts": {"the_content2": "hello world"}, "changed": false}
The debug module has two possible parameter: var and msg. The var parameter expect a variable name.
debug: var={{hostvars}}
In this line, first of all, Ansible extracts the value of hostvars, since it is enclosed with two brackets. Secondly, it tries to find a variable whose name is the value of hostvars, since var parameter expects a variable name directly. That is why you see the following strange output. This means Ansible couldn't find a variable whose name is <ansible.vars.hostvars.HostVars object at 0x7f3b6602b290>.
"<ansible.vars.hostvars.HostVars object at 0x7f3b6602b290>": "VARIABLE IS NOT DEFINED!"
You can use the following:
debug: var=hostvars
debug: msg={{hostvars}}
References:
Register variables don't survive across plays with different hosts
set_fact - Set host facts from a task
debug - Print statements during execution

Resources