Null_resource is always replaced even if triggers don't change

Hi,

I’m trying to upload an archive when it changes.

In the configuration below:
The “null_resource.server_build” generates a build.
The “data.archive_file.server_bundle” makes an archive of the build output directory.
The “null_resource.server_bundle_upload” uploads the archive.

My problem is that the “null_resource.server_bundle_upload” is always triggered.

Does anyone have an idea of what’s wrong?

resource null_resource server_build {
  triggers = {
    timestamp = timestamp()
  }

  provisioner local-exec {
    working_dir = "server"
    command     = "node build-server"
  }
}

data archive_file server_bundle {
  depends_on = [
    local_file.server_env,
    null_resource.server_build
  ]

  type        = "zip"
  source_dir  = "${path.module}/../server/build"
  output_path = "${path.module}/${local.serverBundleFileName}"
}

resource null_resource server_bundle_upload {
  triggers = {
    server_bundle_hash = data.archive_file.server_bundle.output_base64sha256
  }

  connection {
    (...)
  }

  provisioner file {
    source      = data.archive_file.server_bundle.output_path
    destination = "/tmp/${local.serverBundleFileName}"
  }

  provisioner remote-exec {
    (...)
  }
}

Hi @Tolgor,

Because you’ve used depends_on in your data "archive_file" "server_bundle" block, Terraform must always wait until the apply step to read it, and thus data.archive_file.server_bundle.output_base64sha256 will always be unknown during planning and cause Terraform to plan to replace null_resource.server_bundle_upload.

It looks like this configuration can never converge anyway, because null_resource.server_build has timestamp() in its triggers and so will get a new value every second. It seems like you’re trying to use Terraform for an unusual use case that it isn’t really intended for here: Terraform is designed to describe long-lived objects that are occasionally replaced, not to produce new artifacts on every run.


In order to allow data.archive_file.server_bundle to be handled during planning you’ll need to remove the depends_on argument and find some other way to describe these dependencies. For example, you could put the source_dir and output_path values in the null_resource.server_build triggers and refer to them:

resource "null_resource" "server_build" {
  triggers = {
    timestamp        = timestamp()
    source_dir       = "${path.module}/../server/build"
    output_path      = "${path.module}/${local.serverBundleFileName}"
    server_env_file  = local_file.server_env.filename
  }

  provisioner "local-exec" {
    working_dir = "server"
    command     = "node build-server"
  }
}

data "archive_file" "server_bundle" {
  type        = "zip"
  source_dir  = null_resource.server_build.triggers.source_dir
  output_path = null_resource.server_build.triggers.output_path
}

resource "null_resource" "server_bundle_upload" {
  triggers = {
    server_bundle_hash = data.archive_file.server_bundle.output_base64sha256
  }

  # ... etc
}

Unfortunately I think the above will still run into a problem on the first run of Terraform because Terraform will try to read the data.archive_file.server_bundle before the null_resource.server_build has been created for the first time. You might need to bootstrap it by first running terraform apply -target=null_resource.server_build.

In the long run it’d probably be better to deal with this build set via some other program outside of Terraform, and then use Terraform to make use of this bundle in whatever way makes sense. Terraform is not designed to be an artifact building tool.

@apparentlymart,

I’m pretty new to Terraform.
That can be the explanation of my “out of Terraform scope” attempt.

I won’t fight against the system and will had a custom script to build, bundle and upload the artifact after a terraform apply. (that local_file.server_env.filename file, produced by a terraform apply, must be up-to-date and bundled in my artifact)

Anyway, thanks a lot for your quick answer!
I’ll try to stop doing weird stuff with Terraform :slight_smile: