Prevent recreation for key_revocation_action in compute-vm module (#3620)

* fix(compute-vm): prevent instance recreation for key_revocation_action_type

The `key_revocation_action_type` attribute in the `google_compute_instance`
resource defaults to `NONE` on the provider side.

When this optional attribute was not explicitly set in the module's
`options` variable, it resolved to `null` in the Terraform configuration.
This caused Terraform to detect a change from `null` to `NONE` on every
plan, leading to unnecessary instance recreation.

This change applies `coalesce` to
`var.options.key_revocation_action_type` in the resource definition so
that it defaults to `NONE` when unset, aligning the configuration with
provider behavior and preventing a permadiff.

* updated the regional compute template too with the key_revocation_action_type

* fixed the formatting
This commit is contained in:
Suryansh Singhal
2026-01-05 16:23:47 +05:30
committed by GitHub
parent d0d7c64670
commit ba304518f1
13 changed files with 144 additions and 131 deletions

View File

@@ -1160,8 +1160,8 @@ module "sole-tenancy" {
|---|---|:---:|:---:|:---:|
| [name](variables.tf#L322) | Instance name. | <code>string</code> | ✓ | |
| [network_interfaces](variables.tf#L334) | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | <code title="list&#40;object&#40;&#123;&#10; network &#61; string&#10; subnetwork &#61; string&#10; alias_ips &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; nat &#61; optional&#40;bool, false&#41;&#10; nic_type &#61; optional&#40;string&#41;&#10; stack_type &#61; optional&#40;string&#41;&#10; addresses &#61; optional&#40;object&#40;&#123;&#10; internal &#61; optional&#40;string&#41;&#10; external &#61; optional&#40;string&#41;&#10; &#125;&#41;, null&#41;&#10; network_tier &#61; optional&#40;string&#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | ✓ | |
| [project_id](variables.tf#L419) | Project id. | <code>string</code> | ✓ | |
| [zone](variables.tf#L539) | Compute zone. | <code>string</code> | ✓ | |
| [project_id](variables.tf#L429) | Project id. | <code>string</code> | ✓ | |
| [zone](variables.tf#L549) | Compute zone. | <code>string</code> | ✓ | |
| [attached_disk_defaults](variables.tf#L17) | Defaults for attached disks options. | <code title="object&#40;&#123;&#10; auto_delete &#61; optional&#40;bool, false&#41;&#10; mode &#61; string&#10; replica_zone &#61; string&#10; type &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; auto_delete &#61; true&#10; mode &#61; &#34;READ_WRITE&#34;&#10; replica_zone &#61; null&#10; type &#61; &#34;pd-balanced&#34;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [attached_disks](variables.tf#L37) | Additional disks, if options is null defaults will be used in its place. Source type is one of 'image' (zonal disks in vms and template), 'snapshot' (vm), 'existing', and null. | <code title="list&#40;object&#40;&#123;&#10; name &#61; optional&#40;string&#41;&#10; device_name &#61; optional&#40;string&#41;&#10; size &#61; string&#10; snapshot_schedule &#61; optional&#40;list&#40;string&#41;&#41;&#10; source &#61; optional&#40;string&#41;&#10; source_type &#61; optional&#40;string&#41;&#10; options &#61; optional&#40;&#10; object&#40;&#123;&#10; architecture &#61; optional&#40;string&#41;&#10; auto_delete &#61; optional&#40;bool, false&#41; &#35; applies only to vm templates&#10; mode &#61; optional&#40;string, &#34;READ_WRITE&#34;&#41;&#10; provisioned_iops &#61; optional&#40;number&#41;&#10; provisioned_throughput &#61; optional&#40;number&#41; &#35; in MiB&#47;s&#10; replica_zone &#61; optional&#40;string&#41;&#10; storage_pool &#61; optional&#40;string&#41;&#10; type &#61; optional&#40;string, &#34;pd-balanced&#34;&#41;&#10; &#125;&#41;,&#10; &#123;&#10; auto_delete &#61; true&#10; mode &#61; &#34;READ_WRITE&#34;&#10; replica_zone &#61; null&#10; type &#61; &#34;pd-balanced&#34;&#10; &#125;&#10; &#41;&#10;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#91;&#93;</code> |
| [boot_disk](variables.tf#L92) | Boot disk properties. Initialize params are ignored when source is set. | <code title="object&#40;&#123;&#10; auto_delete &#61; optional&#40;bool, true&#41;&#10; snapshot_schedule &#61; optional&#40;list&#40;string&#41;&#41;&#10; source &#61; optional&#40;string&#41;&#10; initialize_params &#61; optional&#40;object&#40;&#123;&#10; architecture &#61; optional&#40;string&#41;&#10; image &#61; optional&#40;string, &#34;projects&#47;debian-cloud&#47;global&#47;images&#47;family&#47;debian-11&#34;&#41;&#10; provisioned_iops &#61; optional&#40;number&#41;&#10; provisioned_throughput &#61; optional&#40;number&#41; &#35; in MiB&#47;s&#10; size &#61; optional&#40;number, 10&#41;&#10; storage_pool &#61; optional&#40;string&#41;&#10; type &#61; optional&#40;string, &#34;pd-balanced&#34;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; use_independent_disk &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; initialize_params &#61; &#123;&#125;&#10;&#125;">&#123;&#8230;&#125;</code> |
@@ -1185,16 +1185,16 @@ module "sole-tenancy" {
| [min_cpu_platform](variables.tf#L316) | Minimum CPU platform. | <code>string</code> | | <code>null</code> |
| [network_attached_interfaces](variables.tf#L327) | Network interfaces using network attachments. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [network_tag_bindings](variables.tf#L355) | Resource manager tag bindings in arbitrary key => tag key or value id format. Set on both the instance only for networking purposes, and modifiable without impacting the main resource lifecycle. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [options](variables.tf#L362) | Instance options. | <code title="object&#40;&#123;&#10; advanced_machine_features &#61; optional&#40;object&#40;&#123;&#10; enable_nested_virtualization &#61; optional&#40;bool&#41;&#10; enable_turbo_mode &#61; optional&#40;bool&#41;&#10; enable_uefi_networking &#61; optional&#40;bool&#41;&#10; performance_monitoring_unit &#61; optional&#40;string&#41;&#10; threads_per_core &#61; optional&#40;number&#41;&#10; visible_core_count &#61; optional&#40;number&#41;&#10; &#125;&#41;&#41;&#10; allow_stopping_for_update &#61; optional&#40;bool, true&#41;&#10; deletion_protection &#61; optional&#40;bool, false&#41;&#10; graceful_shutdown &#61; optional&#40;object&#40;&#123;&#10; enabled &#61; optional&#40;bool, false&#41;&#10; max_duration_secs &#61; optional&#40;number&#41;&#10; &#125;&#41;&#41;&#10; max_run_duration &#61; optional&#40;object&#40;&#123;&#10; nanos &#61; optional&#40;number&#41;&#10; seconds &#61; number&#10; &#125;&#41;&#41;&#10; node_affinities &#61; optional&#40;map&#40;object&#40;&#123;&#10; values &#61; list&#40;string&#41;&#10; in &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; spot &#61; optional&#40;bool, false&#41;&#10; termination_action &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; allow_stopping_for_update &#61; true&#10; deletion_protection &#61; false&#10; spot &#61; false&#10; termination_action &#61; null&#10;&#125;">&#123;&#8230;&#125;</code> |
| [project_number](variables.tf#L424) | Project number. Used in tag bindings to avoid a permadiff. | <code>string</code> | | <code>null</code> |
| [resource_policies](variables.tf#L430) | Resource policies to attach to the instance or template. | <code>list&#40;string&#41;</code> | | <code>null</code> |
| [scratch_disks](variables.tf#L437) | Scratch disks configuration. | <code title="object&#40;&#123;&#10; count &#61; number&#10; interface &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; count &#61; 0&#10; interface &#61; &#34;NVME&#34;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [service_account](variables.tf#L449) | Service account email and scopes. If email is null, the default Compute service account will be used unless auto_create is true, in which case a service account will be created. Set the variable to null to avoid attaching a service account. | <code title="object&#40;&#123;&#10; auto_create &#61; optional&#40;bool, false&#41;&#10; email &#61; optional&#40;string&#41;&#10; scopes &#61; optional&#40;list&#40;string&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [shielded_config](variables.tf#L459) | Shielded VM configuration of the instances. | <code title="object&#40;&#123;&#10; enable_secure_boot &#61; optional&#40;bool, true&#41;&#10; enable_vtpm &#61; optional&#40;bool, true&#41;&#10; enable_integrity_monitoring &#61; optional&#40;bool, true&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [snapshot_schedules](variables.tf#L469) | Snapshot schedule resource policies that can be attached to disks. | <code title="map&#40;object&#40;&#123;&#10; schedule &#61; object&#40;&#123;&#10; daily &#61; optional&#40;object&#40;&#123;&#10; days_in_cycle &#61; number&#10; start_time &#61; string&#10; &#125;&#41;&#41;&#10; hourly &#61; optional&#40;object&#40;&#123;&#10; hours_in_cycle &#61; number&#10; start_time &#61; string&#10; &#125;&#41;&#41;&#10; weekly &#61; optional&#40;list&#40;object&#40;&#123;&#10; day &#61; string&#10; start_time &#61; string&#10; &#125;&#41;&#41;&#41;&#10; &#125;&#41;&#10; description &#61; optional&#40;string&#41;&#10; retention_policy &#61; optional&#40;object&#40;&#123;&#10; max_retention_days &#61; number&#10; on_source_disk_delete_keep &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10; snapshot_properties &#61; optional&#40;object&#40;&#123;&#10; chain_name &#61; optional&#40;string&#41;&#10; guest_flush &#61; optional&#40;bool&#41;&#10; labels &#61; optional&#40;map&#40;string&#41;&#41;&#10; storage_locations &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [tag_bindings](variables.tf#L512) | Resource manager tag bindings in arbitrary key => tag key or value id format. Set on both the instance and zonal disks, and modifiable without impacting the main resource lifecycle. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [tag_bindings_immutable](variables.tf#L519) | Immutable resource manager tag bindings, in tagKeys/id => tagValues/id format. These are set on the instance or instance template at creation time, and trigger recreation if changed. | <code>map&#40;string&#41;</code> | | <code>null</code> |
| [tags](variables.tf#L533) | Instance network tags for firewall rule targets. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [options](variables.tf#L362) | Instance options. | <code title="object&#40;&#123;&#10; advanced_machine_features &#61; optional&#40;object&#40;&#123;&#10; enable_nested_virtualization &#61; optional&#40;bool&#41;&#10; enable_turbo_mode &#61; optional&#40;bool&#41;&#10; enable_uefi_networking &#61; optional&#40;bool&#41;&#10; performance_monitoring_unit &#61; optional&#40;string&#41;&#10; threads_per_core &#61; optional&#40;number&#41;&#10; visible_core_count &#61; optional&#40;number&#41;&#10; &#125;&#41;&#41;&#10; allow_stopping_for_update &#61; optional&#40;bool, true&#41;&#10; deletion_protection &#61; optional&#40;bool, false&#41;&#10; key_revocation_action_type &#61; optional&#40;string&#41;&#10; graceful_shutdown &#61; optional&#40;object&#40;&#123;&#10; enabled &#61; optional&#40;bool, false&#41;&#10; max_duration_secs &#61; optional&#40;number&#41;&#10; &#125;&#41;&#41;&#10; max_run_duration &#61; optional&#40;object&#40;&#123;&#10; nanos &#61; optional&#40;number&#41;&#10; seconds &#61; number&#10; &#125;&#41;&#41;&#10; node_affinities &#61; optional&#40;map&#40;object&#40;&#123;&#10; values &#61; list&#40;string&#41;&#10; in &#61; optional&#40;bool, true&#41;&#10; &#125;&#41;&#41;, &#123;&#125;&#41;&#10; spot &#61; optional&#40;bool, false&#41;&#10; termination_action &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; allow_stopping_for_update &#61; true&#10; deletion_protection &#61; false&#10; spot &#61; false&#10; termination_action &#61; null&#10; key_revocation_action_type &#61; &#34;NONE&#34;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [project_number](variables.tf#L434) | Project number. Used in tag bindings to avoid a permadiff. | <code>string</code> | | <code>null</code> |
| [resource_policies](variables.tf#L440) | Resource policies to attach to the instance or template. | <code>list&#40;string&#41;</code> | | <code>null</code> |
| [scratch_disks](variables.tf#L447) | Scratch disks configuration. | <code title="object&#40;&#123;&#10; count &#61; number&#10; interface &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code title="&#123;&#10; count &#61; 0&#10; interface &#61; &#34;NVME&#34;&#10;&#125;">&#123;&#8230;&#125;</code> |
| [service_account](variables.tf#L459) | Service account email and scopes. If email is null, the default Compute service account will be used unless auto_create is true, in which case a service account will be created. Set the variable to null to avoid attaching a service account. | <code title="object&#40;&#123;&#10; auto_create &#61; optional&#40;bool, false&#41;&#10; email &#61; optional&#40;string&#41;&#10; scopes &#61; optional&#40;list&#40;string&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [shielded_config](variables.tf#L469) | Shielded VM configuration of the instances. | <code title="object&#40;&#123;&#10; enable_secure_boot &#61; optional&#40;bool, true&#41;&#10; enable_vtpm &#61; optional&#40;bool, true&#41;&#10; enable_integrity_monitoring &#61; optional&#40;bool, true&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [snapshot_schedules](variables.tf#L479) | Snapshot schedule resource policies that can be attached to disks. | <code title="map&#40;object&#40;&#123;&#10; schedule &#61; object&#40;&#123;&#10; daily &#61; optional&#40;object&#40;&#123;&#10; days_in_cycle &#61; number&#10; start_time &#61; string&#10; &#125;&#41;&#41;&#10; hourly &#61; optional&#40;object&#40;&#123;&#10; hours_in_cycle &#61; number&#10; start_time &#61; string&#10; &#125;&#41;&#41;&#10; weekly &#61; optional&#40;list&#40;object&#40;&#123;&#10; day &#61; string&#10; start_time &#61; string&#10; &#125;&#41;&#41;&#41;&#10; &#125;&#41;&#10; description &#61; optional&#40;string&#41;&#10; retention_policy &#61; optional&#40;object&#40;&#123;&#10; max_retention_days &#61; number&#10; on_source_disk_delete_keep &#61; optional&#40;bool&#41;&#10; &#125;&#41;&#41;&#10; snapshot_properties &#61; optional&#40;object&#40;&#123;&#10; chain_name &#61; optional&#40;string&#41;&#10; guest_flush &#61; optional&#40;bool&#41;&#10; labels &#61; optional&#40;map&#40;string&#41;&#41;&#10; storage_locations &#61; optional&#40;list&#40;string&#41;&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [tag_bindings](variables.tf#L522) | Resource manager tag bindings in arbitrary key => tag key or value id format. Set on both the instance and zonal disks, and modifiable without impacting the main resource lifecycle. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [tag_bindings_immutable](variables.tf#L529) | Immutable resource manager tag bindings, in tagKeys/id => tagValues/id format. These are set on the instance or instance template at creation time, and trigger recreation if changed. | <code>map&#40;string&#41;</code> | | <code>null</code> |
| [tags](variables.tf#L543) | Instance network tags for firewall rule targets. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
## Outputs

View File

@@ -190,23 +190,24 @@ resource "google_compute_region_disk" "disks" {
}
resource "google_compute_instance" "default" {
provider = google-beta
count = local.template_create ? 0 : 1
project = local.project_id
zone = local.zone
name = var.name
hostname = var.hostname
description = var.description
tags = var.tags
machine_type = var.instance_type
min_cpu_platform = var.min_cpu_platform
can_ip_forward = var.can_ip_forward
allow_stopping_for_update = var.options.allow_stopping_for_update
deletion_protection = var.options.deletion_protection
enable_display = var.enable_display
labels = var.labels
metadata = var.metadata
metadata_startup_script = var.metadata_startup_script
provider = google-beta
count = local.template_create ? 0 : 1
project = local.project_id
zone = local.zone
name = var.name
hostname = var.hostname
description = var.description
tags = var.tags
machine_type = var.instance_type
min_cpu_platform = var.min_cpu_platform
can_ip_forward = var.can_ip_forward
allow_stopping_for_update = var.options.allow_stopping_for_update
deletion_protection = var.options.deletion_protection
key_revocation_action_type = var.options.key_revocation_action_type
enable_display = var.enable_display
labels = var.labels
metadata = var.metadata
metadata_startup_script = var.metadata_startup_script
resource_policies = (
var.resource_policies == null && var.instance_schedule == null
? null

View File

@@ -20,20 +20,21 @@ locals {
}
resource "google_compute_instance_template" "default" {
provider = google-beta
count = local.template_create && !local.template_regional ? 1 : 0
project = local.project_id
region = local.region
name_prefix = "${var.name}-"
description = var.description
tags = var.tags
machine_type = var.instance_type
min_cpu_platform = var.min_cpu_platform
can_ip_forward = var.can_ip_forward
metadata = var.metadata
metadata_startup_script = var.metadata_startup_script
labels = var.labels
resource_manager_tags = var.tag_bindings_immutable
provider = google-beta
count = local.template_create && !local.template_regional ? 1 : 0
project = local.project_id
region = local.region
name_prefix = "${var.name}-"
description = var.description
tags = var.tags
machine_type = var.instance_type
min_cpu_platform = var.min_cpu_platform
can_ip_forward = var.can_ip_forward
metadata = var.metadata
metadata_startup_script = var.metadata_startup_script
labels = var.labels
resource_manager_tags = var.tag_bindings_immutable
key_revocation_action_type = var.options.key_revocation_action_type
resource_policies = (
var.resource_policies == null && var.instance_schedule == null
? null
@@ -245,20 +246,21 @@ resource "google_compute_instance_template" "default" {
}
resource "google_compute_region_instance_template" "default" {
provider = google-beta
count = local.template_create && local.template_regional ? 1 : 0
project = local.project_id
region = local.region
name_prefix = "${var.name}-"
description = var.description
tags = var.tags
machine_type = var.instance_type
min_cpu_platform = var.min_cpu_platform
can_ip_forward = var.can_ip_forward
metadata = var.metadata
metadata_startup_script = var.metadata_startup_script
labels = var.labels
resource_manager_tags = var.tag_bindings_immutable
provider = google-beta
count = local.template_create && local.template_regional ? 1 : 0
project = local.project_id
region = local.region
name_prefix = "${var.name}-"
description = var.description
tags = var.tags
machine_type = var.instance_type
min_cpu_platform = var.min_cpu_platform
can_ip_forward = var.can_ip_forward
metadata = var.metadata
metadata_startup_script = var.metadata_startup_script
labels = var.labels
resource_manager_tags = var.tag_bindings_immutable
key_revocation_action_type = var.options.key_revocation_action_type
resource_policies = (
var.resource_policies == null && var.instance_schedule == null
? null

View File

@@ -370,8 +370,9 @@ variable "options" {
threads_per_core = optional(number)
visible_core_count = optional(number)
}))
allow_stopping_for_update = optional(bool, true)
deletion_protection = optional(bool, false)
allow_stopping_for_update = optional(bool, true)
deletion_protection = optional(bool, false)
key_revocation_action_type = optional(string)
graceful_shutdown = optional(object({
enabled = optional(bool, false)
max_duration_secs = optional(number)
@@ -388,10 +389,11 @@ variable "options" {
termination_action = optional(string)
})
default = {
allow_stopping_for_update = true
deletion_protection = false
spot = false
termination_action = null
allow_stopping_for_update = true
deletion_protection = false
spot = false
termination_action = null
key_revocation_action_type = "NONE"
}
validation {
condition = (
@@ -414,6 +416,14 @@ variable "options" {
)
error_message = "Allowed values for options.advanced_machine_features.performance_monitoring_unit are ARCHITECTURAL', 'ENHANCED', 'STANDARD' and null."
}
validation {
condition = (
var.options.key_revocation_action_type == null
||
contains(["NONE", "STOP"], var.options.key_revocation_action_type)
)
error_message = "Allowed values for options.key_revocation_action_type are 'NONE' or 'STOP'."
}
}
variable "project_id" {