Learn through the super-clean Baeldung Pro experience:
>> Membership and Baeldung Pro.
No ads, dark-mode and 6 months free of IntelliJ Idea Ultimate to start with.
Last updated: September 30, 2024
Ansible is a simple and powerful IT automation tool. In this tutorial, we see different ways to create directories using Ansible. Moreover, we cover different use cases. This includes setting permissions, creating directory trees, deleting them, and others.
Before we move on with this tutorial, let’s set up a test environment. Also, we need to ensure some prerequisites:
With the above requirements in place, we can start using Ansible to create directories.
The file module in Ansible is a handy tool for handling files and directories. It has many options for creating, modifying, and deleting files and directories.
Also, we’ve got some commonly used parameters in the file module:
Let’s start with some examples of handling directories with Ansible.
To create a simple directory, we use the state: directory parameter from the file module. Along with this, we set the path of the directory:
$ cat creating_directory.yml
---
- hosts: client1
become: true
tasks:
- name: Create a directory
file:
path: /opt/my_dir
state: directory
Here’s the breakdown of the above playbook:
Notably, we’re creating directories in the system-owned /opt directory, which requires elevated privileges. Thus, we’ve got the become keyword in the above playbook.
Many of the above options will repeat in the coming playbooks.
Next, we run the playbook:
$ ansible-playbook -i project_inventory.ini creating_directory.yml
PLAY [client1] *******************************************************************************
TASK [Gathering Facts] ***********************************************************************
ok: [192.168.29.21]
TASK [Create a directory] ********************************************************************
changed: [192.168.29.21]
PLAY RECAP *********
192.168.29.21 : ok=2 changed=1 ...
...
The option -i sets the inventory file to use. On the target host, we can see to confirm the changes:
$ ls /opt/
my_dir
...
As a result, the above playbook creates my_directory on the remote system.
To set access permissions for the created directory, we use the mode parameter. For example, let’s create a directory with different read, write, and execute permissions for the owner, group, and others:
$ cat directory_permissions.yml
---
- hosts: client1
become: true
tasks:
- name: Adding access permissions
file:
path: /opt/secured_directory
state: directory
mode: '0750'
The above playbook has a new parameter mode. As a matter of fact, the mode value 0750 is in octal notation. This means the owner has read, write, and execute permissions. However, others can’t read, write, and execute the directory.
Next, we run the playbook:
$ ansible-playbook -i project_inventory.ini directory_permissions.yml
PLAY [client1] ******...
TASK [Gathering Facts] ******...
ok: [192.168.29.21]
TASK [Adding access permissions] ******...
PLAY RECAP *******
192.168.29.21 : ok=2 changed=1 ...
...
Thus, we can see secure_directory is created with the right permissions. On the remote machine, we can check the set permission:
$ ls -ll /opt/
drwxr-x--- 2 root root 4096 Sep 17 04:01 secured_directory
We can also add owner and group rights from the playbook.
To create multiple nested directories, we again use the file module. This is a tree-type structure. Again, we can do this by setting the path and state parameters.
Going ahead, we’ve got a new playbook for this use case:
$ cat directory_tree.yml
---
- hosts: client1
become: true
tasks:
- name: Create a directory tree
file:
path: /opt/parent/child/grandchild
state: directory
The above task creates the whole directory tree. This also includes any missing parent directories. Thus, we get a nested structure with parent, child, and grandchild directories under /opt.
Next, we run the example playbook to see how to create nested directories:
$ ansible-playbook -i project_inventory.ini directory_tree.yml
PLAY [client1] **********************************************
TASK [Gathering Facts] **************************************
ok: [192.168.29.21]
TASK [Create a directory tree] *****************************
changed: [192.168.29.21]
PLAY RECAP **********
192.168.29.21 : ok=2 changed=1 ...
...
We can now check the result on the remote machine:
$ tree /opt/parent/
/opt/parent/
└── child
└── grandchild
2 directories, 0 files
As a result, we can see the tree command listing all the directories.
Sometimes a part of the directory tree does not exist (e.g., parent or child). In that case, the playbook will create that part. Thus, we get the whole path.
We can also create multiple directories in a single task in Ansible. We can do this by using a loop. In this way, we can reduce redundancy in the playbook.
$ cat multiple_directories.yml
---
- hosts: client1
become: true
tasks:
- name: Create multiple directories
file:
path: "{{ item }}"
state: directory
with_items:
- /opt/dir1
- /opt/dir2
- /opt/dir3
In the above playbook, the with_items parameter loops through the given paths.
Moving on, we run the playbook:
$ ansible-playbook -i project_inventory.ini multiple_directories.yml
PLAY [client1] ****************...
TASK [Gathering Facts] *********...
ok: [192.168.29.21]
TASK [Create multiple directories] ********...
changed: [192.168.29.21] => (item=/opt/dir1)
changed: [192.168.29.21] => (item=/opt/dir2)
changed: [192.168.29.21] => (item=/opt/dir3)
PLAY RECAP **********
192.168.29.21 : ok=2 changed=1 ...
...
When we check on the remote machine, we see all the directories:
$ ls /opt/dir*
/opt/dir1:
/opt/dir2:
/opt/dir3:
Thus, the playbook loops over a list of directory paths and creates each one.
A timestamped directory is useful for logging or backup purposes. For this, we can use the ansible_date_time variable. It dynamically creates directories with the current date and time.
Let’s write a new playbook:
$ cat timestamped_directory.yml
---
- hosts: client1
become: true
tasks:
- name: Adding a timestamp to directory name
file:
path: "/opt/backup_{{ ansible_date_time.date }}_{{ ansible_date_time.time }}"
state: directory
When we run the playbook, we get a directory named with the current date and time:
$ ansible-playbook -i project_inventory.ini timestamped_directory.yml
PLAY [client1] ************
TASK ****.....
ok: [192.168.29.21]
TASK [Adding a timestamp to directory name] ************ changed: [192.168.29.21] PLAY RECAP *************** 192.168.29.21 : ok=2 changed=1 ... ...
Here, the ansible_date_time built-in variable dynamically fetches the current date and time. As a result, the directory name is time-stamped with the current date and time.
We can check the directory name on the remote machine:
$ ls /opt/
backup_2024-09-17_04:28:44
This way of naming is useful when we need directories for special purposes. For example, backup directories need to have a unique, time-stamped name. In the same manner, we can use it for logging work.
The file module also supports deleting directories. By setting the state parameter to absent, we can remove a directory and all its contents.
Let’s have a playbook for this case:
$ cat deleting_directory.yml
---
- hosts: client1
become: true
tasks:
- name: Remove a directory
file:
path: /opt/dir1
state: absent
When we run above the playbook, the given directory is removed:
$ ansible-playbook -i project_inventory.ini deleting_directory.yml
PLAY [client1] *******************************************************************************
TASK [Gathering Facts] ***********************************************************************
ok: [192.168.29.21]
TASK [Remove a directory] ********************************************************************
changed: [192.168.29.21]
PLAY RECAP ***********************************************************************************
192.168.29.21 : ok=2 changed=1 ...
...
Again, we can use the ls command to check changes on the remote host.
This is useful when we want to clean up old or unused directories in a system. Notably, all the files inside them are also removed.
Sometimes, the directory to be removed may not exist on the remote machine. In this case, the playbook runs without any error. However, the status of the changed flag in the playbook output doesn’t change.
Another option to create a directory is by using the install command. For this, we can use the command or shell module. The install command allows setting directory permissions during creation.
Next, we use a playbook to see how the install command works:
$ cat install_directory.yml
---
- hosts: client1
become: true
tasks:
- name: Using the install command
command: install -d -m 0755 /opt/install_directory
In the above playbook, install creates a directory if it doesn’t already exist. Also, we’ve set the permission using the mode option.
Further, we run the playbook:
$ ansible-playbook -i project_inventory.ini install_directory.yml
PLAY [client1] *******************************************************************************
TASK [Gathering Facts] ***********************************************************************
ok: [192.168.29.21]
TASK [Using the install command] ******************************************
changed: [192.168.29.21]
PLAY RECAP **********
192.168.29.21 : ok=2 changed=1 ...
...
The above playbook uses the command module for running shell commands directly on the host. As a result, we can see the changes on the remote machine:
$ ls -l /opt/
drwxr-xr-x 2 root root 4096 Sep 17 04:04 install_directory
Here, the install command creates the directory with -d. This is short for directory. We then set the permissions with -m 0755.
In this article, we discussed many ways to add a directory on the remote host with Ansible.
First, we saw how to add a simple directory on the remote machine. Further, we followed up by adding the access permissions. Moving on, we set up multiple and time-stamped directories on the remote host. Then, we saw how to remove them from the remote system.
Finally, we used the install command.