terraform-provider-time icon indicating copy to clipboard operation
terraform-provider-time copied to clipboard

time_rotating constantly re-creates resource after rfc3339 + rotation_xy has passed the first time.

Open m273d15 opened this issue 3 years ago • 9 comments

Community Note

  • Please vote on this issue by adding a 👍 reaction to the original issue to help the community and maintainers prioritize this request
  • Please do not leave "+1" or other comments that do not add relevant new information or questions, they generate extra noise for issue followers and do not help prioritize the request
  • If you are interested in working on this issue or have submitted a pull request, please leave a comment

Terraform Version

Terraform v0.15.4
on darwin_amd64
+ provider registry.terraform.io/hashicorp/time v0.7.1

Affected Resource(s)

  • time_rotating

Terraform Configuration Files

resource "time_rotating" "test" {
  rfc3339          = "2021-06-20T12:43:13Z"
  rotation_minutes = 7
}

Debug Output

Output
> terraform apply -auto-approve
time_rotating.test: Refreshing state... [id=2021-06-20T12:43:13Z]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of
Terraform since the last "terraform apply":

  # time_rotating.test has been deleted
  - resource "time_rotating" "test" {
      - day              = 20 -> null
      - hour             = 12 -> null
      - id               = "2021-06-20T12:43:13Z" -> null
      - minute           = 43 -> null
      - month            = 6 -> null
      - rfc3339          = "2021-06-20T12:43:13Z" -> null
      - rotation_minutes = 7 -> null
      - rotation_rfc3339 = "2021-06-20T12:50:13Z" -> null
      - second           = 13 -> null
      - unix             = 1624192993 -> null
      - year             = 2021 -> null
    }

Unless you have made equivalent changes to your
configuration, or ignored the relevant attributes using
ignore_changes, the following plan may include actions to
undo or respond to these changes.

