30

I'm working in a project, and we use ansible to create a deploy a cluster of servers. One of the tasks that I've to implement, is to copy a local file to the remote host, only if that file exists locally. Now I'm trying to solve this problem using this

- hosts: 127.0.0.1 
  connection: local
  tasks:
    - name: copy local filetocopy.zip to remote if exists
    - shell: if [[ -f "../filetocopy.zip" ]]; then /bin/true; else /bin/false; fi;
      register: result    
    - copy: src=../filetocopy.zip dest=/tmp/filetocopy.zip
      when: result|success

Bu this is failing with the following message: ERROR: 'action' or 'local_action' attribute missing in task "copy local filetocopy.zip to remote if exists"

I've tried to create this if with command task. I've already tried to create this task with a local_action, but I couldn't make it work. All samples that I've found, doesn't consider a shell into local_action, there are only samples of command, and neither of them have anything else then a command. Is there a way to do this task using ansible?

dirceusemighini
  • 1,272
  • 2
  • 15
  • 35
  • Does this answer your question? [Ansible include task only if file exists](https://stackoverflow.com/questions/28119521/ansible-include-task-only-if-file-exists) – Helder Pereira Jun 09 '20 at 18:40
  • Hi @HelderPereira this was posted sometime ago, at that time the accepted answer solved my problem. The most voted one also solved this problem at that time, I can't evaluate it anymore, because I don't have access to it's code. – dirceusemighini Aug 01 '20 at 17:44

5 Answers5

33

A more comprehensive answer:

If you want to check the existence of a local file before performing some task, here is the comprehensive snippet:

- name: get file stat to be able to perform a check in the following task
  local_action: stat path=/path/to/file
  register: file

- name: copy file if it exists
  copy: src=/path/to/file dest=/destination/path
  when: file.stat.exists

If you want to check the existence of a remote file before performing some task, this is the way to go:

- name: get file stat to be able to perform check in the following task
  stat: path=/path/to/file
  register: file

- name: copy file if it exists
  copy: src=/path/to/file dest=/destination/path
  when: file.stat.exists
9769953
  • 4,966
  • 3
  • 14
  • 24
edelans
  • 6,529
  • 4
  • 31
  • 45
23

Change your first step into the following on

- name: copy local filetocopy.zip to remote if exists
  local_action: stat path="../filetocopy.zip"
  register: result    
Sandra Parsick
  • 687
  • 7
  • 14
  • Hi @sandra-parsick , thanks for the reply, this is still failing with < TASK: copy local filetocopy.zip to remote if exists > failed: [52.11.12.29 -> 127.0.0.1] => {"failed": true, "parsed": false} [sudo via ansible, key=] password: – dirceusemighini Mar 04 '15 at 14:48
  • it seems, it doesn't like a sudo. How are you calling the playbook? – Sandra Parsick Mar 04 '15 at 15:44
  • the standard pattern for this is the [stat module](http://docs.ansible.com/stat_module.html), which avoids the need for a shell/command. – tedder42 Mar 04 '15 at 15:50
  • @SandraParsick I'm calling it like this: ansible-playbook -i inventory/hosts my.yml – dirceusemighini Mar 04 '15 at 17:27
  • @tedder42 You mean to use stat to know if the file exists? – dirceusemighini Mar 04 '15 at 17:28
  • yes, I mean use stat for existence. [here's an example](http://stackoverflow.com/a/23370071/659298). – tedder42 Mar 04 '15 at 18:09
  • @tedder42 you are right. My main point was that he has to use the local action command for running the check on the local machine. I corrected the step – Sandra Parsick Mar 05 '15 at 08:01
  • 1
    You also want "ignore_errors: true" and "changed_when: false" in the "register" stanza. – Sean Reifschneider Sep 04 '15 at 17:41
  • 3
    In the current version of Ansible, I had to add become: false to get this to work. Otherwise, it gives an error about not being able to sudo and fails. – Craig Mar 21 '17 at 12:31
  • Thanks @Craig this worked for me. Odd to me that Ansible seemingly defaults to attempting `sudo` for local tasks – cdmo May 23 '17 at 20:10
18

If you don't wont to set up two tasks, you could use 'is file' to check if local files exists:

tasks:
- copy: src=/a/b/filetocopy.zip dest=/tmp/filetocopy.zip
  when: '/a/b/filetocopy.zip' is file

The path is relative to the playbook directory, so using the magic variable role_path is recommended if you are referring to files inside the role directory.

Ref: http://docs.ansible.com/ansible/latest/playbooks_tests.html#testing-paths

Victor Jerlin
  • 456
  • 3
  • 6
  • 5
    This is clearly the most declarative version and it can be used in any tasks without requiring additional tasks. In recent versions of Ansible (2.6+) it can be written as `when: '/a/b/filetocopy.zip' is file` as can be seen from the URL that you provided for the documentation. – Christian Ulbrich Sep 19 '18 at 11:37
4

Fileglob permits a lookup of an eventually present file.

- name: copy file if it exists
  copy: src="{{ item }}" dest=/destination/path
  with_fileglob: "/path/to/file"
-1

How about this?

tasks:
- copy: src=../filetocopy.zip dest=/tmp/filetocopy.zip
  failed_when: false

This will copy the file to the target if it exists locally. If it does not exists, it simply does nothing since the error is ignored.

Michael Wyraz
  • 3,117
  • 1
  • 23
  • 22