Table of Contents
Go from Ansible beginner to Ansible pro with this full video course.
What does the Ansible file
module do?
Ansible’s file
module can:
- Create files, directories and symlinks
- name: create an empty file if it doesn't exist
file:
path: $HOME/test_file
state: touch
- Delete files, directories and symlinks
- name: delete a file (or symlink) if it exists
file:
path: $HOME/test_file
state: absent
- Modify permissions and properties of files and directories
- name: modify permissions and properties of a directory (or create it if it doesn't exist)
file:
path: $HOME/test_directory/inner_test_directory
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: 0755
modification_time: "201812271410.15"
access_time: now
Ansible file
Module Video Tutorial
If you prefer watching to reading, here’s a full video tutorial from the TopTechSkills YouTube channel covering a many of the points and examples from this article. Feel free to comment on this article or the video if you have any questions.
state: file
vs state: touch
There are 2 states for dealing specifically with files using the file
module: state: file
and state: touch
.
state: file
ensures a path is a file, but will throw an error if the path does not exist or if the path is not a file
- name: check file that doesn't exist with state file
file:
path: $HOME/absent_test_file
state: file
fatal: [123.123.123.123]: FAILED! => {"changed": false,
"msg": "file (/home/ubuntu/absent_test_file) is absent, cannot continue",
"path": "/home/ubuntu/absent_test_file", "state": "absent"}
- name: check directory with state file
file:
path: $HOME/test_directory
state: file
fatal: [123.123.123.123]: FAILED! => {"changed": false, "gid": 1000, "group": "ubuntu", "mode": "0775",
"msg": "file (/home/ubuntu/test_directory) is directory, cannot continue", "owner": "ubuntu",
"path": "/home/ubuntu/test_directory", "size": 4096, "state": "directory", "uid": 1000}
state: touch
will create an empty file if a path does not exist and will not throw an error if the path is a directory or symlink
- name: check file that doesn't exist with state touch
file:
path: $HOME/absent_test_file
state: touch
ok: [123.123.123.123] => {
"file_output": {
"changed": true,
"dest": "/home/ubuntu/absent_test_file",
...
"state": "file",
"uid": 1000
}
}
- name: check directory with state touch
file:
path: $HOME/test_directory
state: touch
ok: [123.123.123.123] => {
"file_output": {
"changed": true,
"dest": "/home/ubuntu/test_directory",
...
"state": "directory",
"uid": 1000
}
}
This behavior of state: touch
matches the touch
command.
Examples
Create a directory or ensure a directory exists
You can ensure a directory exists by setting the state
parameter to directory
. If the directory already exists, Ansible will do nothing. Note that state: directory
behaves like mkdir -p
and will create any parent directories if they don’t exist. In the example below, test_directory
(the parent directory) will be created in addition to inner_test_directory
if it doesn’t already exist.
- name: ensure a directory exists
file:
path: $HOME/test_directory/inner_test_directory
state: directory
Create multiple directories in a loop
Use the loop
keyword and {{ item }}
to create multiple directories in a loop.
- name: create multiple directories in a loop
file:
path: "$HOME/test_directory/{{ item }}"
state: directory
register: file_output
loop:
- inner_test_directory
- another_test_directory/another_inner_directory
.
└── test_directory
├── another_test_directory
│ └── another_inner_directory
└── inner_test_directory
Delete a directory recursively
You can delete a directory by setting the state
parameter to absent
. If the directory does not exist, Ansible will do nothing.
- name: delete a directory recursively if it exists
file:
path: $HOME/test_directory
state: absent
Change permissions of a directory
The owner
, group
and mode
parameters of the file
module give you fine control over ownership and file permissions. Remember that you will need become: true
if you are setting the owner
or group
to values that don’t match the ansible_user
.
The mode
parameter accepts the following:
- Octal mode format: e.g.
0755
- Symbolic mode format: e.g.
u=rwx,g=rx,o=rx
(whereu
is the owner,g
is the group, ando
is others). The permissions arer
forread
,w
for write andx
for execute.
With octal mode:
- name: modify ownership & permissions of a directory (octal mode)
file:
path: $HOME/test_directory/inner_test_directory
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: 0755
With symbolic mode (equivalent to 0755
):
- name: modify ownership & permissions of a directory (symbolic mode)
file:
path: $HOME/test_directory/inner_test_directory
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: u=rwx,g=rx,o=rx
Setting a different owner with become: true
:
- name: change ownership & permissions of directory with become
file:
path: /var/log/nginx
state: directory
owner: root
group: root
mode: 0755
become: true
Change permissions of a directory recursively
You can use the recurse
keyword to change directory permissions recursively. This will affect the path
, as well as all the files and directories inside it.
- name: modify ownership & permissions of a directory recursively
file:
path: $HOME/test_directory
state: directory
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
mode: 0755
recurse: true
Set directories to 0755 and files to 0644 recursively
A common task when ensuring correct file permissions on a system is to recursively apply a mode
of 0755
on a directory so that all files and directories inside can be read by all users. Applying a mode
of 755
to directories is fine, but applying that mode to files is not good practice because it allows all users to execute them, which is insecure. It’s better practice to set files to a mode
of 0644
, which lets all users read a file but not execute it.
It’s possible to recursively apply a mode
of 0755
to directories and 0644
to files with the file
module by using symbolic mode
:
- name: recursively set 0755 on directories and 0644 on files
file:
path: $HOME/test_directory
state: directory
mode: u=rwX,g=rX,o=rX
recurse: true
The X
(instead of x
) will affect only directories or files that already allow execution.
Create a symlink
You can create symlinks by setting the state
parameter to link
. You will need to set src
and dest
parameters for the symlink. The src
is the original file and dest
is the symlink.
- name: create a symlink if it doesn't exist
file:
src: $HOME/test_file
dest: $HOME/test_directory/inner_test_directory/test_file_symlink
state: link
Delete a symlink
You can delete a symlink with the file
module in the same way as a file or directory: simply use state: absent
.
- name: delete a symlink if it exists
file:
path: $HOME/test_directory/inner_test_directory/test_file_symlink
state: absent
Create an empty file or ensure a file exists
You can ensure a file exists at a certain path by setting state
to touch
, which will do nothing if a file already exists, or create an empty file if it doesn’t.
- name: create an empty file if it doesn't exist
file:
path: $HOME/test_file
state: touch
Delete a file if it exists
You can delete a file by setting state
to absent
. If the file doesn’t exist, Ansible will do nothing.
- name: delete a file if it exists
file:
path: $HOME/test_file
state: absent
Update the modified time or access time of a file
Since Ansible 2.7, you can update the access and modified times of a file by using the access_time
and modification_time
parameters. The parameters accept the following values:
preserve
- no change (default when no value is provided)now
- set to the current time"YYYYmmddHHMM.SS"
- set to a specific time (note the quotation marks, without them Ansible interprets it as a float)
- name: modify access and modified times of a file
file:
path: $HOME/test_file
state: file
access_time: now
modification_time: "201812271410.15"
How to capture file
module output
Use the register
keyword to capture the output of the file
module.
- name: ensure a directory exists
file:
path: $HOME/test_directory/inner_test_directory
state: directory
register: file_output
- debug: var=file_output
The debug
task above will output the following:
ok: [123.123.123.123] => {
"file_output": {
"changed": true,
"diff": {
"after": {
"path": "/home/ubuntu/test_directory/inner_test_directory",
"state": "directory"
},
"before": {
"path": "/home/ubuntu/test_directory/inner_test_directory",
"state": "absent"
}
},
"failed": false,
"gid": 1000,
"group": "ubuntu",
"mode": "0775",
"owner": "ubuntu",
"path": "/home/ubuntu/test_directory/inner_test_directory",
"size": 4096,
"state": "directory",
"uid": 1000
}
}
How to capture file
module output from a loop
When using the file
module in a loop, the output of each item in the loop will go into the results
key of the registered variable.
- name: create multiple directories in a loop
file:
path: "$HOME/test_directory/{{ item }}"
state: directory
register: file_output
loop:
- inner_test_directory
- another_test_directory/another_inner_directory
- debug: var=file_output
ok: [123.123.123.123] => {
"file_output": {
"changed": true,
"msg": "All items completed",
"results": [
{
...
"changed": true,
"diff": {
"after": {
"path": "/home/ubuntu/test_directory/inner_test_directory",
"state": "directory"
},
"before": {
"path": "/home/ubuntu/test_directory/inner_test_directory",
"state": "absent"
}
},
"failed": false,
"gid": 1000,
"group": "ubuntu",
"invocation": {...},
"item": "inner_test_directory",
"mode": "0775",
"owner": "ubuntu",
"path": "/home/ubuntu/test_directory/inner_test_directory",
"size": 4096,
"state": "directory",
"uid": 1000
},
{
...
"changed": true,
"diff": {
"after": {
"path": "/home/ubuntu/test_directory/another_test_directory/another_inner_directory",
"state": "directory"
},
"before": {
"path": "/home/ubuntu/test_directory/another_test_directory/another_inner_directory",
"state": "absent"
}
},
"failed": false,
"gid": 1000,
"group": "ubuntu",
"invocation": {...},
"item": "another_test_directory/another_inner_directory",
"mode": "0775",
"owner": "ubuntu",
"path": "/home/ubuntu/test_directory/another_test_directory/another_inner_directory",
"size": 4096,
"state": "directory",
"uid": 1000
}
]
}
}
Further reading
Ansible file
Module on Ansible Docs