Search code examples
linuxansiblersyncoverwrite

Ansible 'synchronize' overwrites folder even though delete=no


In my Ansible role "xen", I have this task:

---
- name: Install Xen
  synchronize: src=install/
               dest=/
               archive=yes
               delete=no

I want to copy the following structure to the destination without overwriting files in the existing folders like /boot and /lib64:

root@node51 [~]# tree -L 1 /etc/ansible/xenhost/xen/files/install
/etc/ansible/xenhost/xen/files/install
├── boot
├── etc
├── lib64
├── usr
└── var

5 directories, 0 files

The task worked, but it replaced all the files in /lib64. That killed my server:

[root@localhost ~]# ls /lib64/
-bash: /usr/bin/ls: /lib64/ld-linux-x86-64.so.2: bad ELF interpreter: No such file or directory

Here's the verbose task output, truncated for brevity:

TASK: [xen | Install Xen] ***************************************************** 
<127.0.0.1> EXEC ['/bin/sh', '-c', 'mkdir -p $HOME/.ansible/tmp/ansible-tmp-1448470134.66-193795609318676 && echo $HOME/.ansible/tmp/ansible-tmp-1448470134.66-193795609318676']
<127.0.0.1> PUT /tmp/tmpb7EusD TO /root/.ansible/tmp/ansible-tmp-1448470134.66-193795609318676/synchronize
<127.0.0.1> EXEC ['/bin/sh', '-c', u'LANG=C LC_CTYPE=C /usr/bin/python /root/.ansible/tmp/ansible-tmp-1448470134.66-193795609318676/synchronize; rm -rf /root/.ansible/tmp/ansible-tmp-1448470134.66-193795609318676/ >/dev/null 2>&1']
changed: [192.168.0.123] => {"changed": true, "cmd": "rsync --delay-updates -FF --compress --archive --rsh 'ssh  -o StrictHostKeyChecking=no' --out-format='<<CHANGED>>%i %n%L' \"/etc/ansible/xenhost/xen/files/install/\" \"[email protected]:/\"", "msg": "…truncated…"}

Curiously, the task didn't erase the existing files in /boot.

I made sure to specify delete=no explicitly, just in case, so it should not "Delete files that don't exist (after transfer, not before) in the src path."

Why did the Ansible 'synchronize' module replace /lib64 but copy to /boot as expected?


Solution

  • The issue is that /lib64 is not a directory. It is a symbolic link:

    [root@localhost ~]# file /lib64
    /lib64: symbolic link to `usr/lib64'
    

    By having Ansible 'synchronize' rsync your lib64 directory, it removes the symbolic link and puts an actual folder in its place.

    As a result, the libraries in /usr/lib64 are no longer reachable from /lib64, which is why everything that depended on finding libraries in /lib64 failed:

    [root@localhost ~]# ldd /usr/bin/ls
        linux-vdso.so.1 =>  (0x00007fffa9118000)
        libselinux.so.1 => /lib64/libselinux.so.1 (0x00007fe4b9630000)
        libcap.so.2 => /lib64/libcap.so.2 (0x00007fe4b9428000)
        libacl.so.1 => /lib64/libacl.so.1 (0x00007fe4b9218000)
        libc.so.6 => /lib64/libc.so.6 (0x00007fe4b8e50000)
        libpcre.so.1 => /lib64/libpcre.so.1 (0x00007fe4b8be8000)
        liblzma.so.5 => /lib64/liblzma.so.5 (0x00007fe4b89c0000)
        libdl.so.2 => /lib64/libdl.so.2 (0x00007fe4b87b8000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fe4b9860000)
        libattr.so.1 => /lib64/libattr.so.1 (0x00007fe4b85b0000)
        libpthread.so.0 => /lib64/libpthread.so.0 (0x00007fe4b8390000)
    

    Remedy

    Copy to /usr/lib64 instead. Put the libraries to copy in /etc/ansible/xenhost/xen/files/install/usr/lib64 instead of in /etc/ansible/xenhost/xen/files/install/lib64, and make sure the latter path does not exist.