2

I want to perform the exec operation only once per hour. Meaning, if it's now 12 then don't exec again until it's 13 o'clock.

The timestamp in combination with the fomatdate will result in timestamps that only differ every hour.

resource "null_resource" "helm_login" {
  triggers = {
    hour = formatdate("YYYYMMDDhh", timestamp())
  }
  provisioner "local-exec" {
    command = <<-EOF
      az acr login -n ${var.helm_chart_acr_fqdn} -t -o tsv --query accessToken \
        | helm registry login ${var.helm_chart_acr_fqdn} \
          -u "00000000-0000-0000-0000-000000000000" \
          --password-stdin
    EOF
  }

The problem is that terraform reports that this value will be only known after appy and always wants to recreate the resource.

  # module.k8s.null_resource.helm_login must be replaced
-/+ resource "null_resource" "helm_login" {
      ~ id       = "4503742218368236410" -> (known after apply)
      ~ triggers = {
          - "hour" = "2021112010"
        } -> (known after apply) # forces replacement
    }

I have observed similar issues where values are fetched from data and passed to resources on creation, forcing me to not use those data values but hard code them.

The Fool
  • 16,715
  • 5
  • 52
  • 86
  • I guess that the problem relis on the `trigger`. Do docs says `The triggers argument allows specifying an arbitrary set of values that, when changed, will cause the resource to be replaced.` – Felipe Nov 20 '21 at 12:02
  • "I want to perform the exec operation only once per hour." It is unclear what you mean by this, and also how the `timestamp()` function would help achieve this. Please add more details to the question. – Matthew Schuchard Nov 20 '21 at 12:10
  • If the timestamp hasnt changed then dont exec. Thats why its formatted to be only different if its a new hour. Problem is that terraform doesnt evualate this first and then determines if the trigger value is different or not. – The Fool Nov 20 '21 at 12:17
  • That precise problem is what I mentioned in terms of taking values from data. Even if the data brings each time the exact same value. Terraform wants to recreate certain resources because it's saying this is only known after apply. It's kind of silly that it works that way. What's the point of taking it from data if you can do it only once, when you don't want to recreate resources constantly. – The Fool Nov 20 '21 at 12:26
  • 1
    Let's clarify that "exec operation only once per hour" terraform is not a scheduler, this code could trigger the execution at 8:59 and again at 9:01 ... if you need this to run hourly you need some other tool – Helder Sepulveda Nov 20 '21 at 17:30
  • I mean that if you run this 10 times (using terrafrom apply) within the hour, the exec will only trigger once. I was thinking this is clear. Sorry if its not. – The Fool Nov 20 '21 at 17:31
  • And yes, it can happen that it triggers 2 times 1 minute apart as you describe, I am aware of that. Its kind of obvious, at least in my mind. You may also notice that's its only a login, so probably fine. I still dont want to login every single time, if I dont have to. – The Fool Nov 20 '21 at 17:34
  • You could rephrase it and say "once per full hour ony the clock" if it makes you feel more comfortable. Looking at your answer, you understood perfectly well what I want to achieve. – The Fool Nov 20 '21 at 17:37
  • My clarification was to address the comment from Matt, on my answer I only focus on a workaround to the `(known after apply) # forces replacement` – Helder Sepulveda Nov 20 '21 at 17:50
  • It looks like you're trying to refresh your auth but Terraform probably isn't the best place to do this. I would take this back to the pipeline and ensure that it is handling auth and passing any tokens in as env vars if the provider supports it or directly as a sensitive Terraform variable. I realise that's not the question here. If you really wanted to handle tasks hourly from within Terraform and you didn't need the outputs to be accessibly within Terraform, I would create a cloud function and cron trigger (depending on cloud env). I know that doesn't fit this use case though. – Jake Nelson Nov 21 '21 at 04:16

1 Answers1

2

As you just find out terraform evaluates the timestamp function at runtime,
that is why we see the: (known after apply) # forces replacement

But we can do something about that to meet your goal, we can pass the hour as a parameter:

variable "hour" {
  type = number
}

resource "null_resource" "test" {
  triggers = {
    hour = var.hour
  }
  provisioner "local-exec" {
    command = "echo 'test'"
  }
}

Then to call terraform we do:
hour=$(date +%G%m%d%H); sudo terraform apply -var="hour=$hour"


First run:

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.test will be created
  + resource "null_resource" "test" {
      + id       = (known after apply)
      + triggers = {
          + "hour" = "2021112011"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

null_resource.test: Creating...
null_resource.test: Provisioning with 'local-exec'...
null_resource.test (local-exec): Executing: ["/bin/sh" "-c" "echo 'test'"]
null_resource.test (local-exec): test
null_resource.test: Creation complete after 0s [id=6793564729560967989]

Second run:

null_resource.test: Refreshing state... [id=6793564729560967989]

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
Helder Sepulveda
  • 15,500
  • 4
  • 29
  • 56
  • It's not really nice to do it this way, to be honest. I had the idea already myself but thought it was ugly and cumbersome. I think it's a flaw in terraforms design. In this case, you may get away with hard coding it. But as mentioned, when you take this stuff from data, it gets really annoying. Even though this wasn't my question. – The Fool Nov 20 '21 at 16:47
  • 1
    Certainly not a flaw, this is the intended design ... hardcoding will certainly not trigger anything every hour ... and if you have issues with a specific data resource open a new question – Helder Sepulveda Nov 20 '21 at 17:25
  • You pretty much hard code it here. Except, you inject the hard coded value from outside. It's not a dynamically generated value within the boundaries of terraform. You don't think it's flawed if a value evaluates 2 times to the same result that terraform goes ahead and recreates a resource? It's precisely not doing what it is promising At that moment. *Trigger only if value has changed.* – The Fool Nov 20 '21 at 17:29
  • Issue is not with specific data resource. Its with all data resources. As soon as you use their values as input for another thing you get the exact same behavior as in this examply. "only known after apply". – The Fool Nov 20 '21 at 17:38
  • absolutely not, I use data resources all the time and that is not the behavior – Helder Sepulveda Nov 20 '21 at 17:40
  • Why is it the behaviour here then? Isnt it inconsistent in that case? – The Fool Nov 20 '21 at 17:41
  • the behavior is here because timestamp function is evaluated at runtime – Helder Sepulveda Nov 20 '21 at 17:42
  • When is data evaluated then? – The Fool Nov 20 '21 at 17:43
  • It depends what data resource is used, can you provide an example – Helder Sepulveda Nov 20 '21 at 17:44
  • you are right that not all data sources do this. I cannot give an example because I have changed to code that made it happen. I cannot remember any more in what context it was happening, but it felt as flawed as in this question. The data would bring the same value each time. The same way, the formatted timestamp is the same value within the hour. – The Fool Nov 20 '21 at 17:54
  • 1
    if the value it brings is known at runtime we will see this same behavior, same applies to functions, resources or data ... this answer to another question here might shed some light, it's from Martin Atkins he is one of the developers on the terraform project: https://stackoverflow.com/a/67063790/7599833 – Helder Sepulveda Nov 20 '21 at 18:05