12

I would like to shape my directory structure of my ansible roles and playbooks.

Currently I have a directory structure like.

group_vars
    * all 
    * group-one
        - group-vars.yml
        - group-vault.yml
    ...
host_vars
  - server1.yml
plays
    - java_plays
       * deploy_fun_java_stuff.yml
    * deploy_playbook.yml
roles
    - role1 
            - tasks
               * main.yml
            - handlers 
            - (the rest of the needed directories)
    - role2
    - java 
        - java_role1
            - tasks
               * main.yml
            - handlers 
            - (the rest of the needed directories)

I would like to be able to call upon the role java_role1 in the play deploy_fun_java_stuff.yml

I can call

 ---
 - name: deploy fun java stuff
   hosts: java
   roles:
    - { role: role1 }

but I cannot call (I've tried multiple ways). Is this possible?


 - name: deploy fun java stuff
   hosts: java
   roles:
    - { role: java/java_role1 }

What I really want to accomplish is to be able to structure my plays in an orderly fashion along with my roles. I will end up with a large number of both roles and plays I would like to organize them.

I can handle this with a separate ansible.cfg file for each play directory but I cannot add those cfg files to ansible tower (So I'm looking for an alternate solution).

Eddie
  • 1,081
  • 2
  • 12
  • 28

3 Answers3

24

I think the problem is that you need to set the relative path properly. Ansible first applies the given path relative to the called playbooks directory, then looks in the current working path (from which you are executing the ansible-playbook command) and finally checks in /etc/ansible/roles, so instead of { role: java/java_role1 } in your dir structure you could use { role: ../../roles/java/java_role1 } or { role: roles/java/java_role1 }. Yet another option would be to configure the paths in which ansible is looking for roles. For that you could set the roles_path inside your projects ansible.cfg as described in the Ansible docs.

Based on your example:

Dir tree:

ansible/
├── hosts
│   └── dev
├── plays
│   └── java_plays
│       └── java.yml
└── roles
    ├── java
    │   └── java_role1
    │       └── tasks
    │           └── main.yml
    └── role1
        └── tasks
            └── main.yml

To test it, the play would include java_role1 and role1.

plays/java_plays/java.yml:

---
 - name: deploy java stuff
   hosts: java
   roles:
    - { role: roles/role1 }
    - { role: roles/java/java_role1 }

For testing purposes these roles simply print a debug msg.

role1/tasks/main.yml:

---
- debug: msg="Inside role1"

The dev hosts file simply sets localhost to the java group. Now I can use the playbook:

fishi@zeus:~/workspace/ansible$ ansible-playbook -i hosts/dev plays/java_plays/java.yml

PLAY [deploy java stuff] *******************************************************

TASK [setup] *******************************************************************
ok: [localhost]

TASK [role1 : debug] ***********************************************
ok: [localhost] => {
    "msg": "Inside role1"
}

TASK [java_role1 : debug] *************************************
ok: [localhost] => {
    "msg": "Inside java_role1"
}

PLAY RECAP *********************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0

Now doing the same when you use { role: ../../roles/java/java_role1 } and { role: ../../roles/role1 } your log output inside the TASK brackets would show the whole relative path instead of just the role name:

fishi@zeus:~/workspace/ansible$ ansible-playbook -i hosts/dev plays/java_plays/java.yml

PLAY [deploy java stuff] *******************************************************

TASK [setup] *******************************************************************
ok: [localhost]

TASK [../../roles/role1 : debug] ***********************************************
ok: [localhost] => {
    "msg": "Inside role1"
}

TASK [../../roles/java/java_role1 : debug] *************************************
ok: [localhost] => {
    "msg": "Inside java_role1"
}

PLAY RECAP *********************************************************************
localhost                  : ok=3    changed=0    unreachable=0    failed=0
fishi0x01
  • 3,579
  • 21
  • 25
  • 1
    I'd like to add a comment that if you place an alternate relative roles_path in ansible.cfg, Ansible Tower will happily ignore this and then state the role could not be found upon execution. I've also had trouble getting playbooks to run that refer to roles in ../../ style paths. Tower just does something funky that's apparently not compatible with these styles of referring to where the role really is... – DaVince Aug 20 '21 at 06:24
8

Another option and one that I use is to create an ansible.cfg file in your playbook directory and place the following in it:

[defaults]

roles_path = /etc/ansible/roles: :

or in your case:

[defaults]

roles_path = /etc/ansible/roles:/etc/ansible/roles/java

Then don't use any relative paths.

prankin
  • 1,784
  • 1
  • 14
  • 5
7

A more elegant solution (imo) is symlinking your roles directory to inside the playbooks directory.

My directory structure is as follows:

inventory/
playbooks/
  |-> roles -> ../roles
  |-> group_vars -> ../group_vars
  |-> host_vars -> ../host_vars
roles/
group_vars/
host_vars/

In my case, I created the symlink by running ln -s ../roles playbooks/roles

Rystraum
  • 1,985
  • 1
  • 20
  • 32