How to set hostname with cloud-init and Terraform?

10,711

Solution 1

Using a Terraform provisioner with the local-exec block will execute it on the device from which Terraform is applying: documentation. Note specifically the line:

This invokes a process on the machine running Terraform, not on the resource. See the remote-exec provisioner to run commands on the resource.

Therefore, switching the provisioner from a local-exec to a remote-exec:

provisioner "remote-exec" {
  inline = ["sudo hostnamectl set-hostname friendly.example.com"]
}

should fix your issue with setting the hostname.

Solution 2

Since you are supplying the tag to the instance as a string, why not just make that a var?

Replace the string friendly.example.com with ${var.instance-name} in your instance resource and in your data template. Then set the var:

variable "instance-name" {
    default="friendly.example.com"
}
Share:
10,711
ilvidel
Author by

ilvidel

Updated on June 17, 2022

Comments

  • ilvidel
    ilvidel almost 2 years

    I am starting with Terraform. I am trying to make it set a friendly hostname, instead of the usual ip-10.10.10.10 that AWS uses. However, I haven't found how to do it.

    I tried using provisioners, like this:

    provisioner "local-exec" {
       command = "sudo hostnamectl set-hostname friendly.example.com"
    }
    

    But that doesn't work, the hostname is not changed.

    So now, I'm trying this:

    resource "aws_instance" "example" {
      ami           = "ami-XXXXXXXX"
      instance_type = "t2.micro"
      tags = {
        Name    = "friendly.example.com"
      }
      user_data = "${data.template_file.user_data.rendered}"
    }
    
    data "template_file" "user_data" {
      template = "${file("user-data.conf")}"
      vars {
        hostname = "${aws_instance.example.tags.Name}"
      }
    }
    

    And in user-data.conf I have a line to use the variable, like so:

    hostname = ${hostname}
    

    But this gives me a cycle dependency:

    $ terraform apply
    Error: Error asking for user input: 1 error(s) occurred:
    * Cycle: aws_instance.example, data.template_file.user_data
    

    Plus, that would mean I have to create a different user_data resource for each instance, which seems a bit like a pain. Can you not reuse them? That should be the purpose of templates, right?

    I must be missing something, but I can't find the answer. Thanks.

  • ilvidel
    ilvidel over 5 years
    ok, that solves the cycle problem, and gets the correct hostname, yay! However, if I now add a second instance, I need to create a different variable, and a different user_data template, right? That doesn't seem very flexible.
  • James Woolfenden
    James Woolfenden over 5 years
    Lookup use count and then count.index to iterate through multiple instances. Also use aws_launch-configs not aws_instance
  • ydaetskcoR
    ydaetskcoR over 5 years
    This would be a better answer if it was a more complete example showing how to refer to the variable/local and was properly formatted.
  • Eat at Joes
    Eat at Joes over 4 years
    the remote-exec provisioner uses inline and not command. Also make sure inline is an array of commands; inline = ['sudo hostnamectl set-hostname friendly.example.com']