In ansible how do I concatenate a already defined variable in a settings file yaml and an extra-var? - variables

I created a settings file called settings.yaml that looks like this:
cust_int: 'ens224'
cust_sub_int: '{{ cust_int }}.{{ cust }}
cust_int, is the already defined variable above
cust, Is a variable provided with --extra-var
here is the playbook:
- name: Include vars
include_vars:
file: ../../../settings.yaml
name: settings
- debug: msg="{{ settings.cust_sub_int }}"
When trying to concatenate this way I get unclear error that the playbook "did not find the expected key".
My question is, how can I combine these two variables in my settings file? I dont want to have to use set_fact in all my playbooks.

See ansible cannot use variable to learn details why this is not working. The solution is rather simple. Split the settings into common variables and the dictionary. For example,
shell> cat settings-common.yaml
_cust_int: 'ens224'
shell> cat settings.yaml
cust_int: '{{ _cust_int }}'
cust_sub_int: '{{ _cust_int }}.{{ cust }}'
Include both files
- include_vars:
file: settings-common.yaml
- include_vars:
file: settings.yaml
name: settings
Running the play with extra var cust=foo gives the expected result
settings:
cust_int: ens224
cust_sub_int: ens224.foo
Example of a complete project for testing
shell> tree .
.
├── ansible.cfg
├── hosts
├── pb.yml
├── settings-common.yaml
└── settings.yaml
0 directories, 5 files
shell> cat ansible.cfg
[defaults]
gathering = explicit
inventory = $PWD/hosts
retry_files_enabled = false
stdout_callback = yaml
shell> cat hosts
localhost
shell> cat pb.yml
- hosts: localhost
tasks:
- include_vars:
file: settings-common.yaml
- include_vars:
file: settings.yaml
name: settings
- debug:
var: settings
- debug:
msg: "{{ settings.cust_sub_int }}"
gives
shell> ansible-playbook pb.yml -e cust=foo
PLAY [localhost] *****************************************************************************************************************
TASK [include_vars] **************************************************************************************************************
ok: [localhost]
TASK [include_vars] **************************************************************************************************************
ok: [localhost]
TASK [debug] *********************************************************************************************************************
ok: [localhost] =>
settings:
cust_int: ens224
cust_sub_int: ens224.foo
TASK [debug] *********************************************************************************************************************
ok: [localhost] =>
msg: ens224.foo
PLAY RECAP ***********************************************************************************************************************
localhost: ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Related

Overwrite vars_prompt variable in playbook with host variable from inventory in Ansible

I want to overwrite some variables in my playbook file from the inventory file for a host that are defined as "vars_prompt". If I understand it correctly, Ansible shouldn't prompt for the variables if they were already set before, however, it still prompts for the variables when I try to execute the playbook.
How can I overwrite the "vars_prompt" variables from the inventory or is this not possible because of the variable precedence definition of Ansible?
Example:
playbook.yml
---
- name: Install Gateway
hosts: all
become: yes
vars_prompt:
- name: "hostname"
prompt: "Hostname"
private: no
...
inventory.yml
---
all:
children:
gateways:
hosts:
gateway:
ansible_host: 192.168.1.10
ansible_user: user
hostname: "gateway-name"
...
Q: "If I understand it correctly, Ansible shouldn't prompt for the variables if they were already set before, however, it still prompts for the variables when I try to execute the playbook."
A: You're wrong. Ansible won't prompt for variables defined by the command line --extra-vars. Quoting from Interactive input: prompts:
Prompts for individual vars_prompt variables will be skipped for any variable that is already defined through the command line --extra-vars option, ...
You can't overwrite vars_prompt variables from the inventory. See Understanding variable precedence. Inventory variables (3.-9.) is lower precedence compared to play vars_prompt (13.). The precedence of extra vars is 22.
Use the module pause to ask for the hostname if any variable is not defined. For example, the inventory
shell> cat hosts
host_1
host_2
and the playbook
hosts: all
gather_facts: false
vars:
hostnames: "{{ ansible_play_hosts_all|
map('extract', hostvars, 'hostname')|
list }}"
hostnames_undef: "{{ hostnames|from_yaml|
select('eq', 'AnsibleUndefined')|
length > 0 }}"
tasks:
- debug:
msg: |
hostnames: {{ hostnames }}
hostnames_undef: {{ hostnames_undef }}
run_once: true
- pause:
prompt: "Hostname"
register: out
when: hostnames_undef
run_once: true
- set_fact:
hostname: "{{ out.user_input }}"
when: hostname is not defined
- debug:
var: hostname
gives
shell> ansible-playbook pb.yml
PLAY [all] ************************************************************************************
TASK [debug] **********************************************************************************
ok: [host_1] =>
msg: |-
hostnames: [AnsibleUndefined, AnsibleUndefined]
hostnames_undef: True
TASK [pause] **********************************************************************************
[pause]
Hostname:
gw.example.com^Mok: [host_1]
TASK [set_fact] *******************************************************************************
ok: [host_1]
ok: [host_2]
TASK [debug] **********************************************************************************
ok: [host_1] =>
hostname: gw.example.com
ok: [host_2] =>
hostname: gw.example.com
PLAY RECAP ************************************************************************************
host_1: ok=4 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
host_2: ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The playbook won't ovewrite variables defined in the inventory. For example
shell> cat hosts
host_1
host_2 hostname=gw2.example.com
gives
TASK [debug] **********************************************************************************
ok: [host_1] =>
hostname: gw.example.com
ok: [host_2] =>
hostname: gw2.example.com
I don't know if you can stop the prompts but you can se a default value directly in vars_prompts. In this way you do not need to type "gateway-name" every time.
vars_prompt:
- name: "hostname"
prompt: "Hostname"
private: no
default: "gateway-name"
Source: https://docs.ansible.com/ansible/latest/user_guide/playbooks_prompts.html

