user21190291
user21190291

Reputation:

Can I use ansible-playbook "--extra-vars" to execute roles conditionally

I have an Ansible playbook I am working on and I am trying to make the execution a little more dynamic. I have two roles that don't always need to be run in conjunction, sometimes only one of them needs to be run. I have been digging into the Ansible docs, and I am wondering if I can pass --extra-vars parameters to only run a specific role.

Currently, my playbook looks like this:

---
- hosts: default
  become: true

  roles:
      - role: upgrades
        when: {{ upgrades_role }}

      - role: custom-packages 
        when: {{ custom_packages_role }}

So, the goal is to be able to run:

ansible-playbook playbook.yml -e "upgrades_role=upgrades"

And this would only run the upgrades role and skip the custom_packages role.

Similarly, if I want to run both roles on the same hosts/system:

ansible-playbook playbook.yml -e "upgrades_role=upgrades custom_packages_role=custom-packages"

This would run both roles.

Based on my understating of Ansible syntax and the --extra-vars, -e parameter, this seems like it should work. I just want to be sure I am doing this the proper way and avoiding anti-patterns.

Ansible Version: 2.14

Upvotes: 1

Views: 4009

Answers (2)

Vladimir Botka
Vladimir Botka

Reputation: 68229

Let me provide you with a framework to automate the use case that you described:

Pass --extra-vars parameters to only run a specific role

Create the project

shell> ls -1
ansible.cfg
hosts
playbook.yml.j2
roles
setup.yml
shell> cat ansible.cfg 
[defaults]
gathering = explicit
collections_path = $HOME/.local/lib/python3.9/site-packages/
inventory = $PWD/hosts
roles_path = $PWD/roles
retry_files_enabled = false
stdout_callback = yaml
shell> cat hosts 
localhost

The playbook setup.yml

  • Gets the list of the roles. Fit the variable my_roles_dir to your needs.

  • Creates file my_roles_order.yml with the list my_roles_order. The purpose of this file is to create the order of the roles.

  • Creates file my_roles_enable.yml with the dictionary my_roles_enable. The purpose of this file is to create defaults.

  • Creates file playbook.yml from the template. Fit the template to your needs.

shell> cat setup.yml 
- hosts: localhost

  vars:

    my_roles_dir: "{{ lookup('config', 'DEFAULT_ROLES_PATH') }}"

  tasks:

    - set_fact:
        my_roles: "{{ my_roles|default([]) +
                      lookup('pipe', 'ls -1 ' ~ item).splitlines() }}"
      loop: "{{ my_roles_dir }}"

    - copy:
        dest: "{{ playbook_dir }}/my_roles_order.yml"
        content: |
          my_roles_order:
          {{ my_roles|to_nice_yaml|indent(2, true) }}
        force: "{{ my_roles_order_force|default(false) }}"
    - include_vars: my_roles_order.yml

    - copy:
        dest: "{{ playbook_dir }}/my_roles_enable.yml"
        content: |
          my_roles_enable:
          {% for role in my_roles %}
            {{ role }}: false
          {% endfor %}
        force: "{{ my_roles_enable_force|default(false) }}"
    - include_vars: my_roles_enable.yml

    - template:
        src: playbook.yml.j2
        dest: "{{ playbook_dir }}/playbook.yml"
shell> cat playbook.yml.j2
- hosts: localhost
  become: true

  vars_files:
    - my_roles_enable.yml

  roles:
{% for role in my_roles_order %}
    - role: {{ role }}
      when: {{ role }}_role|default(my_roles_enable.{{ role }})|bool
{% endfor %}

Test the trivial roles

shell> tree roles/
roles/
├── current_packages
│   └── tasks
│       └── main.yml
├── custom_packages
│   └── tasks
│       └── main.yml
├── stable_packages
│   └── tasks
│       └── main.yml
└── upgrades
    └── tasks
        └── main.yml

