Introduction
Ansible is a powerful IT automation tool that simplifies infrastructure management. In this hands-on lab, you will learn how to use Ansible to create files with specific content on target systems. By the end of this lab, you will understand the basics of Ansible file management and be able to implement automated file creation in your own infrastructure.
Installing and Setting Up Ansible
Before we can start using Ansible to create files, we need to install and configure it on our system. Let us set up our environment:
Installing Ansible
First, we will update the package lists and install Ansible on our Ubuntu 22.04 system:
sudo apt update
sudo apt install -y ansible
After running these commands, you should see output indicating that Ansible has been successfully installed. Let us verify the installation:
ansible --version
You should see output similar to this:
ansible [core 2.12.0]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/labex/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /home/labex/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.10.x (default, ...) [GCC 11.2.0]
jinja version = 3.0.3
libyaml = True
Creating a Simple Ansible Inventory
Ansible uses an inventory file to define the hosts it will manage. For this lab, we will create a local inventory that includes our own machine:
- Create a new directory for our Ansible project:
mkdir -p ~/project/ansible-files
cd ~/project/ansible-files
- Create an inventory file using VSCode:
- Click on the Explorer icon in the WebIDE
- Navigate to the
~/project/ansible-filesdirectory - Right-click and select "New File"
- Name the file
inventory - Add the following content to the file:
[local]
localhost ansible_connection=local
This inventory file tells Ansible to run commands on the local machine without using SSH.
- Create a simple
ansible.cfgfile in the same directory:- Click on the Explorer icon in the WebIDE
- Navigate to the
~/project/ansible-filesdirectory - Right-click and select "New File"
- Name the file
ansible.cfg - Add the following content to the file:
[defaults]
inventory = ./inventory
host_key_checking = False
- Let us verify our setup by running a simple Ansible command:
cd ~/project/ansible-files
ansible local -m ping
You should see output similar to:
localhost | SUCCESS => {
"changed": false,
"ping": "pong"
}
This confirms that Ansible is correctly installed and configured to run commands on your local machine.
Creating Files with Content Using Ansible Playbooks
Now that we have Ansible set up, let us learn how to create files with content. Ansible provides several modules for managing files, and we will focus on the copy module in this step.
Understanding Ansible Playbooks
Ansible Playbooks are YAML files that describe a set of tasks to be executed on target hosts. Each task utilizes a specific Ansible module to perform an action.
Let us create our first playbook to create a file with content:
- In the WebIDE, create a new file in the
~/project/ansible-filesdirectory:- Right-click on the directory and select "New File"
- Name the file
create_file.yml - Add the following content:
---
- name: Create a file with content
hosts: local
tasks:
- name: Create a simple text file
copy:
dest: "~/project/hello.txt"
content: |
Hello from Ansible!
This file was created using the Ansible copy module.
Current date: {{ ansible_date_time.date }}
Let us understand what this playbook does:
- The
hosts: localline specifies that this playbook will run on the hosts in thelocalgroup from our inventory. - The
taskssection contains a list of tasks to execute. - The
copymodule is used to create a file with content. - The
destparameter specifies the destination path for the file. - The
contentparameter contains the text content that will be written to the file. - The
{{ ansible_date_time.date }}is a variable that will be replaced with the current date when the playbook runs.
- Now, let us run the playbook:
cd ~/project/ansible-files
ansible-playbook create_file.yml
You should see output similar to:
PLAY [Create a file with content] ***********************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Create a simple text file] ***********************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- Let us verify that the file was created and contains the expected content:
cat ~/project/hello.txt
You should see output similar to:
Hello from Ansible!
This file was created using the Ansible copy module.
Current date: 2023-08-15
The date will reflect the current date when you run the playbook.
Idempotence in Ansible
Idempotence is a key feature of Ansible - running the same playbook multiple times should produce the same result. Let us run the playbook again to see idempotence in action:
ansible-playbook create_file.yml
This time, you should see that the "changed" count is 0:
PLAY [Create a file with content] ***********************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Create a simple text file] ***********************************************
ok: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
This shows that Ansible recognizes the file already exists with the correct content, so it does not modify it again.
Using Variables and Templates in Ansible
In this step, we will explore how to use variables and templates to create more dynamic files with Ansible.
Working with Variables
Variables make your playbooks more flexible and reusable. Let us create a playbook that uses variables to create a configuration file:
- Create a new file in the WebIDE in the
~/project/ansible-filesdirectory:- Right-click on the directory and select "New File"
- Name the file
variables_demo.yml - Add the following content:
---
- name: Create files using variables
hosts: local
vars:
app_name: "MyApplication"
app_version: "1.0.0"
port_number: 8080
log_level: "INFO"
tasks:
- name: Create config file with variables
copy:
dest: "~/project/app_config.ini"
content: |
## Configuration for {{ app_name }}
## Generated by Ansible
[application]
name = {{ app_name }}
version = {{ app_version }}
[server]
port = {{ port_number }}
log_level = {{ log_level }}
In this playbook:
- The
varssection defines variables that can be used throughout the playbook. - The variables are referenced using the
{{ variable_name }}syntax. - The
copymodule is used to create a file with content that includes these variables.
- Now, let us run the playbook:
cd ~/project/ansible-files
ansible-playbook variables_demo.yml
You should see output similar to:
PLAY [Create files using variables] ********************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Create config file with variables] ***************************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- Let us examine the content of the generated file:
cat ~/project/app_config.ini
You should see output similar to:
## Configuration for MyApplication
## Generated by Ansible
[application]
name = MyApplication
version = 1.0.0
[server]
port = 8080
log_level = INFO
Using Jinja2 Templates
For more complex file content, Ansible supports Jinja2 templates. Let us create a template file and use it in a playbook:
- Create a templates directory:
mkdir -p ~/project/ansible-files/templates
- Create a template file in the WebIDE:
- Navigate to the
~/project/ansible-files/templatesdirectory - Right-click and select "New File"
- Name the file
web_config.j2 - Add the following content:
- Navigate to the
## Web Server Configuration
## Generated by Ansible on {{ ansible_date_time.date }}
server {
listen {{ web_port }};
server_name {{ server_name }};
location / {
root {{ doc_root }};
index index.html;
}
{% if enable_ssl %}
## SSL Configuration
ssl_certificate {{ ssl_cert }};
ssl_certificate_key {{ ssl_key }};
{% endif %}
}
- Now create a playbook that uses this template:
- Navigate to the
~/project/ansible-filesdirectory - Right-click and select "New File"
- Name the file
template_demo.yml - Add the following content:
- Navigate to the
---
- name: Create files using templates
hosts: local
vars:
web_port: 80
server_name: "example.com"
doc_root: "/var/www/html"
enable_ssl: true
ssl_cert: "/etc/ssl/certs/example.com.crt"
ssl_key: "/etc/ssl/private/example.com.key"
tasks:
- name: Create web server config from template
template:
src: templates/web_config.j2
dest: ~/project/web_server.conf
In this playbook:
- The
templatemodule is used instead ofcopy. - The
srcparameter points to our template file. - The
destparameter specifies where to create the output file. - The variables defined in the
varssection will be used in the template.
- Run the playbook:
cd ~/project/ansible-files
ansible-playbook template_demo.yml
You should see output similar to:
PLAY [Create files using templates] ********************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Create web server config from template] **********************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- Let us examine the generated configuration file:
cat ~/project/web_server.conf
You should see output similar to:
## Web Server Configuration
## Generated by Ansible on 2023-08-15
server {
listen 80;
server_name example.com;
location / {
root /var/www/html;
index index.html;
}
## SSL Configuration
ssl_certificate /etc/ssl/certs/example.com.crt;
ssl_certificate_key /etc/ssl/private/example.com.key;
}
Notice how the Jinja2 template was rendered with our variables, and the conditional section for SSL was included because enable_ssl was set to true.
Advanced File Management with Ansible
In this final step, we will explore some advanced file management techniques with Ansible, including file permissions, conditional file creation, and using multiple file-related modules.
Setting File Permissions and Ownership
When creating files, you often need to set specific permissions and ownership. Let us create a playbook that demonstrates this:
- Create a new file in the WebIDE:
- Navigate to the
~/project/ansible-filesdirectory - Right-click and select "New File"
- Name the file
file_permissions.yml - Add the following content:
- Navigate to the
---
- name: Manage file permissions and ownership
hosts: local
tasks:
- name: Create a script file with execute permissions
copy:
dest: ~/project/script.sh
content: |
#!/bin/bash
echo "This script was created by Ansible"
echo "Current user: $(whoami)"
echo "Current directory: $(pwd)"
mode: "0755"
- name: Create a read-only configuration file
copy:
dest: ~/project/readonly.conf
content: |
## This is a read-only configuration file
setting1 = value1
setting2 = value2
mode: "0444"
In this playbook:
- The
modeparameter is used to set file permissions. 0755means read, write, and execute for the owner, and read and execute for group and others.0444means read-only for everyone.
- Run the playbook:
cd ~/project/ansible-files
ansible-playbook file_permissions.yml
You should see output similar to:
PLAY [Manage file permissions and ownership] **********************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Create a script file with execute permissions] **************************
changed: [localhost]
TASK [Create a read-only configuration file] **********************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- Let us check the permissions of the created files:
ls -l ~/project/script.sh ~/project/readonly.conf
You should see output similar to:
-rwxr-xr-x 1 labex labex 118 Aug 15 12:34 /home/labex/project/script.sh
-r--r--r-- 1 labex labex 73 Aug 15 12:34 /home/labex/project/readonly.conf
- Let us verify that the script can be executed:
~/project/script.sh
You should see output similar to:
This script was created by Ansible
Current user: labex
Current directory: /home/labex/project/ansible-files
Conditional File Creation
Sometimes you need to create files only when certain conditions are met. Let us create a playbook that demonstrates conditional file creation:
- Create a new file in the WebIDE:
- Navigate to the
~/project/ansible-filesdirectory - Right-click and select "New File"
- Name the file
conditional_file.yml - Add the following content:
- Navigate to the
---
- name: Conditional file creation
hosts: local
vars:
environment: "development"
create_debug_file: true
create_backup: false
tasks:
- name: Create environment-specific configuration
copy:
dest: "~/project/{{ environment }}_config.yml"
content: |
## Configuration for {{ environment }} environment
debug: {{ 'enabled' if environment == 'development' else 'disabled' }}
log_level: {{ 'DEBUG' if environment == 'development' else 'INFO' }}
- name: Create debug log file
copy:
dest: ~/project/debug.log
content: |
## Debug log file
## Created: {{ ansible_date_time.iso8601 }}
mode: "0644"
when: create_debug_file
- name: Create backup directory
file:
path: ~/project/backup
state: directory
mode: "0755"
when: create_backup
In this playbook:
- The
whendirective is used for conditional execution of tasks. - Jinja2 conditionals are used in the file content to change values based on variables.
- The
filemodule is used to create a directory.
- Run the playbook:
cd ~/project/ansible-files
ansible-playbook conditional_file.yml
You should see output similar to:
PLAY [Conditional file creation] **********************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Create environment-specific configuration] ******************************
changed: [localhost]
TASK [Create debug log file] **************************************************
changed: [localhost]
TASK [Create backup directory] ************************************************
skipped: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=3 changed=2 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
Notice that the "Create backup directory" task was skipped because create_backup was set to false.
- Let us examine the created files:
cat ~/project/development_config.yml
cat ~/project/debug.log
ls -la ~/project/ | grep backup
You should see the contents of the two files that were created, and confirm that no backup directory was created.
Using Multiple File-Related Modules
Ansible provides several modules for file management. Let us create a playbook that demonstrates using multiple file-related modules:
- Create a new file in the WebIDE:
- Navigate to the
~/project/ansible-filesdirectory - Right-click and select "New File"
- Name the file
file_modules.yml - Add the following content:
- Navigate to the
---
- name: Demonstrate file-related modules
hosts: local
tasks:
- name: Create a directory
file:
path: ~/project/ansible_demo
state: directory
mode: "0755"
- name: Create a file using the copy module
copy:
dest: ~/project/ansible_demo/copied.txt
content: "This file was created using the copy module.\n"
- name: Create a symbolic link
file:
src: ~/project/ansible_demo/copied.txt
dest: ~/project/ansible_demo/link_to_copied.txt
state: link
- name: Create a file with blockinfile module
blockinfile:
path: ~/project/ansible_demo/block.txt
create: true
block: |
This is a block of text
that will be inserted
as a single unit.
marker: "## {mark} ANSIBLE MANAGED BLOCK"
In this playbook:
- The
filemodule is used withstate: directoryto create a directory. - The
filemodule is used withstate: linkto create a symbolic link. - The
blockinfilemodule is used to create a file with a block of text surrounded by marker comments.
- Run the playbook:
cd ~/project/ansible-files
ansible-playbook file_modules.yml
You should see output similar to:
PLAY [Demonstrate file-related modules] ***************************************
TASK [Gathering Facts] *********************************************************
ok: [localhost]
TASK [Create a directory] *****************************************************
changed: [localhost]
TASK [Create a file using the copy module] ************************************
changed: [localhost]
TASK [Create a symbolic link] *************************************************
changed: [localhost]
TASK [Create a file with blockinfile module] **********************************
changed: [localhost]
PLAY RECAP *********************************************************************
localhost : ok=5 changed=4 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
- Let us verify the results:
ls -la ~/project/ansible_demo/
cat ~/project/ansible_demo/copied.txt
cat ~/project/ansible_demo/link_to_copied.txt
cat ~/project/ansible_demo/block.txt
You should see:
- A directory called
ansible_demo - A file called
copied.txtwith the specified content - A symbolic link called
link_to_copied.txtpointing tocopied.txt - A file called
block.txtwith a block of text surrounded by marker comments
The output of the last command should be similar to:
## BEGIN ANSIBLE MANAGED BLOCK
This is a block of text
that will be inserted
as a single unit.
## END ANSIBLE MANAGED BLOCK
This demonstrates the versatility of Ansible's file management capabilities.
Summary
Congratulations on completing this Ansible file management lab. You have learned several important concepts and techniques:
- How to install and configure Ansible for basic automation tasks
- Creating files with specific content using the
copymodule - Using variables to make your file content dynamic
- Working with Jinja2 templates for more complex file generation
- Setting file permissions and ownership
- Implementing conditional file creation based on variables
- Using various Ansible modules for different file management tasks
These skills form a solid foundation for automating file management tasks in your infrastructure. With Ansible, you can ensure consistent file content across multiple servers, apply changes in a controlled manner, and maintain an auditable record of your configuration.
To continue your Ansible learning journey, consider exploring more advanced topics such as roles, playbook organization, and integrating Ansible with other DevOps tools.