How can I print out the actual values of all the variables used by an Ansible playbook?

An answer on StackOverflow suggests using - debug: var=vars or - debug: var=hostvars to print out all the variables used by an Ansible playbook.
Using var=hostvars did not print out all of the variables. But I did get all of the variables printed out when I added the following lines to the top of the main.yml file of the role executed by my playbook:
- name: print all variables
debug:
var=vars
The problem is that the values of the variables printed out are not fully evaluated if they are dependent on the values of other variables. For example, here is a portion of what gets printed out:
"env": "dev",
"rpm_repo": "project-subproject-rpm-{{env}}",
"index_prefix": "project{{ ('') if (env=='prod') else ('_' + env) }}",
"our_server": "{{ ('0.0.0.0') if (env=='dev') else ('192.168.100.200:9997') }}",
How can I get Ansible to print out the variables fully evaluated like this?
"env": "dev",
"rpm_repo": "project-subproject-rpm-dev",
"index_prefix": "project_dev",
"our_server": "0.0.0.0",
EDIT:
After incorporating the tasks section in the answer into my playbook file and removing the roles section, my playbook file looks like the following (where install-vars.yml contains some variable definitions):
- hosts: all
become: true
vars_files:
- install-vars.yml
tasks:
- debug:
msg: |-
{% for k in _my_vars %}
{{ k }}: {{ lookup('vars', k) }}
{% endfor %}
vars:
_special_vars:
- ansible_dependent_role_names
- ansible_play_batch
- ansible_play_hosts
- ansible_play_hosts_all
- ansible_play_name
- ansible_play_role_names
- ansible_role_names
- environment
- hostvars
- play_hosts
- role_names
_hostvars: "{{ hostvars[inventory_hostname].keys() }}"
_my_vars: "{{ vars.keys()|
difference(_hostvars)|
difference(_special_vars)|
reject('match', '^_.*$')|
list|
sort }}"
When I try to run the playbook, I get this failure:
shell> ansible-playbook playbook.yml
SSH password:
SUDO password[defaults to SSH password]:
PLAY [all] *********************************************************************
TASK [setup] *******************************************************************
ok: [192.168.100.111]
TASK [debug] *******************************************************************
fatal: [192.168.100.111]: FAILED! => {"failed": true, "msg": "lookup plugin (vars) not found"}
to retry, use: --limit #/usr/local/project-directory/installer-1.0.0.0/playbook.retry
PLAY RECAP *********************************************************************
192.168.100.111 : ok=1 changed=0 unreachable=0 failed=1
The minimal playbook below
shell> cat pb.yml
- hosts: localhost
gather_facts: false
vars:
test_var1: A
test_var2: "{{ test_var1 }}"
tasks:
- debug:
var: vars
reproduces the problem you described. For example,
shell> ansible-playbook pb.yml | grep test_var
test_var1: A
test_var2: '{{ test_var1 }}'
Q: How can I print out the actual values of all the variables used by an Ansible playbook?
A: You can get the actual values of the variables when you evaluate them. For example,
shell> cat pb.yml
- hosts: localhost
gather_facts: false
vars:
test_var1: A
test_var2: "{{ test_var1 }}"
tasks:
- debug:
msg: |-
{% for k in _my_vars %}
{{ k }}: {{ lookup('vars', k) }}
{% endfor %}
vars:
_special_vars:
- ansible_dependent_role_names
- ansible_play_batch
- ansible_play_hosts
- ansible_play_hosts_all
- ansible_play_name
- ansible_play_role_names
- ansible_role_names
- environment
- hostvars
- play_hosts
- role_names
_hostvars: "{{ hostvars[inventory_hostname].keys() }}"
_my_vars: "{{ vars.keys()|
difference(_hostvars)|
difference(_special_vars)|
reject('match', '^_.*$')|
list|
sort }}"
gives the evaluated playbook's vars
msg: |-
test_var1: A
test_var2: A
Looking for an answer to the same question, I found the following solution from this link:
- name: Display all variables/facts known for a host
debug:
var: hostvars[inventory_hostname]
tags: debug_info