──────────────────────────────────────────────────────────

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:

  # time_rotating.test will be created
  + resource "time_rotating" "test" {
      + day              = (known after apply)
      + hour             = (known after apply)
      + id               = (known after apply)
      + minute           = (known after apply)
      + month            = (known after apply)
      + rfc3339          = "2021-06-20T12:43:13Z"
      + rotation_minutes = 7
      + rotation_rfc3339 = (known after apply)
      + second           = (known after apply)
      + unix             = (known after apply)
      + year             = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.
time_rotating.test: Creating...
time_rotating.test: Creation complete after 0s [id=2021-06-20T12:43:13Z]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Panic Output

Expected Behavior

  • The resource is created after the first call of terraform apply and not created again before the date rfc3339 + rotation_minutes (in the example above: 2021-06-20T12:50:13Z) has passed.
  • After the date has passed the next call of terraform apply will re-create the resource. If I call terraform apply again the resource should not be re-created as long as the current date is lower than the next rotation date (would be rfc3339 + rotation_minutes * 2)

short:

  • tf init
  • tf apply -> initial create
  • tf apply -> nop
  • tf apply -> nop
  • time has passed rfc3339 + rotation_minutes
  • tf apply -> re-create resource
  • tf apply -> nop
  • time has passed rfc3339 + rotation_minutes * 2
  • tf apply -> re-create resource
  • tf apply -> nop ...

Actual Behavior

  • As expected: The resource is created after the first call of terraform apply and not created again before the date rfc3339 + rotation_minutes (in the example above: 2021-06-20T12:50:13Z) has passed.
  • After the date has passed each call of terraform apply leads to the re-creation of the resource.

short:

  • tf init
  • tf apply -> initial create
  • tf apply -> nop
  • tf apply -> nop
  • time has passed rfc3339 + rotation_minutes
  • tf apply -> re-create resource
  • tf apply -> re-create resource
  • tf apply -> re-create resource
  • tf apply -> re-create resource ...

Steps to Reproduce

With the example above it should be enough to call:

  1. terraform init
  2. terraform apply - initial creation
  3. terraform apply - re-creation

Important Factoids

References

  • #0000

Thank you for your work on Terraform ❤️

m273d15 avatar Jun 28 '21 13:06 m273d15

Can someone confirm this issue? Is this a bug or a lack of documentation? It does work as expected without the rfc3339.

m273d15 avatar Jul 21 '21 07:07 m273d15

I'm experiencing this issue too.

My assumption was that the rfc3339 argument was setting the initial time for calculating the rotation time, after which the rotation_X argument would become the increment and the resource would be recreated every N rotation_X's time.

I can't see how the actual behaviour is useful.

carldjohnston avatar Aug 06 '21 02:08 carldjohnston

This really needs to be fixed. I think what needs to happen is that the provider should compare the id to rotation_rfc3339 and not rotate if it's past it.

davidcorrigan714 avatar Jan 23 '23 15:01 davidcorrigan714

At the moment the time_rotating doesn't work like a clock. "if timestamp()>rotation_rfc3339 then delete the resource" and then terraform says "the resource does not exist - create from code" and the provider says simply "rotation_rfc3339 = rfc3339 + rot_X rotation interval "

The rotation_rfc3339 calculation is too simple and with a fixed rfc3339 ends up constantly in the past, resulting in the Delete -> create identically on every Apply to infinity. Why not have some clock arithmetic, it could be a switch like clock_rotating = true

To illustrate what we want, I think,

if rfc3339 input is not null, if rfc3339 input in the past, we want this:

    v rfc3339                                   v id             v rotation_rfc3339
    |             |             |               |         x      |
                  ^+1rot_X      ^+2rot_X       ^+Nrot_X   ^timestamp()

if rfc3339 input in the future, we want this:

                      v id
                      v rfc3339     v rotation_rfc3339
|         x           |             |                    |
          ^timestamp()              ^+1rot_X

So could it be coded like this?

if (rfc3339 input)
  rfc3339 = rfc3339 input 
  if (rfc3339 in the past)
    id = timestamp() minus ( (timestamp() - rfc3339) MOD rot_X )
  else
    ' rfc3339 in the future
    id = rfc3339
  fi
else
  ' no rfc3339 input, use timestamp()
  rfc3339 = timestamp()
  id = rfc3339
fi
rotation_rfc3339 = id + rot_X

mikew3432 avatar Feb 02 '23 04:02 mikew3432

Why has this issue has not been fixed since Jun 28, 2021? How else can one create a rotating timestamp starting say 15 days from now to rotate every 30 days?

rfc3339 should be the base timestamp. It should only be used to start the rotation from.

pkeecom avatar May 02 '23 11:05 pkeecom

BTW, I also ran into this bug...

The workaround requires that the rfc3339 is not defined and for the time_rotating when defining the resource. Instead seed the resource with the desired time via import.

Example command to obtain timestamps:

  • gdate -u +%Y-%m-%dT%H:%M:%SZ - current time
  • gdate -u +%Y-%m-%dT%H:%M:%SZ --date="+12 hours" - 12 hours in the future

Example import command 12 hours in the future w/ daily rotation:

terraform import time_rotating.example_daily "$(gdate -u +%Y-%m-%dT%H:%M:%SZ --date="+12 hours"),,,1,,"

Looks like https://github.com/hashicorp/terraform-provider-time/pull/180 would resolve this issue.

faultymonk avatar May 04 '23 22:05 faultymonk

Hi @m273d15 thanks for raising this issue, fixing this issue requires a significant rewrite in the resource's logic and will result in a breaking change for practitioners. We will consider this issue as part of a larger effort for a Time Provider major release in the future but we do not have a timeline for this at the moment.

SBGoods avatar Jun 13 '23 13:06 SBGoods

I think another workaround is to only set rfc3339 on creation and then leave it null going forward. Seemed to work for me:

resource "time_static" "first_run_timestamp" {
  rfc3339 = plantimestamp()

  lifecycle {
    ignore_changes = [ rfc3339 ]
  }
}


resource "time_rotating" "test" {
  rfc3339 = time_static.first_run_timestamp.rfc3339 == plantimestamp() ? timeadd(plantimestamp(), "-5m") : null
  rotation_minutes = 10
}

Unfortunately time_static seems to have similar issues where when you set rfc3339 it will perpetually recreate it, which is why I ignore that attribute after creation.

Mike-Nahmias avatar Nov 22 '23 21:11 Mike-Nahmias

Just commenting to say I found this after encountering the same issue those have described above - this resource is pointless if it doesn't maintain a constantly rotating time. At the moment, after the rotation period has elapsed the resource behaves like timestamp()!

james-woodbridge avatar Sep 06 '24 17:09 james-woodbridge