Automatic compute rebuild - every hour

Hello,

Im looking to create gcp compute instance via terraform. I have a requirement that I need to rebuild that compute every week. So thought of having a lifecycle block with replaced_triggered_by in the resource section for the automatic rebuild ( anyhow I need to run terraform apply via cron or Cloud scheduler)

For testing purpose, instead of weekly rebuild, i planned for hourly rebuild in my code.

main.tf

resource “null_resource” “trigger1” {
triggers = {
rebuild_time = local.trigger_value
}
}

resource “google_compute_instance” “ml_instance” {
count = var.enable_rebuild_value ? 1 : 0

name = “ml-instance”
machine_type = “n4-standard-2”
zone = “europe-north2-a”

boot_disk {
initialize_params {
image = “debian-cloud/debian-11”
}
}

network_interface {
network = “default”
access_config {}
}

lifecycle {
replace_triggered_by = [null_resource.trigger1.id]
}
}

local.tf

locals {
now = timestamp()
current_hour = tonumber(formatdate(“HH”, local.now))
current_day = formatdate(“YYYY-MM-DD”, local.now)

trigger_value = (var.enable_frequency_value == “hour” ? local.current_hour :
var.enable_frequency_value == “day” ? local.current_day : null)
}

variables.tf

variable “project_id” {}
variable “credentials_file” {}
variable “region” {}
variable “zone1” {}
variable “enable_rebuild_value” {
type = bool
default = true
}

variable “enable_frequency_value” {
type = string
default = “hour”
}

But problem is whenever I run terraform plan within the same hour, terraform plan shows always rebuild. How to solve this issue? Please help me on the issue.

Hi @helannivas,

The simplest example of rotating a resource would look something like so, which may answer your question:

resource "time_rotating" "replace_instance" {
  rotation_hours = 1
}

resource "google_compute_instance" "ml_instance" {
...
  lifecycle {
    replace_triggered_by = [time_rotating.replace_instance]
  }
}

If you do need to compute something more specific in your configuration, it would help to format it so that others can easily, read, copy, and paste the example verbatim.

Thank you @jbardin for your response.

As you have suggested, I have used time rotating , but still the resource is not trying to destroy and create it. Its seems the new value gets added after 5 minutes ( i.e. after I run terraform plan/apply ). Below is the code and terraform plan. Please let me know if Im doing anything wrong here. Thanks

resource “time_rotating” “trigger” {
rotation_minutes = 5
}

resource “google_compute_instance” “ml_instance” {

name = “ml-instance”
machine_type = “n4-standard-2”
zone = “europe-north2-a”

boot_disk {
initialize_params {
image = “debian-cloud/debian-11”
}
}

network_interface {
network = “default”
access_config {}
}

lifecycle {
replace_triggered_by = [time_rotating.trigger.id]
}
}

Terraform plan

PS C:\Terraform\gcp-ml-terraform> terraform plan
time_rotating.trigger: Refreshing state… [id=2025-08-21T21:22:37Z]
google_compute_instance.ml_instance: Refreshing state… [id=projects/gke-learning-468906/zones/europe-north2-a/instances/ml-instance]

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.trigger will be created

  • resource “time_rotating” “trigger” {
    • day = (known after apply)
    • hour = (known after apply)
    • id = (known after apply)
    • minute = (known after apply)
    • month = (known after apply)
    • rfc3339 = (known after apply)
    • rotation_minutes = 5
    • 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.

I tried additional resource (time_static) and it worked. Thank you for your assistance

resource “time_rotating” “trigger” {
rotation_minutes = 5
}

resource “time_static” “trigger” {
rfc3339 = time_rotating.trigger.rfc3339
}

resource “google_compute_instance” “ml_instance” {

name = “ml-instance”
machine_type = “n4-standard-2”
zone = “europe-north2-a”

boot_disk {
initialize_params {
image = “debian-cloud/debian-11”
}
}

network_interface {
network = “default”
access_config {}
}

lifecycle {
replace_triggered_by = [time_static.trigger]
}
}

Hi @jbardin

I have got a strange requriement with this automatic rebuild. Yes, above code works fine for my requirement and one more additonal requirement is that we dont have perform rebuild everytime and its based on the parameter which are passing. So I have modified the script as per below , but nothings helps for me.

resource "time_rotating" "trigger" {
  count            = var.enable_lifecycle ? 1 : 0
  rotation_minutes = 5 #var.enable_lifecycle ? var.rotation_minutes : 99999999
}

resource "time_static" "trigger" {
  #count = var.enable_lifecycle ? 1 : 0
  rfc3339 = one(time_rotating.trigger[*].rfc3339)

}

resource "google_compute_instance" "ml_instance" {

  name         = "ml-instance"
  machine_type = "n4-standard-2"
  zone         = "europe-north2-a"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-11"
    }
  }

  network_interface {
    network = "default"
    access_config {}
  }


  lifecycle {
     replace_triggered_by = var.enable_lifecycle ? [time_static.trigger.id] : []
  }
}

It throws me an invalid expression error

PS C:\Terraform\gcp-ml-terraform> terraform plan
╷
│ Error: Invalid expression
│
│   on main.tf line 31, in resource "google_compute_instance" "ml_instance":
│   31:      replace_triggered_by = var.enable_lifecycle ? [time_static.trigger.id] : []
│
│ A static list expression is required.

I need this lifecycle to be executed when my enable_lifecycle variable is true. If it is provided as false , this lifecycle should be avoided and no rebuild should happen.

Any thoughts about this would be really helpful for me to sort this out? Thank you

Sorry, it does seem that the time_rotate resource behaves a bit strangely by simply disappearing when it needs to rotate, so it doesn’t present a change to trigger the replacement directly.

Changing the count of the resource won’t work here, because that would cause the resource to be destroyed or created defeating the purpose of trying to suppress the change. What we can do is use the fact that the replaced time_rotate will have unknown attributes to trigger a change in the plan. This will only work with recent versions of Terraform which allow boolean short-circuiting of the expression to avoid always seeing the value as unknown.

resource "time_rotating" "trigger" {
  rotation_minutes = 5
}

resource "terraform_data" "trigger" {
  triggers_replace = !var.rotate || time_rotating.trigger.id != null
}

resource "google_compute_instance" "ml_instance" {
...
  lifecycle {
     replace_triggered_by = [terraform_data.trigger]
  }
}

If var.rotate is false, only the time_rotate resource will be created, and true will cause all three to be replaced.

1 Like

Thank you @jbardin for your assistance. It worked as expected.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.