1

I have a synchronisation task in ansible:

---
- name: Copy over code - lib
  synchronize:
    src: ../lib/some/parent/directories/
    dest: ~/project/lib/some/parent/directories/

This fails as the destination lacks ~/project/lib/some/parent/ but succeeds otherwise. I produced the following work around:

---
- set_fact:
    directory_lib_dest: ~/project/lib/some/parent/directories/
- name: Create directories
  file: path={{ item }} state=directory
  with_items:
    - "{{ directory_lib_dest }}"
- name: Copy over code - lib
  synchronize:
    src: ../lib/some/parent/directories/
    dest: "{{ directory_lib_dest }}"

Is there a better solution that can be done using soley the ansible synchronize module and or avoids me using set_fact whilst keeping it DRY and the variable declared in the same role .yml that is consuming it?

AJP
  • 26,547
  • 23
  • 88
  • 127

2 Answers2

2

This is how rsync works. But you can read about workarounds here.

If you going to adopt relative behaviour with dot-slash trick, keep in mind that you should pass full path to src in Ansible (otherwise Ansible will expand it on its own and your /./ trick will be eliminated).

If you need to recreate lib/some/parent/directories/ your task may look like this:

TEST IT BEFORE REAL USE!

- synchronize:
    src: '{{ playbook_dir }}/./lib/some/parent/directories/'
    dest: ~/project/
    rsync_opts: 
      - '--relative'

As I said src: .././lib/some/parent/dir will not work, we need full path (so I used playbook_dir magic variable).

Excerpt from rsync man page about relative:

To limit the amount of path information that is sent, you have a couple options: (1) With a modern rsync on the sending side (beginning with 2.6.7), you can insert a dot and a slash into the source path, like this: rsync -avR /foo/./bar/baz.c remote:/tmp/

Community
  • 1
  • 1
Konstantin Suvorov
  • 65,183
  • 9
  • 162
  • 193
  • Hey @Konstantin, if you'd like to copy my answer into yours I'll mark yours as correct and delete mine and this comment, up to you. Thanks very much for your answer! It really helped. – AJP Feb 14 '17 at 23:15
  • @AJP, thanks, but I'd rather not. I'd like to keep my answer text intact. – Konstantin Suvorov Feb 15 '17 at 06:20
0

Thanks very much to Konstantin's answer, I ended up using:

---
- name: Set name of local and remote project directory
  set_fact:
    LOCAL_PROJECT_DIRECTORY:  "{{ playbook_dir | dirname }}"
    REMOTE_PROJECT_DIRECTORY: "{{ ansible_env.HOME }}/project-remote-dir/"
- name: Create remote project directory {{ REMOTE_PROJECT_DIRECTORY }}
  file: path={{ REMOTE_PROJECT_DIRECTORY }} state=directory
- name: Copy over code
  synchronize:
    src: "{{ LOCAL_PROJECT_DIRECTORY }}/./{{ item }}"
    dest: "{{ REMOTE_PROJECT_DIRECTORY }}"
    rsync_opts:
      - "--relative"
  with_items:
    - lib/some/parent/directories/
    - src/some/other/directories/

The LOCAL_PROJECT_DIRECTORY took the dirname of the playbook_dir as the project is structured like:

myproject
    deploy
        playbook.yml
        roles
             etc...
    lib
        etc...
    src
        etc...

This is doubly nice as it's removed repetition of the some/parent/directories and made everything much more explicit.

AJP
  • 26,547
  • 23
  • 88
  • 127