Copying a single file from your workstation to a target host is one of the most common tasks you run into when using ansible. Ansible has a built-in copy module for this that makes it quite simple and straightforward. Here is a typical task to copy a configuration file to the target host.
- name: Copy the myconf.conf file to the target server
copy:
src: myconf.conf
dest: /etc/myconf.conf
owner: root
group: root
mode: u=rw, g=rw, o=r
This will copy myconf.conf from your local machine and place it in /etc on the target host.
What if I need to copy a hundred files?
This is all fine if you have one file to copy. But if you need to copy a bunch of files, you might not want to create a task for each file. This will make for an unnecessary big playbook. Not to mention the tedious task of copy, pasting, and editing each task. There are a couple of ways to solve this problem.
Copy the contents of a directory
The simplest way to do this is to place all your files in a directory and just copy the directory or its contents. I have seen some complicated ways to copy the contents of a directory to a server. The ansible docs don’t make it very obvious that you don’t need to specify a file name.
Here is one example where we copy all the files in the myconf/ directory to /etc/myapp/.
- name: Copy the contents of the myconf/ directory to the target server
copy:
src: myconf/
dest: /etc/myapp/
owner: root
group: root
mode: u=rw, g=rw, o=r
Note the trailing slash in src field. If you skip the slash, ansible will assume you want to copy the directory itself and recursively copy the contents and place it inside the directory. So if we change the src field to this:
src: myconf
Ansible will create /etc/myapp/myconf/ and copy the files into that directory.
The slightly more complicated way
The above method is probably the most straightforward way to do this. But if you for some reason don’t want to copy all the files in a directory, you can also create a loop to copy each file one by one.
In this example, we will do the same as in the example above, copy all the files in a directory to the remote host.
- name: Copy all the files in myconf/ but do it with a loop
copy:
src: {{ item }}
dest: /etc/myapp/
owner: root
group: root
mode: u=rw, g=rw, o=r
with_fileglob:
- "myconf/*"
Why you would want to do it this way is beyond me. But it seems to be a common method of choice for many ansible users. However, using loops to copy files does give you more control over the copy process. For instance, if you just want to copy some files to a destination and not the entire contents of a directory.
In this example, we will copy three files to /etc/myapp
- name: Copy some files to /etc/myapp/
copy:
src: {{ item }}
dest: /etc/myapp/
owner: root
group: root
mode: u=rw, g=rw, o=r
with_items:
- db.conf
- myapp.conf
- cert.crt
Copy multiple files to multiple destinations
You can even condense your playbook even more creating just one loop to copy files to multiple destinations. Instead of making a task for each destination folder. Let’s try copying the configuration files for three different apps in one go:
- name: Copy some files to /etc/myapp/
copy:
src: {{ item.src }}
dest: {{ item.dest }}
owner: root
group: root
mode: u=rw, g=rw, o=r
with_items:
- { src: app1.conf, dest: /etc/app1/ }
- { src: app2.conf, dest: /etc/app2/ }
- { src: app3.conf, dest: /etc/app3/ }
Good luck with your project!
As in most DevOps tasks, there is more than one way to skin the proverbial cat. I hope I have helped you in some way to find the best way to copy files in your playbook. Happy hacking!