How to Properly Remove Dead Symbolic Links in Ansible Playbooks


4 views

When working with Ansible's file module, you might encounter a peculiar situation where dead symlinks aren't being removed despite playbook execution showing "ok" status. This typically happens when there's either a syntax issue in your playbook or when Ansible's path resolution behaves differently than expected.

The problem in your playbook stems from incorrect parameter formatting. In your remove task, you've included path= as part of the string value, which Ansible interprets literally rather than as a parameter. Here's how it should be properly written:

- name: Remove symlink correctly
  file:
    path: /usr/local/bin/dead_symlink
    state: absent

Here's a complete playbook example that checks for the symlink's existence and removes it properly:

- hosts: localhost
  tasks:
    - name: Check symlink status
      stat:
        path: /usr/local/bin/dead_symlink
      register: symlink_status
    
    - name: Debug symlink info
      debug:
        var: symlink_status.stat
    
    - name: Remove dead symlink
      file:
        path: /usr/local/bin/dead_symlink
        state: absent
      when: symlink_status.stat.exists

For more robust symlink management, consider these additional scenarios:

# Force removal regardless of target existence
- name: Force symlink removal
  file:
    path: "{{ item }}"
    state: absent
  loop:
    - /usr/local/bin/dead_symlink
    - /another/path/broken_link
    
# Recursive directory cleaning
- name: Clean up all dead symlinks in directory
  find:
    paths: /usr/local/bin
    file_type: link
    follow: no
  register: symlinks_to_check

- name: Remove dead symlinks found
  file:
    path: "{{ item.path }}"
    state: absent
  loop: "{{ symlinks_to_check.files }}"
  when: not item.lnk_target_stat.exists

Ansible's file module with state: absent removes both valid and dead symlinks. The key is proper path specification without the path= prefix in the value. The module specifically handles symbolic links differently from regular files, which explains why the original syntax failed.


When working with Ansible's file module to manage symbolic links, you might encounter a frustrating scenario where a broken symlink refuses to disappear despite using state: absent. Here's what's happening under the hood:


# This correctly detects the symlink exists
- stat:
    path: /usr/local/bin/dead_symlink
  register: dead_symlink_bin

- debug:
    var: dead_symlink_bin.stat.exists

The issue lies in how Ansible handles path specifications. Your current playbook has a syntax error in the path parameter. The correct format should be:


- name: Remove symlink PROPERLY
  file:
    path: /usr/local/bin/dead_symlink  # Remove "path=" prefix
    state: absent

Here's a robust approach that handles both detection and removal:


- name: Check symlink status
  stat:
    path: /usr/local/bin/dead_symlink
  register: symlink_status

- name: Remove broken symlink if exists
  file:
    path: "{{ symlink_status.stat.lnk_target if symlink_status.stat.islnk else '/usr/local/bin/dead_symlink' }}"
    state: absent
  when: symlink_status.stat.islnk or symlink_status.stat.exists

If the symlink still persists, try these additional steps:


- name: Force removal (be cautious!)
  command: rm -f /usr/local/bin/dead_symlink
  args:
    removes: /usr/local/bin/dead_symlink
  when: symlink_status.stat.exists

Remember that when dealing with system directories like /usr/local/bin, you might need elevated privileges. Always include become: yes when appropriate.