28

I am launching an aws_launch_configuration instance using terraform.

I'm using a shell script for the user_data variable, like so:

resource "aws_launch_configuration" "launch_config" {
    ...
    user_data = "${file("router-init.sh")}"
    ...  
}

Within this router-init.sh, one of the things I would like to do is to have access to the IP addresses for other instances I am launching via terraform.

I know that I can use a splat to access all the IP addresses of that instance, for instance:

output ip_address {
    value = ${aws_instance.myAWSInstance.*.private_ip}"
}

Is there a way to pass/access these IP addresses within the router-init.sh script?

Josh Correia
  • 3,807
  • 3
  • 33
  • 50
Timothy T.
  • 1,031
  • 1
  • 12
  • 25

3 Answers3

49

You can do this using a template_file data source:

data "template_file" "init" {
  template = "${file("router-init.sh.tpl")}"

  vars = {
    some_address = "${aws_instance.some.private_ip}"
  }
}

Then reference it inside the template like:

#!/bin/bash

echo "SOME_ADDRESS = ${some_address}" > /tmp/

Then use that for the user_data:

 user_data = ${data.template_file.init.rendered}
b.b3rn4rd
  • 8,494
  • 2
  • 45
  • 57
Brandon Miller
  • 4,695
  • 1
  • 20
  • 27
  • Is that possible when you are relying on the output of the instances being created? I'd expect this to be a cyclical dependency where the user data needs to know the output of the IP address of itself plus other instances being created at the same time (via `count`). – ydaetskcoR Jun 13 '18 at 11:45
  • Ack, nevermind, just realised the LC wants to know about some different AWS instances that are not in an ASG. Odd use case but yeah that will work. – ydaetskcoR Jun 13 '18 at 11:46
  • Yeah the dependency can be difficult but you can have resources depend on another more explicitly using depends_on. If it needs to know its ip you could pull that from within the instance itself. – Brandon Miller Jun 13 '18 at 11:48
  • Thanks very much! I have implemented this and it works. – Timothy T. Jun 14 '18 at 09:52
  • I think the second line should be: template = "${file("router-init.sh.tpl")}" – Rezler Oct 08 '18 at 10:57
  • Correct @rezler, not sure how I managed to include some extra characters. It's been fixed. – Brandon Miller Nov 26 '18 at 18:19
13

For people coming here since Terraform 0.12 and later, the templatefile function should be used instead of using template_file resource, so for the example in the question, it would be something like

locals {
  vars = {
    some_address = aws_instance.some.private_ip
  }
}

user_data = base64encode(templatefile("${path.module}/router-init.sh", local.vars))
Henridv
  • 766
  • 12
  • 23
Mo Hajr
  • 1,253
  • 1
  • 15
  • 31
4

From Terraform 0.12 and later, you can use the templatefile function instead of the template_file resource, so for a general use case where you need to access more than one variable, you can use:

    locals {
      variable1       = "your_username"
      variable2       = "your_password"
      db_address      = aws_db_instance.some-db.address
      public_alb_dns  = aws_lb.some-alb.dns_name
    }
    
    resource "aws_instance" "web_01" {
      ....
      user_data = base64encode(templatefile("user_data.sh", {
        db_address      = local.db_address
        admin_user      = local.variable1
        admin_password  = local.variable2
        public_alb_dns  = local.private_alb_dns
      } ))
      ....
    }

You can also access other terraform resource attribute references.

Sanim16
  • 151
  • 3
  • 6