Data external runs too early - before resource it depends on is actually ready

Hello,

I have an issue in terraform where I’m running a data external that I’m using to connect over SSH to a virtual machine that I’m creating before that:

data "external" "vault_transit_token" {
  program = ["ssh", "-o", "StrictHostKeyChecking=no", "root@${var.vault_transit["ip_address"]}", <<EOF
  sleep 15
  token=$(cat /etc/vault.d/.vault/transit_token)
  jq -n --arg token "$token" '{"token":$token}'
  EOF
  ]
  depends_on = [
        vsphere_virtual_machine.vault_transit
        ]
}

So the data depends on the ‘vault_transit’ vm, so that I make sure it runs afterwards.
The problem that I’m having is that when ssh is running, the VM hasn’t booted properly yet, so I need to wait a little bit still, as I get ‘connection refused’.
Is there a way I could maybe make it retry until it works or delay the task entirely or something to that effect?

Hi @lethargosapatheia,

The external data source isn’t designed to handle this situation itself, but since it runs arbitrary code you could perhaps tell the data source to run a wrapper script which itself tries running this command in a loop, possibly with sleep commands to make it poll politely, and then only exit once the ssh command returns a successful exit code.

Another option would be to configure a provisioner on the vsphere_virtual_machine.vault_transit resource which uses remote-exec to run a do-nothing command over SSH. Terraform only considers a resource to have been fully created once its provisioners are complete, so you can use the provisioner’s built-in support for polling SSH to delay completion of this resource until SSH is available. The data source depends on the VM, and so it won’t be read until after the VM is “complete”.

1 Like

Hi @lethargosapatheia,

You could try using the time_sleep resource to set up a delay.
That would look like the following:

resource "time_sleep" "wait_30_seconds" {
  create_duration = "30s"
  depends_on = [vsphere_virtual_machine.vault_transit]
}

data "external" "vault_transit_token" {
  program = ["ssh", "-o", "StrictHostKeyChecking=no", "root@${var.vault_transit["ip_address"]}", <<EOF
  sleep 15
  token=$(cat /etc/vault.d/.vault/transit_token)
  jq -n --arg token "$token" '{"token":$token}'
  EOF
  ]
  depends_on = [
        time_sleep.wait_30_seconds
        ]
}

Hope this helps!

1 Like