Overview
Terraform offers a data source
for cloudinit which is really useful for bootstrapping EC2 instances with an
initial configuration. For me, this is usually a script with just enough code to run
salt-call. I was
having a hard time figuring out exactly how to include files into
the data source
template_cloudinit_config since my bootstrap script had a dependency on
a second script.
Scenario
In specific provisioning cases I’ve had two scripts that I wanted to include for
bootstrapping a Linux EC2 instance via terraform. The problem was that I had one
script dependent on the other.
Here’s a simplified example of this with simple shell scripts:
deps.sh:
#!/bin/bash
$ cat << EOF >> /tmp/output.txt
Hello from dependent script!
EOF
bootstrap.sh:
#!/bin/bash
$ cat << EOF >> /tmp/output.txt
Hello from bootstrap script!
EOF
/usr/local/bin/deps.sh
How can I ensure that deps.sh exists so that bootstrap.sh correctly calls it
via cloudinit? Keeping DRY (Don’t repeat yourself) in mind, there is a way to do
this in terraform!
Solution
Assuming there’s a subdirectory of scripts in our terraform directory that
contains the above bootstrap.sh and deps.sh scripts, create the following
data source inside a new or existing .tf file:
data "template_cloudinit_config" "example" {
gzip = true
base64_encode = true
part {
content_type = "text/cloud-config"
content = <<EOF
#cloud-config
write_files:
- content: |
${base64encode(file("${path.module}/scripts/deps.sh"))}
encoding: b64
owner: root:root
path: /usr/local/bin/deps.sh
permissions: '0750'
EOF
}
part {
content_type = "text/x-shellscript"
content = "${file("${path.module}/scripts/bootstrap.sh")}"
}
}
Notice a couple interesting things about the above data source:
- The script order matters due to the
bootstrap.shdepending ondeps.sh deps.shis not called directly but instead just put in its expected path with the correct permissions- The content for the
deps.shhas to bebase64encodeddue to the line indents required by the pipe
Then all that’s needed when to referencing the user_data in an
aws_launch_configuration resource is:
user_data = "${data.template_cloudinit_config.example.rendered}"
Add after a successful bootstrap you should see the following after
cat /tmp/output.txt:
Hello from dependent script!
Hello from bootstrap script!
Overall this helped alleviate some of my own needs for custom AMIs and duplicate scripts! I hope this tutorial helps you out as well with your next cloud deployment!
