Ansible how to assign new value to extra vars value - variables

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

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 to deal with multiple when condition for registered variable in ansible

I have a playbook 3 raw task (or more) with sample commands like below:
Playbook mytest.yml
- hosts: remotehost
gather_facts: no
tasks:
- name: Execute command1
raw: "ls -ltr"
register: cmdoutput
when: remcmd == "list"
- name: Execute command2
raw: "hostname"
register: cmdoutput
when: remcmd == "host"
- name: Execute command3
raw: "uptime"
register: cmdoutput
when: remcmd == "up"
- hosts: localhost
gather_facts: no
tasks:
- debug:
msg: "Printing {{ hostvars['remotehost']['cmdoutput'] }}"
This is my nventory myhost.yml
[remotehost]
myserver1
Here is how I run the playbook:
ansible-playbook -i myhost.yml mytest.yml -e remcmd="host"
PLAY [remotehost] ***************************************************************************************************************
TASK [Execute command1] *********************************************************************************************************
Thursday 06 October 2022 07:06:06 -0500 (0:00:00.013) 0:00:00.013 ******
skipping: [myserver1]
TASK [Execute command2] *********************************************************************************************************
Thursday 06 October 2022 07:06:06 -0500 (0:00:00.023) 0:00:00.036 ******
changed: [myserver1]
TASK [Execute command3] *********************************************************************************************************
Thursday 06 October 2022 07:06:06 -0500 (0:00:00.521) 0:00:00.557 ******
skipping: [myserver1]
PLAY [localhost] ****************************************************************************************************************
TASK [debug] ********************************************************************************************************************
Thursday 06 October 2022 07:06:06 -0500 (0:00:00.032) 0:00:00.590 ******
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: \"hostvars['remotehost']\" is undefined\n\nThe error appears to be in '/home/wladmin/mytest.yml': line 22, 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 - debug:\n ^ here\n"}
PLAY RECAP **********************************************************************************************************************
localhost : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
myserver1 : ok=1 changed=1 unreachable=0 failed=0 skipped=2 rescued=0 ignored=0
My requirement is no matter what value is passed for remcmd my localhost play should print stdoutlines of cmdoutput
Preliminary notes:
Using raw is evil.
Don't use raw unless to install prereqs (i.e. python) on the target host. Then switch to modules or at the very least command/shell
If you still intend to use raw, go back to point 1 above
In case your forgot to go back to point 1: using raw is evil
Don't register several tasks with the same var name (the last one always win, even if skipped). Don't create tasks you can avoid up-start.
As an illustration of the above principles
- hosts: remotehost
gather_facts: no
vars:
cmd_map:
list: ls -ltr
host: hostname
up: uptime
tasks:
- name: Make sure remcmd is known
assert:
that: remcmd in cmp_map.keys()
fail_msg: "remcmd must be one of: {{ cmd_map.keys() | join(', ') }}"
- name: Execute command
command: "{{ cmd_map[remcmd] }}"
register: cmdoutput
- name: Show entire result from above task
debug:
var: cmdoutput
my localhost play should print stdout_lines of cmdoutput
As far as I understand "How the debug module works", it can only print on the Control Node.
Therefore you could just remove three (3) lines in your example
- hosts: localhost
gather_facts: no
tasks:
and give it a try with
- hosts: remotehost
gather_facts: no
tasks:
- name: Execute command1
raw: "ls -ltr"
register: cmdoutput
when: remcmd == "list"
- name: Execute command2
raw: "hostname"
register: cmdoutput
when: remcmd == "host"
- name: Execute command3
raw: "uptime"
register: cmdoutput
when: remcmd == "up"
- debug:
msg: "Printing {{ cmdoutput }}"
and independently of which task became executed the result would be provided.
Apart from the answer about "How the debug module works" here, I like to recommended to proceed further with the answer of Zeitounator, since it will address your possible use case more complete.

Ansible variable interpolation not working in brackets

