Terraform: Feature request: Delay resource creation

Created on 29 Mar 2018  ยท  13Comments  ยท  Source: hashicorp/terraform

It would be very nice to have an option to delay a creation of resource. I know there is a possibility to use a null resource and a provisioner, but that means that on windows machines we need to have winrm enabled, there are some hardened servers that we cannot enable winrm on.. also, there are some resources that just do not support provisioners, what then? For example, creation time between keyvault and secrets or between a windows ad domain controller that takes 15minutes to boot up and prepare the directory to servers that try to join the domain before its ready and just fail.

Most helpful comment

Let's back up to the original request here then, what are you intending to use to delay a resource? Do you want to execute a script locally, or do you want to delay by some arbitrary amount of time. Either of these can be done with null_resource:

This for example, will wait 10s between creating "before" and "after"

resource "null_resource" "before" {
}

resource "null_resource" "delay" {
  provisioner "local-exec" {
    command = "sleep 10"
  }
  triggers = {
    "before" = "${null_resource.before.id}"
  }
}

resource "null_resource" "after" {
  depends_on = ["null_resource.delay"]
}

All 13 comments

Hi @pixelicous,

The goal of terraform is to usually apply the changes in the most efficient way possible, which almost always includes delaying resource creation until dependencies have been met. Arbitrarily delaying a resource by a fixed duration is only a guess at best, and can still fail when something takes longer than expected, so is not a feature that is likely to be added to every resource. In general it's better to have the provider able to properly detect when resource creation completes.

In the rare case that you need to delay creation, the example is usually to use a null_resource like you mentioned. Can you explain why you need winrm installed on the remote hosts in order to make this work?

@jbardin hey thanks for the info.. As far as i understand the null resource will execute a provisioner with a script to check whatever event that would trigger the null resource creation "completion" which will trigger the resource i actually want to wait. So it happens that there is a bug with how keyvault is creted in azure, the azurem provider was implemented a fix some point at 2015/6 but it doesnt work

Let's back up to the original request here then, what are you intending to use to delay a resource? Do you want to execute a script locally, or do you want to delay by some arbitrary amount of time. Either of these can be done with null_resource:

This for example, will wait 10s between creating "before" and "after"

resource "null_resource" "before" {
}

resource "null_resource" "delay" {
  provisioner "local-exec" {
    command = "sleep 10"
  }
  triggers = {
    "before" = "${null_resource.before.id}"
  }
}

resource "null_resource" "after" {
  depends_on = ["null_resource.delay"]
}

@jbardin I was after something like this, it will work for me

Thanks again for your quick and helpful response, sorry for not responding any sooner, i wasn't available near a PC.

@jbardin took me some time to check it, this crashes on exactly the same issue.
The null_resource cannot find the ID of the keyvault, thus it crashes.
error (names changed):

azurerm_key_vault.keyvault: dial tcp: lookup examplekvname.vault.azure.net: no such host
2018/04/22 17:01:15 [ERROR] root.terraformdep: eval: *terraform.EvalSequence, err: 1 error(s) occurred:

azurerm_key_vault.keyvault: dial tcp: lookupexamplekvname.vault.azure.net: no such host
2018/04/22 17:01:15 [TRACE] [walkApply] Exiting eval tree: module.mymodule.azurerm_key_vault.keyvault

resource "null_resource" "delay" {
  #Due to keyvault issues
  provisioner "local-exec" {
    command     = "Start-Sleep 20"
    interpreter = ["PowerShell", "-Command"]
  }

  triggers = {
    "keyvault" = "${azurerm_key_vault.keyvault.id}"
  }
}

I tried using only azurerm_key_vault.keyvault, but it seems like there is an issue with that.. i get

TYPE.NAME.ATTR in:

${azurerm_key_vault.keyvault}

But i cannot use a variables with 2 parts on a trigger as far as i see.. it is possible to depend on a 2 part resource..

I tried the following adding depends on like so:

resource "null_resource" "delay" {
  depends_on = ["azurerm_key_vault.keyvault"]

  #Due to keyvault issues
  provisioner "local-exec" {
    command     = "Start-Sleep 20"
    interpreter = ["PowerShell", "-Command"]
  }

  /*
  triggers = {
    "keyvault" = "${azurerm_key_vault.keyvault}"
  }*/
}

This also fails sometimes, and at others it succeeds, same issue that is..
Any other suggestions?

by the way, what would be the difference if i work with the trigger or dependency? if i reexecute it seems like both methods would yield the same results.

Hi @pixelicous,

That last example may seem to work intermittently because depends_on only affects the order of operations, it does not cause the null_resource to be re-provisioned each time, which is what triggers is for.

I'm not sure what you mean by "it is possible to depend on a 2 part resource". Can you provide a more complete example?

@jbardin by 2 parts i mean that when we reference a resource using a trigger i must also use an attribute to trigger. for example azurerm_key_vault.keyvault.id if i will try to use azurerm_key_vaut.keyvault as reference in the trigger, it will fail.
Using azurerm_key_vault.keyvault.id is problematic because then it fails on the same problem that im trying to avoid that the keyvault hostname cannot be found

I tried using only azurerm_key_vault.keyvault, but it seems like there is an issue with that.. i get
TYPE.NAME.ATTR in:
${azurerm_key_vault.keyvault}

But i cannot use a variables with 2 parts on a trigger as far as i see.. it is possible to depend on a 2 part resource..

I'll close this as 1.4.0 came out and it solves our issues with the keyvault.

Thanks for your help! :)

Is it possible to convert this to an inbuilt terraform resource? There are a lot of asynchonous resources other than EC2 instances(for Example: network interfaces) that are created and this feature would help to accomplish automating them.

Something like

resource "delay_resource" "delay1" {
delay_period = 10.0
input = "${resource_pre.id}"
}

and it can output a dummy delay.complete flag that can be passed to another resource

This way it can be OS independent rather than using the local-exec provisioner

In the short term (before a delay/cross platform approach), does something like the following work?

resource "google_service_account" "kubernetes" {
  provider = google-beta

  account_id   = "kubernetes"
  display_name = "Kubernetes Service Account"
  description = "Service Account for Kubernetes cluster(s)"

  # Service account creation is eventually consistent, so add a delay.
  provisioner "local-exec" {
    command = "sleep 5"
  }
}

The null_resource approach above makes sense, but as far as I can tell, requires each downstream thing using the service account (in my example) to also depend on the null_resource. The above worked for me, but it triggered a few other updates, so not certain if the race just happened to work.

I'm going to lock this issue because it has been closed for _30 days_ โณ. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

Was this page helpful?
0 / 5 - 0 ratings