8 directories, 4 files
shell> cat roles/*/tasks/main.yml
- debug:
    msg: Role current_packages running ...
- debug:
    msg: Role custom_packages running ...
- debug:
    msg: Role stable_packages running ...
- debug:
    msg: Role upgrades running ...

Run the playbook setup.yml

shell> ansible-playbook setup.yml

PLAY [localhost] ****************************************************************************************

TASK [set_fact] *****************************************************************************************
ok: [localhost] => (item=/scratch/tmp7/test-204/roles)

TASK [copy] *********************************************************************************************
changed: [localhost]

TASK [include_vars] *************************************************************************************
ok: [localhost]

TASK [copy] *********************************************************************************************
changed: [localhost]

TASK [include_vars] *************************************************************************************
ok: [localhost]

TASK [template] *****************************************************************************************
changed: [localhost]

PLAY RECAP **********************************************************************************************
localhost: ok=6    changed=3    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0

This creates playbook.yml

shell> cat playbook.yml
- hosts: localhost
  become: true

  vars_files:
    - my_roles_enable.yml

  roles:
    - role: current_packages
      when: current_packages_role|default(my_roles_enable.current_packages)|bool
    - role: custom_packages
      when: custom_packages_role|default(my_roles_enable.custom_packages)|bool
    - role: stable_packages
      when: stable_packages_role|default(my_roles_enable.stable_packages)|bool
    - role: upgrades
      when: upgrades_role|default(my_roles_enable.upgrades)|bool

and the files

shell> cat my_roles_order.yml
my_roles_order:
  - current_packages
  - custom_packages
  - stable_packages
  - upgrades
shell> cat my_roles_enable.yml
my_roles_enable:
  current_packages: false
  custom_packages: false
  stable_packages: false
  upgrades: false

By default, the playbook runs nothing. Here you can "pass --extra-vars parameters to only run a specific role". For example, enable the role upgrades

shell> ansible-playbook playbook.yml -e upgrades_role=true

PLAY [localhost] *****************************************************************************

TASK [current_packages : debug] **************************************************************
skipping: [localhost]

TASK [custom_packages : debug] ***************************************************************
skipping: [localhost]

TASK [stable_packages : debug] ***************************************************************
skipping: [localhost]

TASK [upgrades : debug] **********************************************************************
ok: [localhost] => 
  msg: Role upgrades running ...

PLAY RECAP ***********************************************************************************
localhost: ok=1    changed=0    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0

If you want to change the order and/or the enablement defaults of the roles edit the files my_roles_order.yml and my_roles_enable.yml. For example, put the role upgrades in the first place and enable it by default

shell> cat my_roles_order.yml
my_roles_order:
  - upgrades
  - current_packages
  - custom_packages
  - stable_packages
shell> cat my_roles_enable.yml
my_roles_enable:
  current_packages: false
  custom_packages: false
  stable_packages: false
  upgrades: true

Update the playbook

shell> ansible-playbook setup.yml

Test it

shell> ansible-playbook playbook.yml

PLAY [localhost] *****************************************************************************

TASK [upgrades : debug] **********************************************************************
ok: [localhost] => 
  msg: Role upgrades running ...

TASK [current_packages : debug] **************************************************************
skipping: [localhost]

TASK [custom_packages : debug] ***************************************************************
skipping: [localhost]

TASK [stable_packages : debug] ***************************************************************
skipping: [localhost]

PLAY RECAP ***********************************************************************************
localhost: ok=1    changed=0    unreachable=0    failed=0    skipped=3    rescued=0    ignored=0

It's practical to create a file if you want to enable/disable multiple roles on the command line. For example,

shell> cat myroles.yml 
upgrades_role: false
stable_packages_role: true
custom_packages_role: true

Use it in the command line

shell> ansible-playbook playbook.yml -e @myroles.yml

PLAY [localhost] *****************************************************************************

TASK [upgrades : debug] **********************************************************************
skipping: [localhost]

TASK [current_packages : debug] **************************************************************
skipping: [localhost]

TASK [custom_packages : debug] ***************************************************************
ok: [localhost] => 
  msg: Role custom_packages running ...

TASK [stable_packages : debug] ***************************************************************
ok: [localhost] => 
  msg: Role stable_packages running ...

PLAY RECAP ***********************************************************************************
localhost: ok=2    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0

Don't display skipped hosts

shell> ANSIBLE_DISPLAY_SKIPPED_HOSTS=false ansible-playbook playbook.yml -e @myroles.yml

PLAY [localhost] *****************************************************************************

TASK [custom_packages : debug] ***************************************************************
ok: [localhost] => 
  msg: Role custom_packages running ...

TASK [stable_packages : debug] ***************************************************************
ok: [localhost] => 
  msg: Role stable_packages running ...

PLAY RECAP ***********************************************************************************
localhost: ok=2    changed=0    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0

Upvotes: 1

Carlos Monroy Nieblas
Carlos Monroy Nieblas

Reputation: 2283

The most common way will be to use tags; updating the example in the question:

---
- hosts: default
  become: true

  roles:
      - role: upgrades
        tags: upgrades

      - role: custom-packages 
        tags: packages
...

So, the goal is to be able to run:

# Execute all the roles
ansible-playbook playbook.yml

# Execute only the upgrade
ansible-playbook playbook.yml -t upgrades

# Execute only the setup of custom packages
ansible-playbook playbook.yml -t packages

Here is the documentation for tags.

Using variables and when is possible, but you'll need to ensure to cast it to bool.

Upvotes: 1

Related Questions