I there any way to pass/update group variables from within the playbook task?
I need to define variables based on results of some commands from one host to use them for other roles and tasks. I know about set_fact but it stores variable as local variable so that I need to address specific host to get it but hostname/address of this host can vary.
Googling and reading docs.ansible.com doesn't help still.
UPD: there is 2 different roles that playing tasks one after another and I need to pass variables between plays.
An option would be to use ansible modules lineinfile, blockinfile, template, and ini_file to update group variables.
For example the play below
- hosts: test_jails
gather_facts: false
vars:
my_groupvar_file: "{{ inventory_dir }}/group_vars/test_jails.yml"
tasks:
- debug:
var: my_last_run
- block:
- command: date "+%F %T"
register: result
- lineinfile:
path: "{{ my_groupvar_file }}"
regexp: "^my_last_run: "
line: "my_last_run: {{ result.stdout }}"
backup: yes
delegate_to: localhost
run_once: true
with group variables group_vars/test_jails.yml
my_last_run: 2019-04-19 11:51:00
gives (abridged):
> ansible-playbook test1.yml
PLAY [test_jails]
TASK [debug]
ok: [test_01] => {
"my_last_run": "2019-04-19 11:51:00"
}
ok: [test_03] => {
"my_last_run": "2019-04-19 11:51:00"
}
ok: [test_02] => {
"my_last_run": "2019-04-19 11:51:00"
}
TASK [command]
changed: [test_01]
TASK [lineinfile]
changed: [test_01 -> localhost]
PLAY RECAP
test_01 : ok=3 changed=2 unreachable=0 failed=0
test_02 : ok=1 changed=0 unreachable=0 failed=0
test_03 : ok=1 changed=0 unreachable=0 failed=0
> cat group_vars/test_jails.yml
my_last_run: 2019-04-19 11:56:51
Related
I have following inventory file
$ cat hosts
[web]
server1.example.com
server2.example.com
I would like to fetch the hostname, without the part of domain (.example.com).
I tried with the following playbook, however, it is still fetching with the entire hostname..
$ playbook.yaml
- hosts: localhost
tasks:
- debug:
msg: "{{ groups['web'] }}"
Output
PLAY [localhost] *************************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************************
ok: [localhost]
TASK [debug] *****************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"server1.example.com"
"server2.example.com"
]
}
PLAY RECAP *******************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Expected output
PLAY [localhost] *************************************************************************************************************************************************************
TASK [Gathering Facts] *******************************************************************************************************************************************************
ok: [localhost]
TASK [debug] *****************************************************************************************************************************************************************
ok: [localhost] => {
"msg": [
"server1"
"server2"
]
}
PLAY RECAP *******************************************************************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
You can get what you want from a magic variable called inventory_hostname_short which basically returns anything before the first . found in the inventory_hostname.
To get this in a normal play host loop, it's as easy as:
- hosts: all
tasks:
- name: show target short name
debug:
var: inventory_hostname_short
If you need to get that for hosts not in the host loop, you will have to go through hostvars. Here is an example to get all those names in a list for a given group running from localhost:
- hosts: localhost
gather_facts: false
tasks:
- name: show list of shortnames for group 'toto'
debug:
msg: "{{ groups['toto'] | map('extract', hostvars, 'inventory_hostname_short') }}"
An other example to get that name only for the first server in group 'toto'
- hosts: localhost
gather_facts: false
tasks:
- name: show shortnames for first server in group 'toto'
vars:
server_name: "{{ groups['toto'][0] }}"
debug:
msg: "{{ hostvars[server_name].inventory_hostname_short }}"
Based on input from Zeitounator I have updated the original question. The following works
root#devenv:~/scripts/uia# cat addVlanTest.yml
---
- name: PLAY 111 Add Vlan ;
hosts: all
vars_prompt:
- name: vlanIdToAdd
prompt: vlan ID to add
private: no
default: "50"
tasks:
- name: "Debug task Take 1"
ansible.builtin.debug:
var: vlanIdToAdd
- name: "Debug task Take 2"
ansible.builtin.debug:
msg: "{{ vlanIdToAdd }}"
- name: "Debug task Take 3"
ansible.builtin.debug:
msg: "Creating vlan {{ vlanIdToAdd }}"
Correct:
msg: "Creating vlan {{ vlanIdToAdd }}"
Incorrect:
msg:"Creating vlan {{ vlanIdToAdd }}"
What is the scope ? Variables do not survive after plays. If you need to use it in a different play save it.
root#devenv:~/scripts/uia# cat addVlanTest.yml
---
- name: PLAY 111 Add Vlan ;
hosts: all
vars_prompt:
- name: vlanIdToAdd
prompt: vlan ID to add
private: no
default: "50"
tasks:
- name: "Debug vars Take 1"
debug:
var=vlanIdToAdd
- name: "Debug vars Take 1"
set_fact:
new_vlan_id="{{ vlanIdToAdd }}"
- name: PLAY 112 Add Vlan - IOS;
hosts: ios
tasks:
- name: "Debug vars Take 2"
debug:
var=new_vlan_id
As reported in my comment, vars_prompt are only available inside a given play as this is their scope. This is explained in plabooks variable documentation
From my suggestion, you have tried to use set_fact. As you will see in the same documentation, those vars are scoped to host and are only available while playing a task on host having the given fact. Meanwhile, you can access facts from other host using the hostvars magic variable
Here is one way to work arround this kind of chicken-egg problem. It might not be exactly what you are looking for but will hopefully give you some ideas for your best solution. I tried to make it self explanatory.
The following test.yml playbook:
---
- name: Play dedicated to vars_prompt and storing facts in localhost
hosts: localhost
gather_facts: false
vars_prompt:
- name: my_prompt
prompt: enter a value
private: no
tasks:
- name: store prompt in fact
set_fact:
my_prompt: "{{ my_prompt }}"
- name: Use fact on host a by directly calling it in a task
hosts: a
gather_facts: false
tasks:
- name: display the fact
debug:
msg: "{{ hostvars['localhost'].my_prompt }}"
- name: Use the fact on host b by first assigning to a play var
hosts: b
gather_facts: false
vars:
my_prompt: "{{ hostvars['localhost'].my_prompt }}"
tasks:
- name: display the fact
debug:
msg: "{{ my_prompt }}"
Gives:
$ ansible-playbook -i a,b, test.yml
enter a value: toto
PLAY [Play dedicated to vars_prompt and storing facts in localhost] ************************************************************************************************************************************************
TASK [store prompt in fact] ***************************************************************************************************************************************************************************************
ok: [localhost]
PLAY [Use fact on host a by directly calling it in a task] ********************************************************************************************************************************************************
TASK [display the fact] *******************************************************************************************************************************************************************************************
ok: [a] => {
"msg": "toto"
}
PLAY [Use the fact on host b by first assigning to a play var] ****************************************************************************************************************************************************
TASK [display the fact] *******************************************************************************************************************************************************************************************
ok: [b] => {
"msg": "toto"
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
a : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
b : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Meanwhile, if this is possible in your scenario, you can as well set the fact on all hosts in your inventory so as to reuse it anywhere, this makes a much simpler playbook:
---
- name: Play dedicated to vars_prompt and storing facts on all host (except implicit localhost)
hosts: all
gather_facts: false
vars_prompt:
- name: my_prompt
prompt: enter a value
private: no
tasks:
- name: store prompt in fact
set_fact:
my_prompt: "{{ my_prompt }}"
- name: Use fact on host a
hosts: a
gather_facts: false
tasks:
- name: display the fact
debug:
msg: "{{ my_prompt }}"
- name: Use the fact on host b
hosts: b
gather_facts: false
tasks:
- name: display the fact
debug:
msg: "{{ my_prompt }}"
- name: Simple demo implicit localhost is not part of the all group and does not have the fact
hosts: localhost
gather_facts: false
tasks:
- name: show fact is undefined on localhost
debug:
var: my_prompt
Gives:
$ ansible-playbook -i a,b, test.yml
enter a value: titi
PLAY [Play dedicated to vars_prompt and storing facts on all host (except implicit localhost)] ********************************************************************************************************************
TASK [store prompt in fact] ***************************************************************************************************************************************************************************************
ok: [a]
ok: [b]
PLAY [Use fact on host a] *****************************************************************************************************************************************************************************************
TASK [display the fact] *******************************************************************************************************************************************************************************************
ok: [a] => {
"msg": "titi"
}
PLAY [Use the fact on host b] *************************************************************************************************************************************************************************************
TASK [display the fact] *******************************************************************************************************************************************************************************************
ok: [b] => {
"msg": "titi"
}
PLAY [Simple demo implicit localhost is not part of the all group and does not have the fact] *********************************************************************************************************************
TASK [show fact is undefined on localhost] ************************************************************************************************************************************************************************
ok: [localhost] => {
"my_prompt": "VARIABLE IS NOT DEFINED!"
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
a : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
b : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
localhost : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
I have a play like this:
- name: Perform an action on a Runtime
hosts: all
roles:
- role: mule_action_on_Runtime
A variable at invocation (--extra-vars 'mule_runtime=MuleS01-3.7.3-Testing') has a prefix of the host needed (MuleS01). I want to set hosts: MuleS01. How do I do this?
Given that your pattern is always PartIWant-PartIDonCareAbout-AnotherPartAfterOtherDash you could use the split method of Python, then get the first item of the list via the Jinja filter first.
Here is full working playbook as example:
- hosts: local
gather_facts: no
tasks:
- debug:
msg: "{{ mule_runtime.split('-') | first }}"
This yield the recap:
play.yml --extra-vars 'mule_runtime=MuleS01-3.7.3-Testing'
PLAY [local] *******************************************************************
TASK [debug] *******************************************************************
ok: [local] => {
"msg": "MuleS01"
}
PLAY RECAP *********************************************************************
local : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
With the inventory
shell> cat hosts
MuleS01
MuleS02
MuleS03
this playbook
shell> cat pb.yml
- hosts: all
tasks:
- debug:
msg: Set {{ mule_runtime }}
when: mule_runtime.split('-').0 == inventory_hostname
gives
skipping: [MuleS02]
ok: [MuleS01] => {
"msg": "Set MuleS01-3.7.3-Testing"
}
skipping: [MuleS03]
Need your help in achieving below:
- use variables provided inline with hostIP (i.e. host variables) in Ansible inventory
my inventory:
[ora_patch]
10.24.29.14 SID=orcl,orcl2
my playbook:
---
- hosts: [ora_patch]
tasks:
- debug:
var: "{{ hostvars[ansible_host]['SID'] }}"
Output ** I GET **:
PLAY [ora_patch] ************************************************************
TASK [patch_ora_si_122 : debug] *****************************************
ok: [10.24.29.14] => {
"orcl,orcl2": "(Undefined, Undefined)"
}
PLAY RECAP ******************************************************************
10.24.29.14 : ok=1 changed=0 unreachable=0 failed=0
Output ** I want ** :
PLAY [ora_patch] ***********************************************************
TASK [patch_ora_si_122 : debug] ****************************************
ok: [10.24.29.14] => {
"SID": "orcl,orcl2"
}
PLAY RECAP *****************************************************************
10.24.29.14 : ok=1 changed=0 unreachable=0 failed=0
Command I execute:
ansible-playbook -i inventory patch_ora_si_122.yml
Your playbook is slightly wrong. You are trying to use the content of the hostvar "{{ hostvars[ansible_host]['SID'] }}" as a variable name to display with debug: var=....
Simply change your playbook to
---
- hosts: ora_patch
tasks:
- debug:
msg: "SID: {{ hostvars[ansible_host]['SID'] }}"
or you could also use the variable name directly:
---
- hosts: ora_patch
tasks:
- debug:
var: SID
Ansible inventory.ini follows beloe format.
[hosts]
[hosts:vars]
The below should work:
[ora_patch]
10.24.29.14 SID=orcl,orcl2
[ora_patch:vars]
SID=orcl,orcl2
Here is my playbook that builds a dynamic inventory using add_host:
---
- name: "Play 1"
hosts: localhost
gather_facts: no
tasks:
- name: "Search database"
command: > mysql --user=root --password=p#ssword deployment
--host=localhost -Ns -e "SELECT dest_ip,username FROM deploy_dets"
register: command_result
- name: Add hosts
add_host:
name: "{{ item.split('\t')[0] }}"
ansible_user: "{{ item.split('\t')[1] }}"
groups: dest_nodes
with_items: "{{ command_result.stdout_lines }}"
- hosts: dest_nodes
gather_facts: false
tasks:
- debug:
msg: Run the shell script with the arguments `{{ ansible_user }}` here"
The Output is good and as expected when the 'name:' attribute of add_host are of different values IPs viz '10.9.0.100' & '10.8.2.144'
$ ansible-playbook duplicate_hosts.yml
PLAY [Play 1] ***********************************************************************************************************************************************
TASK [Search database] **************************************************************************************************************************************
changed: [localhost]
TASK [Add hosts] ********************************************************************************************************************************************
changed: [localhost] => (item=10.9.0.100 user1)
changed: [localhost] => (item=10.8.2.144 user2)
PLAY [dest_nodes] *******************************************************************************************************************************************
TASK [debug] ************************************************************************************************************************************************
ok: [10.9.0.100] => {
"msg": "Run the shell script with the arguments `user1` here\""
}
ok: [10.8.2.144] => {
"msg": "Run the shell script with the arguments `user2` here\""
}
PLAY RECAP **************************************************************************************************************************************************
10.8.2.144 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
10.9.0.100 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
localhost : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
The problem is when the 'name:' attribute for add_host gets duplicate entry say 10.8.2.144 despite having unique 'ansible_user' value the play ignores the first name, ansible_user entry and runs only once with the latest final entry.
$ ansible-playbook duplicate_hosts.yml
PLAY [Play 1] ***********************************************************************************************************************************************
TASK [Search database] **************************************************************************************************************************************
changed: [localhost]
TASK [Add hosts] ********************************************************************************************************************************************
changed: [localhost] => (item=10.8.2.144 user1)
changed: [localhost] => (item=10.8.2.144 user2)
PLAY [dest_nodes] *******************************************************************************************************************************************
TASK [debug] ************************************************************************************************************************************************
ok: [10.8.2.144] => {
"msg": "Run the shell script with the arguments `user2` here\""
}
PLAY RECAP **************************************************************************************************************************************************
10.8.2.144 : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
localhost : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Interestingly the debug shows two entries for add_host name: 10.8.2.144 with the different ansible_users i.e 'user1' and 'user2' but when we run the group it runs just the single and latest name entry and seen in the output above.
I'm on the latest version of ansible.
Can you please provide some solution where i can run the play for every unique 'ansible_user' on the same host ?
In summary: I wish to run multiple tasks on the same host first with 'user1' and then with 'user2'
You can add a alias as inventory hostname. Here I have given the username as hostname(alias).
Please try this, I have not tested it.
- name: Add hosts
add_host:
hostname: "{{ item.split('\t')[1] }}"
ansible_host: "{{ item.split('\t')[0] }}"
ansible_user: "{{ item.split('\t')[1] }}"
groups: dest_nodes
with_items: "{{ command_result.stdout_lines }}"