Search code examples
stringazureterraform

terraform formatdate and timestamp constant updates


I have the following code on one of the properties of a azurerm_resource (:

formatdate("YYYY-MM", timestamp())

naturally one would think this would only update the resource once a month, but it keeps updating to the same value every run. any pointers?

terraform: 1.5.7
azapi provider: v1.13.1
azurerm provider: v3.88.0

i have the exact same behaviour with azurerm provider

EDIT: plan snippet:

# module.foundation.azapi_resource.windows_vm_runcommands["xyz"] will be updated in-place
  ~ resource "azapi_resource" "windows_vm_runcommands" {
      ~ body                      = (sensitive value) << happens here
        id                        = "xyz"
        name                      = "abc"
      ~ output                    = jsonencode({}) -> (known after apply)
      ~ tags                      = {} -> (known after apply)
        # (7 unchanged attributes hidden)
    }

for azurerm:

enter image description here


Solution

  • The timestamp function returns the time when the plan is applied, so during the planning phase Terraform doesn't yet know what its final value would be. Therefore it must conservatively assume that it could be a different month by the time you apply the plan.

    You haven't stated what your underlying goal is, so it's hard to make recommendations for alternatives. However, the following are two potential alternatives that might fit your situation. You'll need to consider each one yourself to see if it fits.


    The hashicorp/time provider has a resource type time_rotating which is designed to propose to recreate itself after a given amount of time has passed.

    You can define a resource that will be planned for recreation after one month using a declaration like the following:

    resource "time_rotating" "monthly" {
      rotation_months = 1
    }
    

    You can then derive a YYYY-MM string from this resource using an expression like this:

    format(
      "%04d-%02d",
      time_rotating.monthly.year,
      time_rotating.monthly.month,
    )
    

    This expression will produce a YYYY-MM string that changes every month.

    However, it will only change after one month has passed from the time that time_rotating.monthly was created. If that resource was created on the 15th of April 2024 then the string would remain as 2024-04 until the 15th of May.


    Terraform also offers the plantimestamp function, which is similar to timestamp except that it captures the time that the plan was created, rather than the time the plan was applied. Therefore Terraform can know the result of it during the planning phase and doesn't need to wait until the apply phase to decide.

    formatdate("YYYY-MM", plantimestamp())
    

    This approach means that if you create your plan on the last day of April 2024 but apply it on the first day of May then the applied result will be 2024-04, because that was when the plan was created.

    The above can also potentially cause problems if you create a "refresh-only plan" (using the -refresh-only option): in that case the result of these functions would change but Terraform would not actually be able to change the resource to reflect it. I think that's probably fine with the way you've written your configuration -- you're not using this result anywhere except the configuration for this one resource -- but I mention it just because other people with slightly different goals are likely to find this answer in future.