Search code examples
terraform

When using depends_on, will terraform wait for the entire dependency tree or only explicit dependencies?


A simple question about the inner workings of Terraform, for which I could not find documentation.

Assume the following:

  • I create resource B with Terraform.
  • I then modify my code to also declare resources A and C.
    • There is no inherent dependency between these resources
  • I use depends_on to declare that B depends on A, and C depends on B
  • I invoke terraform apply

One of two things is going to happen:

  • Since B already exists, the dependency for C is fulfilled. A and C are created in parallel.
  • Since B depends on A, and C depends on B, Terraform knows that C depends on A transitively. It creates A first and only after this is done moves on to create C.

But which of the two is it? Both seem reasonable.


Solution

  • Interesting question. I created a small PoC to see what happens.

    Creating resource B

    resource "null_resource" "b" {
      triggers = {
        description = "Resource B"
      }
    }
    

    Output of terraform apply:

    Terraform used the selected providers to generate the following execution
    plan. Resource actions are indicated with the following symbols:
      + create
    
    Terraform will perform the following actions:
    
      # null_resource.b will be created
      + resource "null_resource" "b" {
          + id       = (known after apply)
          + triggers = {
              + "description" = "Resource B"
            }
        }
    
    Plan: 1 to add, 0 to change, 0 to destroy.
    null_resource.b: Creating...
    null_resource.b: Creation complete after 0s [id=1123007074489954098]
    
    Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
    

    Adding resources A and C

    resource "null_resource" "b" {
      triggers = {
        description = "Resource B"
      }
    
      depends_on = [ null_resource.a ]
    }
    
    resource "null_resource" "a" {
      triggers = {
        description = "Resource A"
      }
    
      provisioner "local-exec" {
        command     = "Start-Sleep 60"
        interpreter = ["PowerShell", "-Command"]
      }
    }
    
    resource "null_resource" "c" {
      triggers = {
        description = "Resource C"
      }
    
      provisioner "local-exec" {
        command     = "Start-Sleep 60"
        interpreter = ["PowerShell", "-Command"]
      }
    
      depends_on = [ null_resource.b ]
    }
    

    Output of terraform apply:

    null_resource.b: Refreshing state... [id=5916431791595061011]
    
    Terraform used the selected providers to generate the following execution
    plan. Resource actions are indicated with the following symbols:
      + create
    
    Terraform will perform the following actions:
    
      # null_resource.a will be created
      + resource "null_resource" "a" {
          + id       = (known after apply)
          + triggers = {
              + "description" = "Resource A"
            }
        }
    
      # null_resource.c will be created
      + resource "null_resource" "c" {
          + id       = (known after apply)
          + triggers = {
              + "description" = "Resource C"
            }
        }
    
    Plan: 2 to add, 0 to change, 0 to destroy.
    null_resource.a: Creating...
    null_resource.a: Provisioning with 'local-exec'...
    null_resource.a (local-exec): Executing: ["PowerShell" "-Command" "Start-Sleep 60"]
    null_resource.a: Still creating... [10s elapsed]
    null_resource.a: Still creating... [20s elapsed]
    null_resource.a: Still creating... [30s elapsed]
    null_resource.a: Still creating... [40s elapsed]
    null_resource.a: Still creating... [50s elapsed]
    null_resource.a: Still creating... [1m0s elapsed]
    null_resource.a: Creation complete after 1m1s [id=6341824471776991203]
    null_resource.c: Creating...
    null_resource.c: Provisioning with 'local-exec'...
    null_resource.c (local-exec): Executing: ["PowerShell" "-Command" "Start-Sleep 60"]
    null_resource.c: Still creating... [10s elapsed]
    null_resource.c: Still creating... [20s elapsed]
    null_resource.c: Still creating... [30s elapsed]
    null_resource.c: Still creating... [40s elapsed]
    null_resource.c: Still creating... [50s elapsed]
    null_resource.c: Still creating... [1m0s elapsed]
    null_resource.c: Creation complete after 1m0s [id=8942321372455105138]
    
    Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
    

    As we can see from the logs, resources A and C are not created in parallel.

    So the right answer seems to be:

    Since B depends on A, and C depends on B, Terraform knows that C depends on A transitively. It creates A first and only after this is done moves on to create C.

    Note: