Define `become=yes' per role with Ansible

Ansible

Ansible Problem Overview


In my system provisioning with Ansible, I don't want to specify become=yes in every task, so I created the following ansible.cfg in the project main directory, and Ansible automatically runs everything as root:

[privilege_escalation]
become = True

But as the project kept growing, some new roles should not be run as root. I would like to know if it is possible to have some instruction inside the role that all tasks whithin that role should be run as root (eg. something in vars/), instead of the global ansible.cfg solution above!

Ansible Solutions


Solution 1 - Ansible

I have found a solution, although I think a better solution should be implemented by the Ansible team. Rename main.yml to tasks.yml, and then write the following to main.yml:

---
- { include: tasks.yml, become: yes }

Another solution is to pass the parameter directly in site.yml, but the main idea of the question was reusing the role in other projects without forgetting it needs root:

---
- hosts: localhost
  roles:
    - { role: name, become: yes }

Solution 2 - Ansible

You can also wrap your tasks in a block and put become: yes on the block. So, inside your roles/role_name/tasks/main.yml, you'd do this:

- block:

  - name: Tasks go here as normal
    ...

  become: yes

This will run all the tasks inside the block as root. More details of Ansible's blocks here (latest docs).

Solution 3 - Ansible

Not really a fundamentally different answer, rather a cosmetic reformatting of what's already been said. Looks the shortest, cleanest and YAML-ishest to me:

- name: My play
  hosts: myhosts
  roles:
    - role: role1
      become: yes

    - role: role2

Role1 will be run as root while role2 won't.

Solution 4 - Ansible

In Ansible documentation for 2.4, you can find a way to define connection variables, such as ansible_become and ansible_user. They are defined as usual variables. Below is a snippet.

The first role prepare_user connects to hosts using user root without elevation rights. The second role register connects to hosts using the remote_user set via ansible.cfg (looked for in a defined order; search for "in the following order").

---
- hosts: all
  name: Prepare VMs for cluster
  roles:
    - role: prepare_user
      vars:
        - ansible_become: false
        - ansible_user: root

    - role: register
...

Solution 5 - Ansible

There is a way to do what you are asking, but you need to be careful with how you use it, because Ansible evaluates most vars before running any tasks. If you use this trick, you must be sure to use it consistently or you could unintentionally use become where you don't want to.

Under the hood, Ansible uses the variable ansible_become to determine whether to use become for that task. Within your role, you can create a defaults/main.yml and set ansible_become: [true/false] This will cause that entire role to accept that value, unless overwritten by a higher-precedence definition (important to understand variable precedence)

The critical "gotcha" here is that if you use a role where this is defined, it will affect all other roles called below it in the play, unless they also have it defined.

Examples:

role_default_become_true has ansible_become: true defined as true in defaults role_default_become_false has ansible_become: false defined as true in defaults role_no_default has no default ansible_become value

---
- name: test1
  hosts: localhost
  connection: local
  roles:
  - role_default_become_true
  - role_default_become_false
  - role_no_default

- name: test2
  hosts: localhost
  connection: local
  roles:
  - role_default_become_false
  - role_default_become_true
  - role_no_default

- name: test3
  hosts: localhost
  connection: local
  roles:
  - role_default_become_false
  - role_default_become_true
  - { role: role_no_default, become: false }

In test1, role_no_default will run without become, because the previous role defined it as false, and it does not have its own definition.

In test2, role_no_default will run with become, because the previous role defined it as true, and it does not have its own definition.

In test3, role_no_default will run without become, because it has its own definition.

Solution 6 - Ansible

This is also possible using the include_task module

Create a main.yaml which includes the yaml with the tasks

---
- name: main
  include_tasks:
    file: "my_tasks_that_needs_become_true.yaml"
    apply:
      become: true

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionadmirabilisView Question on Stackoverflow
Solution 1 - AnsibleadmirabilisView Answer on Stackoverflow
Solution 2 - AnsibleDuncan LockView Answer on Stackoverflow
Solution 3 - Ansibleuser3071170View Answer on Stackoverflow
Solution 4 - AnsibleOndrej A. BenesView Answer on Stackoverflow
Solution 5 - AnsibleMillerGeekView Answer on Stackoverflow
Solution 6 - AnsiblewarunapwwView Answer on Stackoverflow