Use AWS Instance Tag Name as the hostname

7,364 views
Skip to first unread message

anthony...@actual-experience.com

unread,
Dec 12, 2017, 10:39:03 AM12/12/17
to Terraform
Hello, I have been trying to set the machine hostname using a mix of user_data, template_file and variables but I can't see to get it to budge.

Ideally I want the ec2.instance.tag.name to be the hostname, for example:



resource
"aws_instance" "app01" {
  ami
= "${var.aws_ami}"
  key_name
= "x-key"
  vpc_security_group_ids
= ["${aws_security_group.x_sg.id}","${aws_security_group.outbound_access_sg.id}"]
  subnet_id
= "${element(module.vpc.private_subnets, 0)}"
  instance_type
= "m4.2xlarge"
  tags
{
   
Name = "x_app_01"
 
}

I want "x_app_01" to become the hostname of the server, I attempted to use userdata:


  user_data
= "${data.template_file.init.rendered}"



#!/bin/bash


HOSTNAME
=${hostname}


OLDHOSTNAME
=$(cat /etc/hostname)


hostnamectl
set-hostname $HOSTAME


sed
-i "s/$OLDHOSTNAME/$HOSTNAME/g" /etc/hostname
sed
-i "s/$OLDHOSTNAME/$HOSTNAME/g" /etc/hosts

Enter code here...# Load Hostname Script
data "template_file" "init" {
  template = "${file("scripts/hostname.tpl")}"
  #vars {
  #  hostname = "${user_data.hostname}"
  #}
}

(Note the user_data.hostname was a test which didn't work"

However I can't think of a sensible way to set "hostname" without repeating a template.file for each ec2 instance which isn't ideal.

Is there a way to pass the "hostname" variable to the script via the aws_instance resource?

anthony...@actual-experience.com

unread,
Dec 12, 2017, 10:55:00 AM12/12/17
to Terraform
Worth adding it doesn't HAVE to be the AWS tag, it will be nice have it that way. Essentially all I want is a variable within the resource block that can be passed to the template.

terraform headache

unread,
Dec 13, 2017, 3:55:36 AM12/13/17
to Terraform
so for windows we do something like this in user-data to rename and bind machine to domain with powershell

Add-Computer -ComputerName $env:COMPUTERNAME -NewName (((Get-EC2Instance -Instance (Invoke-RestMethod -Method Get -Uri http://169.254.169.254/latest/meta-data/instance-id)).RunningInstance.Tags | Where-Object { $_.Key -eq "Name" }).Value) -DomainName example.com -Credential example\user -restart 

now sure that wont work for linux but the idea is the same - you need to make a web call to the meta data endpoint to get the tag values as the ec2 instance is not aware of them

Re-factor this to work in bash (maybe using aws cli) and you should be golden

(((Get-EC2Instance -Instance (Invoke-RestMethod -Method Get -Uri http://169.254.169.254/latest/meta-data/instance-id)).RunningInstance.Tags | Where-Object { $_.Key -eq "Name" }).Value)

anthony...@actual-experience.com

unread,
Dec 13, 2017, 5:45:03 AM12/13/17
to Terraform
Thanks, bit of a saga but i'll give it a go

Jay

unread,
Dec 14, 2017, 7:23:41 PM12/14/17
to Terraform
probably you can have custom boot script to read ec2 tags after instance is up and set hostname based on that

jhansi joe

unread,
Feb 24, 2018, 5:41:31 AM2/24/18
to Terraform
Thanks Anthony, It's really informative & it worked well

Regards

Miguel Cruz

unread,
Feb 25, 2018, 1:41:53 AM2/25/18
to Terraform
I usually have a bootstrap script on the AMI that does this, you could push the script and trigger it through terraform too.

These are the important bits:

INSTANCEID=`curl -s http://169.254.169.254/latest/meta-data/instance-id`
INSTANCEIP=`curl -s http://169.254.169.254/latest/meta-data/local-ipv4`
AWSREGION=`curl -s 169.254.169.254/latest/meta-data/placement/availability-zone | sed 's/.$//'`

#Create aws dir for root user
mkdir ~/.aws

#Create config file with minimum required content for aws cli to work
cat << EOF > ~/.aws/config
[default]
region = ${AWSREGION}
EOF

#Get Name tag value
INSTANCENAME=`aws ec2 describe-tags --filters "Name=resource-id,Values=${INSTANCEID}" --output=text | grep Name | awk '{print $5}'`

#Make sure we got a name, fail if we dont.
if [ -z "${INSTANCENAME}" ]
        then
        echo "I have no name!"
        exit 1
fi

echo "127.0.0.1 ${INSTANCENAME}.example.org localhost.localdomain localhost" > /etc/hosts
echo "perserve_hostname:true" >> /etc/cloud/cloud.cfg

After this point, I had a case statement which handled the different Linux versions we run.

For RHEL/Centos:
echo "${INSTANCENAME}.example.org" > /etc/hostname
echo "HOSTNAME=${INSTANCENAME}.example.org" >> /etc/sysconfig/network
hostnamectl set-hostname "${INSTANCENAME}.example.org"


Hopefully this is helpful for someone.

Cheers,

anand kumar

unread,
Aug 13, 2018, 1:32:00 PM8/13/18
to Terraform
  # this inline shell script also works!
  provisioner "remote-exec" {
    inline = [
      "echo '127.0.0.1 ${self.tags.Name}' | sudo tee -a /etc/hosts",
      "sudo hostnamectl set-hostname ${self.tags.Name}",
      # this will update hostname in swarm 
      "sudo systemctl restart docker",
    ]
  }
Reply all
Reply to author
Forward
0 new messages