How to Dynamically Copy Files Based on Hostname or Role in Ansible


2 views

When managing multiple servers with Ansible, you often need to distribute configuration files that share the same filename but contain different content based on the target machine's role or hostname. A classic example would be deploying /etc/nginx/nginx.conf with role-specific configurations across web servers.

Ansible provides several elegant ways to handle this:

# Method 1: Using host_vars and group_vars
# In your inventory file:
[webservers]
web1 ansible_host=192.168.1.10 role=frontend
web2 ansible_host=192.168.1.11 role=backend

# Then in group_vars/webservers/file.yml or host_vars/web1/file.yml
file_content: |
  This is specific content for {{ role }}

For more complex scenarios, Jinja2 templates work best:

- name: Deploy role-specific configuration
  template:
    src: "templates/file.conf.j2"
    dest: "/etc/service/file.conf"
    owner: root
    group: root
    mode: '0644'

When you need completely different source files (not just variable substitution):

- name: Copy role-specific file
  copy:
    src: "files/{{ inventory_hostname }}.file"
          or
    src: "files/{{ ansible_hostname }}.file"
          or  
    src: "files/{{ role }}.file"
    dest: "/path/to/destination/file"

For more complex decision trees:

- name: Deploy appropriate file
  copy:
    src: "files/{% if 'db' in group_names %}db.file{% elif 'web' in group_names %}web.file{% else %}default.file{% endif %}"
    dest: "/etc/application/config.file"
  • Store role-specific files in roles/rolename/files/ directory structure
  • Use Ansible facts (ansible_hostname, inventory_hostname) for maximum flexibility
  • Consider using the first_found lookup for fallback scenarios

Here's a full playbook example:

- hosts: all
  tasks:
    - name: Determine correct source file
      set_fact:
        config_file: "{{ 'file.' + role | default('default') }}"
      
    - name: Deploy configuration
      copy:
        src: "files/{{ config_file }}"
        dest: "/etc/app/config"
        owner: appuser
        group: appgroup
        mode: '0640'

When managing infrastructure with Ansible, we often need to distribute configuration files that share the same filename but contain different content based on either:

  • The target host's hostname
  • The role assigned to the host

Here are three effective methods to implement this in Ansible:

1. Using Role-Based File Selection


- name: Copy role-specific file
  ansible.builtin.copy:
    src: "files/file.{{ ansible_role }}"
    dest: "/path/to/destination/file"

2. Hostname-Based Conditional Copy


- name: Copy file based on hostname
  ansible.builtin.copy:
    src: "files/file.{{ inventory_hostname }}"
    dest: "/path/to/destination/file"
  when: inventory_hostname in ['host1', 'host2', 'host3']

3. Combined Hostname and Role Logic


- name: Copy file with complex conditions
  ansible.builtin.copy:
    src: "files/file.{{ ansible_role }}"
    dest: "/path/to/destination/file"
  when: 
    - ansible_role == 'webserver'
    - inventory_hostname.startswith('prod-')

For more complex scenarios, consider using Ansible's vars_files directive:


- name: Include host-specific variables
  include_vars: "host_vars/{{ inventory_hostname }}.yml"

- name: Copy dynamically determined file
  ansible.builtin.copy:
    src: "files/file.{{ file_variant }}"
    dest: "/path/to/destination/file"
  • Store all variant files in a dedicated directory structure
  • Use consistent naming conventions (e.g., role-based suffixes)
  • Document the file distribution logic in your playbook comments
  • Consider using Ansible Vault for sensitive configuration files

Here's a complete playbook example for Nginx configuration distribution:


- hosts: webservers
  tasks:
    - name: Determine config variant
      set_fact:
        config_variant: "{% if 'production' in inventory_hostname %}prod{% else %}dev{% endif %}"

    - name: Copy Nginx config
      ansible.builtin.copy:
        src: "templates/nginx.conf.{{ config_variant }}"
        dest: "/etc/nginx/nginx.conf"
        owner: root
        group: root
        mode: '0644'