Hello Guys this is another post on the Ansible learning experiments, well in this post, I've explored about files and directories which can be created and copied and downloaded and uploaded. We could also do file permission changes how we do in Linux 'chmod' and 'chown' commands.
Let's begin with effectively doing automation management with configurations and deploy the challenges related to files and directories.
We can compare ansible modules copy and fetch both are related to file moment and they work in opposite directions as shown below:
|
Ansible modules copy vs fetch |
We have many files related modules available in the Ansible.
- acl archive unarchive iso_extract read_csv synchronize
- assemble tempfile template xattr xml
- blockinfile lineinfile patch
- copy fetch file find stat replace
In this post we will have three modules to experiment here.
- file
- copy
- fetch
Prerequisites
- Ansible installed controller node
- SSH password less connectivity established
Here is a sample inventory file which I have used for this experiment:
inventory file
[db]
192.168.33.210
192.168.33.220
Following is the Syntax for all ad-hoc command line will be used
ansible[-i inventory] server1:server2[group1:group2] -m file -a "arguments such as path status-action-value" [-b]
Exploring 'file' module
This section we will experiment with the file module and the following file related operations using Ansible Ad-hoc commands
- Create a file
- Create a directory
- modify the file permissions
- Delete a file or directory
Creating a file using the 'file' module
Creating a file (just like touch command in Linux) first we can tryout with ad-hoc command, later we can use this inside a playbook.
ansible db -m file -a "path=/tmp/hello.txt state=touch"
|
Ansible file module creating file |
Change file permission mode
We can change any file attribute value while creating it, Example change the file mode to 0777
ansible db -m file -a "path=/tmp/newfile.txt state=touch mode=0777"
Above steps we can include as a task inside the playbook.
Remove a file on remote host
To delete a file using the file module we need to use the argument values dif
ansible db -m file -a "path=/tmp/newdir.txt state=absent"
To delete use 'absent' state
|
Ansible file delete optin |
Creating Directory
We can create directories on the remote hosts as :
ansible db -m file -a "path=/tmp/newdir state=directory"
|
Ansible direcoty creation |
Troubleshooting point : When you pass the wrong argument value for status then Ansible Engine will suggest message with state must be one of the :
absent, directory, file, hard, link, touch.
Superuser access for file operations
To write files where root owns the directory, example create file text.txt under /etc foldeer permission deny. If your user have sudo access you can do. Similar to it we can do with Ansible CLI
ansible db -m file -a "path=/etc/test.txt state=touch" -b
Here -b or --become option will allow as prefixing as sudo to a command. note that this will only works for the sudoer users.
2. The copy module
A small change in the current folder to use as custom ansible configuration folder where it has two files ansible.cfg and hosts inventory as 'prod_inv' file same thing is mentioned in the ansible.cfg file. As Ansible will take the prority to current directory containing ansible.cfg event though the default exists :
[defaults]
inventory = ./prod_inv
host_key_checking = False
let's see the copy module now, the copy module will help you to transfer the files from the source(Ansible engine) to the destination (Ansible nodes).
Simple example test for copy module, from Ansible Engine hello.txt from /tmp location copied to the remote web servers into /tmp location.
ansible web -m copy -a "src=/tmp/hello.txt dest=/tmp/hello.txt"
How to copy a directory to remote box in Ansible?
This is little tricky idea we can do
Copying directories using copy module just like scp command in Linux. Let's try this with the playbook
---
- name: Ansible copy module test
hosts: web
tasks:
- name: copy dir
copy:
src: /tmp/testdir
dest: /tmp
Execution of the Playbook will be as follows:
ansible-playbook copydir.yaml
|
Ansible playbook execution for copy module |
Note: if you have/ at the end of src it will consider as files of that dir instead of selecting directory.
How to copy multiple files or directories to remote box in Ansible?
Copying multiple files/directories selecting 'witth_item'
Let's re-use the YAML file and name it as copy-mutliple.yaml follows:
---
- name: Ansible copy module test 2
hosts: web
tasks:
- name: copy multiple files
copy:
src: /tmp/testdir/{{ item }}
dest: /tmp
mode: 0774
with_items:
['hello2.txt', 'hello4.txt', 'sub1/hello5.txt']
Execution of the Playbook will be as follows:
ansible-playbook copy-multiple.yaml
Multi-copy image
|
Multiple files and sub directories copy to remote node using 'with_items' |
Can I create text content when I use copy module?
Yes, this is possible the copy module allows us to create the content into a file using a special attribute 'content' which takes text line to insert into the file. This is like Linux echo command to create single line entry to a file [ echo "Hello World!" > /tmp/test_01.txt ]
When content used instead of `src', sets the contents of a file directly to the specified value. Works only when `dest' is a file. And also it reates the file if it does not exist.
---
# Filename: copy_content.yml
- name: Ansible copy content test
hosts: localhost
tasks:
- name: create a file with content
copy:
dest: /tmp/test_content.yml
content: "hello world!\n"
The execution of the copy content example as:
ansible-playbook copy-content.yaml
|
copy module with content to a file in Ansible |
Observe that you can run this copy_content task only once next time onwards no changes!
3. The fetch module
Guys here we will explore the file 'fetch' module, this module will like a wget in Linux, it is used for download the files or directories from remote box.
Default fetch[important logic need to understand]
By default
fetch module will fetches the whole folder structure as-is from the remote host to the local that is Ansible Engine running 'dest' location which is specified in the arguments.
ansible -i prod_inv web \
-m fetch -a "src=/tmp/hello.txt dest=./downloaded"
|
Ansible default fetch operation |
File flattening
Downloaded to a single file from multiple source hosts. Flatten folder structure
ansible -i prod_inv web -m fetch -a "src=/tmp/hello.txt dest=./download flat=true"
When you execute the above ansible ad-hoc command it will download from host1 but fails when host2
ansible -i prod_inv web -m fetch -a "src=/tmp/hello.txt dest=./downloads/ flat=true"
Downloads from host1, host2 but will be downloads to the same destination location, as a solution to this, separates the destination filename with inventory hostname should be added.
To separate the file destinations use ansible facts {{ inventory_hostname }} with special notations where it should be enclosed within {{}} braces.
ansible -i prod_inv web -m fetch \
-a "src=/tmp/hello.txt dest=./{{ inventory_hostname }}_download/ flat=true"
|
Ansible ad-hoc fetch command that includes variables in download |
To use the fetch module in ansible to retrieve the file /tmp/p1-sample.txt from my-src.host, you can use the following playbook:
---
- hosts: my-src.host
tasks:
- name: fetch file from my-src.host
fetch:
src: /tmp/p1-sample.txt
dest: /tmp/p1-sample.txt
flat: true
Here, You can also specify a different destination path by modifying the dest parameter. The 'flat' parameter is set to true indicates fetch operation on a flat file. For example, to store the file in the /tmp directory on the localhost with a different file-name, we can use the following dest value:
dest: /tmp/p1-sample-fetched.txt
Can I fetch multiple files from remote host to local host?
You can also specify a list of src files to fetch multiple files at once. For example:
---
- hosts: my-src.host
tasks:
- name: fetch files from my-src.host
fetch:
src:
- /tmp/p1-sample.txt
- /tmp/p2-sample.txt
dest: /tmp/
This playbook will retrieve the files /tmp/p1-sample.txt and /tmp/p2-sample.txt from the host my-src.host and store them in the /tmp directory on the local host where Ansible runs.
Observation of Ansible Idempotency
Repeat the same above command again then due to Ansible idempotency, nothing changed at source and destination no action will be performed.
Important Note: We cannot copy a file between remote servers using copy, fetch module. But combination of these two fetch the file from source server and copy to target server is possible that means we can do this with two tasks, in between the Ansible controller node/AWX Tower will be storing the file temporarily.
Official Reference: