Ansible 2.0 changes in variables scoping in playbooks

477 views
Skip to first unread message

Simon Lipp

unread,
Mar 18, 2016, 4:00:15 PM3/18/16
to Ansible Project
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

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:

# 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
Reply all
Reply to author
Forward
0 new messages