Ansible File Modules
Introduction
Managing files and directories is a fundamental operation in system administration. Whether you're creating configuration files, setting up directory structures, or managing file permissions, Ansible provides a robust set of modules to handle these tasks efficiently and consistently across your infrastructure.
In this guide, we'll explore Ansible's file modules, which allow you to automate file-related operations that would otherwise require manual intervention or custom scripts. These modules are essential building blocks for creating maintainable and scalable infrastructure as code.
Core File Modules
The file
Module
The file
module is the Swiss Army knife of file operations in Ansible. It can create, delete, and modify files and directories, as well as manage their attributes.
Basic Usage
- name: Create a directory if it doesn't exist
file:
path: /etc/app/config
state: directory
mode: '0755'
Available States
The state
parameter defines what you want to do with the specified path:
file
: Ensures it exists as a regular filedirectory
: Ensures it exists as a directorylink
: Creates a symbolic linkhard
: Creates a hard linktouch
: Similar to the Unixtouch
command, creates an empty file if it doesn't existabsent
: Ensures the file/directory doesn't exist
Example: Managing File Permissions
- name: Ensure SSH private key has correct permissions
file:
path: ~/.ssh/id_rsa
mode: '0600'
owner: "{{ ansible_user }}"
group: "{{ ansible_user }}"
This task ensures that an SSH private key has strict permissions, which is crucial for security.
The copy
Module
The copy
module transfers files from the control node (where Ansible is running) to the managed nodes.
Basic Usage
- name: Copy configuration file to remote server
copy:
src: files/app.conf
dest: /etc/app/app.conf
owner: app_user
group: app_group
mode: '0644'
backup: yes
Key Features
- Backup: When
backup: yes
is specified, Ansible creates a backup of any existing file before overwriting it. - Content: Instead of copying a file, you can directly specify content:
- name: Create a file with specific content
copy:
content: |
# This is a configuration file
app_name: MyApp
app_port: 8080
debug: false
dest: /etc/app/config.yml
mode: '0644'
- Validation: You can validate the file before copying:
- name: Copy and validate nginx configuration
copy:
src: files/nginx.conf
dest: /etc/nginx/nginx.conf
validate: "nginx -t -c %s"
The template
Module
The template
module is similar to copy
, but it processes the source file as a Jinja2 template before transferring it, allowing for dynamic content generation.
Basic Usage
- name: Configure application using a template
template:
src: templates/app.conf.j2
dest: /etc/app/app.conf
owner: app_user
group: app_group
mode: '0644'
Template Example (app.conf.j2)
# Application configuration for {{ inventory_hostname }}
# Generated by Ansible on {{ ansible_date_time.date }}
app_name: {{ app_name | default('MyApp') }}
app_port: {{ app_port | default(8080) }}
log_level: {{ log_level | default('info') }}
database:
host: {{ db_host | default('localhost') }}
port: {{ db_port | default(5432) }}
name: {{ db_name | default('app_db') }}
user: {{ db_user | default('app_user') }}
The power of templates comes from their ability to incorporate variables, conditionals, loops, and filters to generate tailored configurations.
Advanced File Operations
The lineinfile
Module
The lineinfile
module ensures a particular line is present in a file, or replaces an existing line using regular expressions.
Adding a Line
- name: Add a line to hosts file
lineinfile:
path: /etc/hosts
line: "192.168.1.100 app-server"
Replacing a Line
- name: Change SSH port configuration
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?Port\s+\d+$'
line: 'Port 2222'
validate: 'sshd -t -f %s'
This is particularly useful for making small changes to configuration files without replacing the entire file.
The blockinfile
Module
The blockinfile
module is similar to lineinfile
but works with blocks of text rather than single lines.
- name: Add a block of text to a configuration file
blockinfile:
path: /etc/ntp.conf
block: |
# NTP servers for internal network
server ntp1.internal.example.com iburst
server ntp2.internal.example.com iburst
server ntp3.internal.example.com iburst
marker: "# {mark} ANSIBLE MANAGED NTP SERVERS"
The marker
parameter defines the comments that will surround your block, making it easy to identify Ansible-managed sections.
The find
Module
The find
module allows you to search for files based on various criteria and optionally perform actions on the results.
- name: Find all log files older than 30 days
find:
paths: /var/log
patterns: "*.log"
age: 30d
recurse: yes
register: old_logs
- name: Remove old log files
file:
path: "{{ item.path }}"
state: absent
loop: "{{ old_logs.files }}"
This example shows how to find and remove log files older than 30 days.
Real-World Examples
Example 1: Deploying a Web Application Configuration
- name: Configure Nginx for web application
hosts: web_servers
become: yes
vars:
app_name: my_webapp
app_domain: example.com
app_port: 8080
tasks:
- name: Ensure Nginx configuration directory exists
file:
path: /etc/nginx/sites-available
state: directory
mode: '0755'
- name: Ensure sites-enabled directory exists
file:
path: /etc/nginx/sites-enabled
state: directory
mode: '0755'
- name: Generate Nginx site configuration from template
template:
src: templates/nginx-site.conf.j2
dest: "/etc/nginx/sites-available/{{ app_name }}"
owner: root
group: root
mode: '0644'
validate: "nginx -t -c /etc/nginx/nginx.conf"
notify: Restart Nginx
- name: Enable site configuration
file:
src: "/etc/nginx/sites-available/{{ app_name }}"
dest: "/etc/nginx/sites-enabled/{{ app_name }}"
state: link
notify: Restart Nginx
handlers:
- name: Restart Nginx
service:
name: nginx
state: restarted
This example shows how multiple file modules work together to deploy and configure an Nginx web server setup.
Example 2: Managing System Configuration Files
- name: Configure system settings
hosts: all
become: yes
tasks:
- name: Set system-wide environment variables
blockinfile:
path: /etc/environment
block: |
APP_ENV=production
APP_LOG_LEVEL=info
APP_PATH=/opt/myapp
marker: "# {mark} ANSIBLE MANAGED APP ENVIRONMENT"
- name: Configure system limits
copy:
dest: /etc/security/limits.d/custom.conf
content: |
# Custom system limits
* soft nofile 65536
* hard nofile 65536
* soft nproc 4096
* hard nproc 4096
mode: '0644'
- name: Ensure sysctl configuration includes our file
lineinfile:
path: /etc/sysctl.conf
line: "include /etc/sysctl.d/*.conf"
state: present
- name: Configure kernel parameters
template:
src: templates/sysctl-custom.conf.j2
dest: /etc/sysctl.d/99-custom.conf
mode: '0644'
notify: Apply sysctl settings
handlers:
- name: Apply sysctl settings
command: sysctl -p /etc/sysctl.d/99-custom.conf
This playbook demonstrates how to use various file modules to manage system configuration files, ensuring consistent settings across your infrastructure.
Flow Diagram for File Operations
Advanced Topics
Managing SELinux Context
When working with systems that use SELinux, you may need to manage file contexts:
- name: Create directory with specific SELinux context
file:
path: /var/www/html/app
state: directory
mode: '0755'
setype: httpd_sys_content_t
Managing Extended Attributes
Some file operations require setting extended attributes:
- name: Set attributes on a file
file:
path: /var/log/audit/audit.log
attributes: +a
This example sets the append-only attribute on an audit log file.
Synchronizing Directories
For more complex file synchronization needs, Ansible provides the synchronize
module, which is a wrapper around rsync
:
- name: Sync application files to servers
synchronize:
src: /local/path/to/app/
dest: /remote/path/to/app/
delete: yes
recursive: yes
rsync_opts:
- "--exclude=.git"
- "--exclude=node_modules"
Summary
Ansible's file modules provide a robust toolset for managing files and directories across your infrastructure:
- The
file
module manages file existence, permissions, and attributes - The
copy
module transfers files from the control node to managed nodes - The
template
module allows for dynamic file generation using Jinja2 - The
lineinfile
andblockinfile
modules make precise modifications to existing files - The
find
module helps locate files based on various criteria
By leveraging these modules, you can ensure consistent file management across your entire infrastructure, reduce manual configuration errors, and implement infrastructure as code effectively.
Exercises
- Create a playbook that sets up a standard directory structure for a web application, with appropriate permissions for different components.
- Write a task that finds all files with world-writable permissions in
/etc
and corrects them. - Create a template for an application configuration file that adapts based on the environment (development, testing, production).
- Implement a playbook that backs up all configuration files before modifying them.
- Write a task that ensures all shell scripts in a directory are executable, but not world-writable.
Additional Resources
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)