# Ansible 2.0 changes in variables scoping in playbooks

**URL:** <https://forum.ansible.com/t/ansible-2-0-changes-in-variables-scoping-in-playbooks/20915>\
**Category:** Ansible Project\
**Created:** [March 18, 2016, 11:42am UTC](https://forum.ansible.com/t/ansible-2-0-changes-in-variables-scoping-in-playbooks/20915 "2016-03-18T11:42:09Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Simon\_Lipp](https://avatars.discourse-cdn.com/v4/letter/s/97f17d/32.png) [@Simon\_Lipp](https://forum.ansible.com/u/Simon_Lipp)\
**Post date:** [March 18, 2016, 11:42am UTC](https://forum.ansible.com/t/ansible-2-0-changes-in-variables-scoping-in-playbooks/20915/1 "2016-03-18T11:42:09Z")

</div>

Hello,

I’m in the process of migrating my playbooks to Ansible 2.0, and I’m quite distressed by changes in variable scoping with Ansible 1.9.

Let’s take this simple setup : [https://gist.github.com/sloonz/7144dde17b3bb013f357](https://gist.github.com/sloonz/7144dde17b3bb013f357)

In summary, we have :

- a role, profile, which is “intended” to create an user (user name is variable “name”) with a configurable home (defaults to “/home/{{name}}”, but overwritable by the “home” variable). For this test, the only action of this role is to use the debug module to print “name” and “home” variables
- a role, base, which is “intended” to create basic users of a system: “root”, whose home is “/root”, and “git” (using its default home “/home/git”). For this test, it also just prints the “home” and “name” variables
- two playbook : one which invokes base and prints (using the debug module) the values of “name” and “home”, and another one which bypass base and directly uses profile role and also prints the variables

Now let’s see the difference in output between 1.9 and 2.0 (note: by 2.0 I refer to v2.0.1.0-1: commit bb6cadefa2d68ed2a668fba14dc027947e043ae5) :

**I. With private\_role\_vars = no**

**1.** The “name” and “role” variables are not available to the “test-profile.yml” playbook in 2.0 :

TASK [debug] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“name”: “VARIABLE IS NOT DEFINED!”  
}

TASK [debug] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“home”: “VARIABLE IS NOT DEFINED!”  
}

But they are in 1.9, and take the value of the last role :

TASK: [debug var=name] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“var”: {  
“name”: “git”  
}  
}

TASK: [debug var=home] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“var”: {  
“home”: “/home/git”  
}  
}

**2.** The reverse is true for “test-base.yml” ! Variables are not accessible in 1.9 (although it work is a playbook-level variable instead of a role parameter) :

TASK: [debug var=name] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“var”: {  
“name”: “name”  
}  
}

TASK: [debug var=home] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“var”: {  
“home”: “/home/{{name}}”  
}  
}

They become accessible in 2.0, but with an incorrect value for “home” :

TASK [debug] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“name”: “git”  
}

TASK [debug] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“home”: “/root”  
}

**3.** Same remarks as (2), but inside of the “base” role : variables accessible in 2.0 but not in 1.9

**4.** test-base.yml behave differently inside the profile role (more exactly, for the git user). In 1.9, I get the expected :

TASK: [profile | debug var=name] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“var”: {  
“name”: “git”  
}  
}

TASK: [profile | debug var=home] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“var”: {  
“home”: “/home/git”  
}  
}

However, in 2.0 I get :

TASK [profile : debug] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“name”: “git”  
}

TASK [profile : debug] \*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*  
ok: [localhost] =\> {  
“home”: “/root”  
}

For test-profile.yml, however, we get the same result between 1.9 and 2.0 (the “expected” one where git’s home is /home/git, not /root)

**II. With private\_role\_vars = yes**

Now that’s the really confusing part for me. Documentation (well… comment in configuration file) states:

> ```auto
> # by default, variables from roles will be visible in the global variable
> # scope. To prevent this, the following option can be enabled, and only
> # tasks and handlers within the role will see the variables there
> 
> ```

And on bug #12081, @jimi-c (ansible developer, it seems), states:

> In 2.0, we did implement the `private_role_vars` boolean setting in ansible.cfg (ANSIBLE\_PRIVATE\_ROLE\_VARS for the environment variable) to prevent variables from roles showing up in the global scope, so you might want to use that in 2.0 if you really don’t want to change variable names. By default, the value is `False`, which makes 2.0 behave as 1.9.x and all versions before.

OK, now I’m confused, because that’s not what my tests shows.

When I set private\_role\_vars to yes, role defaults are still available in the global scope. What is not available anymore in the global scope is the role parameters (the “name” variable in the - {role: profile, name: git} defined in meta/main.yml). And that’s exactly the behavior of Ansible 1.9 ! In fact, as far as I can tell, setting the private\_role\_vars parameter to yes seems to make all my tests behave exactly the same as with ansible 1.9.

Some questions :

1. In ansible 1.9, are role parameters intended to be accessible in global scope ? My tests indicate that they aren’t, but @jimi-c seems to indicate that they should.
2. In ansible 2.0, are role parameters intended to be accessible in global scope when private\_role\_vars is yes ? My tests indicate that they aren’t (err… kinda expected ?).
3. In ansible 2.0, are role parameters intended to be accessible in global scope when private\_role\_vars is no ? My tests indicate that they are (expected too).
4. In ansible 1.9, are role variables (defaults/\*) intended to be accessible in global scope ? My tests indicate that they are (that’s expected).
5. In ansible 2.0, are role variables (defaults/\*) intended to be accessible in global scope when private\_role\_vars is yes ? My tests indicate that they are (huh… not expected ? Unless we want private\_role\_vars=yes to be the same behavior than 1.9 ?)
6. In ansible 2.0, are role variables (defaults/\*) intended to be accessible in global scope when private\_role\_vars is no ? My tests indicate that they are (expected).
7. Is there a parameter to make ansible 2.0 behave like 1.9 in this respect. My tests seems to indicate that yes, there is : private\_role\_vars=yes. @jimi-c comment seems to indicate that yes, there is : private\_role\_vars=no.

I can imagine three scenarios for what’s going on there :

1. private\_role\_vars=no is really intended to work like ansible 1.9, that’s why it’s the default ; private\_role\_vars = yes is intended to prevent role defaults from appearing in global scope. In this case, there’s two bugs in private\_role\_vars implementation : role parameters should not appear in global scope (they does) when private\_role\_vars=no and role defaults should not appear in global scope when private\_role\_vars = yes (they does).

2. private\_role\_vars refers to role parameters, and work as intended. It should be set to yes to have the same behavior as ansible 1.9, and the only “mistake” here is @jimi-c saying that the private\_role\_vars=no (the default) behave like ansible 1.9.

3. i didn’t understood anything

So… which one is it ?

Cheers,

Simon Lipp
