Mark K.
Mark K.

Reputation: 2099

Copy multiple files with Ansible

How can I copy more than a single file into remote nodes by Ansible in a task?

I've tried to duplicate the copy module line in my task to define files but it only copies the first file.

Upvotes: 154

Views: 271791

Answers (16)

Shaha Nawaj Mulla
Shaha Nawaj Mulla

Reputation: 171

Use the following source code for copy multiple files on your client machine.


 - name: Copy data to the client machine
   hosts: hostname
   become_method: sudo
   become_user: root
   become: true
   tasks: 
     # Copy twice as sometimes files get skipped (mostly only one file skipped from a folder if the folder does not exist)
     - name: Copy UFO-Server 
       copy:
         src: "source files path"
         dest: "destination file path"
         owner: root
         group: root
         mode: 0644
         backup: yes
       ignore_errors: true

Note:

If you are passing multiple paths by using variable then

src: "/root/{{ item }}"

If you are passing path by using a variable for different items then

src: "/root/{{ item.source_path }}"

Upvotes: 2

hussains8
hussains8

Reputation: 731

Here is a sample Ansible Script to copy multiple Files on remote Hosts:

- name: Copy Multiple Files on remote Hosts
  ansible.windows.win_copy:
    src: "{{ srcPath }}/{{ item }}" # Remeber to us {{item}}
                                    # as a postfix to source path

    dest: "{{ destPath }}"
    remote_src: yes # if source path is available on remote Host
  with_items:
    - abc.txt
    - abc.properties

Upvotes: 1

Deepak Shinde
Deepak Shinde

Reputation: 1

Below is some code that will show you how to copy all files from one location and paste them to another. Please refer to the screenshots here: https://prnt.sc/QcyfJU1l_rQB , and if you have additional files to copy and paste, simply append the entry in with_items. The rest is straightforward.

- name: Copy multiple files from local machine to remote nodes
  hosts: your_remote_nodes
  tasks:
    - name: Copy multiple files to remote nodes
      copy:
        src: "{{ item.src }}"
        dest: "{{ item.dest }}"
      with_items:
        - { src: '/path/to/local/file1.txt', dest: '/path/to/remote/file1.txt' }
        - { src: '/path/to/local/file2.txt', dest: '/path/to/remote/file2.txt' }
        - { src: '/path/to/local/file3.txt', dest: '/path/to/remote/file3.txt' }

Upvotes: 0

Richlv
Richlv

Reputation: 4143

Since Ansible 2.5 the with_* constructs are not recommended, and loop syntax should be used. A simple practical example:

- name: Copy CA files
  copy:
    src: '{{item}}'
    dest: '/etc/pki/ca-trust/source/anchors'
    owner: root
    group: root
    mode: 0644
  loop:
    - symantec-private.crt
    - verisignclass3g2.crt

Please note that in many cases a specific list of files would be preferred over globbing (using wildcards). If specific files are not known, with_fileglob would still be suggested over a loop with lookup.

Upvotes: 59

guenhter
guenhter

Reputation: 12167

- name: copy multiple items
    copy: 
      src: "{{ item.src }}" 
      dest: "{{ item.dest }}"
    loop:
      - src: containerizers
        dest: /etc/mesos/containerizers
      - src: another_file
        dest: /etc/somewhere
      - src: dynamic
        dest: "{{ var_path }}"

Upvotes: 178

Arbab Nazar
Arbab Nazar

Reputation: 23771

You can use the with_fileglob loop for this:

- copy:
    src: "{{ item }}"
    dest: /etc/fooapp/
    owner: root
    mode: 600
  with_fileglob:
    - "/playbooks/files/fooapp/*"

Upvotes: 179

You can use a find, and then copy those files.

---
- hosts: lnx
  tasks:
    - find: 
        paths: /appl/scripts/inq
        recurse: true
        patterns: "inq.Linux*"
      register: file_to_copy

     - copy: 
         src: "{{ item.path }}" 
         dest: /usr/local/sbin/
         owner: root
         mode: 0775
       loop: "{{ files_to_copy.files }}"

Upvotes: 10

Michael Zaidman
Michael Zaidman

Reputation: 81

Copy files from multiple directories to multiple directories with Ansible

I found the guenhter answer helpful but needed to change also the remote files' mode. I don't have enough reputation to put this as a comment, which would be a more appropriate place for this. In the example, I copy two files from two directories into /tmp and /tmp/bin, which I create first and modify remote files mode.

- name: cpldupd
  hosts: test
  remote_user: root
  become: true
  vars:
    - rpth: /tmp
  tasks:
    - name: Create '{{rpth}}/bin'
      file:
        path: '{{rpth}}/bin'
        state: directory

    - name: Transfer
      copy: src={{ item.src }} dest={{ item.dest }} mode=0775
      with_items:
      - { src: '../utils/cpldupd', dest: '{{rpth}}/cpldupd' }
      - { src: '../utils/bin/cpldupd', dest: '{{rpth}}/bin/cpldupd' }