Build a variable in a playbook with the hostname and call it in a task

I have a two main variable with subvariables. The main variable VELABx and VELABy match the ansible_hostnames. Following an example of the variables mentioned:
VELABx
location: "text1.1"
initialism: "text1.2"
VELABy
location: "text2.1"
initialism: "text2.2"
Now I'd like to run a task which replaces a regexp with the location variable based on the current ansible_hostname. So, I tried this code, but it leads into an error.
- name: Replace location for VELABx
replace:
dest: "/path/to/file"
regexp: 'location'
replace: "{{ {{ansible_hostname}}.location }}"
remote_user: rssuser
become: no
when: ansible_hostname == "VELABx"
What am I doing wrong? How can I solve this? Can anyone bring up a solution?
Things are always easier when you manage to create a proper structure of data. For example, given the dictionaries in a file
shell> cat velab.yml
VELABx:
location: "text1.1"
initialism: "text1.2"
VELABy:
location: "text2.1"
initialism: "text2.2"
you can include the data from the file into a dictionary, e.g.
- hosts: VELABx,VELABy,VELABz
tasks:
- include_vars:
file: velab.yml
name: velab
run_once: true
- debug:
var: velab
run_once: true
gives
velab:
VELABx:
initialism: text1.2
location: text1.1
VELABy:
initialism: text2.2
location: text2.1
The data you provided in the question are not YAML dictionaries. The colon is missing behind the keys. Either fix it, if you can or parse the file. Anyway, create the dictionary whatever is the source.
Then, given the files
shell> ssh admin#10.1.0.61 cat /tmp/velab.txt
location
shell> ssh admin#10.1.0.62 cat /tmp/velab.txt
location
shell> ssh admin#10.1.0.63 cat /tmp/velab.txt
location
the task to replace the location is simple
- name: Replace location for VELAB*
replace:
dest: /tmp/velab.txt
regexp: location
replace: "{{ velab[inventory_hostname]['location'] }}"
when: velab[inventory_hostname] is defined
gives
shell> ansible-playbook playbook.yml -CD
PLAY [VELABx,VELABy,VELABz] ******************************************
...
TASK [Replace location for VELAB*] ***********************************
skipping: [VELABz]
--- before: /tmp/velab.txt
+++ after: /tmp/velab.txt
## -1 +1 ##
-location
+text1.1
changed: [VELABx]
--- before: /tmp/velab.txt
+++ after: /tmp/velab.txt
## -1 +1 ##
-location
+text2.1
changed: [VELABy]
The next option is to remove the condition and use the default value, instead of skipping the host, when the host is missing in the dictionary
- name: Replace location for VELAB*
replace:
dest: /tmp/velab.txt
regexp: location
replace: "{{ velab[inventory_hostname]['location']|
default(default_location) }}"
vars:
default_location: "text99.1"
you must use loopkup, {{}} inside other {{}} is incorrect
---
- hosts: localhost
gather_facts: false
vars:
ansible_hostname: VELABx
VELABx:
location: "text1.1"
initialism: "text1.2"
VELABy:
location: "text2.1"
initialism: "text2.2"
tasks:
- name: DEBUG
debug:
msg: "{{ lookup('vars', ansible_hostname ).location }}"
- name: Replace location for VELABx
replace:
dest: "/path/to/file"
regexp: 'location'
replace: "{{ lookup('vars', ansible_hostname ).location }}"
when: ansible_hostname == "VELABx"

Ansible how to assign new value to extra vars value

