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 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 additional 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 that referenced the other.
In a simplified example say I have the following 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.sh
depending ondeps.sh
deps.sh
is not called directly but instead just put in its expected path with the correct permissions- The content for the
deps.sh
has to bebase64encoded
due to the line indents required by the pipe
Then all that’s needed when to referencing 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!