Upvotes: 2

Kalpesh Kolap
Kalpesh Kolap

Reputation: 1


  • hosts: test gather_facts: false become: true vars: path: '/home/ansibm/playbooks' remote_path: '/home/{{ansible_ssh_user}}' dir: 'yml_files' tasks:
    • name: "creating directory for backup file" file: path: '{{ remote_path }}/{{ dir }}' state: directory owner: '{{ansible_ssh_user}}' group: '{{ansible_ssh_user}}' mode: 0700
    • name: "copying yml files" copy: src: '{{item}}' dest: '{{ remote_path }}/{{ dir }}' owner: '{{ansible_ssh_user}}' group: '{{ansible_ssh_user}}' mode: 0644 loop: - '{{ path }}/ab.html' - '{{ path }}/cp.yml'

Upvotes: -1

Lawrence Warren
Lawrence Warren

Reputation: 68

Here is a generic solution for copying files:

   ...
    - name: Find files you want to move
      ansible.builtin.find:
        paths: /path/to/files/
        file_type: file
        excludes: "*.txt" # Whatever pattern you want to exclude
      register: files_output

    - name: Copy the files
      ansible.builtin.copy:
        src: "{{ item.path }}"
        dest: /destination/directory/
      loop: "{{ files_output.files }}"
   ...

This is more powerful than using with_fileglob as you can match using regexes. Here is this play in action:

$ ls /path/to/files
demo.yaml  test.sh  ignore.txt

$ ls /destination/directory
file.h

$ ansible-playbook playbook.yaml
...[some output]...

$ ls /destination/directory
file.h demo.yaml test.sh

As you can see from the above example, ignore.txt was not copied over to the destination directory because of the excludes regex in the playbook. Ignoring files like this is not possible as simply using with_fileglob.

Additionally, you can move files from multiple directories with relative ease:

   ...
    - name: Find files you want to move
      ansible.builtin.find:
        paths: /path/to/files/
        # ... the rest of the task
      register: list1

    - name: Find more files you want to move
      ansible.builtin.find:
        paths: /different/path/
        # ... the rest of the task
      register: list2

    - name: Copy the files
      ansible.builtin.copy:
        src: "{{ item.path }}"
        dest: /destination/directory/
      loop: "{{ list1.files + list2.files }}"
   ...

Upvotes: 1

Stan
Stan

Reputation: 21

You can loop through variable with list of directories:

- name: Copy files from several directories
  copy:
    src: "{{ item }}"
    dest: "/etc/fooapp/"
    owner: root
    mode: "0600"
  loop: "{{ files }}"
  vars:
    files:
      - "dir1/"
      - "dir2/"

Upvotes: 2

mrówa
mrówa

Reputation: 5771

copy module is a wrong tool for copying many files and/or directory structure, use synchronize module instead which uses rsync as backend. Mind you, it requires rsync installed on both controller and target host. It's really powerful, check ansible documentation.

Example - copy files from build directory (with subdirectories) of controller to /var/www/html directory on target host:

synchronize:
  src: ./my-static-web-page/build/
  dest: /var/www/html
  rsync_opts:
    - "--chmod=D2755,F644" # copy from windows - force permissions

Upvotes: 3

Fredric Andersson
Fredric Andersson

Reputation: 79

- name: find inq.Linux*
  find:  paths="/appl/scripts/inq" recurse=yes patterns="inq.Linux*"
  register: find_files


- name: set fact
  set_fact:
    all_files:
      - "{{ find_files.files | map(attribute='path') | list }}"
  when: find_files > 0


- name: copy files
  copy:
    src: "{{ item }}"
    dest: /destination/
  with_items: "{{ all_files }}"
  when: find_files > 0

Upvotes: 7

MxWild
MxWild

Reputation: 3738

Or you can use with_items:

- copy:
    src: "{{ item }}"
    dest: /etc/fooapp/
    owner: root
    mode: 600
  with_items:
    - dest_dir

Upvotes: 5

Mircea Husz
Mircea Husz

Reputation: 207

You can use with_together for this purpose:

- name: Copy multiple files to multiple directories
  copy: src={{ item.0 }} dest={{ item.1 }}
  with_together:
    - [ 'file1', 'file2', 'file3' ]
    - [ '/dir1/', '/dir2/', '/dir3/' ]

Upvotes: 19

flxPeters
flxPeters

Reputation: 1542

If you need more than one location, you need more than one task. One copy task can copy only from one location (including multiple files) to another one on the node.

- copy: src=/file1 dest=/destination/file1
- copy: src=/file2 dest=/destination/file2

# copy each file over that matches the given pattern
- copy: src={{ item }} dest=/destination/
  with_fileglob:
    - /files/*

Upvotes: 15

Related Questions