Ansible, relative paths and the 'files' directory

I’ve recently started building a tool to help network operators troubleshoot network related issues, which requires me to deploy nodes across multiple geographies. The deployment process comprises of multiple steps, and there are going to be 10s (if not 100s) of nodes that I need to deploy. So, I decided to automate the node deployment process.

Since I have played with Ansible in the past, I decided to use Ansible as my tool of choice for automation. I created a directory named ansible to contain all ansible related files.

At this point my directory structure looked like the following:

        app
        |- ansible
        |  |- deploy.yml
        |  |- inventory.yml
        |- main.py
        |- ....
        |- tools.py
        |- requirements.txt

As my application has a few python scripts and I had to copy these files over to the remote host. I used the ansible.builtin.copy module, along with with_fileglob to pattern match the file names. Following is the code block copying all files with .py extension and the requirements.txt file:

        - name: copy files
          ansible.builtin.copy:
            src: "{{ item }}"
            dest: "path-to-the-dest-directory"
          with_fileglob:
            - "../*.py"
            - "../requirements.txt"

Since these files are put one level up in the directory structure, I had to refer them accordingly and everything was working as expected.

Then I needed to add a few .conf files to tweak the linux behaviour. Since these files were of a specific use, I decided to puth them in a saperate directory. I named the new directory files and the new directory structure looks like the following:

        app
        |- ansible
        |  |- deploy.yml
        |  |- inventory.yml
        |  |- files
        |    |- 99-routing-sysctl.conf
        |    |- 99-rpf-loose-sysctl.conf
        |- main.py
        |- ....
        |- tools.py
        |- requirements.txt

And this is where things become interesting.

Suddenly ansible started to skip the “copy files” block. I spent a few hours trying to figure out what’s going on. But didn’t find anything. Upgraded my ansible installation, switched from mac to linux, but to no avail. Running the playbook in verbose mode will not spit out anything. I was clueless.

All I needed was a way to update the files, not necessarily with ansible.builtin.copy . So I gave a shot to the ansible.posix.synchronize module, which uses rsync under the hood, just to check if files are being synced. The new copy files block looked like this:

        - name: copy files
          ansible.posix.synchronize:
            src: "../"
            dest: "path-to-the-dest-directory"

This actually synced the files, but not the ones I wanted to sync. Instead, to my surprise, the files in the ansible directory were synced, which included the playbook itself as well as the inventory.

This was weird, because the src was set to ../ (one directory up) and not the same directory. Changing the src to ../../ (two directories up) would fix the issue, but that is not the expected behaviour.

Now, at least, I know what was causing the ansible.builtin.copy module to skip in the first place. Because with_fileglob could not find any matching files in the ansible directory.

While doing online research to find a possible cause for this behaviour, I found that in a Ansible Role, all relative paths start from the files directory.

Since I had a files directory put right besides my playbook, ansible assumed that I’m building a Role hence it was picking the path from there.

I renamed the files directory to static and the behaviour changed to “normal”. ansible.posix.synchronize as well as the ansible.builtin.copy module worked as expected.

I found this Ansible behaviour weird, but maybe I’ll change my opinion as I learn more about Ansible Roles.

© The Binary Blog 2022