I'm using Ansible to grab an VIP from InfoBlox and running into an issue when trying to build my exclude list. I need to exclude the first 3 IP's as they are reserved, however the CIDR range is a dynamic variable so I need to build this exclude list on the fly. Here's a representation of what I have so far:
---
- name: Assign VIP to FQDN in Grid Manager
hosts: all
connection: local
gather_facts: false
vars:
CIDR: 10.0.0.
tasks:
- set_fact:
EXCLUDES: "{{ EXCLUDES | default([]) + [item] }}"
with_sequence: start=1 end=3 format=''{{ CIDR }}%d''
- set_fact:
formated_excludes: "{{ EXCLUDES |join(', ') }}"
- debug:
msg: "{{ formated_excludes }}"
- set_fact:
VIP: "{{ lookup('nios_next_ip', '10.0.0.0/25', exclude=[formated_excludes]) | first }}"
- name: Print next IP address
debug:
msg: "The next available IP is {{ VIP }}"
Here are the results of the play:
PLAY [Assign VIP to FQDN in Grid Manager] *****************************************************************************************************************
TASK [set_fact] *******************************************************************************************************************************************
ok: [localhost] => (item='10.0.0.1')
ok: [localhost] => (item='10.0.0.2')
ok: [localhost] => (item='10.0.0.3')
TASK [set_fact] *******************************************************************************************************************************************
ok: [localhost]
TASK [debug] **********************************************************************************************************************************************
ok: [localhost] => {
"msg": "'10.0.0.1', '10.0.0.2', '10.0.0.3'"
}
TASK [set_fact] *******************************************************************************************************************************************
fatal: [localhost]: FAILED! => {"msg": "An unhandled exception occurred while running the lookup plugin 'nios_next_ip'. Error was a <class 'ansible.errors.AnsibleError'>, original message: Invalid value for exclude: \"'10.0.0.1', '10.0.0.2', '10.0.0.3'\": Invalid IPv4 address"}
PLAY RECAP ************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
The formatting appears to be fine, however the lookup won't accept it. For comparison, using the following works fine:
- set_fact:
VIP: "{{ lookup('nios_next_ip', '10.0.0.0/25', exclude=['10.0.0.1', '10.0.0.2', '10.0.0.3']) | first }}"
Here are the results:
PLAY [Assign VIP to FQDN in Grid Manager] *****************************************************************************************************************
TASK [set_fact] *******************************************************************************************************************************************
ok: [localhost]
TASK [Print next IP address] ******************************************************************************************************************************
ok: [localhost] => {
"msg": "The next available IP is 10.0.0.4"
}
PLAY RECAP ************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Any thoughts on why this variable isn't working would be much appreciated!
Parameter exclude is "List of IP's ...", but the filter join makes a string from the list
- set_fact:
formated_excludes: "{{ EXCLUDES |join(', ') }}"
Use the list EXCLUDES in the parameter
- set_fact:
VIP: "{{ lookup('nios_next_ip', '10.0.0.0/25', exclude=EXCLUDES) | first }}"

Unable to get value of a variable from another Play in Ansible

I wish to obtain the value of "fdet_APP" variable of Play 2 into Play 3.
Below is my playbook which case be used as a testcase:
- name: "Play 1"
hosts: localhost
tasks:
- add_host: name={{ item }}
groups=dest_nodes
ansible_user={{ USER }}
with_items: "{{ Dest_IP.split(',') }}"
- name: "Play 2"
hosts: dest_nodes
user: "{{ USER }}"
tasks:
- set_fact:
fdet_APP: "Yellow"
- name: "Play 3"
hosts: localhost
user: "{{ USER }}"
vars:
dbfiledet: "{{ hostvars['dest_nodes']['fdet_APP'] }}"
tasks:
- debug: msg="{{ dbfiledet.stdout }}"
I get the below error for my attempt:
playbook RUN command:
ansible-playbook variabletest.yml -e "USER=user1 Dest_IP=10.17.44.26,10.17.54.26"
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'
PLAY [Play 1]
TASK [Gathering Facts]
************************************************************************************************************************************** ok: [localhost]
TASK [add_host]
********************************************************************************************************************************************* changed: [localhost] => (item=10.17.44.26) changed: [localhost] =>
(item=10.17.54.26)
PLAY [Play 2]
TASK [Gathering Facts]
************************************************************************************************************************************** ok: [10.17.54.26] ok: [10.17.44.26]
TASK [set_fact]
********************************************************************************************************************************************* ok: [10.17.44.26] ok: [10.17.54.26]
PLAY [Play 3]
TASK [Gathering Facts]
************************************************************************************************************************************** ok: [localhost]
TASK [debug]
************************************************************************************************************************************************ fatal: [localhost]: FAILED! => {"msg": "The task includes an option
with an undefined variable. The error was: \"hostvars['dest_nodes']\"
is undefined\n\nThe error appears to be in 'variabletest.yml': line
36, column 6, but may\nbe elsewhere in the file depending on the exact
syntax problem.\n\nThe offending line appears to be:\n\n\n - debug:
msg=\"{{ dbfiledet.stdout }}\"\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
10.17.44.26 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.17.54.26 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0 localhost
: ok=3 changed=1 unreachable=0 failed=1 skipped=0
rescued=0 ignored=0
I'm on the latest version of ansible and python 2.7.5
Can someone suggest what is wrong and how can i get the value for the variable in Play 3 please ?
hostvars are tied to a single Ansible managed host, not an inventory group. Try running debug: var=hostvars to see what I mean. In your case dest_nodes is an inventory group, not a host.
If just want to pull the variable from any host in the group, try:
- debug:
msg: "{{ hostvars[groups.dest_nodes|first]['fdet_APP'] }}"
If you are looking to parse the value for all hosts in the group, then you'll need to implement either a loop or a json_query filter

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.