19

Does anyone know how to put playbooks into folders, but share the same roles, group_vars, and other stuff typically located at the root dir?

Here's what I'd like to have:

root_dir:
- group_vars
- roles
- inventory
- playbooks
  - my_playbook.yml
- site.yml
- deploy.yml

Our root dir is getting pretty big now and I'd like to split out some playbooks into their own folder (shown as playbooks/ above). An identical tiny playbook fails to run when inside a directory (say, playbooks/) vs at the root dir, because it doesn't grab stuff from group_vars.

I can partially work around this, and run a playbook inside my playbooks/ directory:

- hosts: host_group
  sudo: true
  gather_facts: false
  vars_files:
  - ../group_vars/all/main.yml

This picks up the vars defined in main.yml. However, it's not clear to me if this would add group variables defined in group_vars/, as opposed to the explicitly specificed ../group_vars/.

Thanks!

user1784469
  • 450
  • 1
  • 4
  • 7

5 Answers5

7

Ansible will pick up group_vars without stating path explicitly:

Here is the example directory structure in /tmp/ansible:

/tmp/ansible
├── group_vars
│   └── test_group.yml
├── inventory
├── playbooks
│   └── foo.yml
└── site.yml

Inventory file:

[test_group]
localhost

Main Playbook site.yml:

# site.yml
---
- include: playbooks/foo.yml 

Secondary Playbook foo.yml:

---
- hosts: localhost

  tasks:

      - debug: var=foo

Group Variables test_group.yml:

foo: bar

Here are all the ways to execute the secondary playbook:

  • From root folder using relative path /tmp/ansible:

    ansible-playbook -i inventory playbooks/foo.yml -c local
    
    PLAY [localhost] **************************************************************
    
    GATHERING FACTS ***************************************************************
    ok: [localhost]
    
    TASK: [debug var=foo] *********************************************************
    ok: [localhost] => {
        "var": {
            "foo": "bar"
        }
    }
    
    PLAY RECAP ********************************************************************
    localhost                  : ok=2    changed=0    unreachable=0    failed=0
    
  • From Playbooks subfolder with inventory in parent path /tmp/ansible/playbooks:

    ansible-playbook -i ../inventory foo.yml -c local
    
    PLAY [localhost] **************************************************************
    
    GATHERING FACTS ***************************************************************
    ok: [localhost]
    
    TASK: [debug var=foo] *********************************************************
    ok: [localhost] => {
        "var": {
            "foo": "bar"
        }
    }
    
    PLAY RECAP ********************************************************************
    localhost                  : ok=2    changed=0    unreachable=0    failed=0
    

As we can see in the above examples, ansible-playbook will look for variables based on the path of inventory file or folder were ansible was executed from. Playbooks can be separated without additional effort.

Gregory Shulov
  • 204
  • 1
  • 4
  • While this works, it has an unexpected side effect of making all my ansible ad-hoc commands want to decrypt the vault files. Any idea why? – Jontia Nov 17 '17 at 10:27
6

The group/host vars are relative to wherever your inventory is defined. I had a similar issue to your when I started. Here are the steps I took

  1. move your inventory (static or dynamic) into a separate directory. ie $PROJECT_HOME/inventory/base_inventory. Ansible will automatically parse all files in that directory and add to inventory. This always be overridden later. eg ansible -i inventory/other_hosts

  2. update ansible.cfg to point to the new inventory directory. ie. hostfile = $PROJECT_HOME/inventory

  3. move your groups_vars and host_vars into the new inventory directory. ie $PROJECT_HOME/inventory/group_vars

Now you don't need to worry about relative pathing Also if you want to user your roles from anywhere in your source tree update ansible.cfg and set the roles_path to the base project path. ie roles_path = roles:$PROJECT_HOME/roles

Petro026
  • 1,269
  • 8
  • 6
5

Gregory Shulov's answer works if you don't use roles. If you use roles, though, your subfolder playbooks won't be able to reference them normally.

If you don't have too many files, I would recommend separating them "subfolder" files by prepending them with an underscore. That helped me separate some building block plays from the real playbooks I expect people to run.

CorayThan
  • 17,174
  • 28
  • 113
  • 161
2

You can define this in ansible.cfg to solve your problem.

Example:

# additional paths to search for roles in, colon separated
roles_path = /etc/ansible/roles
runar
  • 2,667
  • 2
  • 15
  • 23
AnmolNagpal
  • 387
  • 2
  • 8
  • Suggested edit queue is full, wanted to add I've also found we can use absolute or relative paths for role names so using `../roles/rolename` works. I actually nest two levels deep, so some of mine look like `../../roles/rolename` but it works fine. Adding role path through config is easy and should be considered - Ansible will read one in local directory as long as some permissions are met, or with ENV var `ANSIBLE_CONFIG` in all cases. But this is also a good option to know. Also consider https://github.com/ansible/ansible/issues/12862#issuecomment-461015045 regarding vars – Jasmine Hegman Nov 17 '21 at 02:07
1

I ran into the same problem.

ln -s ../roles playbooks/roles

just symlinking the roles/vars folder solved it.

# site.yml
---
- include: "playbooks/appserver.yml"
- include: "playbooks/gitlab-runner.yml"

or include them direct from the playbook dir

# playbooks/site.yml
---
- include: "appserver.yml"
- include: "gitlab-runner.yml"