Ansible: Capture Hostname and Configure it in Linux Configuration Files using lineinfile Module


2 views

When automating server configurations with Ansible, one common requirement is to capture a server's hostname and inject it into configuration files. Many services like Zabbix, Puppet, or custom applications need accurate hostname references in their configs. The challenge comes when we need to:

  • Dynamically capture the current hostname
  • Insert it into configuration files while maintaining idempotency
  • Handle various file formats and existing configurations

Ansible's lineinfile module is perfect for this task because it:

- Handles in-place file modifications
- Supports regex pattern matching
- Maintains idempotency (won't make changes unless needed)
- Allows precise location control via insertafter/insertbefore

Here's the complete implementation that solves the original problem:

- name: Get system hostname (method 1 - using ansible facts)
  ansible.builtin.set_fact:
    current_hostname: "{{ ansible_hostname }}"

- name: Get system hostname (method 2 - using shell command)
  ansible.builtin.shell: |
    hostname -s
  register: hostname_result
  changed_when: false

- name: Set hostname in zabbix configuration
  ansible.builtin.lineinfile:
    path: /etc/teste/linux/zabbix_agentd.conf
    regexp: '^Hostname='
    line: "Hostname={{ hostname_result.stdout | default(ansible_hostname) }}"
    backrefs: yes
    state: present

For more complex scenarios, consider these enhancements:

# Handling multiple possible hostname sources
- name: Set final hostname value
  ansible.builtin.set_fact:
    final_hostname: >-
      {{
        custom_hostname | default(hostname_var.stdout) |
        default(ansible_hostname) | default(inventory_hostname)
      }}

# Multi-line configuration with insertafter
- name: Configure Apache with hostname
  ansible.builtin.lineinfile:
    path: /etc/httpd/conf/httpd.conf
    insertafter: '^# ServerName'
    line: "ServerName {{ final_hostname }}"
    state: present
  • Always test regex patterns with ansible-playbook --check
  • Use backrefs: yes when you want to preserve existing content
  • For complex files, consider blockinfile instead
  • When permissions matter, add mode parameter to lineinfile

When automating server configuration with Ansible, a common requirement is to dynamically insert the current host's hostname into configuration files. The standard approach using the lineinfile module can be tricky when dealing with shell command outputs.

Here's a complete working solution that captures the hostname and inserts it into a configuration file:

- name: Get system hostname
  shell: hostname
  register: hostname_result
  changed_when: false

- name: Update configuration with hostname
  lineinfile:
    path: /etc/teste/linux/zabbix_agentd.conf
    regexp: "^Hostname=.*"
    line: "Hostname={{ hostname_result.stdout }}"
    backup: yes

The improved solution includes several important enhancements:

- Uses the dedicated hostname command instead of environment variables
- Sets changed_when: false to prevent unnecessary notifications
- Includes backup: yes to maintain a safety copy
- Properly handles the command output using stdout

For more complex scenarios, consider these approaches:

# Using Ansible facts (preferred when possible)
- name: Set hostname using facts
  lineinfile:
    path: /path/to/config
    regexp: "^Hostname=.*"
    line: "Hostname={{ ansible_hostname }}"

# Multi-line replacement example
- name: Update multiple configuration parameters
  blockinfile:
    path: /etc/app/config.conf
    marker: "# {mark} ANSIBLE MANAGED BLOCK"
    block: |
      Hostname={{ ansible_hostname }}
      ServerRole=production
      Timezone=UTC

To make your playbook more robust:

- name: Validate hostname format
  fail:
    msg: "Invalid hostname format"
  when: "' ' in hostname_result.stdout or not hostname_result.stdout"

- name: Verify config file update
  command: grep -q "Hostname={{ hostname_result.stdout }}" /path/to/config
  register: config_verify
  failed_when: config_verify.rc != 0