I can run the following from main.tf
inline = [
"sudo /etc/bootstrap.sh --vault-token ${var.certificate} --vault-address ${var.vault_uri} --secret-manager-type vault --vault-skip-verify --force-download-certs --vault-cert-sans ${var.agent_ips[count.index]} --component agent"
]
I have migrated all inline commands to functions in platform-setup.sh script. All work except this one as I’m having difficulty rendering agent_ips[count.index].
locals {
platform_setup = templatefile("${path.module}/files/platform-setup.sh", {
certificate = var.certificate
vault_uri = var.vault_uri
user = var.user
agent_ips = var.agent_ips
}
)
}
inline = [
"set -x",
"bash /home/${var.user}/platform-setup.sh --configure_agent_vault
]
configure_agent_vault () {
sudo /etc/bootstrap.sh --vault-token ${certificate} --vault-address ${vault_uri} --secret-manager-type vault --vault-skip-verify --force-download-certs --component agent --vault-cert-sans {agent_ips[count.index]}
}
1 Like
I think I’m having a similar question; wondering what the “right” approach for this type of thing is:
resource "local_file" "ssh" {
count = 4
content = <<-DOC
#!/bin/bash
exec ssh -o "UserKnownHostsFile /dev/null" -o StrictHostKeyChecking=no ubuntu@${libvirt_domain.workers.${count.index}.network_interface.0.addresses.0}
DOC
filename = "./ssh-worker-${count.index}.sh"
file_permission = "0755"
}
The nested variable doesn’t work. Also I’m interested in nicer ways to arrange convenience for a user to be able to ssh to the newly created VM instances.
Hi @nick.piper,
I think a key thing to notice about your original approach is that, although it may not have been obvious from the way Terraform provisioner configuration is shaped, Terraform was processing the template multiple times with one render for each of the resource instances, and thus a different count.index
value each time.
To get the same effect for your separate templatefile
call, then, will require calling templatefile
once for each index, producing a list of strings containing different versions of the script.
Since you didn’t include the full example of the resource containing that inline
argument I’m going to just assume for the sake of example that you had something like count = length(var.agent_ips)
in that resource, and so continue under that assumption:
locals {
platform_setup_scripts = [
for agent_ip in var.agent_ips : templatefile("${path.module}/files/platform-setup.sh", {
certificate = var.certificate
vault_uri = var.vault_uri
user = var.user
agent_ip = agent_ip
})
]
}
resource "example" "example" {
count = length(var.agent_ips)
# ...
provisioner "remote-exec" {
inline = local.platform_setup_scripts[count.index]
}
}
The above uses a for
expression to call templatefile
once for each element of var.agent_ips
, thus producing a separate rendered result for each element.
Then inside the provisioner configuration we can look up the appropriate rendered script in local.platform_setup_scripts
using count.index
, because the for
expression here guarantees that the indices of the rendered scripts will correlate with the indices of var.agent_ips
.
With all of this said, please note that provisioners are a last resort and so I’d recommend using another mechanism to run this script if there’s a suitable mechanism available for whatever platform you’re using. The features described in Passing data into virtual machines and other compute resources might be appropriate for this situation, if your intent is to have this script run on initial boot.
Thank you for your advice. Excellent, as usual!
I worked around the issue as follows.
locals.tf remains as above
then in main.tf I retained ${var.agent_ips[count.index]}.
inline = [
"set -x",
"bash /home/${var.user}/platform-setup.sh --configure_agent_vault ${var.agent_ips[count.index]}"
]
And in platform-setup.sh:
......
......
configure_agent_vault () {
sudo /etc/bootstrap.sh --vault-token ${certificate} --vault-address ${vault_uri} --secret-manager-type vault --vault-skip-verify --force-download-certs --vault-cert-sans $agent_ips --component agent
}
......
......
while [[ $# -gt 0 ]]; do
option="$1"
case $option in
......
......
--configure_agent_vault)
agent_ips=$2
configure_agent_vault
;;
......
......
esac
shift
done