ansibleansible-galaxy

group default vars in roles


Is it possible to have group vars defined in roles?

For example I have the following structure in my role repo:

my_repo
|-defaults
| |-main.yml
| |-debian.yml
| |-redhat.yml

In debian.yml I have defined a variable called ssh-package as well in redhat.yml but with different values.

If I install my role with ansible-galaxy and I have hosts defined in group redhat or debian, they wont pickup the variables. Do I need to specify the roles variables inside my target structure?


Solution

  • The statement in Role directory structure is horrible

    Directories defaults and vars may also include nested directories. If your variables file is a directory, Ansible reads all variables files and directories inside in alphabetical order. If a nested directory contains variables files as well as directories, Ansible reads the directories first. Below is an example of a vars/main directory

    IMO, you can put default variables into the files in the directory defaults/main instead of the file defaults/main.yml. This is what the above statement tries to describe. Other directories and files will be ignored. For example, given the inventory

    shell> cat hosts
    host_A
    [debian]
    host_B
    host_D
    [redhat]
    host_C
    host_D
    

    Create the role my_repo

    shell> tree roles
    roles
    └── my_repo
        ├── defaults
        │   ├── debian.yml
        │   ├── main.yml
        │   └── redhat.yml
        └── tasks
    
    shell> cat roles/my_repo/defaults/main.yml 
    test_var: defaults
    
    shell > cat roles/my_repo/defaults/debian.yml 
    test_var: debian
    
    shell > cat roles/my_repo/defaults/redhat.yml 
    test_var: redhat
    
    shell> cat roles/my_repo/tasks/main.yml
    - debug:
        msg: |
          test_var: {{ test_var }}
          group_names: {{ group_names }}
    

    The play

    shell> cat pb.yml
    - hosts: all
    
      roles:
        - my_repo
    

    gives (abridged)

    ok: [host_A] => 
      msg: |-
        test_var: defaults
        group_names: ['ungrouped']
    ok: [host_B] => 
      msg: |-
        test_var: defaults
        group_names: ['debian']
    ok: [host_D] => 
      msg: |-
        test_var: defaults
        group_names: ['debian', 'redhat']
    ok: [host_C] => 
      msg: |-
        test_var: defaults
        group_names: ['redhat']
    

    All values of test_var are defaults because only roles/my_repo/defaults/main.yml was included.

    What will be the best option to include debian.yml and redhat.yml? Look at the Resolving local relative paths

    Ansible tries to find the file in the following order: In the current role. In its appropriate subdirectory: “files”, “vars”, “templates”, or “tasks”; depending on the kind of file Ansible is searching for...

    Knowing this, let's put the debian.yml and redhat.yml files into the directory vars. Remember, the files will be ignored if not in the directory vars/main

    shell> tree roles/
    roles/
    └── my_repo
        ├── defaults
        │   └── main.yml
        ├── tasks
        │   └── main.yml
        └── vars
            ├── debian.yml
            └── redhat.yml
    

    Use include_vars

    shell> cat roles/my_repo/tasks/main.yml
    - include_vars: "vars/{{ item }}.yml"
      loop: "{{ group_names | difference(['ungrouped']) }}"
    - debug:
        msg: |
          test_var: {{ test_var }}
          group_names: {{ group_names }}
    

    gives (abridged)

    ok: [host_A] => 
      msg: |-
        test_var: defaults
        group_names: ['ungrouped']
    ok: [host_B] => 
      msg: |-
        test_var: debian
        group_names: ['debian']
    ok: [host_D] => 
      msg: |-
        test_var: redhat
        group_names: ['debian', 'redhat']
    ok: [host_C] => 
      msg: |-
        test_var: redhat
        group_names: ['redhat']
    

    Notes:

    - include_vars: "{{ item }}.yml"
    
    shell> tree roles/my_repo
    roles/my_repo
    ├── defaults
    │   └── main.yml
    └── tasks
        └── main.yml
    
    shell> cat roles/my_repo/defaults/main.yml 
    test_var: |
      {% if 'redhat' in group_names %}
      redhat
      {% elif 'debian' in group_names %}
      debian
      {% else %}
      default
      {% endif %}
    

    Then, the include_vars task is not needed. The below debug will give the same results

    shell> cat roles/my_repo/tasks/main.yml
    - debug:
        msg: |
          test_var: {{ test_var }}
          group_names: {{ group_names }}