patternterraformMinor
Can you inherit a template_cloudinit_config in another template_cloudinit_config object in Terraform?
Viewed 0 times
canyoutemplate_cloudinit_configanotherinheritobjectterraform
Problem
I recently discovered
Then I'd like to declare a 2nd
That way from a compute perspective, I could easily create specialized instances that have custom scripts applied to them, but still inherit a number of basic configurations. I know I could make this work with remote-exec provisioners, but I am trying to avoid them since Terraform says they should be used as a last resort.
template_cloudinit_config within Terraform, and I'm hoping I can utilize it to specify something like the code below. Basically my goal is to declare a core template_cloudinit_config that contains a number of shell scripts that should get run on every machine.Then I'd like to declare a 2nd
template_cloudinit_config that, without duplicating code, lets me essentially inherit the core set of scripts that should get applied to every instance AND define an additional script to run.That way from a compute perspective, I could easily create specialized instances that have custom scripts applied to them, but still inherit a number of basic configurations. I know I could make this work with remote-exec provisioners, but I am trying to avoid them since Terraform says they should be used as a last resort.
data "template_cloudinit_config" "core_config" {
part {
content_type = "text/x-shellscript"
content = file("scripts/core_script1.sh")
}
part {
content_type = "text/x-shellscript"
content = file("scripts/core_script2.sh")
}
}
data "template_cloudinit_config" "custom_config" {
part {
content = "${data.template_cloudinit_config.core_config.rendered}"
}
part {
content_type = "text/x-shellscript"
content = file("scripts/custom_script.sh")
}
}
resource "aws_instance" "vm1" {
instance_type = "t2.small"
ami = data.aws_ami.ubuntu_ami.image_id
# Other variables that declare subnet, key, etc
user_data = "${data.template_cloudinit_config.core_config.rendered}"
}
resource "aws_instance" "vm2" {
instance_type = "t2.small"
ami = data.aws_ami.ubuntu_ami.image_id
# Other variables that declare subnet, key, etc
user_data = "${data.template_cloudinit_config.custom_config.rendered}"
}Solution
The
However, a different way to frame your problem is of constructing a sequence of part objects in a local value and then passing them all together to the
The above is using
Note: the
cloudinit provider only knows how to encode multipart MIME documents to pass to cloud init; there is no mechanism for parsing to modify and then re-encode.However, a different way to frame your problem is of constructing a sequence of part objects in a local value and then passing them all together to the
cloudinit_config data source, like this:locals {
core_config = tolist([
{
content_type = "text/x-shellscript"
content = file("${path.module}/scripts/core_script1.sh")
},
{
content_type = "text/x-shellscript"
content = file("${path.module}/scripts/core_script2.sh")
},
])
custom_config = tolist([
{
content_type = "text/x-shellscript"
content = file("${path.module}/scripts/custom_script.sh")
},
])
}
data "cloudinit_config" "core" {
dynamic "part" {
for_each = local.core_config
content {
content_type = part.value.content_type
content = part.value.content
}
}
}
data "cloudinit_config" "custom" {
dynamic "part" {
for_each = concat(
local.core_config,
local.custom_config,
)
content {
content_type = part.value.content_type
content = part.value.content
}
}
}
resource "aws_instance" "vm1" {
instance_type = "t2.small"
ami = data.aws_ami.ubuntu_ami.image_id
# ...
user_data = data.cloudinit_config.core.rendered
}
resource "aws_instance" "vm2" {
instance_type = "t2.small"
ami = data.aws_ami.ubuntu_ami.image_id
# ...
user_data = data.cloudinit_config.custom.rendered
}The above is using
dynamic blocks to generate a dynamic number of part blocks based on the number of elements in a list, which means you can focus on making sure the lists have the necessary items, using whatever dynamic expressions you need to decide that, and have Terraform project that into zero or more part blocks automatically.Note: the
hashicorp/template provider has been deprecated and continues to be available only for backward-compatibility. For that reason, I wrote the above to use the hashicorp/cloudinit provider instead. Its cloudinit_config data source is based on what was formerly template_cloudinit_config.Code Snippets
locals {
core_config = tolist([
{
content_type = "text/x-shellscript"
content = file("${path.module}/scripts/core_script1.sh")
},
{
content_type = "text/x-shellscript"
content = file("${path.module}/scripts/core_script2.sh")
},
])
custom_config = tolist([
{
content_type = "text/x-shellscript"
content = file("${path.module}/scripts/custom_script.sh")
},
])
}
data "cloudinit_config" "core" {
dynamic "part" {
for_each = local.core_config
content {
content_type = part.value.content_type
content = part.value.content
}
}
}
data "cloudinit_config" "custom" {
dynamic "part" {
for_each = concat(
local.core_config,
local.custom_config,
)
content {
content_type = part.value.content_type
content = part.value.content
}
}
}
resource "aws_instance" "vm1" {
instance_type = "t2.small"
ami = data.aws_ami.ubuntu_ami.image_id
# ...
user_data = data.cloudinit_config.core.rendered
}
resource "aws_instance" "vm2" {
instance_type = "t2.small"
ami = data.aws_ami.ubuntu_ami.image_id
# ...
user_data = data.cloudinit_config.custom.rendered
}Context
StackExchange DevOps Q#12819, answer score: 2
Revisions (0)
No revisions yet.