Sometimes there's a need to automatically setup the hostname of an EC2 instance. This post shows how to do it from 'outside' of the instance itself, using Ansible.
Let's assume here that the instance already has a tag Name, that will be used as the hostname and the VPC uses DHCP options that set the correct domain.
The instance must have an IAM Profile that allows for DescribeInstances.
Prerequisites
For the change to work the EC2 instance must have two Python packages installed:
- boto3
- botocore
They can be installed using pip
.
Workflow
First we have to determine the region the instance is in. The easiest way is to look at the search domains in /etc/resolv.conf
. One of them contains the region, for example: ap-southeast-2.compute.internal. Those domains are available in Ansible facts via ansible_dns.search
, there is another domain there too (sourced from DHCP options) so it has to be filtered out:
- name: "set region"
set_fact:
aws_region: "{{ domain.split('.')[0] }}"
when: "'compute' in domain"
loop: "{{ ansible_dns.search }}"
loop_control:
loop_var: domain
label: "{{ domain }}"
The next step is to determine the instance id. The easiest way of doing it is to call the meta-data service:
- name: get instance id
uri:
url: "http://169.254.169.254/latest/meta-data/instance-id"
return_content: true
register: inststance_id_raw
That instance id can be used by ec2_instance_facts
Ansible module to filter out only information that pertains to current instance:
- name: get ec2 instance facts
ec2_instance_facts:
region: "{{ aws_region }}"
instance_ids: "{{ inststance_id_raw.content }}"
register: ec2_facts
Finally, we can set the hostname to the value extracted from instance tag Name and the ansible domain (in this case on Amazon Linux 2):
- name: setup hostname
command: hostnamectl set-hostname {{ ec2_facts.instances[0].tags.Name }}.{{ ansible_domain }}