Global variable to pas dynamic data between plays with different hosts

1,410 views
Skip to first unread message

Pieter Voet

unread,
Nov 28, 2016, 7:05:36 PM11/28/16
to Ansible Project
Hi all,

I've been looking into this for some time now, and I think I definitely can use some help here.  
What I want is to set a variable from a task specific to one host from a group, with a value that is set dynamically by the task outcome.
Then next, I want to use this variable by another play, with more hosts from that same group.

e.g. :

group = { host_a, host_b, host_c }

---
- hosts: host_a
  tasks:
  - name: get the variable value
    whatever_module: arg=arg_a
    register: result

- hosts: all
  tasks:
  - debug: var="{{result}}"


I know there already has been some discussion about this... Hopefully I didn't miss something in previous posts..

I can't use 'set_fact' in the first play, since that will only set the fact for the hosts specified, i.e. 'host_a'.
Trying to write some action plugin to 'set a global variable' failed, because I stumbled upon the point that
now ( V2 ) a 'fork()' is used, hence rendering all references in the plugin immutable..
( was able to get to 'self._task.get_variable_manager()' which returned a reference to the Plays' VariableManager,
but setting any value in it's '_extra_vars' was lost after the 'os._exit()' in 'forking.py' 'Popen' class..

I think this is caused by design : Play information should be on a 'need to know' base, and also a Play should not be
able to change a value set as an 'extra_var'.

Then I found a post from august where Matt Davis said : 'There are still ways to root around in inventory from an action plugin under 2.x (eg, self._templar._available_variables), but the objects are effectively immutable...' ..

So, the question I want to ask here is : is it / will it  be possible to pass  values from plays with certain hosts back to different hosts in other plays ?

Thanks in advance, and apologies if I could have found the answer myself...
have a nice day !

pieter.

Kai Stian Olstad

unread,
Nov 29, 2016, 12:48:51 PM11/29/16
to ansible...@googlegroups.com
On 25. nov. 2016 17:11, Pieter Voet wrote:
> I can't use 'set_fact' in the first play, since that will only set the fact
> for the hosts specified, i.e. 'host_a'.

Why can't do that?
You can in the second play also access the result variable directly like so
{{ hostvars['host_a']['result'] }}


--
Kai Stian Olstad

Pieter Voet

unread,
Nov 30, 2016, 4:08:29 AM11/30/16
to Ansible Project


True. And thanks for contributing. 
I knew this.  I think I oversimplified my testcase...   Thing is, our inventory has many groups, where hosts can be member 
of multiple groups..  Here's a modified testcase :

groupall = { host_a, host_b, host_c }
    group1 = { host_a }
    group2 = { host_b, host_c } 

---
- hosts: group1
  tasks:
  - name: get the variable value
    whatever_module: arg=arg_a
    register: result

- hosts: group2
  tasks:
  - debug: var="{{result}}"

The playbook is started with the '--limit groupall'  argument. 

Now, because of the groups, the second play cannot lookup 'host_a' in the hostvars, since it has no knowledge
about the hosts in 'group1'...

Any ideas ?

 

Kai Stian Olstad

unread,
Nov 30, 2016, 5:42:37 AM11/30/16
to ansible...@googlegroups.com
Knowledge of members in group1 you find with groups['group1']

So this should work.

hostvars[groups['group1'][0]]['result']

--
Kai Stian Olstad

Pieter Voet

unread,
Nov 30, 2016, 5:50:16 AM11/30/16
to Ansible Project
Hi Kai,

you said :
> Knowledge of members in group1 you find with groups['group1'] 
> hostvars[groups['group1'][0]]['result'] 

actually, the 'group1' group contains a lot of hosts..  There is no quarantee
that the first entry in that array actually is the host that applies to my playbook. 

Kai Stian Olstad

unread,
Nov 30, 2016, 7:24:47 AM11/30/16
to ansible...@googlegroups.com
Then I don't understand what you are trying to achieve, your testcase
must be flawed.

Every host in group1 will run that task, so every host in the group will
have a "result" variable set.
You must choose at some level who is going to be the "global" one.

--
Kai Stian Olstad

Pieter Voet

unread,
Nov 30, 2016, 7:51:49 AM11/30/16
to Ansible Project
OK, redefining my testcase then :


groupall = { host_a, host_b, host_c }
    group1 = { host_x, host_y, host_a, host_z }
    group2 = { host_b, host_c } 

---
- hosts: group1
  tasks:
  - name: get the variable value
    whatever_module: arg=arg_a
    register: result

- hosts: group2
  tasks:
  - debug: var="{{result}}"

The playbook is started with the '--limit groupall'  argument. 

Yes, every host in 'group1' will have access to the result. 
What I want is to access that result in the other play ( for 'group2' ).
( BTW, I understand that the first play will only be executed on 'host_a' since that's the only host that is in 'groupall'...)

For now I'll call it a playbook 'global'  variable...  Like an 'extra_var' , but then settable from within a play.

Thanks !

Pieter Voet

unread,
Dec 5, 2016, 7:12:22 AM12/5/16
to Ansible Project
OK, so I looked at Ansible's code, and I now know how to implement this.   I tried my modification locally and
it works fine.  It basically adds a module that adds an 'extra_vars'  variable if it does not yet exist.
That way, any variable set on the commandline using the '--extra-vars'  argument cannot be overruled by the 
playbook.

Now this scenario works :

Inventory :
     group_all = { host_1, host_2, host_3 }
     group_one = { host_1 }
     group_two = { host_2, host3 }


Playbook 'my_playbook.yml' :

---
- hosts: group_one
  tasks:
  - name: list /tmp
    shell: ls /tmp
    register: out

  - name: set global variable
    setglobal: name=myvar value="{{out}}"

- hosts: group_two
  tasks:
  - debug: msg="{{myvar}}"


command :  'ansible-playbook  my_playbook.yml --limit group_all'


Anyone interested in this modification ?  I can create a pull request... 
Reply all
Reply to author
Forward
0 new messages