When using Ansible's synchronize
module, you'll encounter this common scenario: you want to copy the contents of a directory to a target location without preserving the parent directory structure. By default, running:
- name: Basic directory sync
synchronize:
src: files/to/synchronize
dest: /tmp/1
Creates /tmp/1/synchronize/
containing your files, when what you really want is all files directly in /tmp/1/
.
The key is leveraging rsync's --relative
and --no-implied-dirs
flags through Ansible's rsync_opts
parameter:
- name: Sync directory contents only
synchronize:
src: files/to/synchronize/
dest: /tmp/1/
rsync_opts:
- "--relative"
- "--no-implied-dirs"
archive: yes
Important notes about this solution:
- The trailing slashes on both
src
anddest
are crucial archive: yes
preserves permissions and timestamps- Works with recursive directory structures
For smaller directory trees, you might consider Ansible's copy
module with content: yes
:
- name: Copy directory contents
copy:
src: "files/to/synchronize/"
dest: "/tmp/1/"
remote_src: yes
content: yes
Limitations to be aware of:
- Doesn't support delta transfers like rsync
- Less efficient for large directories
- No native checksum verification
For complex scenarios where you need to exclude certain patterns:
- name: Sync with exclusions
synchronize:
src: "files/to/synchronize/"
dest: "/tmp/1/"
rsync_opts:
- "--relative"
- "--no-implied-dirs"
- "--exclude=*.tmp"
- "--exclude=.git/"
checksum: yes
delete: yes
This configuration will:
- Skip temporary files and Git directories
- Use checksums for change detection
- Remove files in destination not present in source
When using Ansible's synchronize
module, you'll notice it preserves the entire source directory structure by default. For example, syncing files/to/synchronize
to /tmp/1
creates /tmp/1/synchronize
- an extra directory level you may not want.
The key is to leverage rsync's --relative
and --no-implied-dirs
flags through Ansible's rsync_flags
parameter:
- name: Sync directory contents without parent folder
synchronize:
src: files/to/synchronize/
dest: /tmp/1/
rsync_flags:
- "--relative"
- "--no-implied-dirs"
- "--copy-links"
recursive: yes
delete: yes
1. Trailing slashes matter: Both src
and dest
should end with /
2. --relative
preserves path relativity without the parent dir
3. --no-implied-dirs
prevents automatic directory creation
4. Add delete: yes
for true mirror synchronization
For smaller directory trees, you might prefer the copy
module with remote_src
:
- name: Copy directory contents
copy:
src: "files/to/synchronize/"
dest: "/tmp/1/"
remote_src: no
The synchronize
method is significantly faster for large directories as it uses rsync's delta-transfer algorithm. Benchmark tests show 3-5x speed improvement over copy
for directories exceeding 1GB.
If you encounter permission problems, add these rsync flags:
rsync_flags:
- "--chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r"
- "--times"
- "--omit-dir-times"