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