0

I have an ansible role that defines two parameters and a default for the second one.

roles/upstream/tasks/main.yml:

---
- debug:
    msg: "Parameter in upstream is {{param}} and param2 is {{param2}}"

roles/upstream/defaults/main.yml:

---
param2: []

And then this exemplary play:

---
- name: test
  hosts: localhost
  roles:
    - role: upstream
      vars:
        param: 21
    - role: upstream
      vars:
        param: 42
        param2: test

When I execute this, I see the following:

TASK [Gathering Facts] **********************************************************************************
ok: [localhost]

TASK [upstream : debug] *********************************************************************************
ok: [localhost] => {
    "msg": "Parameter in upstream is 21 and param2 is test"
}

TASK [upstream : debug] *********************************************************************************
ok: [localhost] => {
    "msg": "Parameter in upstream is 42 and param2 is test"
}

What is the rationale that the second call to the role also overrides the default for param2 for the other call and how to avoid this?

languitar
  • 6,554
  • 2
  • 37
  • 62
  • https://serverfault.com/q/926732/197039 – techraf Aug 30 '18 at 15:17
  • @techraf thanks, that prevents this problem, but also makes variables inaccessible to other roles... hmmm... – languitar Aug 30 '18 at 19:27
  • Because roles in Ansible were originally just an organisational feature. Variables can be play-scoped, or task-scoped, but not role-scoped (there are also extravars, different story). With `vars` inside `roles` section of a play, they are first read as play variables (last value wins), then for each task inside a role the `vars` from that role declaration is applied. – techraf Aug 30 '18 at 19:59
  • @techraf I see the technical reasons, but that is extremely counter-intuitive and I see no way to work around that? – languitar Aug 31 '18 at 08:57

1 Answers1

1

The behaviour you observe is expected.

Roles in Ansible were originally just an organisational feature. Variables can be play-scoped, or task-scoped, but not role-scoped (there are also extravars, facts, magic variables behaving differently, but not relevant here).

With vars inside the roles section of a play, they are first read as play variables (last value defined wins), then for each task inside a role the vars from that role declaration is applied.


To avoid the problem, you should use use include_role or import_role module in tasks (or pre_tasks).

Then, per your additional requirement in the comment:

[this] makes variables inaccessible to other roles...

You can make the defaults and vars defined in roles visible outside of the roles by setting a new parameter public in Ansible 2.7 (in development as of writing this answer).


Final solution:

- hosts: localhost
  connection: local
  gather_facts: no

  tasks:
    - include_role:
        name: upstream
        public: true
      vars:
        param: 21

    - debug:
        var: param2

    - include_role:
        name: upstream
      vars:
        param: 42
        param2: test
techraf
  • 64,883
  • 27
  • 193
  • 198