Skip to content

Local Ansible Role Test Environment

I develop my Ansible roles, synced to GitHub, locally and test them before they get tagged for Ansible Galaxy. This blog shows how to set up a development environment in your favorite IDE (Visual Studio Code, Cursor AI, or your preference) and create a local test playbook synced to your roles—no Galaxy upload required!

1. Directory Layout

I use a folder in my home directory named Git sync. Inside, I have a sub-folder named ANSIBLE_ROLES where I clone all my Ansible roles for development. Before pushing them to GitHub (and triggering a GitHub Action for Galaxy upload), I test them locally.

Here’s a visual of my test environment structure:

role_test_environment/
├── group_vars/
│   └── all
├── host_vars/
├── inventory.yml
├── install_nautobot.yml
├── roles/
└── link_dev_roles.sh

2. Basic Setup Files

group_vars/all:

ansible_user: <your_ssh_user>
ansible_password: <your_ssh_pass>
ansible_become_method: sudo
ansible_become_pass: <your_ssh_pass>
ansible_connection: ssh

inventory.yml:

all:
  children:
    devmachines:
      hosts:
        dev1:
          ansible_host: 172.20.10.8

3. The Magic: Linking Local Roles with Namespace

To test local, unstaged changes, I create symlinks from my development roles to the roles/ directory in my test project. This is important because my GitHub repos are named ansible_role_xxxx, but for Ansible Galaxy, the namespace is bsmeding and the role is referenced as bsmeding.rolename.

Why? - Ansible expects roles in the format namespace.rolename (e.g., bsmeding.nautobot_docker) for Galaxy-style usage. - This matches how you’d reference roles in requirements.yml or in your playbooks.

NOTE that the correct meta/main.yml is set with role_name when using roles! NOTE that the correct galaxy.yml is set in the root folder when using collections!

Save this script as link_dev_roles.sh in your test project directory:

#!/bin/bash

SRC_DIR="$HOME/code/ansible_roles"   # where roles/collections are cloned
DEST_DIR="./roles"
mkdir -p "$DEST_DIR"

for role_path in "$SRC_DIR"/*; do
    [ -d "$role_path" ] || continue

    # Case 1: Ansible collection (.galaxy.yml)
    if [[ -f "$role_path/.galaxy.yml" ]]; then
        namespace=$(grep '^namespace:' "$role_path/.galaxy.yml" | awk '{print $2}' | tr -d '\r')
        name=$(grep '^name:' "$role_path/.galaxy.yml" | awk '{print $2}' | tr -d '\r')

    # Case 2: Ansible role (meta/main.yml)
    elif [[ -f "$role_path/meta/main.yml" ]]; then
        name=$(grep 'role_name:' "$role_path/meta/main.yml" | awk '{print $2}' | tr -d '\r')
        author=$(grep 'author:' "$role_path/meta/main.yml" | awk '{print $2}' | tr -d '\r')
        namespace="${author:-$(basename "$role_path" | cut -d'-' -f3)}"
    else
        echo "⚠️  No metadata found in $role_path, skipping."
        continue
    fi

    # Validate
    if [[ -z "$namespace" || -z "$name" ]]; then
        echo "⚠️  Skipping $role_path — missing name or namespace."
        continue
    fi

    link_name="$DEST_DIR/${namespace}.${name}"
    if [ ! -L "$link_name" ]; then
        echo "🔗 Linking $link_name$role_path"
        ln -s "$role_path" "$link_name"
    else
        echo "✔️  Link exists: $link_name"
    fi
done

Make it executable:

chmod +x link_dev_roles.sh
Run it every time you add a new folder to your ANSIBLE_ROLES development environment:
./link_dev_roles.sh

4. Example: Minimal Test Playbook

Here’s a simple playbook to test your role:

- hosts: all
  become: true
  roles:
    - role: bsmeding.docker  # Ensure Docker is installed, this is not my development role, but to be shure Docker is installed
    - role: bsmeding.nautobot_docker # This is my testing Ansible role from the symlink
      vars:
        nautobot__superuser_name: admin
        nautobot__superuser_password: admin
        nautobot__superuser_api_token: "myapitoken"

5. .gitignore Advice

Add roles/ to your .gitignore in the test project so you don’t accidentally commit symlinks:

roles/

6. Troubleshooting Tips

  • Symlinks not working? On Windows, use WSL or Git Bash, or manually copy roles if symlinks are unsupported.
  • Permissions issues? Ensure you have the right permissions for both source and destination directories.
  • Role not found? Double-check the symlink names and that your playbook references the correct namespace and role name.

8. Feedback

Have your own tips or questions? Leave a comment below or connect with me on LinkedIn. Happy automating!