AJP
AJP

Reputation: 28453

Ansible synchronise fails if parent directories are not already created

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?

Upvotes: 1

Views: 1818

Answers (2)

AJP
AJP

Reputation: 28453

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.

Upvotes: 0

Konstantin Suvorov
Konstantin Suvorov

Reputation: 68239

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/

Upvotes: 2

Related Questions