I'd like to start a discussion on the ability to define roles to 
`import_role` from within host_vars. Instead of *only* defining those roles 
statically in a playbook.

My goal is to be able to give an inventory_host the ability to define any 
[extra] roles it should import [on top of what is expressed in the 
playbook].

The inspiration for this comes from an extensive use of Puppet and Hiera in 
production.

### What I'd like to get out of this discussion:
1. How weird is this? / "correctness" / best practices
2. Are there other methods I had not considered?
3. Am I just running into a fundamental limit of the tool?

## My investigation and methods on how a host could define its own roles

This is what I was dealing with in my `site.yml` before my investigation:
```
- hosts:
  - hostname1
  user: deployuser
  become: yes
  gather_facts: yes
  roles:
  - common
  - router
  - route53
  - cloudflare
  vars_files:
  - "./vars/specificfilename.yml"

- hosts:
  - hostname2
  user: deployuser
  become: yes
  gather_facts: yes
  roles:
  - common
  - router
  - route53
  vars_files:
  - "./vars/specificfilename.yml"

- hosts:
  - hostname3
  user: deployuser
  become: yes
  gather_facts: yes
  roles:
  - common
  - wireguard_client
  - zeus
  vars_files:
  - "./vars/specificfilename.yml"

...
... more hosts with roles applied in a similar manner
... all with slightly different role sets
...
```

Lots of repeated lines where most of the time I actually just need to 
adjust the role list.


### Before we begin:
1. Lets assume that I have good reasons for what I want to do, even if that 
ends up not being the case. I'd like to explore this to see if it is a bad 
idea.
2. Inventory organization: I am aware I can create groups of hosts and 
apply roles to those groups. Unfortunately, I have a few roles where that 
would be useful, but most hosts will get a set of their own unique roles.
3. Directory structure:
```
./site.yml
./roles/include-roles/
./roles/render-role-import/
./roles/proxmox/ # installs proxmox-ve and used as an example role
./rendered/{{ inventory_hostname }}/ # created by role:render-role-import
./host_vars/{{ inventory_hostname }}/custom_roles
        # contents
        ---
        roles:
        - role1
        - role2
        - role3
        - etc
```

### My solutions so far:

#### Create a role whose only job it is, is to `include_role` from 
host_vars/<hostname>/custom_roles.

```
site.yml
---
- hosts: all
  roles:
  - include-roles
```

```
roles/include-roles/tasks/main.yml 
---
- name: host_vars defined roles
  include_role:
    name: "{{ r }}"
  loop: "{{ roles }}"
  loop_control:
    loop_var: r
```

This is reasonably effective, but I lose the ability to use tags I've set 
in the roles I include.

This is super annoying since I specifically setup my roles like this to 
make it easier while building and debugging.

```
roles/proxmox/tasks/main.yml 
---
- include: hosts.yml
  tags:
  - proxmox
  - proxmox-hosts

- include: repo.yml
  tags:
  - proxmox
  - proxmox-repo

- include: install.yml
  tags:
  - proxmox
  - proxmox-install

- include: web-redirect.yml
  tags:
  - proxmox
  - proxmox-web-redirect

- include: nag.yml
  tags:
  - proxmox
  - proxmox-nag
```

```
ansible-playbook site.yml -l whale --tags=proxmox

PLAY [whale] 
***************************************************************************************
skipping: no hosts matched

PLAY [whale] 
***************************************************************************************
skipping: no hosts matched

PLAY RECAP 
****************************************************************************************
```
This is because `include_role` is dynamic and import_role is static. Those 
includes have not happened at the time you specify the tags.


Ok, fine. Let's try to use `import_role` instead. Spoiler: you _cannot_ use 
loops.

So we continue and use loops anyways... but not in the same way as above.


#### Render a task file for the specific host and include that in the 
playbook.

```
roles/render-role-import/tasks/main.yml 
---
- name: create rendered directory
  file:
    path: "{{ item }}"
    state: directory
  with_items:
  - ./rendered
  - "./rendered/{{ inventory_hostname }}"
  delegate_to: localhost

- name: render role import task file
  template:
    src: tasks.yml.j2
    dest: "./rendered/{{ inventory_hostname }}/roles.yml"
    mode: '0644'
  delegate_to: localhost
```

```
roles/render-role-import/templates/tasks.yml.j2 
---

{% for r in roles %}
- import_role:
    name: {{ r }}

{% endfor  %}
```

Which results in the following file being created:
```
rendered/whale/roles.yml
---

- import_role:
    name: common

- import_role:
    name: proxmox

```

Now my `site.yml` looks like this:
```
site.yml
---
- hosts: all
  connection: local
  roles:
  - render-role-import
  tags:
  - always

- hosts: all
  user: deployuser
  become: yes
  gather_facts: yes
  tasks:
  - include: "./rendered/{{ inventory_hostname }}/roles.yml"
```

This sort of works. You still cannot use `--list-tags`. But the role tags 
(from <rolename>/main.yml) are available and can be used.

```
$ ansible-playbook site.yml --tags=proxmox-install

PLAY [whale] 
**************************************************************************************
... removed for clarity ...
TASK [include] 
************************************************************************************
included: /home/myuser/ansible/cloud/rendered/whale/roles.yml for whale
... removed for clarity ...
```

It then proceeds to run the roles that are imported in 
`rendered/whale/roles.yml` or the specific tag you specified.

### Conclusion
Overall the rendered task file that imports all the roles does most 
everything I need, but it feels incorrect. Like I abused the tool into 
working how I wanted it to work and not how it was intended to be used. Is 
there some Ansible-ism that I'm not aware of?

-- 
You received this message because you are subscribed to the Google Groups 
"Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/ansible-project/7fdee7bf-6604-46ad-81c5-886a932f409fn%40googlegroups.com.

Reply via email to