admirabilis
admirabilis

Reputation: 2420

Define `become=yes' per role with Ansible

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!

Upvotes: 59

Views: 67083

Answers (7)

mathewguest
mathewguest

Reputation: 640

You can use a block to become_root on a series of import_tasks to separate file(s) in the role.

roles/my_fav_role/main.yml:

---
name: block to perform tasks defined below as root
become: true
block:
  - import_tasks: task_file1.yml
  - import_tasks: task_file2.yml

roles/my_fav_role/task_file1.yml:

---
- name: example task
  debug:
    msg: "yay" 

See Also:

Upvotes: 0

warunapww
warunapww

Reputation: 1006

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

Upvotes: 3

Duncan Lock
Duncan Lock

Reputation: 12751

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).

Upvotes: 60

user3071170
user3071170

Reputation: 485

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.

Upvotes: 18

Ondrej A. Benes
Ondrej A. Benes

Reputation: 41

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
...

Upvotes: 4

admirabilis
admirabilis

Reputation: 2420

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 }

Upvotes: 94

MillerGeek
MillerGeek

Reputation: 3137

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.

Upvotes: 3

Related Questions