Scope gets polluted with variables from included roles even though private_role_vars = yes

Hi!

Whenever I include a role using the meta dependencies tag I ended up with the scope of the included role in the current role, even though I set private_role_vars = yes

As an example, consider a project like this

`

├── ansible.cfg
├── roles
│ ├── some_other_role
│ │ └── vars
│ │ └── main.yml
│ └── some_role
│ ├── defaults
│ │ └── main.yml
│ ├── meta
│ │ └── main.yml
│ └── tasks
│ └── main.yml
└── test.yml

`

the playbook test.yml simply includes ‘some_role’

`

  • hosts: all
    tasks:
  • include_role:
    name: some_role

`

In some_role meta definition I include a dependency (some_role/meta/main.yml)

`

`

The private setting does not affect dependencies as those are
specifically 'included' by the role. It is only mean to keep role vars
from polluting the rest of the play.

Oh I see

I have changed the code and if I include the role by means of include_role in the main tasks I get the expected result.

`

Funny thing is that if I refactor to explicitly include instead of meta dependencies I hit this bug, https://github.com/ansible/ansible/issues/23609.

Actually, include_role is currently bugged in that it does NOT expose
the vars. So I would not rely on that behaviour.

But still, I think that a proper mechanism for role scoping should be implemented, if you try to reuse code odds are that you end up having several roles with several variables declared inside each job. Things like ‘path’ or ‘port’ are expected to be declared inside those roles, either by vars statements while including or inside the role.

Imagine the following scenario

`

vars (vars/main.yml)
porrt:3000

metafile (meta/main.yml):
dependencies:

  • { role:nginx_server }

task (tasks/main.yml):
-include_role:
unicorn_server
args:
listen: {{ port }}

`

In the dependency you don’t specify a role so an internal port variable is used (lets say port 80)

The second one has parameter that you set to port, but given that you misspelled it in the vars file you end up having an 80 here. This should be an ‘undefined variable’ because you should not bother with name clashing.

There is also a bigger issue in here. Variables are lazy evaluated (https://github.com/ansible/ansible/issues/10374).

So if for example you include a role and use a variable evaluation in its args, you have absolutely no way if ensuring what is going to be the value when that arg is used inside the role.

`
roles/some_role/tasks/main.yml:

That makes modules completely unusable, code cannot be reused in Ansible?

It’s not ideal, but a simple workaround is simply to prefix your role variables with the name of the role. For example, using the names “nginx_port” and “unicorn_port” instead of just “port”. It’s actually worked fine in practice; the trick is that Ansible’s flexibility tempts you to buck the convention.

Oh—just re-read the example. If that’s actually the case then it would be a bug, since task vars are supposed to have higher precedence than role vars. The example doesn’t work as-written, however, because the task should be called with “vars:” (not “args:”). Perhaps that’s the source of the problem?