Tower: 3.2.3
Ansible 2.4.2
I have a Tower playbook where a value is assigned lets say build_cl: latest. This is defined in the Ansible Tower's survey, which I believe is regarded as extra-vars. I have a task that performs a check, and if condition is right I need to modify the value of build_cl.
So lets say when Tower playbook is kicked off the var is:
build_cl: latest
Then:
- name: "Get latest installed CL on groups['Healthcheck_Host'][0]"
shell: |
grep -oP '(?<=\:)(.*?)(?=\-)' {{ latest_deployed_build_dir.stdout }}/buildinfo.txt
register: latest_deployed_cl
- debug:
var: latest_deployed_cl
- set_fact:
build_cl: "{{ latest_deployed_cl.stdout }}"
cacheable: yes
- debug:
var: build_cl
I have tested and the debug for the first task here returns lets say 123456.
However I try to use the set_fact module, but the second debug output still gives: latest.
Nothing I try seems to be effecting the original value. Help would be greatly appreciated. Thanks
Extra vars (i.e. vars passed on the command line with the -e option), have the highest precedence and cannot be changed during playbook life. set_fact will not throw any error but the value will remain the one passed at launch.
Here is a quick example to illustrate:
---
- name: Immutable extra var demo
hosts: localhost
gather_facts: false
vars:
test_var: value set in playbook var
tasks:
- name: debug var value at playbook start
debug:
var: test_var
- name: change var value
set_fact:
test_var: value set in set_fact
- name: debug var value at playbook end
debug:
var: test_var
Without extra var:
$ ansible-playbook test.yml
PLAY [Immutable extra var demo] ********************************************************************************************************************************************************************************************************
TASK [debug var value at playbook start] ***********************************************************************************************************************************************************************************************
ok: [localhost] => {
"test_var": "value set in playbook var"
}
TASK [change var value] ****************************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [debug var value at playbook end] *************************************************************************************************************************************************************************************************
ok: [localhost] => {
"test_var": "value set in set_fact"
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
With extra var:
$ ansible-playbook test.yml -e "test_var='value set in extra vars'"
PLAY [Immutable extra var demo] ********************************************************************************************************************************************************************************************************
TASK [debug var value at playbook start] ***********************************************************************************************************************************************************************************************
ok: [localhost] => {
"test_var": "value set in extra vars"
}
TASK [change var value] ****************************************************************************************************************************************************************************************************************
ok: [localhost]
TASK [debug var value at playbook end] *************************************************************************************************************************************************************************************************
ok: [localhost] => {
"test_var": "value set in extra vars"
}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Ansible: How to use variables defined in inventory file (hosts) in my playbook?

As the subject says. I have some host variables defined in my hosts inventory file. How do I access them in my playbook?
Here is an example. Based on all my research I was expecting foo and bar to be part of hostvars. I can put host specific variables in separate var files, but I would love to keep them in my inventory file "attached" to a host. I don't want to use it in templates.
ansible version: 1.3.2, ansible_distribution_version: 6.4
bash $
bash $ ansible --version
ansible 1.3.2
bash $
bash $ cat test_inv.ini
[foobar]
someHost foo="some string" bar=123
someOtherHost foo="some other string" bar=456
bash $
bash $ cat test.yml
---
- name: test variables...
hosts: all
vars:
- some_junk: "1"
# gather_facts: no # foo and bar are unavailable whether I gather facts or not.
tasks:
- debug: msg="hostvars={{hostvars}}"
- debug: msg="vars={{vars}}"
- debug: msg="groups={{groups}}"
- debug: msg="some_junk={{some_junk}}"
# - debug: msg="???? HOW DO I PRINT values of host specific variables foo and bar defined in inventory file ???"
bash $
bash $
bash $ ansible-playbook -i test_inv.ini test.yml
PLAY [test variables...] ******************************************************
GATHERING FACTS ***************************************************************
ok: [someHost]
TASK: [debug msg="hostvars={{hostvars}}"] *************************************
ok: [someHost] => {"msg": "hostvars={'someHost': {u'facter_operatingsystem': u'RedHat', u'facter_selinux_current_mode': u'enforcing', u'facter_hostname': u'someHost', 'module_setup': True, u'facter_memoryfree_mb': u'1792.70', u'ansible_distribution_version': u'6.4' // ...........snip...........// u'VMware IDE CDR10'}}"}
TASK: [debug msg="vars={{vars}}"] *********************************************
ok: [someHost] => {"msg": "vars={'some_junk': '1', 'delegate_to': None, 'changed_when': None, 'register': None, 'inventory_dir': '/login/sg219898/PPP/automation/ansible', 'always_run': False, 'ignore_errors': False}"}
TASK: [debug msg="groups={{groups}}"] *****************************************
ok: [someHost] => {"msg": "groups={'ungrouped': [], 'foobar': ['someHost'], 'all': ['someHost']}"}
TASK: [debug msg="some_junk=1"] ***********************************************
ok: [someHost] => {"msg": "some_junk=1"}
PLAY RECAP ********************************************************************
someHost : ok=5 changed=0 unreachable=0 failed=0
bash $
Doing the following should work:
debug: msg="foo={{foo}}"
The foo variable will be evaluated in the context of the current host. Tested locally with ansible 1.3.4.