Search code examples
variablesansiblerolesansible-2.x

Ansible 2.8 Roles - using the vars/main directory


I am trying to split my Ansible role variables into multiple files - as per this answer, it should be possible to create a vars/main directory, and all the .yml files in that directory should be automatically loaded.

However, this does not seem to happen in my case.

My directory structure:

vars
└── main
    ├── gce_settings.yml
    ├── vsphere_settings.yml
    └── vsphere_zone.yml

However, when I try to use a variable defined inside vsphere_settings.yml, Ansible complains that the variable is undefined: {"msg": "The task includes an option with an undefined variable. The error was: 'vsphere_user' is undefined

If I move the variable declaration into vars/main.yml, everything works as expected. But, of course, I would prefer to separate my variables into multiple files.

I was unable to find any reference to this "feature" in the official Ansible documentation, and I do not know how I could troubleshoot it. Can anyone point me in the right direction?

My ansible version: ansible 2.8.5 on Ubuntu 16.04

And before you ask: yes, I did make sure that main.yml was not present when trying to load vars/main/*.yml...


Solution

  • TL;DR version: it is a bug in ansible, caused by the presence of empty .yml files in vars/main. There is a PR out for it already. See here .

    The actual result (as mentioned in the comments) actually depends on the order the files are processed (by default, it looks like my Ansible processes them in alphabetical order - but this might depend on the version, or the underlying OS):

    • If the empty file is processed first, you get an error message: ERROR! failed to combine variables, expected dicts but got a 'NoneType' and a 'AnsibleMapping'
    • If the empty file is processed after other files, there is no error message, but all the variables that have been set up to this point are destroyed

    More details: since I have no idea how to troubleshoot this in Ansible itself, I went to the code and started to add print statements to see what is happening.

    In my case, I had some empty .yml files in the vars/main directory (files that I was planning to populate later on. Well... it looks like when the code encounters such an empty file, it destroys the entire dictionary that it has built so far.

    Either I'm missing something very important, or this is a bug... Steps to reproduce:

    • create a role
    • create the vars/main directory, and populate it with some .yml files
    • add an empty .yml file (named so that it is processed after the other files)
    • try to print the variables from the first files
        ansible# tree roles 
        roles
        +-- test
            +-- tasks
            ¦   +-- main.yml
            +-- vars
                +-- main
                    +-- correct_vars.yml
    
        4 directories, 2 files
    
        ansible# cat roles/test/vars/main/correct_vars.yml  myname: bogd
    
        ansible# ansible-playbook -i inventory.yml test.yml 
        ... 
        ok: [localhost] => {
            "myname": "bogd" } 
        ...
    
        ansible# echo > roles/test/vars/main/emptyfile.yml
    
        ansible# ansible-playbook -i inventory.yml test.yml 
        ... ok: [localhost] => {
            "myname": "VARIABLE IS NOT DEFINED!" } 
        ...
    

    Later edit: yep, it's a bug... See here.