How to Create Symlinks with Ansible Using List Variables: Fixing “item is undefined” Error


2 views

When working with Ansible's file module to create symbolic links using a list of variables, you might encounter the frustrating error:

fatal: [vmdev] => One or more undefined variables: 'item' is undefined

The error occurs because the with_items directive isn't properly formatted in modern Ansible versions (2.4+). The correct approach uses loop instead:

tasks:
  - name: Create drush alias symlinks
    file:
      src: /drupal/drush/{{ item.path }}.aliases.drushrc.php
      dest: /home/vagrant/.drush/{{ item.dest }}.aliases.drushrc.php
      state: link
    loop:
      - { path: 'new', dest: 'new' }
      - { path: 'vmdev', dest: 'vmdev' }

Here's a full playbook example that demonstrates the correct implementation:

- hosts: all
  become: yes
  tasks:
    - name: Ensure .drush directory exists
      file:
        path: /home/vagrant/.drush
        state: directory
        mode: '0755'
        owner: vagrant
        group: vagrant
    
    - name: Create multiple symlinks for drush aliases
      file:
        src: "/drupal/drush/{{ item.path }}.aliases.drushrc.php"
        dest: "/home/vagrant/.drush/{{ item.dest }}.aliases.drushrc.php"
        state: link
        force: yes
      loop:
        - { path: 'new', dest: 'new' }
        - { path: 'vmdev', dest: 'vmdev' }
        - { path: 'production', dest: 'prod' }

The solution includes several best practices:

  • Uses modern loop instead of deprecated with_items
  • Adds directory creation as a prerequisite
  • Includes force: yes to handle existing files
  • Sets proper permissions with mode, owner, and group

For more complex scenarios where the list comes from a variable:

vars:
  drush_aliases:
    - { path: 'new', dest: 'new' }
    - { path: 'vmdev', dest: 'vmdev' }

tasks:
  - name: Create symlinks from variable list
    file:
      src: "/drupal/drush/{{ item.path }}.aliases.drushrc.php"
      dest: "/home/vagrant/.drush/{{ item.dest }}.aliases.drushrc.php"
      state: link
    loop: "{{ drush_aliases }}"

If you still encounter issues:

  1. Verify file paths exist with ls -la /drupal/drush/
  2. Check Ansible version with ansible --version
  3. Run with -vvv flag for detailed debugging
  4. Ensure proper permissions on target directories

When working with Ansible's file module to create symbolic links using a list of variables, you might encounter the frustrating error:

fatal: [vmdev] => One or more undefined variables: 'item' is undefined

This typically occurs when trying to use the with_items loop incorrectly with the file module.

The proper way to create multiple symlinks using variables in Ansible is:

- name: Create drush alias symlinks
  file:
    src: "/drupal/drush/{{ item.path }}.aliases.drushrc.php"
    dest: "/home/vagrant/.drush/{{ item.dest }}.aliases.drushrc.php"
    state: link
  loop:
    - { path: 'new', dest: 'new' }
    - { path: 'vmdev', dest: 'vmdev' }
  • Use loop instead of deprecated with_items (Ansible 2.5+)
  • Proper YAML formatting with consistent indentation
  • Quoted paths to handle potential spaces

For more complex scenarios where you need additional parameters:

- name: Create multiple symlinks with various parameters
  file:
    src: "{{ item.src_path }}"
    dest: "{{ item.dest_path }}"
    owner: "{{ item.owner | default('vagrant') }}"
    group: "{{ item.group | default('vagrant') }}"
    mode: "{{ item.mode | default('0644') }}"
    state: link
  loop:
    - { src_path: '/drupal/drush/new.aliases.drushrc.php', dest_path: '/home/vagrant/.drush/new.aliases.drushrc.php' }
    - { src_path: '/drupal/drush/vmdev.aliases.drushrc.php', dest_path: '/home/vagrant/.drush/vmdev.aliases.drushrc.php', owner: 'root' }

Sometimes you might need to:

- name: Ensure parent directory exists
  file:
    path: "/home/vagrant/.drush"
    state: directory
    mode: '0755'

- name: Create symlinks only if source exists
  file:
    src: "{{ item.src }}"
    dest: "{{ item.dest }}"
    state: link
  loop: "{{ symlink_items }}"
  when: item.src is file

If you're still having issues:

  1. Run with -vvv for verbose output
  2. Check variable names are consistent in your loop
  3. Verify paths exist on the target system
  4. Consider using ignore_errors: yes temporarily to identify which item fails