override variable from outside role

Greetings Ansible users!

I have a role “nftables” that is assigned to all nodes in my inventory. It has a variable ‘forward_policy’ that has a default value:

$ cat roles/nftables/defaults/main.yaml
forward_policy: drop

I’d like to have another role (applied only to my router system) that can override that variable:

$ cat roles/router/vars/main.yaml
forward_policy: accept

I don’t know how to override the variable in the nftables role from within the router role. Does anyone have any suggestions?

Thanks for any help!

-m

PS. Here is are my current playbooks:

roles
├── nftables
│ ├── defaults
│ │ └── main.yaml
│ ├── files
│ │ └── etc
│ │ ├── nftables.conf
│ │ └── nftables.conf.d
│ │ └── 000-flush-ruleset.nft
│ ├── handlers
│ │ └── main.yaml
│ ├── tasks
│ │ └── main.yaml
│ └── templates
│ └── etc
│ └── nftables.conf.d
│ └── 050-default-chains.nft.j2
└── router
├── files
│ └── etc
│ └── nftables.conf.d
│ └── 070-default-nat-table.nft
├── tasks
│ ├── main.yaml
│ └── nftables_nat_table.yaml
└── vars
└── main.yaml

17 directories, 10 files

And the contents:

───────┬────────────────────────────────────────────────────────────────────────
│ File: hosts.yaml
───────┼────────────────────────────────────────────────────────────────────────
1 │ ungrouped:
2 │ hosts:
3 │ zed:
4 │
5 │ router:
6 │ hosts:
7 │ zed:
───────┴────────────────────────────────────────────────────────────────────────
───────┬────────────────────────────────────────────────────────────────────────
│ File: roles/nftables/defaults/main.yaml
───────┼────────────────────────────────────────────────────────────────────────
1 │ forward_policy: drop
───────┴────────────────────────────────────────────────────────────────────────
───────┬────────────────────────────────────────────────────────────────────────
│ File: roles/nftables/files/etc/nftables.conf
───────┼────────────────────────────────────────────────────────────────────────
1 │ #!/usr/sbin/nft -f
2 │
3 │ include “/etc/nftables.conf.d/*.nft”
───────┴────────────────────────────────────────────────────────────────────────
───────┬────────────────────────────────────────────────────────────────────────
│ File: roles/nftables/files/etc/nftables.conf.d/000-flush-ruleset.nft
───────┼────────────────────────────────────────────────────────────────────────
1 │ flush ruleset
───────┴────────────────────────────────────────────────────────────────────────
───────┬────────────────────────────────────────────────────────────────────────
│ File: roles/nftables/handlers/main.yaml
───────┼────────────────────────────────────────────────────────────────────────
1 │ -
2 │ name: restart nftables
3 │ service:
4 │ name: nftables
5 │ state: restarted
───────┴────────────────────────────────────────────────────────────────────────

───────┬────────────────────────────────────────────────────────────────────────
│ File: roles/nftables/tasks/main.yaml
───────┼────────────────────────────────────────────────────────────────────────
1 │ —
2 │ # This playbook contains plays to configure nftables.
3 │
4 │ -
5 │ name: enable service nftables
6 │ service:
7 │ name: nftables
8 │ enabled: yes
9 │
10 │ -
11 │ name: configure nftables.conf
12 │ copy:
13 │ src: files/etc/nftables.conf
14 │ dest: /etc/nftables.conf
15 │ tags:
16 │ - nftables
17 │ notify: restart nftables
18 │
19 │ -
20 │ name: configure nftables.conf.d
21 │ copy:
22 │ src: files/etc/nftables.conf.d
23 │ dest: /etc
24 │ tags:
25 │ - nftables
26 │ notify: restart nftables
27 │
28 │ -
29 │ name: configure nftables.conf.d/050-default-chains.nft
30 │ template:
31 │ src: etc/nftables.conf.d/050-default-chains.nft.j2
32 │ dest: /etc/nftables.conf.d/050-default-chains.nft
33 │ tags:
34 │ - nftables
35 │ notify: restart nftables
───────┴────────────────────────────────────────────────────────────────────────
───────┬────────────────────────────────────────────────────────────────────────
│ File: roles/nftables/templates/etc/nftables.conf.d/050-default-chains.nft.j2
───────┼────────────────────────────────────────────────────────────────────────
1 │ table inet filter {
2 │ chain input {
3 │ type filter hook input
4 │ priority 0;
5 │ policy accept;
6 │ }
7 │ chain forward {
8 │ type filter hook forward
9 │ priority 0;
10 │ policy {{ forward_policy }};
11 │ }
12 │ chain output {
13 │ type filter hook output
14 │ priority 0;
15 │ policy accept;
16 │ }
17 │ }
───────┴────────────────────────────────────────────────────────────────────────
───────┬────────────────────────────────────────────────────────────────────────
│ File: roles/router/files/etc/nftables.conf.d/070-default-nat-table.nft
───────┼────────────────────────────────────────────────────────────────────────
1 │ table inet nat {
2 │ chain postrouting {
3 │ type nat hook postrouting
4 │ priority srcnat;
5 │ }
6 │
7 │ chain prerouting {
8 │ type nat hook prerouting
9 │ priority dstnat;
10 │ }
11 │ }
───────┴────────────────────────────────────────────────────────────────────────
───────┬────────────────────────────────────────────────────────────────────────
│ File: roles/router/tasks/main.yaml
───────┼────────────────────────────────────────────────────────────────────────
1 │ —
2 │ # This playbook contains plays to configure the router.
3 │
4 │ -
5 │ include_tasks: nftables_nat_table.yaml
───────┴────────────────────────────────────────────────────────────────────────
───────┬────────────────────────────────────────────────────────────────────────
│ File: roles/router/tasks/nftables_nat_table.yaml
───────┼────────────────────────────────────────────────────────────────────────
1 │ —
2 │ # This playbook contains plays to add nat table for nftables.
3 │
4 │ -
5 │ name: configure nftables nat table
6 │ copy:
7 │ src: files/etc/nftables.conf.d/070-default-nat-table.nft
8 │ dest: /etc/nftables.conf.d/070-default-nat-table.nft
9 │ tags:
10 │ - router
11 │ notify: restart nftables
───────┴────────────────────────────────────────────────────────────────────────
───────┬────────────────────────────────────────────────────────────────────────
│ File: roles/router/vars/main.yaml
───────┼────────────────────────────────────────────────────────────────────────
1 │ forward_policy: accept
───────┴────────────────────────────────────────────────────────────────────────
───────┬────────────────────────────────────────────────────────────────────────
│ File: site.yaml
───────┼────────────────────────────────────────────────────────────────────────
1 │ —
2 │ -
3 │ name: apply common configuration to all nodes
4 │ hosts: all
5 │ roles:
6 │ - nftables
7 │
8 │ -
9 │ name: apply router configurations
10 │ hosts: router
11 │ roles:
12 │ - router
───────┴────────────────────────────────────────────────────────────────────────

$ cat roles/nftables/defaults/main.yaml
forward_policy: drop

$ cat roles/router/vars/main.yaml
forward_policy: accept

I don't know how to override the variable in the nftables role from within
the router role.

Is it possible to minimize the example?

tree .

.
├── hosts
├── pb.yml
└── roles
    ├── nftables
    │ ├── defaults
    │ │ └── main.yml
    │ └── tasks
    │ └── main.yml
    └── router
        ├── tasks
        │ └── main.yml
        └── vars
            └── main.yml

cat roles/nftables/defaults/main.yml

forward_policy: drop

cat roles/nftables/tasks/main.yml

- debug:
    var: forward_policy

cat roles/router/vars/main.yml

forward_policy: accept

cat roles/router/tasks/main.yml

- debug:
    var: forward_policy

cat hosts

[router]
zed

cat pb.yml

- hosts: all
  roles:
    - nftables

- hosts: router
  roles:
    - router

Running the playbook gives

ansible-playbook pb.yml

PLAY [all] *****************************

TASK [nftables : debug] ****************
ok: [zed] =>
  forward_policy: drop

PLAY [router] **************************

TASK [router : debug] ******************
ok: [zed] =>
  forward_policy: accept

Does this reproduce your problem? If yes what do you expect?

Hi Vladimir,

$ cat roles/nftables/defaults/main.yaml
forward_policy: drop

$ cat roles/router/vars/main.yaml
forward_policy: accept

I don’t know how to override the variable in the nftables role from within
the router role.

Is it possible to minimize the example?

tree .
.
├── hosts
├── pb.yml
└── roles
├── nftables
│ ├── defaults
│ │ └── main.yml
│ └── tasks
│ └── main.yml
└── router
├── tasks
│ └── main.yml
└── vars
└── main.yml

cat roles/nftables/defaults/main.yml
forward_policy: drop
cat roles/nftables/tasks/main.yml

  • debug:
    var: forward_policy

cat roles/router/vars/main.yml
forward_policy: accept
cat roles/router/tasks/main.yml

  • debug:
    var: forward_policy

cat hosts
[router]
zed
cat pb.yml

  • hosts: all
    roles:

  • nftables

  • hosts: router
    roles:

  • router

Running the playbook gives

ansible-playbook pb.yml

PLAY [all] *****************************

TASK [nftables : debug] ****************
ok: [zed] =>
forward_policy: drop

I would like forward_policy to be “accept” for the nftables role - since I want the “router” role to affect how a j2 template gets set in the “nftables” role.

PLAY [router] **************************

TASK [router : debug] ******************
ok: [zed] =>
forward_policy: accept

So, I’d like to be able to modify a variable in one role from a different role.

Or perhaps have a global variable that can bet set to a default value in the role “nftables”, but overridden in the role “router”.

Thanks for the help!

-m

> PLAY [all] *****************************
>
> TASK [nftables : debug] ****************
> ok: [zed] =>
> forward_policy: drop

I would like forward_policy to be "accept" for the nftables role ...
I want the "router" role to affect ... "nftables" role.

Create task that will "instantiate" the variable *forward_policy*

cat roles/router/tasks/instantiate_vars.yml

- set_fact:
    forward_policy: "{{ forward_policy }}"
  when: forward_policy is defined

and run it in the first play *pre_tasks*

cat pb.yml

- hosts: all
  pre_tasks:
    - include_role:
        name: router
        tasks_from: instantiate_vars
      run_once: true
  roles:
    - nftables

- hosts: router
  roles:
    - router

Hi Vladamir,

Thanks for all your help. Unfortunately the variables (and how and where they are being set) just aren’t working the way I am expecting. I’ll punt for now and just set the variable in the hosts.yaml file.

Very appreciative of your time and energy.

Cheers,

-m

There are many other options on how to override defaults.
The solution might be simple if you provide the detail. See
https://en.wikipedia.org/wiki/Minimal_reproducible_example

I did not fully understand the problem, but might worth having a look at variable precedence https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_variables.html#understanding-variable-precedence

I did not fully understand the problem, but might worth having a look at
variable precedence

The problem is as follows: You have two roles and want to override
defaults in the first role by the variables from the second role.

The precedence of variables is a substantial part of the solution. It
is not sufficient though. There might be more solutions depending on
the use-case's details. An option might be creating the below task in
the second role

  > cat roles/role2/tasks/instantiate_vars.yml
  - set_fact:
      var1_common: "{{ var1_common }}"
    when: var1_common is defined

and "instantiate" the variable(s) before you run the first role. This
way *set_fact* (precedence 19.) overrides the roles' defaults
(precedence 2.)

  > cat pb.yml
  - hosts: all
    pre_tasks:
      - include_role:
          name: role2
          tasks_from: instantiate_vars
        run_once: true
    roles:
      - role1

Notes:

* You don't have to include or import *instantiate_vars.yml* in role2.
* You can "instantiate* more variables.
* You have to keep in mind the limitation of this solution. Only
  precedence 20.-22. are left to override such "instantiated"
  variables.

Have you considered the following?

This is not a solution to the problem:

  You have two roles and want to override defaults in the first role
  by the variables from the second role.