Compute VM module refactor (#3805)

* add ad for compute-vm refactor

* Exclue nic_type from validated fields, add split of main.tf and template.tf

* boot disk

* fix examples and fixtures

* attached disks

* fix further examples and module-level tests

* remove extra file

* fix mig examples

* finish refactoring variables

* align fast and other modules

* refactor(compute-vm): align examples and ADR with the newly implemented interface

This commit addresses the remaining references of the `instance_type` and `confidential_compute` parameters in the testing environment and updates the ADR.

* feat(compute-vm): add network_performance_config to instance and templates

This change implements the usage of the `network_performance_tier` variable we added earlier into the actual Terraform resources.

---------

Co-authored-by: Wiktor Niesiobędzki <wiktorn@google.com>
This commit is contained in:
Ludovico Magnocavallo
2026-03-26 12:31:40 +01:00
committed by GitHub
parent 2c39df6453
commit a4eb4d24fd
64 changed files with 1971 additions and 1119 deletions

View File

@@ -151,12 +151,12 @@ module "vm-managed-sa-example2" {
#### Disk sources
Attached disks can be created and optionally initialized from a pre-existing source, or attached to VMs when pre-existing. The `source` and `source_type` attributes of the `attached_disks` variable allows several modes of operation:
Attached disks can be created and optionally initialized from a pre-existing source, or attached to VMs when pre-existing. The `source` attribute of the `attached_disks` variable allows several modes of operation:
- `source_type = "image"` can be used with zonal disks in instances and templates, set `source` to the image name or self link
- `source_type = "snapshot"` can be used with instances only, set `source` to the snapshot name or self link
- `source_type = "attach"` can be used for both instances and templates to attach an existing disk, set source to the name (for zonal disks) or self link (for regional disks) of the existing disk to attach; no disk will be created
- `source_type = null` can be used where an empty disk is needed, `source` becomes irrelevant and can be left null
- `source.image` can be used with zonal disks in instances and templates, set to the image name or self link
- `source.snapshot` can be used with instances only, set to the snapshot name or self link
- `source.attach` can be used for both instances and templates to attach an existing disk, set to the name (for zonal disks) or self link (for regional disks) of the existing disk to attach; no disk will be created
- `source = null` can be used where an empty disk is needed
This is an example of attaching a pre-existing regional PD to a new instance:
@@ -170,15 +170,16 @@ module "vm-disks-example" {
network = var.vpc.self_link
subnetwork = var.subnet.self_link
}]
attached_disks = [{
name = "repd-1"
size = 10
source_type = "attach"
source = "regions/${var.region}/disks/repd-test-1"
options = {
replica_zone = "${var.region}-c"
attached_disks = {
repd-1 = {
initialize_params = {
replica_zone = "${var.region}-c"
}
source = {
attach = "regions/${var.region}/disks/repd-test-1"
}
}
}]
}
service_account = {
auto_create = true
}
@@ -198,15 +199,17 @@ module "vm-disks-example" {
network = var.vpc.self_link
subnetwork = var.subnet.self_link
}]
attached_disks = [{
name = "repd"
size = 10
source_type = "attach"
source = "https://www.googleapis.com/compute/v1/projects/${var.project_id}/regions/${var.region}/disks/repd-test-1"
options = {
replica_zone = "${var.region}-c"
attached_disks = {
repd = {
auto_delete = false
initialize_params = {
replica_zone = "${var.region}-c"
}
source = {
attach = "https://www.googleapis.com/compute/v1/projects/${var.project_id}/regions/${var.region}/disks/repd-test-1"
}
}
}]
}
service_account = {
auto_create = true
}
@@ -217,7 +220,7 @@ module "vm-disks-example" {
#### Disk types and options
The `attached_disks` variable exposes an `option` attribute that can be used to fine tune the configuration of each disk. The following example shows a VM with multiple disks
The `attached_disks` variable exposes an `initialize_params` attribute that can be used to fine tune the configuration of each disk. The following example shows a VM with multiple disks
```hcl
module "vm-disk-options-example" {
@@ -229,27 +232,26 @@ module "vm-disk-options-example" {
network = var.vpc.self_link
subnetwork = var.subnet.self_link
}]
attached_disks = [
{
name = "data1"
size = "10"
source_type = "image"
source = "image-1"
options = {
attached_disks = {
data1 = {
initialize_params = {
replica_zone = "${var.region}-c"
}
},
{
name = "data2"
size = "20"
source_type = "snapshot"
source = "snapshot-2"
options = {
type = "pd-ssd"
mode = "READ_ONLY"
source = {
image = "image-1"
}
}
]
data2 = {
mode = "READ_ONLY"
initialize_params = {
size = 20
type = "pd-ssd"
}
source = {
snapshot = "snapshot-2"
}
}
}
service_account = {
auto_create = true
}
@@ -261,47 +263,51 @@ For hyperdisks there are additional options available to configure performance.
```hcl
module "vm-disk-options-example" {
source = "./fabric/modules/compute-vm"
project_id = var.project_id
zone = "${var.region}-b"
name = "test"
instance_type = "n4-standard-2"
source = "./fabric/modules/compute-vm"
project_id = var.project_id
zone = "${var.region}-b"
name = "test"
machine_type = "n4-standard-2"
network_interfaces = [{
network = var.vpc.self_link
subnetwork = var.subnet.self_link
}]
boot_disk = {
initialize_params = {
image = "projects/debian-cloud/global/images/family/debian-12"
provisioned_iops = 3000
provisioned_throughput = 140
type = "hyperdisk-balanced"
}
}
attached_disks = [
{
name = "data1"
size = "10"
options = {
type = "hyperdisk-balanced"
hyperdisk = {
provisioned_iops = 3000
provisioned_throughput = 140
type = "hyperdisk-balanced"
}
},
{
name = "data2"
size = "10"
source_type = "image"
source = "projects/debian-cloud/global/images/family/debian-12"
options = {
provisioned_iops = 5000
provisioned_throughput = 500
type = "hyperdisk-balanced"
}
source = {
image = "projects/debian-cloud/global/images/family/debian-12"
}
}
attached_disks = {
data1 = {
initialize_params = {
type = "hyperdisk-balanced"
hyperdisk = {
provisioned_iops = 3000
provisioned_throughput = 140
}
}
},
]
}
data2 = {
mode = "READ_ONLY"
initialize_params = {
type = "hyperdisk-balanced"
hyperdisk = {
provisioned_iops = 5000
provisioned_throughput = 500
}
}
source = {
image = "projects/debian-cloud/global/images/family/debian-12"
}
}
}
service_account = {
auto_create = true
}
@@ -316,24 +322,22 @@ You can use storage pool for better management of storage capacity.
```hcl
# hyperdisk - with storage pool
resource "google_compute_storage_pool" "default" {
project = var.project_id
name = "storage-pool-basic"
project = var.project_id
name = "storage-pool-basic"
pool_provisioned_capacity_gb = "20480"
pool_provisioned_iops = "10000"
pool_provisioned_throughput = 1024
storage_pool_type = "hyperdisk-balanced"
zone = "${var.region}-c"
deletion_protection = false
deletion_protection = false
}
module "vm-disk-options-example" {
source = "./fabric/modules/compute-vm"
project_id = var.project_id
zone = "${var.region}-c"
name = "test"
instance_type = "c4d-standard-2"
source = "./fabric/modules/compute-vm"
project_id = var.project_id
zone = "${var.region}-c"
name = "test"
machine_type = "c4d-standard-2"
network_interfaces = [
{
network = var.vpc.self_link
@@ -341,40 +345,41 @@ module "vm-disk-options-example" {
}
]
boot_disk = {
use_independent_disk = true
use_independent_disk = {}
initialize_params = {
image = "projects/debian-cloud/global/images/family/debian-12"
provisioned_iops = 3000
provisioned_throughput = 140
storage_pool = google_compute_storage_pool.default.id
type = "hyperdisk-balanced"
type = "hyperdisk-balanced"
hyperdisk = {
provisioned_iops = 3000
provisioned_throughput = 140
storage_pool = google_compute_storage_pool.default.id
}
}
source = {
image = "projects/debian-cloud/global/images/family/debian-12"
}
}
attached_disks = [
{
name = "data1"
size = "10"
options = {
# provisioned_iops = 3000
# provisioned_throughput = 140
storage_pool = google_compute_storage_pool.default.id
type = "hyperdisk-balanced"
attached_disks = {
data1 = {
initialize_params = {
type = "hyperdisk-balanced"
hyperdisk = {
storage_pool = google_compute_storage_pool.default.id
}
}
},
{
name = "data2"
size = "10"
source_type = "image"
source = "projects/debian-cloud/global/images/family/debian-12"
options = {
provisioned_iops = 5000
provisioned_throughput = 500
type = "hyperdisk-balanced"
}
data2 = {
initialize_params = {
type = "hyperdisk-balanced"
hyperdisk = {
provisioned_iops = 5000
provisioned_throughput = 500
}
}
},
]
source = {
image = "projects/debian-cloud/global/images/family/debian-12"
}
}
}
service_account = {
auto_create = true
}
@@ -390,50 +395,51 @@ For hyperdisks there are additional options available to configure performance.
```hcl
module "vm-arm" {
source = "./fabric/modules/compute-vm"
project_id = var.project_id
zone = "${var.region}-c"
name = "test"
instance_type = "c4a-standard-1"
source = "./fabric/modules/compute-vm"
project_id = var.project_id
zone = "${var.region}-c"
name = "test"
machine_type = "c4a-standard-1"
network_interfaces = [{
network = var.vpc.self_link
subnetwork = var.subnet.self_link
}]
boot_disk = {
architecture = "ARM64"
initialize_params = {
image = "projects/debian-cloud/global/images/family/debian-12-arm64"
architecture = "ARM64"
provisioned_iops = 3000
provisioned_throughput = 140
type = "hyperdisk-balanced"
}
}
attached_disks = [
{
name = "data1"
size = "10"
options = {
architecture = "ARM64"
type = "hyperdisk-balanced"
hyperdisk = {
provisioned_iops = 3000
provisioned_throughput = 140
type = "hyperdisk-balanced"
}
},
{
name = "data2"
size = "10"
source_type = "image"
source = "projects/debian-cloud/global/images/family/debian-12-arm64"
options = {
architecture = "ARM64"
provisioned_iops = 5000
provisioned_throughput = 500
type = "hyperdisk-balanced"
}
source = {
image = "projects/debian-cloud/global/images/family/debian-12-arm64"
}
}
attached_disks = {
data1 = {
initialize_params = {
type = "hyperdisk-balanced"
hyperdisk = {
provisioned_iops = 3000
provisioned_throughput = 140
}
}
},
]
}
data2 = {
initialize_params = {
type = "hyperdisk-balanced"
hyperdisk = {
provisioned_iops = 5000
provisioned_throughput = 500
}
}
source = {
image = "projects/debian-cloud/global/images/family/debian-12-arm64"
}
}
}
service_account = {
auto_create = true
}
@@ -445,7 +451,7 @@ module "vm-arm" {
#### Boot disk as an independent resource
To create the boot disk as an independent resources instead of as part of the instance creation flow, set `boot_disk.use_independent_disk` to `true` and optionally configure `boot_disk.initialize_params`.
To create the boot disk as an independent resources instead of as part of the instance creation flow, set `boot_disk.use_independent_disk` to a non-null object (e.g. `{}`) and optionally configure `boot_disk.initialize_params`.
This will create the boot disk as its own resource and attach it to the instance, allowing to recreate the instance from Terraform while preserving the boot disk.
@@ -456,8 +462,7 @@ module "simple-vm-example" {
zone = "${var.region}-b"
name = "test"
boot_disk = {
initialize_params = {}
use_independent_disk = true
use_independent_disk = {}
}
network_interfaces = [{
network = var.vpc.self_link
@@ -536,7 +541,6 @@ resource "google_compute_image" "cos-gvnic" {
project = var.project_id
name = "my-image"
source_image = "https://www.googleapis.com/compute/v1/projects/cos-cloud/global/images/cos-89-16108-534-18"
guest_os_features {
type = "GVNIC"
}
@@ -558,8 +562,10 @@ module "vm-with-gvnic" {
name = "test"
boot_disk = {
initialize_params = {
type = "pd-ssd"
}
source = {
image = google_compute_image.cos-gvnic.self_link
type = "pd-ssd"
}
}
network_interfaces = [{
@@ -674,8 +680,8 @@ module "spot-vm-example" {
project_id = var.project_id
zone = "${var.region}-b"
name = "test"
options = {
spot = true
scheduling_config = {
provisioning_model = "SPOT"
termination_action = "STOP"
}
network_interfaces = [{
@@ -696,10 +702,10 @@ module "vm-confidential-example" {
project_id = var.project_id
zone = "${var.region}-b"
name = "confidential-vm"
confidential_compute = true
instance_type = "n2d-standard-2"
confidential_compute = "SEV"
machine_type = "n2d-standard-2"
boot_disk = {
initialize_params = {
source = {
image = "projects/debian-cloud/global/images/family/debian-12"
}
}
@@ -714,11 +720,11 @@ module "template-confidential-example" {
project_id = var.project_id
zone = "${var.region}-b"
name = "confidential-template"
confidential_compute = true
confidential_compute = "SEV"
create_template = {}
instance_type = "n2d-standard-2"
machine_type = "n2d-standard-2"
boot_disk = {
initialize_params = {
source = {
image = "projects/debian-cloud/global/images/family/debian-12"
}
}
@@ -790,10 +796,9 @@ module "kms-vm-example" {
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["${var.region}/production"]
}]
attached_disks = [{
name = "attached-disk"
size = 10
}]
attached_disks = {
attached-disk = {}
}
service_account = {
auto_create = true
}
@@ -819,10 +824,9 @@ module "autokey-vm-example" {
network = "projects/myhost/global/networks/dev-spoke-0"
subnetwork = "projects/myhost/regions/europe-west8/subnetworks/gce"
}]
attached_disks = [{
name = "attached-disk"
size = 10
}]
attached_disks = {
attached-disk = {}
}
service_account = {
auto_create = true
}
@@ -839,7 +843,7 @@ module "autokey-vm-example" {
### Advanced machine features
Advanced machine features can be configured via the `options.advanced_machine_features` variable.
Advanced machine features can be configured via the `machine_features_config` variable.
```hcl
module "simple-vm-example" {
@@ -851,12 +855,10 @@ module "simple-vm-example" {
network = var.vpc.self_link
subnetwork = var.subnet.self_link
}]
options = {
advanced_machine_features = {
enable_nested_virtualization = true
enable_turbo_mode = true
threads_per_core = 2
}
machine_features_config = {
enable_nested_virtualization = true
enable_turbo_mode = true
threads_per_core = 2
}
}
# tftest modules=1 resources=1
@@ -879,13 +881,13 @@ module "cos-test" {
subnetwork = var.subnet.self_link
}]
boot_disk = {
initialize_params = {
source = {
image = "projects/cos-cloud/global/images/family/cos-stable"
}
}
attached_disks = [
{ size = 10 }
]
attached_disks = {
disk-0 = {}
}
service_account = {
email = module.iam-service-account.email
}
@@ -909,13 +911,15 @@ module "cos-test" {
subnetwork = var.subnet.self_link
}]
boot_disk = {
initialize_params = {
source = {
image = "projects/cos-cloud/global/images/family/cos-stable"
}
}
attached_disks = [
{ size = 10 }
]
attached_disks = {
disk-0 = {
auto_delete = true
}
}
service_account = {
email = module.iam-service-account.email
}
@@ -945,7 +949,7 @@ module "instance-group" {
subnetwork = var.subnet.self_link
}]
boot_disk = {
initialize_params = {
source = {
image = "projects/cos-cloud/global/images/family/cos-stable"
}
}
@@ -976,7 +980,7 @@ module "instance" {
subnetwork = var.subnet.self_link
}]
boot_disk = {
initialize_params = {
source = {
image = "projects/cos-cloud/global/images/family/cos-stable"
}
}
@@ -1019,7 +1023,7 @@ module "instance" {
subnetwork = var.subnet.self_link
}]
boot_disk = {
initialize_params = {
source = {
image = "projects/cos-cloud/global/images/family/cos-stable"
}
}
@@ -1047,21 +1051,19 @@ module "instance" {
subnetwork = var.subnet.self_link
}]
boot_disk = {
initialize_params = {
source = {
image = "projects/cos-cloud/global/images/family/cos-stable"
}
snapshot_schedule = ["boot"]
}
attached_disks = [
{
name = "disk-1"
size = 10
options = {
attached_disks = {
disk-1 = {
initialize_params = {
replica_zone = "${var.region}-c"
}
snapshot_schedule = ["data"]
}
]
}
snapshot_schedules = {
boot = {
schedule = {
@@ -1141,16 +1143,16 @@ You can add node affinities (and anti-affinity) configurations to allocate the V
```hcl
module "sole-tenancy" {
source = "./fabric/modules/compute-vm"
project_id = var.project_id
zone = "${var.region}-b"
instance_type = "n1-standard-1"
name = "test"
source = "./fabric/modules/compute-vm"
project_id = var.project_id
zone = "${var.region}-b"
machine_type = "n1-standard-1"
name = "test"
network_interfaces = [{
network = var.vpc.self_link
subnetwork = var.subnet.self_link
}]
options = {
scheduling_config = {
node_affinities = {
workload = {
values = ["frontend"]
@@ -1169,43 +1171,45 @@ module "sole-tenancy" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
| [name](variables.tf#L323) | Instance name. | <code>string</code> | ✓ | |
| [network_interfaces](variables.tf#L335) | 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#L430) | Project id. | <code>string</code> | ✓ | |
| [zone](variables.tf#L550) | 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; name &#61; optional&#40;string&#41;&#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> |
| [can_ip_forward](variables.tf#L135) | Enable IP forwarding. | <code>bool</code> | | <code>false</code> |
| [confidential_compute](variables.tf#L141) | Enable Confidential Compute for these instances. | <code>bool</code> | | <code>false</code> |
| [context](variables.tf#L147) | Context-specific interpolations. | <code title="object&#40;&#123;&#10; addresses &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; custom_roles &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; kms_keys &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; iam_principals &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; locations &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; networks &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; project_ids &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; subnets &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; tag_values &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [create_template](variables.tf#L164) | Create instance template instead of instances. Defaults to a global template. | <code title="object&#40;&#123;&#10; regional &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [description](variables.tf#L173) | Description of a Compute Instance. | <code>string</code> | | <code>&#34;Managed by the compute-vm Terraform module.&#34;</code> |
| [enable_display](variables.tf#L179) | Enable virtual display on the instances. | <code>bool</code> | | <code>false</code> |
| [encryption](variables.tf#L185) | Encryption options. Only one of kms_key_self_link and disk_encryption_key_raw may be set. If needed, you can specify to encrypt or not the boot disk. | <code title="object&#40;&#123;&#10; encrypt_boot &#61; optional&#40;bool, false&#41;&#10; disk_encryption_key_raw &#61; optional&#40;string&#41;&#10; kms_key_self_link &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [gpu](variables.tf#L195) | GPU information. Based on https://cloud.google.com/compute/docs/gpus. | <code title="object&#40;&#123;&#10; count &#61; number&#10; type &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [group](variables.tf#L230) | Define this variable to create an instance group for instances. Disabled for template use. | <code title="object&#40;&#123;&#10; named_ports &#61; map&#40;number&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [hostname](variables.tf#L238) | Instance FQDN name. | <code>string</code> | | <code>null</code> |
| [iam](variables.tf#L244) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [instance_schedule](variables.tf#L250) | Assign or create and assign an instance schedule policy. Either resource policy id or create_config must be specified if not null. Set active to null to dtach a policy from vm before destroying. | <code title="object&#40;&#123;&#10; active &#61; optional&#40;bool, true&#41;&#10; description &#61; optional&#40;string&#41;&#10; expiration_time &#61; optional&#40;string&#41;&#10; start_time &#61; optional&#40;string&#41;&#10; timezone &#61; optional&#40;string, &#34;UTC&#34;&#41;&#10; vm_start &#61; optional&#40;string&#41;&#10; vm_stop &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [instance_type](variables.tf#L274) | Instance type. | <code>string</code> | | <code>&#34;e2-micro&#34;</code> |
| [kms_autokeys](variables.tf#L280) | KMS Autokey key handles. If location is not specified it will be inferred from the zone. Key handle names will be added to the kms_keys context with an `autokeys/` prefix. | <code title="map&#40;object&#40;&#123;&#10; location &#61; optional&#40;string&#41;&#10; resource_type_selector &#61; optional&#40;string, &#34;compute.googleapis.com&#47;Disk&#34;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [labels](variables.tf#L298) | Instance labels. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [metadata](variables.tf#L304) | Instance metadata. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [metadata_startup_script](variables.tf#L310) | Instance startup script. Will trigger recreation on change, even after importing. | <code>string</code> | | <code>null</code> |
| [min_cpu_platform](variables.tf#L317) | Minimum CPU platform. | <code>string</code> | | <code>null</code> |
| [network_attached_interfaces](variables.tf#L328) | Network interfaces using network attachments. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [network_tag_bindings](variables.tf#L356) | 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#L363) | 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#L435) | Project number. Used in tag bindings to avoid a permadiff. | <code>string</code> | | <code>null</code> |
| [resource_policies](variables.tf#L441) | Resource policies to attach to the instance or template. | <code>list&#40;string&#41;</code> | | <code>null</code> |
| [scratch_disks](variables.tf#L448) | 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#L460) | 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#L470) | 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#L480) | 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#L523) | 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#L530) | 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#L544) | Instance network tags for firewall rule targets. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [name](variables.tf#L353) | Instance name. | <code>string</code> | ✓ | |
| [network_interfaces](variables.tf#L365) | 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; network_tier &#61; optional&#40;string&#41;&#10; nic_type &#61; optional&#40;string&#41;&#10; stack_type &#61; optional&#40;string&#41;&#10; queue_count &#61; optional&#40;number&#41; &#35; NEW&#10; internal_ipv6_prefix_length &#61; optional&#40;number&#41; &#35; NEW&#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;&#125;&#41;&#41;">list&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | ✓ | |
| [project_id](variables.tf#L405) | Project id. | <code>string</code> | ✓ | |
| [zone](variables.tf#L562) | Compute zone. | <code>string</code> | ✓ | |
| [attached_disks](variables.tf#L17) | Additional disks. Source type is one of 'image' (zonal disks in vms and template), 'snapshot' (vm), 'existing', and null. | <code title="map&#40;object&#40;&#123;&#10; auto_delete &#61; optional&#40;bool, true&#41; &#35; applies only to vm templates&#10; device_name &#61; optional&#40;string&#41;&#10; force_attach &#61; optional&#40;bool&#41;&#10; mode &#61; optional&#40;string, &#34;READ_WRITE&#34;&#41;&#10; name &#61; optional&#40;string&#41;&#10; initialize_params &#61; optional&#40;object&#40;&#123;&#10; replica_zone &#61; optional&#40;string&#41;&#10; size &#61; optional&#40;number, 10&#41;&#10; type &#61; optional&#40;string, &#34;pd-balanced&#34;&#41;&#10; hyperdisk &#61; optional&#40;object&#40;&#123;&#10; provisioned_iops &#61; optional&#40;number&#41;&#10; provisioned_throughput &#61; optional&#40;number&#41; &#35; in MiB&#47;s&#10; storage_pool &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; snapshot_schedule &#61; optional&#40;list&#40;string&#41;&#41;&#10; source &#61; optional&#40;object&#40;&#123;&#10; attach &#61; optional&#40;string&#41;&#10; image &#61; optional&#40;string&#41; &#35; not supported yet for repd&#10; snapshot &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [boot_disk](variables.tf#L56) | Boot disk properties. | <code title="object&#40;&#123;&#10; architecture &#61; optional&#40;string&#41;&#10; auto_delete &#61; optional&#40;bool, true&#41;&#10; force_attach &#61; optional&#40;bool&#41;&#10; snapshot_schedule &#61; optional&#40;list&#40;string&#41;&#41;&#10; initialize_params &#61; optional&#40;object&#40;&#123;&#10; size &#61; optional&#40;number, 10&#41;&#10; type &#61; optional&#40;string, &#34;pd-balanced&#34;&#41;&#10; hyperdisk &#61; optional&#40;object&#40;&#123;&#10; provisioned_iops &#61; optional&#40;number&#41;&#10; provisioned_throughput &#61; optional&#40;number&#41; &#35; in MiB&#47;s&#10; storage_pool &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; &#125;&#41;, &#123;&#125;&#41;&#10; source &#61; optional&#40;object&#40;&#123;&#10; attach &#61; optional&#40;string&#41;&#10; disk &#61; optional&#40;string&#41;&#10; image &#61; optional&#40;string&#41;&#10; snapshot &#61; optional&#40;string&#41;&#10; &#125;&#41;, &#123; image &#61; &#34;debian-cloud&#47;debian-13&#34; &#125;&#41;&#10; use_independent_disk &#61; optional&#40;object&#40;&#123;&#10; name &#61; optional&#40;string&#41;&#10; &#125;&#41;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [can_ip_forward](variables.tf#L113) | Enable IP forwarding. | <code>bool</code> | | <code>false</code> |
| [confidential_compute](variables.tf#L119) | Confidential Compute configuration. Set to 'SEV' or 'SEV_SNP' to enable. | <code>string</code> | | <code>null</code> |
| [context](variables.tf#L129) | Context-specific interpolations. | <code title="object&#40;&#123;&#10; addresses &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; custom_roles &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; kms_keys &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; iam_principals &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; locations &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; networks &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; project_ids &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; subnets &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10; tag_values &#61; optional&#40;map&#40;string&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [create_template](variables.tf#L146) | Create instance template instead of instances. Defaults to a global template. | <code title="object&#40;&#123;&#10; regional &#61; optional&#40;bool, false&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [description](variables.tf#L155) | Description of a Compute Instance. | <code>string</code> | | <code>&#34;Managed by the compute-vm Terraform module.&#34;</code> |
| [enable_display](variables.tf#L161) | Enable virtual display on the instances. | <code>bool</code> | | <code>false</code> |
| [encryption](variables.tf#L167) | Encryption options. Only one of kms_key_self_link and disk_encryption_key_raw may be set. If needed, you can specify to encrypt or not the boot disk. | <code title="object&#40;&#123;&#10; encrypt_boot &#61; optional&#40;bool, false&#41;&#10; disk_encryption_key_raw &#61; optional&#40;string&#41;&#10; kms_key_self_link &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [gpu](variables.tf#L178) | GPU information. Based on https://cloud.google.com/compute/docs/gpus. | <code title="object&#40;&#123;&#10; count &#61; number&#10; type &#61; string&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [group](variables.tf#L213) | Instance group configuration. Set 'named_ports' to create a new unmanaged instance group, or provide an existing group self_link/id in 'membership' to join one. | <code title="object&#40;&#123;&#10; membership &#61; optional&#40;string&#41; &#35; ID of an existing unmanaged group to join&#10; named_ports &#61; optional&#40;map&#40;number&#41;, &#123;&#125;&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [hostname](variables.tf#L222) | Instance FQDN name. | <code>string</code> | | <code>null</code> |
| [iam](variables.tf#L228) | IAM bindings in {ROLE => [MEMBERS]} format. | <code>map&#40;list&#40;string&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [instance_schedule](variables.tf#L234) | Assign or create and assign an instance schedule policy. Set active to null to detach a policy from vm before destroying. | <code title="object&#40;&#123;&#10; active &#61; optional&#40;bool, true&#41;&#10; description &#61; optional&#40;string&#41;&#10; expiration_time &#61; optional&#40;string&#41;&#10; start_time &#61; optional&#40;string&#41;&#10; timezone &#61; optional&#40;string, &#34;UTC&#34;&#41;&#10; vm_start &#61; optional&#40;string&#41;&#10; vm_stop &#61; optional&#40;string&#41;&#10;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>null</code> |
| [kms_autokeys](variables.tf#L258) | KMS Autokey key handles. If location is not specified it will be inferred from the zone. Key handle names will be added to the kms_keys context with an `autokeys/` prefix. | <code title="map&#40;object&#40;&#123;&#10; location &#61; optional&#40;string&#41;&#10; resource_type_selector &#61; optional&#40;string, &#34;compute.googleapis.com&#47;Disk&#34;&#41;&#10;&#125;&#41;&#41;">map&#40;object&#40;&#123;&#8230;&#125;&#41;&#41;</code> | | <code>&#123;&#125;</code> |
| [labels](variables.tf#L276) | Instance labels. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [lifecycle_config](variables.tf#L282) | Instance lifecycle and operational configurations. | <code title="object&#40;&#123;&#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, &#34;NONE&#34;&#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;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [machine_features_config](variables.tf#L304) | Machine-level configuration. | <code title="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;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [machine_type](variables.tf#L328) | Machine type. | <code>string</code> | | <code>&#34;e2-micro&#34;</code> |
| [metadata](variables.tf#L334) | Instance metadata. | <code>map&#40;string&#41;</code> | | <code>&#123;&#125;</code> |
| [metadata_startup_script](variables.tf#L340) | Instance startup script. Will trigger recreation on change, even after importing. | <code>string</code> | | <code>null</code> |
| [min_cpu_platform](variables.tf#L347) | Minimum CPU platform. | <code>string</code> | | <code>null</code> |
| [network_attached_interfaces](variables.tf#L358) | Network interfaces using network attachments. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
| [network_performance_tier](variables.tf#L388) | Network performance total egress bandwidth tier. | <code>string</code> | | <code>null</code> |
| [network_tag_bindings](variables.tf#L398) | 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> |
| [project_number](variables.tf#L410) | Project number. Used in tag bindings to avoid a permadiff. | <code>string</code> | | <code>null</code> |
| [resource_policies](variables.tf#L416) | Resource policies to attach to the instance or template. | <code>list&#40;string&#41;</code> | | <code>null</code> |
| [scheduling_config](variables.tf#L423) | Scheduling configuration for the instance. | <code title="object&#40;&#123;&#10; automatic_restart &#61; optional&#40;bool&#41; &#35; Defaults to &#33;spot&#10; maintenance_interval &#61; optional&#40;string&#41; &#35; NEW&#10; min_node_cpus &#61; optional&#40;number&#41; &#35; NEW&#10; on_host_maintenance &#61; optional&#40;string&#41; &#35; Defaults to MIGRATE or TERMINATE based on GPU&#47;Spot&#10; provisioning_model &#61; optional&#40;string&#41; &#35; &#34;SPOT&#34; or &#34;STANDARD&#34;&#10; termination_action &#61; optional&#40;string&#41;&#10; local_ssd_recovery_timeout &#61; optional&#40;object&#40;&#123; &#35; NEW&#10; nanos &#61; optional&#40;number&#41;&#10; seconds &#61; number&#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;&#125;&#41;">object&#40;&#123;&#8230;&#125;&#41;</code> | | <code>&#123;&#125;</code> |
| [scratch_disks](variables.tf#L458) | 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#L471) | 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#L482) | 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#L492) | 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#L535) | 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#L542) | 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#L556) | Instance network tags for firewall rule targets. | <code>list&#40;string&#41;</code> | | <code>&#91;&#93;</code> |
## Outputs

127
modules/compute-vm/disks.tf Normal file
View File

@@ -0,0 +1,127 @@
/**
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
locals {
attached_disks_regional = {
for k, v in var.attached_disks : k => v
if v.initialize_params.replica_zone != null
}
attached_disks_zonal = {
for k, v in var.attached_disks : k => v
if v.initialize_params.replica_zone == null
}
}
resource "google_compute_disk" "boot" {
count = (
!local.is_template && var.boot_disk.use_independent_disk != null ? 1 : 0
)
project = local.project_id
zone = local.zone
# by default, GCP creates boot disks with the same name as the instance
# the deviation here is kept for backwards compatibility
name = coalesce(
var.boot_disk.use_independent_disk.name, "${var.name}-boot"
)
image = var.boot_disk.source.image
architecture = var.boot_disk.architecture
type = var.boot_disk.initialize_params.type
size = var.boot_disk.initialize_params.size
provisioned_iops = var.boot_disk.initialize_params.hyperdisk.provisioned_iops
provisioned_throughput = var.boot_disk.initialize_params.hyperdisk.provisioned_throughput
storage_pool = var.boot_disk.initialize_params.hyperdisk.storage_pool
labels = merge(var.labels, {
disk_name = "boot"
disk_type = var.boot_disk.initialize_params.type
})
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
raw_key = var.encryption.disk_encryption_key_raw
kms_key_self_link = lookup(
local.ctx_kms_keys,
var.encryption.kms_key_self_link,
var.encryption.kms_key_self_link
)
}
}
}
resource "google_compute_disk" "disks" {
for_each = local.is_template ? {} : {
for k, v in local.attached_disks_zonal :
k => v if v.source.attach == null
}
project = local.project_id
zone = local.zone
name = coalesce(each.value.name, "${var.name}-${each.key}")
type = each.value.initialize_params.type
size = each.value.initialize_params.size
architecture = var.boot_disk.architecture
image = each.value.source.image
provisioned_iops = each.value.initialize_params.hyperdisk.provisioned_iops
provisioned_throughput = each.value.initialize_params.hyperdisk.provisioned_throughput
snapshot = each.value.source.snapshot
storage_pool = each.value.initialize_params.hyperdisk.storage_pool
labels = merge(var.labels, {
disk_name = coalesce(each.value.name, each.key)
disk_type = each.value.initialize_params.type
})
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
raw_key = var.encryption.disk_encryption_key_raw
kms_key_self_link = lookup(
local.ctx_kms_keys,
var.encryption.kms_key_self_link,
var.encryption.kms_key_self_link
)
}
}
}
resource "google_compute_region_disk" "disks" {
for_each = local.is_template ? {} : {
for k, v in local.attached_disks_regional :
k => v if v.source.attach == null
}
project = local.project_id
region = local.region
replica_zones = [local.zone, each.value.initialize_params.replica_zone]
name = coalesce(each.value.name, "${var.name}-${each.key}")
type = each.value.initialize_params.type
size = each.value.initialize_params.size
# image = each.value.source.image
snapshot = each.value.source.snapshot
labels = merge(var.labels, {
disk_name = coalesce(each.value.name, each.key)
disk_type = each.value.initialize_params.type
})
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
raw_key = var.encryption.disk_encryption_key_raw
# TODO: check if self link works here
kms_key_name = lookup(
local.ctx_kms_keys,
var.encryption.kms_key_self_link,
var.encryption.kms_key_self_link
)
}
}
}

View File

@@ -0,0 +1,311 @@
/**
* Copyright 2026 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
resource "google_compute_instance" "default" {
provider = google-beta
count = local.is_template ? 0 : 1
project = local.project_id
zone = local.zone
name = var.name
hostname = var.hostname
description = var.description
tags = var.tags
machine_type = var.machine_type
min_cpu_platform = var.min_cpu_platform
can_ip_forward = var.can_ip_forward
allow_stopping_for_update = var.lifecycle_config.allow_stopping_for_update
deletion_protection = var.lifecycle_config.deletion_protection
key_revocation_action_type = var.lifecycle_config.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
: concat(
coalesce(var.resource_policies, []),
coalesce(local.ischedule, [])
)
)
dynamic "advanced_machine_features" {
for_each = local.advanced_mf ? [""] : []
content {
enable_nested_virtualization = var.machine_features_config.enable_nested_virtualization
enable_uefi_networking = var.machine_features_config.enable_uefi_networking
performance_monitoring_unit = var.machine_features_config.performance_monitoring_unit
threads_per_core = var.machine_features_config.threads_per_core
turbo_mode = (
var.machine_features_config.enable_turbo_mode == true ? "ALL_CORE_MAX" : null
)
visible_core_count = var.machine_features_config.visible_core_count
}
}
dynamic "attached_disk" {
for_each = local.attached_disks_zonal
iterator = disk
content {
device_name = coalesce(
disk.value.device_name, disk.value.name, disk.key
)
force_attach = disk.value.force_attach
mode = disk.value.mode
source = (
disk.value.source.attach != null
? disk.value.source.attach
: google_compute_disk.disks[disk.key].name
)
}
}
dynamic "attached_disk" {
for_each = local.attached_disks_regional
iterator = disk
content {
device_name = coalesce(
disk.value.device_name, disk.value.name, disk.key
)
force_attach = disk.value.force_attach
mode = disk.value.mode
source = (
disk.value.source.attach != null
? disk.value.source.attach
: google_compute_region_disk.disks[disk.key].id
)
}
}
boot_disk {
auto_delete = (
var.boot_disk.use_independent_disk != null
? false
: var.boot_disk.auto_delete
)
force_attach = var.boot_disk.force_attach
source = (
var.boot_disk.use_independent_disk != null
? google_compute_disk.boot[0].id
: try(coalesce(
var.boot_disk.source.snapshot,
var.boot_disk.source.attach
), null)
)
disk_encryption_key_raw = (
var.encryption != null ?
try(
local.ctx_kms_keys[var.encryption.disk_encryption_key_raw],
var.encryption.disk_encryption_key_raw
)
: null
)
kms_key_self_link = (
var.encryption != null
? try(
local.ctx_kms_keys[var.encryption.kms_key_self_link],
var.encryption.kms_key_self_link
)
: null
)
dynamic "initialize_params" {
for_each = (
var.boot_disk.initialize_params == null
||
var.boot_disk.use_independent_disk != null
|| (
var.boot_disk.source.snapshot != null &&
var.boot_disk.source.attach != null
)
? []
: [""]
)
content {
architecture = var.boot_disk.architecture
image = var.boot_disk.source.image
size = var.boot_disk.initialize_params.size
type = var.boot_disk.initialize_params.type
resource_manager_tags = var.tag_bindings_immutable
provisioned_iops = var.boot_disk.initialize_params.hyperdisk.provisioned_iops
provisioned_throughput = var.boot_disk.initialize_params.hyperdisk.provisioned_throughput
storage_pool = var.boot_disk.initialize_params.hyperdisk.storage_pool
}
}
}
dynamic "confidential_instance_config" {
for_each = var.confidential_compute != null ? [""] : []
content {
enable_confidential_compute = true
}
}
dynamic "network_interface" {
for_each = var.network_interfaces
iterator = config
content {
network = lookup(
local.ctx.networks, config.value.network, config.value.network
)
subnetwork = lookup(
local.ctx.subnets, config.value.subnetwork, config.value.subnetwork
)
network_ip = try(
local.ctx.addresses[config.value.addresses.internal],
config.value.addresses.internal,
null
)
nic_type = config.value.nic_type
stack_type = config.value.stack_type
queue_count = config.value.queue_count
internal_ipv6_prefix_length = config.value.internal_ipv6_prefix_length
dynamic "access_config" {
for_each = config.value.nat || config.value.network_tier != null ? [""] : []
content {
nat_ip = try(
local.ctx.addresses[config.value.addresses.external],
config.value.addresses.external,
null
)
network_tier = try(config.value.network_tier, null)
}
}
dynamic "alias_ip_range" {
for_each = config.value.alias_ips
iterator = config_alias
content {
subnetwork_range_name = config_alias.key
ip_cidr_range = config_alias.value
}
}
}
}
dynamic "network_interface" {
for_each = var.network_attached_interfaces
content {
network_attachment = network_interface.value
}
}
dynamic "network_performance_config" {
for_each = var.network_performance_tier != null ? [""] : []
content {
total_egress_bandwidth_tier = var.network_performance_tier
}
}
scheduling {
automatic_restart = coalesce(
var.scheduling_config.automatic_restart, var.scheduling_config.provisioning_model != "SPOT"
)
instance_termination_action = local.termination_action
on_host_maintenance = local.on_host_maintenance
preemptible = var.scheduling_config.provisioning_model == "SPOT"
provisioning_model = coalesce(var.scheduling_config.provisioning_model, "STANDARD")
min_node_cpus = var.scheduling_config.min_node_cpus
maintenance_interval = var.scheduling_config.maintenance_interval
dynamic "max_run_duration" {
for_each = var.scheduling_config.max_run_duration == null ? [] : [""]
content {
nanos = var.scheduling_config.max_run_duration.nanos
seconds = var.scheduling_config.max_run_duration.seconds
}
}
dynamic "local_ssd_recovery_timeout" {
for_each = var.scheduling_config.local_ssd_recovery_timeout == null ? [] : [""]
content {
nanos = var.scheduling_config.local_ssd_recovery_timeout.nanos
seconds = var.scheduling_config.local_ssd_recovery_timeout.seconds
}
}
dynamic "node_affinities" {
for_each = var.scheduling_config.node_affinities
iterator = affinity
content {
key = affinity.key
operator = affinity.value.in ? "IN" : "NOT_IN"
values = affinity.value.values
}
}
dynamic "graceful_shutdown" {
for_each = var.lifecycle_config.graceful_shutdown != null ? [""] : []
content {
enabled = var.lifecycle_config.graceful_shutdown.enabled
dynamic "max_duration" {
for_each = (
var.lifecycle_config.graceful_shutdown.enabled == true &&
var.lifecycle_config.graceful_shutdown.max_duration_secs != null
? [""]
: []
)
content {
seconds = var.lifecycle_config.graceful_shutdown.max_duration_secs
nanos = 0
}
}
}
}
}
dynamic "scratch_disk" {
for_each = [
for i in range(0, var.scratch_disks.count) : var.scratch_disks.interface
]
iterator = config
content {
interface = config.value
}
}
dynamic "service_account" {
for_each = var.service_account == null ? [] : [""]
content {
email = local.service_account.email
scopes = local.service_account.scopes
}
}
dynamic "shielded_instance_config" {
for_each = var.shielded_config != null ? [var.shielded_config] : []
iterator = config
content {
enable_secure_boot = config.value.enable_secure_boot
enable_vtpm = config.value.enable_vtpm
enable_integrity_monitoring = config.value.enable_integrity_monitoring
}
}
dynamic "params" {
for_each = var.tag_bindings_immutable == null ? [] : [""]
content {
resource_manager_tags = var.tag_bindings_immutable
}
}
dynamic "guest_accelerator" {
for_each = local.gpu ? [var.gpu] : []
content {
type = guest_accelerator.value.type
count = guest_accelerator.value.count
}
}
}

View File

@@ -15,22 +15,10 @@
*/
locals {
_region = join("-", slice(split("-", local.zone), 0, 2))
advanced_mf = var.options.advanced_machine_features
attached_disks = {
for i, disk in var.attached_disks :
coalesce(disk.name, disk.device_name, "disk-${i}") => merge(disk, {
options = disk.options == null ? var.attached_disk_defaults : disk.options
})
}
attached_disks_regional = {
for k, v in local.attached_disks :
k => v if try(v.options.replica_zone, null) != null
}
attached_disks_zonal = {
for k, v in local.attached_disks :
k => v if try(v.options.replica_zone, null) == null
}
_region = join("-", slice(split("-", local.zone), 0, 2))
advanced_mf = anytrue([
for k, v in var.machine_features_config : v != null
])
ctx = {
for k, v in var.context : k => {
for kk, vv in v : "${local.ctx_p}${k}:${kk}" => vv
@@ -42,10 +30,13 @@ locals {
})
ctx_p = "$"
gpu = var.gpu != null
on_host_maintenance = (
var.options.spot || var.confidential_compute || local.gpu
? "TERMINATE"
: "MIGRATE"
on_host_maintenance = coalesce(
var.scheduling_config.on_host_maintenance,
(
var.scheduling_config.provisioning_model == "SPOT" ||
var.confidential_compute != null ||
local.gpu
) ? "TERMINATE" : "MIGRATE"
)
project_id = lookup(local.ctx.project_ids, var.project_id, var.project_id)
region = lookup(local.ctx.locations, local._region, local._region)
@@ -75,7 +66,9 @@ locals {
)
}
termination_action = (
var.options.spot || var.options.max_run_duration != null ? coalesce(var.options.termination_action, "STOP") : null
var.scheduling_config.provisioning_model == "SPOT" || var.scheduling_config.max_run_duration != null
? coalesce(var.scheduling_config.termination_action, "STOP")
: null
)
zone = lookup(local.ctx.locations, var.zone, var.zone)
}
@@ -92,366 +85,6 @@ resource "google_kms_key_handle" "default" {
resource_type_selector = each.value.resource_type_selector
}
resource "google_compute_disk" "boot" {
count = !local.template_create && var.boot_disk.use_independent_disk ? 1 : 0
project = local.project_id
zone = local.zone
# by default, GCP creates boot disks with the same name as instance, the deviation here is kept for backwards
# compatibility
name = coalesce(var.boot_disk.name, "${var.name}-boot")
type = var.boot_disk.initialize_params.type
size = var.boot_disk.initialize_params.size
architecture = var.boot_disk.initialize_params.architecture
image = var.boot_disk.initialize_params.image
provisioned_iops = var.boot_disk.initialize_params.provisioned_iops
provisioned_throughput = var.boot_disk.initialize_params.provisioned_throughput
storage_pool = var.boot_disk.initialize_params.storage_pool
labels = merge(var.labels, {
disk_name = "boot"
disk_type = var.boot_disk.initialize_params.type
})
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
raw_key = var.encryption.disk_encryption_key_raw
kms_key_self_link = lookup(
local.ctx_kms_keys,
var.encryption.kms_key_self_link,
var.encryption.kms_key_self_link
)
}
}
}
resource "google_compute_disk" "disks" {
for_each = local.template_create ? {} : {
for k, v in local.attached_disks_zonal :
k => v if v.source_type != "attach"
}
project = local.project_id
zone = local.zone
name = "${var.name}-${each.key}"
type = each.value.options.type
size = each.value.size
architecture = each.value.options.architecture
image = each.value.source_type == "image" ? each.value.source : null
provisioned_iops = each.value.options.provisioned_iops
provisioned_throughput = each.value.options.provisioned_throughput
snapshot = each.value.source_type == "snapshot" ? each.value.source : null
storage_pool = each.value.options.storage_pool
labels = merge(var.labels, {
disk_name = each.value.name
disk_type = each.value.options.type
})
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
raw_key = var.encryption.disk_encryption_key_raw
kms_key_self_link = lookup(
local.ctx_kms_keys,
var.encryption.kms_key_self_link,
var.encryption.kms_key_self_link
)
}
}
}
resource "google_compute_region_disk" "disks" {
provider = google-beta
for_each = local.template_create ? {} : {
for k, v in local.attached_disks_regional :
k => v if v.source_type != "attach"
}
project = local.project_id
region = local.region
replica_zones = [local.zone, each.value.options.replica_zone]
name = "${var.name}-${each.key}"
type = each.value.options.type
size = each.value.size
# image = each.value.source_type == "image" ? each.value.source : null
snapshot = each.value.source_type == "snapshot" ? each.value.source : null
labels = merge(var.labels, {
disk_name = each.value.name
disk_type = each.value.options.type
})
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
raw_key = var.encryption.disk_encryption_key_raw
# TODO: check if self link works here
kms_key_name = lookup(
local.ctx_kms_keys,
var.encryption.kms_key_self_link,
var.encryption.kms_key_self_link
)
}
}
}
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
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
: concat(
coalesce(var.resource_policies, []),
coalesce(local.ischedule, [])
)
)
dynamic "advanced_machine_features" {
for_each = local.advanced_mf != null ? [""] : []
content {
enable_nested_virtualization = local.advanced_mf.enable_nested_virtualization
enable_uefi_networking = local.advanced_mf.enable_uefi_networking
performance_monitoring_unit = local.advanced_mf.performance_monitoring_unit
threads_per_core = local.advanced_mf.threads_per_core
turbo_mode = (
local.advanced_mf.enable_turbo_mode ? "ALL_CORE_MAX" : null
)
visible_core_count = local.advanced_mf.visible_core_count
}
}
dynamic "attached_disk" {
for_each = local.attached_disks_zonal
iterator = config
content {
device_name = (
config.value.device_name != null
? config.value.device_name
: config.value.name
)
mode = config.value.options.mode
source = (
config.value.source_type == "attach"
? config.value.source
: google_compute_disk.disks[config.key].name
)
}
}
dynamic "attached_disk" {
for_each = local.attached_disks_regional
iterator = config
content {
device_name = coalesce(
config.value.device_name, config.value.name, config.key
)
mode = config.value.options.mode
source = (
config.value.source_type == "attach"
? config.value.source
: google_compute_region_disk.disks[config.key].id
)
}
}
boot_disk {
auto_delete = (
var.boot_disk.use_independent_disk
? false
: var.boot_disk.auto_delete
)
source = (
var.boot_disk.use_independent_disk
? google_compute_disk.boot[0].id
: var.boot_disk.source
)
disk_encryption_key_raw = (
var.encryption != null ?
try(
local.ctx_kms_keys[var.encryption.disk_encryption_key_raw],
var.encryption.disk_encryption_key_raw
)
: null
)
kms_key_self_link = (
var.encryption != null
? try(
local.ctx_kms_keys[var.encryption.kms_key_self_link],
var.encryption.kms_key_self_link
)
: null
)
dynamic "initialize_params" {
for_each = (
var.boot_disk.initialize_params == null
||
var.boot_disk.use_independent_disk
||
var.boot_disk.source != null
? []
: [""]
)
content {
architecture = var.boot_disk.initialize_params.architecture
image = var.boot_disk.initialize_params.image
size = var.boot_disk.initialize_params.size
type = var.boot_disk.initialize_params.type
resource_manager_tags = var.tag_bindings_immutable
provisioned_iops = var.boot_disk.initialize_params.provisioned_iops
provisioned_throughput = var.boot_disk.initialize_params.provisioned_throughput
storage_pool = var.boot_disk.initialize_params.storage_pool
}
}
}
dynamic "confidential_instance_config" {
for_each = var.confidential_compute ? [""] : []
content {
enable_confidential_compute = true
}
}
dynamic "network_interface" {
for_each = var.network_interfaces
iterator = config
content {
network = lookup(
local.ctx.networks, config.value.network, config.value.network
)
subnetwork = lookup(
local.ctx.subnets, config.value.subnetwork, config.value.subnetwork
)
network_ip = try(
local.ctx.addresses[config.value.addresses.internal],
config.value.addresses.internal,
null
)
nic_type = config.value.nic_type
stack_type = config.value.stack_type
dynamic "access_config" {
for_each = config.value.nat || config.value.network_tier != null ? [""] : []
content {
nat_ip = try(
local.ctx.addresses[config.value.addresses.external],
config.value.addresses.external,
null
)
network_tier = try(config.value.network_tier, null)
}
}
dynamic "alias_ip_range" {
for_each = config.value.alias_ips
iterator = config_alias
content {
subnetwork_range_name = config_alias.key
ip_cidr_range = config_alias.value
}
}
}
}
dynamic "network_interface" {
for_each = var.network_attached_interfaces
content {
network_attachment = network_interface.value
}
}
scheduling {
automatic_restart = !var.options.spot
instance_termination_action = local.termination_action
on_host_maintenance = local.on_host_maintenance
preemptible = var.options.spot
provisioning_model = var.options.spot ? "SPOT" : "STANDARD"
dynamic "max_run_duration" {
for_each = var.options.max_run_duration == null ? [] : [""]
content {
nanos = var.options.max_run_duration.nanos
seconds = var.options.max_run_duration.seconds
}
}
dynamic "node_affinities" {
for_each = var.options.node_affinities
iterator = affinity
content {
key = affinity.key
operator = affinity.value.in ? "IN" : "NOT_IN"
values = affinity.value.values
}
}
dynamic "graceful_shutdown" {
for_each = var.options.graceful_shutdown != null ? [""] : []
content {
enabled = var.options.graceful_shutdown.enabled
dynamic "max_duration" {
for_each = var.options.graceful_shutdown.enabled == true && var.options.graceful_shutdown.max_duration_secs != null ? [""] : []
content {
seconds = var.options.graceful_shutdown.max_duration_secs
nanos = 0
}
}
}
}
}
dynamic "scratch_disk" {
for_each = [
for i in range(0, var.scratch_disks.count) : var.scratch_disks.interface
]
iterator = config
content {
interface = config.value
}
}
dynamic "service_account" {
for_each = var.service_account == null ? [] : [""]
content {
email = local.service_account.email
scopes = local.service_account.scopes
}
}
dynamic "shielded_instance_config" {
for_each = var.shielded_config != null ? [var.shielded_config] : []
iterator = config
content {
enable_secure_boot = config.value.enable_secure_boot
enable_vtpm = config.value.enable_vtpm
enable_integrity_monitoring = config.value.enable_integrity_monitoring
}
}
dynamic "params" {
for_each = var.tag_bindings_immutable == null ? [] : [""]
content {
resource_manager_tags = var.tag_bindings_immutable
}
}
dynamic "guest_accelerator" {
for_each = local.gpu ? [var.gpu] : []
content {
type = guest_accelerator.value.type
count = guest_accelerator.value.count
}
}
}
resource "google_compute_instance_iam_binding" "default" {
project = local.project_id
for_each = var.iam
@@ -465,7 +98,7 @@ resource "google_compute_instance_iam_binding" "default" {
}
resource "google_compute_instance_group" "unmanaged" {
count = var.group != null && !local.template_create ? 1 : 0
count = var.group != null && !local.is_template ? 1 : 0
project = local.project_id
network = (
length(var.network_interfaces) > 0

View File

@@ -21,23 +21,21 @@ locals {
google_compute_resource_policy.schedule[0].id
]
disk_zonal_schedule_attachments = flatten([
for disk_key, disk_data in local.attached_disks_zonal :
disk_data.snapshot_schedule != null ? [
for schedule in disk_data.snapshot_schedule : {
disk_key = disk_key
source_type = disk_data.source_type
source = disk_data.source
for k, v in local.attached_disks_zonal :
v.snapshot_schedule != null ? [
for schedule in v.snapshot_schedule : {
disk_key = k
source = v.source
snapshot_schedule = schedule
}
] : []
])
disk_regional_schedule_attachments = flatten([
for disk_key, disk_data in try(local.attached_disks_regional, []) :
disk_data.snapshot_schedule != null ? [
for schedule in disk_data.snapshot_schedule : {
disk_key = disk_key
source_type = disk_data.source_type
source = disk_data.source
for k, v in try(local.attached_disks_regional, []) :
v.snapshot_schedule != null ? [
for schedule in v.snapshot_schedule : {
disk_key = k
source = v.source
snapshot_schedule = schedule
}
] : []
@@ -140,7 +138,7 @@ resource "google_compute_disk_resource_policy_attachment" "boot" {
)
# if independent disk is used for boot disk it will have a different name compared to when created implicitly
disk = (
!local.template_create && var.boot_disk.use_independent_disk
!local.is_template && var.boot_disk.use_independent_disk != null
? google_compute_disk.boot[0].name
: var.name
)
@@ -160,8 +158,8 @@ resource "google_compute_disk_resource_policy_attachment" "attached" {
each.value.snapshot_schedule
)
disk = (
each.value.source_type == "attach"
? each.value.source
each.value.source.attach != null
? each.value.source.attach
: google_compute_disk.disks[each.value.disk_key].name
)
depends_on = [
@@ -182,8 +180,8 @@ resource "google_compute_region_disk_resource_policy_attachment" "attached" {
each.value.snapshot_schedule
)
disk = (
each.value.source_type == "attach"
? each.value.source
each.value.source.attach != null
? each.value.source.attach
: google_compute_region_disk.disks[each.value.disk_key].name
)
depends_on = [

View File

@@ -53,7 +53,7 @@ locals {
# use a different resource to avoid overlapping key issues
resource "google_tags_location_tag_binding" "network" {
for_each = local.template_create ? {} : var.network_tag_bindings
for_each = local.is_template ? {} : var.network_tag_bindings
parent = (
"${local.tag_parent_base}/zones/${local.zone}/instances/${google_compute_instance.default[0].instance_id}"
)
@@ -62,7 +62,7 @@ resource "google_tags_location_tag_binding" "network" {
}
resource "google_tags_location_tag_binding" "instance" {
for_each = local.template_create ? {} : var.tag_bindings
for_each = local.is_template ? {} : var.tag_bindings
parent = (
"${local.tag_parent_base}/zones/${local.zone}/instances/${google_compute_instance.default[0].instance_id}"
)
@@ -72,7 +72,7 @@ resource "google_tags_location_tag_binding" "instance" {
resource "google_tags_location_tag_binding" "boot_disks" {
for_each = (
local.template_create ? {} : { for v in local.boot_disk_tags : v.key => v }
local.is_template ? {} : { for v in local.boot_disk_tags : v.key => v }
)
parent = (
"${local.tag_parent_base}/zones/${local.zone}/disks/${each.value.disk_id}"
@@ -83,7 +83,7 @@ resource "google_tags_location_tag_binding" "boot_disks" {
resource "google_tags_location_tag_binding" "disks" {
for_each = (
local.template_create ? {} : { for v in local.disk_tags : v.key => v }
local.is_template ? {} : { for v in local.disk_tags : v.key => v }
)
parent = (
"${local.tag_parent_base}/zones/${local.zone}/disks/${each.value.disk_id}"
@@ -94,7 +94,7 @@ resource "google_tags_location_tag_binding" "disks" {
resource "google_tags_location_tag_binding" "disks_regional" {
for_each = (
local.template_create ? {} : { for v in local.region_disk_tags : v.key => v }
local.is_template ? {} : { for v in local.region_disk_tags : v.key => v }
)
parent = (
"${local.tag_parent_base}/regions/${local.region}/disks/${each.value.disk_id}"
@@ -106,7 +106,7 @@ resource "google_tags_location_tag_binding" "disks_regional" {
# TODO: enable once the template id is available
# resource "google_tags_location_tag_binding" "template" {
# for_each = local.template_create ? var.tag_bindings : {}
# for_each = local.is_template ? var.tag_bindings : {}
# parent = (
# "${local.tag_parent_base}/regions/${local.region}/instanceTemplates/${google_compute_instance_template.default[0].instance_id}"
# )

View File

@@ -15,26 +15,26 @@
*/
locals {
template_create = var.create_template != null
is_template = var.create_template != null
template_regional = try(var.create_template.regional, null) == true
}
resource "google_compute_instance_template" "default" {
provider = google-beta
count = local.template_create && !local.template_regional ? 1 : 0
count = local.is_template && !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
machine_type = var.machine_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
key_revocation_action_type = var.lifecycle_config.key_revocation_action_type
resource_policies = (
var.resource_policies == null && var.instance_schedule == null
? null
@@ -44,29 +44,29 @@ resource "google_compute_instance_template" "default" {
)
)
dynamic "advanced_machine_features" {
for_each = local.advanced_mf != null ? [""] : []
for_each = local.advanced_mf ? [""] : []
content {
enable_nested_virtualization = local.advanced_mf.enable_nested_virtualization
enable_uefi_networking = local.advanced_mf.enable_uefi_networking
performance_monitoring_unit = local.advanced_mf.performance_monitoring_unit
threads_per_core = local.advanced_mf.threads_per_core
enable_nested_virtualization = var.machine_features_config.enable_nested_virtualization
enable_uefi_networking = var.machine_features_config.enable_uefi_networking
performance_monitoring_unit = var.machine_features_config.performance_monitoring_unit
threads_per_core = var.machine_features_config.threads_per_core
turbo_mode = (
local.advanced_mf.enable_turbo_mode ? "ALL_CORE_MAX" : null
var.machine_features_config.enable_turbo_mode == true ? "ALL_CORE_MAX" : null
)
visible_core_count = local.advanced_mf.visible_core_count
visible_core_count = var.machine_features_config.visible_core_count
}
}
disk {
architecture = var.boot_disk.initialize_params.architecture
auto_delete = var.boot_disk.auto_delete
boot = true
architecture = var.boot_disk.architecture
auto_delete = var.boot_disk.auto_delete
disk_size_gb = var.boot_disk.initialize_params.size
disk_type = var.boot_disk.initialize_params.type
provisioned_iops = var.boot_disk.initialize_params.provisioned_iops
provisioned_throughput = var.boot_disk.initialize_params.provisioned_throughput
source_image = var.boot_disk.source.image
provisioned_iops = var.boot_disk.initialize_params.hyperdisk.provisioned_iops
provisioned_throughput = var.boot_disk.initialize_params.hyperdisk.provisioned_throughput
resource_manager_tags = var.tag_bindings_immutable
source_image = var.boot_disk.initialize_params.image
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
@@ -81,7 +81,7 @@ resource "google_compute_instance_template" "default" {
}
dynamic "confidential_instance_config" {
for_each = var.confidential_compute ? [""] : []
for_each = var.confidential_compute != null ? [""] : []
content {
enable_confidential_compute = true
}
@@ -95,36 +95,39 @@ resource "google_compute_instance_template" "default" {
}
}
dynamic "disk" {
for_each = local.attached_disks
iterator = config
for_each = var.attached_disks
content {
architecture = config.value.options.architecture
auto_delete = config.value.options.auto_delete
device_name = coalesce(
config.value.device_name, config.value.name, config.key
architecture = var.boot_disk.architecture
auto_delete = disk.value.mode == "READ_ONLY" ? null : disk.value.auto_delete
device_name = coalesce(disk.value.device_name, disk.value.name, disk.key)
disk_name = (
disk.value.source.attach == null
? coalesce(disk.value.name, disk.key)
: null
)
mode = disk.value.mode
resource_manager_tags = var.tag_bindings_immutable
source_image = disk.value.source.image
source = disk.value.source.attach
type = "PERSISTENT"
# Cannot use `source` with any of the fields in
# [disk_size_gb disk_name disk_type source_image labels]
disk_type = (
config.value.source_type != "attach" ? config.value.options.type : null
disk.value.source.attach == null
? disk.value.initialize_params.type
: null
)
disk_size_gb = (
config.value.source_type != "attach" ? config.value.size : null
disk.value.source.attach == null
? disk.value.initialize_params.size
: null
)
mode = config.value.options.mode
provisioned_iops = config.value.options.provisioned_iops
provisioned_throughput = config.value.options.provisioned_throughput
source_image = (
config.value.source_type == "image" ? config.value.source : null
provisioned_iops = (
disk.value.initialize_params.hyperdisk.provisioned_iops
)
source = (
config.value.source_type == "attach" ? config.value.source : null
provisioned_throughput = (
disk.value.initialize_params.hyperdisk.provisioned_throughput
)
disk_name = (
config.value.source_type != "attach" ? config.value.name : null
)
resource_manager_tags = var.tag_bindings_immutable
type = "PERSISTENT"
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
@@ -153,8 +156,10 @@ resource "google_compute_instance_template" "default" {
config.value.addresses.internal,
null
)
nic_type = config.value.nic_type
stack_type = config.value.stack_type
nic_type = config.value.nic_type
stack_type = config.value.stack_type
queue_count = config.value.queue_count
internal_ipv6_prefix_length = config.value.internal_ipv6_prefix_length
dynamic "access_config" {
for_each = config.value.nat || config.value.network_tier != null ? [""] : []
content {
@@ -184,22 +189,42 @@ resource "google_compute_instance_template" "default" {
}
}
dynamic "network_performance_config" {
for_each = var.network_performance_tier != null ? [""] : []
content {
total_egress_bandwidth_tier = var.network_performance_tier
}
}
scheduling {
automatic_restart = !var.options.spot
automatic_restart = coalesce(
var.scheduling_config.automatic_restart, var.scheduling_config.provisioning_model != "SPOT"
)
instance_termination_action = local.termination_action
on_host_maintenance = local.on_host_maintenance
preemptible = var.options.spot
provisioning_model = var.options.spot ? "SPOT" : "STANDARD"
preemptible = var.scheduling_config.provisioning_model == "SPOT"
provisioning_model = coalesce(var.scheduling_config.provisioning_model, "STANDARD")
min_node_cpus = var.scheduling_config.min_node_cpus
maintenance_interval = var.scheduling_config.maintenance_interval
dynamic "max_run_duration" {
for_each = var.options.max_run_duration == null ? [] : [""]
for_each = var.scheduling_config.max_run_duration == null ? [] : [""]
content {
nanos = var.options.max_run_duration.nanos
seconds = var.options.max_run_duration.seconds
nanos = var.scheduling_config.max_run_duration.nanos
seconds = var.scheduling_config.max_run_duration.seconds
}
}
dynamic "local_ssd_recovery_timeout" {
for_each = var.scheduling_config.local_ssd_recovery_timeout == null ? [] : [""]
content {
nanos = var.scheduling_config.local_ssd_recovery_timeout.nanos
seconds = var.scheduling_config.local_ssd_recovery_timeout.seconds
}
}
dynamic "node_affinities" {
for_each = var.options.node_affinities
for_each = var.scheduling_config.node_affinities
iterator = affinity
content {
key = affinity.key
@@ -209,13 +234,18 @@ resource "google_compute_instance_template" "default" {
}
dynamic "graceful_shutdown" {
for_each = var.options.graceful_shutdown != null ? [""] : []
for_each = var.lifecycle_config.graceful_shutdown != null ? [""] : []
content {
enabled = var.options.graceful_shutdown.enabled
enabled = var.lifecycle_config.graceful_shutdown.enabled
dynamic "max_duration" {
for_each = var.options.graceful_shutdown.enabled == true && var.options.graceful_shutdown.max_duration_secs != null ? [""] : []
for_each = (
var.lifecycle_config.graceful_shutdown.enabled == true &&
var.lifecycle_config.graceful_shutdown.max_duration_secs != null
? [""]
: []
)
content {
seconds = var.options.graceful_shutdown.max_duration_secs
seconds = var.lifecycle_config.graceful_shutdown.max_duration_secs
nanos = 0
}
}
@@ -248,20 +278,20 @@ 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
count = local.is_template && 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
machine_type = var.machine_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
key_revocation_action_type = var.lifecycle_config.key_revocation_action_type
resource_policies = (
var.resource_policies == null && var.instance_schedule == null
? null
@@ -271,35 +301,36 @@ resource "google_compute_region_instance_template" "default" {
)
)
dynamic "advanced_machine_features" {
for_each = local.advanced_mf != null ? [""] : []
for_each = local.advanced_mf ? [""] : []
content {
enable_nested_virtualization = local.advanced_mf.enable_nested_virtualization
enable_uefi_networking = local.advanced_mf.enable_uefi_networking
performance_monitoring_unit = local.advanced_mf.performance_monitoring_unit
threads_per_core = local.advanced_mf.threads_per_core
enable_nested_virtualization = var.machine_features_config.enable_nested_virtualization
enable_uefi_networking = var.machine_features_config.enable_uefi_networking
performance_monitoring_unit = var.machine_features_config.performance_monitoring_unit
threads_per_core = var.machine_features_config.threads_per_core
turbo_mode = (
local.advanced_mf.enable_turbo_mode ? "ALL_CORE_MAX" : null
var.machine_features_config.enable_turbo_mode == true ? "ALL_CORE_MAX" : null
)
visible_core_count = local.advanced_mf.visible_core_count
visible_core_count = var.machine_features_config.visible_core_count
}
}
disk {
architecture = var.boot_disk.initialize_params.architecture
auto_delete = var.boot_disk.auto_delete
boot = true
architecture = var.boot_disk.architecture
auto_delete = var.boot_disk.auto_delete
disk_size_gb = var.boot_disk.initialize_params.size
disk_type = var.boot_disk.initialize_params.type
provisioned_iops = var.boot_disk.initialize_params.provisioned_iops
provisioned_throughput = var.boot_disk.initialize_params.provisioned_throughput
source_image = var.boot_disk.source.image
provisioned_iops = var.boot_disk.initialize_params.hyperdisk.provisioned_iops
provisioned_throughput = var.boot_disk.initialize_params.hyperdisk.provisioned_throughput
resource_manager_tags = var.tag_bindings_immutable
source_image = var.boot_disk.initialize_params.image
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
kms_key_self_link = try(
local.ctx_kms_keys[var.encryption.kms_key_self_link],
kms_key_self_link = lookup(
local.ctx_kms_keys,
var.encryption.kms_key_self_link,
var.encryption.kms_key_self_link
)
}
@@ -307,7 +338,7 @@ resource "google_compute_region_instance_template" "default" {
}
dynamic "confidential_instance_config" {
for_each = var.confidential_compute ? [""] : []
for_each = var.confidential_compute != null ? [""] : []
content {
enable_confidential_compute = true
}
@@ -320,42 +351,47 @@ resource "google_compute_region_instance_template" "default" {
count = guest_accelerator.value.count
}
}
dynamic "disk" {
for_each = local.attached_disks
iterator = config
for_each = var.attached_disks
content {
architecture = config.value.options.architecture
auto_delete = config.value.options.auto_delete
device_name = coalesce(
config.value.device_name, config.value.name, config.key
architecture = var.boot_disk.architecture
auto_delete = disk.value.mode == "READ_ONLY" ? null : disk.value.auto_delete
device_name = coalesce(disk.value.device_name, disk.value.name, disk.key)
disk_name = (
disk.value.source.attach == null
? coalesce(disk.value.name, disk.key)
: null
)
mode = disk.value.mode
resource_manager_tags = var.tag_bindings_immutable
source_image = disk.value.source.image
source = disk.value.source.attach
type = "PERSISTENT"
# Cannot use `source` with any of the fields in
# [disk_size_gb disk_name disk_type source_image labels]
disk_type = (
config.value.source_type != "attach" ? config.value.options.type : null
disk.value.source.attach == null
? disk.value.initialize_params.type
: null
)
disk_size_gb = (
config.value.source_type != "attach" ? config.value.size : null
disk.value.source.attach == null
? disk.value.initialize_params.size
: null
)
mode = config.value.options.mode
provisioned_iops = config.value.options.provisioned_iops
provisioned_throughput = config.value.options.provisioned_throughput
source_image = (
config.value.source_type == "image" ? config.value.source : null
provisioned_iops = (
disk.value.initialize_params.hyperdisk.provisioned_iops
)
source = (
config.value.source_type == "attach" ? config.value.source : null
provisioned_throughput = (
disk.value.initialize_params.hyperdisk.provisioned_throughput
)
disk_name = (
config.value.source_type != "attach" ? config.value.name : null
)
resource_manager_tags = var.tag_bindings_immutable
type = "PERSISTENT"
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
kms_key_self_link = try(
local.ctx_kms_keys[var.encryption.kms_key_self_link],
kms_key_self_link = lookup(
local.ctx_kms_keys,
var.encryption.kms_key_self_link,
var.encryption.kms_key_self_link
)
}
@@ -378,8 +414,10 @@ resource "google_compute_region_instance_template" "default" {
config.value.addresses.internal,
null
)
nic_type = config.value.nic_type
stack_type = config.value.stack_type
nic_type = config.value.nic_type
stack_type = config.value.stack_type
queue_count = config.value.queue_count
internal_ipv6_prefix_length = config.value.internal_ipv6_prefix_length
dynamic "access_config" {
for_each = config.value.nat || config.value.network_tier != null ? [""] : []
content {
@@ -403,21 +441,34 @@ resource "google_compute_region_instance_template" "default" {
}
scheduling {
automatic_restart = !var.options.spot
automatic_restart = coalesce(
var.scheduling_config.automatic_restart, var.scheduling_config.provisioning_model != "SPOT"
)
instance_termination_action = local.termination_action
on_host_maintenance = local.on_host_maintenance
preemptible = var.options.spot
provisioning_model = var.options.spot ? "SPOT" : "STANDARD"
preemptible = var.scheduling_config.provisioning_model == "SPOT"
provisioning_model = coalesce(var.scheduling_config.provisioning_model, "STANDARD")
min_node_cpus = var.scheduling_config.min_node_cpus
maintenance_interval = var.scheduling_config.maintenance_interval
dynamic "max_run_duration" {
for_each = var.options.max_run_duration == null ? [] : [""]
for_each = var.scheduling_config.max_run_duration == null ? [] : [""]
content {
nanos = var.options.max_run_duration.nanos
seconds = var.options.max_run_duration.seconds
nanos = var.scheduling_config.max_run_duration.nanos
seconds = var.scheduling_config.max_run_duration.seconds
}
}
dynamic "local_ssd_recovery_timeout" {
for_each = var.scheduling_config.local_ssd_recovery_timeout == null ? [] : [""]
content {
nanos = var.scheduling_config.local_ssd_recovery_timeout.nanos
seconds = var.scheduling_config.local_ssd_recovery_timeout.seconds
}
}
dynamic "node_affinities" {
for_each = var.options.node_affinities
for_each = var.scheduling_config.node_affinities
iterator = affinity
content {
key = affinity.key
@@ -427,13 +478,18 @@ resource "google_compute_region_instance_template" "default" {
}
dynamic "graceful_shutdown" {
for_each = var.options.graceful_shutdown != null ? [""] : []
for_each = var.lifecycle_config.graceful_shutdown != null ? [""] : []
content {
enabled = var.options.graceful_shutdown.enabled
enabled = var.lifecycle_config.graceful_shutdown.enabled
dynamic "max_duration" {
for_each = var.options.graceful_shutdown.enabled == true && var.options.graceful_shutdown.max_duration_secs != null ? [""] : []
for_each = (
var.lifecycle_config.graceful_shutdown.enabled == true &&
var.lifecycle_config.graceful_shutdown.max_duration_secs != null
? [""]
: []
)
content {
seconds = var.options.graceful_shutdown.max_duration_secs
seconds = var.lifecycle_config.graceful_shutdown.max_duration_secs
nanos = 0
}
}

View File

@@ -1,9 +0,0 @@
project_id = "tf-playground-svpc-gce"
zone = "europe-west8-b"
name = "test-sa"
instance_type = "e2-small"
network_interfaces = [{
network = "https://www.googleapis.com/compute/v1/projects/ldj-dev-net-spoke-0/global/networks/dev-spoke-0"
subnetwork = "https://www.googleapis.com/compute/v1/projects/ldj-dev-net-spoke-0/regions/europe-west8/subnetworks/gce"
}]
# service_account = null

View File

@@ -14,110 +14,88 @@
* limitations under the License.
*/
variable "attached_disk_defaults" {
description = "Defaults for attached disks options."
type = object({
auto_delete = optional(bool, false)
mode = string
replica_zone = string
type = string
})
default = {
auto_delete = true
mode = "READ_WRITE"
replica_zone = null
type = "pd-balanced"
}
validation {
condition = var.attached_disk_defaults.mode == "READ_WRITE" || !var.attached_disk_defaults.auto_delete
error_message = "auto_delete can only be specified on READ_WRITE disks."
}
}
variable "attached_disks" {
description = "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."
type = list(object({
name = optional(string)
device_name = optional(string)
# TODO: size can be null when source_type is attach
size = string
snapshot_schedule = optional(list(string))
source = optional(string)
source_type = optional(string)
options = optional(
object({
architecture = optional(string)
auto_delete = optional(bool, false) # applies only to vm templates
mode = optional(string, "READ_WRITE")
description = "Additional disks. Source type is one of 'image' (zonal disks in vms and template), 'snapshot' (vm), 'existing', and null."
type = map(object({
auto_delete = optional(bool, true) # applies only to vm templates
device_name = optional(string)
force_attach = optional(bool)
# auto_delete can only be specified for READ_WRITE, force null otherwise
mode = optional(string, "READ_WRITE")
name = optional(string)
initialize_params = optional(object({
replica_zone = optional(string)
size = optional(number, 10)
type = optional(string, "pd-balanced")
hyperdisk = optional(object({
provisioned_iops = optional(number)
provisioned_throughput = optional(number) # in MiB/s
replica_zone = optional(string)
storage_pool = optional(string)
type = optional(string, "pd-balanced")
}),
{
auto_delete = true
mode = "READ_WRITE"
replica_zone = null
type = "pd-balanced"
}
)
}), {})
}), {})
snapshot_schedule = optional(list(string))
source = optional(object({
attach = optional(string)
# disk = optional(string)
image = optional(string) # not supported yet for repd
# instant_snapshot = optional(string)
snapshot = optional(string)
}), {})
}))
default = []
nullable = false
default = {}
validation {
condition = length([
for d in var.attached_disks : d if(
d.source_type == null
||
contains(["image", "snapshot", "attach"], coalesce(d.source_type, "1"))
)
]) == length(var.attached_disks)
error_message = "Source type must be one of 'image', 'snapshot', 'attach', null."
}
validation {
condition = length([
for d in var.attached_disks : d if d.options == null ||
d.options.mode == "READ_WRITE" || !d.options.auto_delete
]) == length(var.attached_disks)
error_message = "auto_delete can only be specified on READ_WRITE disks."
}
validation {
condition = alltrue([for d in var.attached_disks :
(d.options.architecture == null || contains(["ARM64", "X86_64"], d.options.architecture))
condition = alltrue([
for k, v in var.attached_disks :
contains(["READ_WRITE", "READ_ONLY"], v.mode)
])
error_message = "Architecture can be null, 'X86_64' or 'ARM64'."
error_message = "Allowed values for 'mode' are 'READ_WRITE', 'READ_ONLY'."
}
}
variable "boot_disk" {
description = "Boot disk properties. Initialize params are ignored when source is set."
description = "Boot disk properties."
type = object({
name = optional(string)
architecture = optional(string)
auto_delete = optional(bool, true)
force_attach = optional(bool)
snapshot_schedule = optional(list(string))
source = optional(string)
initialize_params = optional(object({
architecture = optional(string)
image = optional(string, "projects/debian-cloud/global/images/family/debian-11")
provisioned_iops = optional(number)
provisioned_throughput = optional(number) # in MiB/s
size = optional(number, 10)
storage_pool = optional(string)
type = optional(string, "pd-balanced")
size = optional(number, 10)
type = optional(string, "pd-balanced")
hyperdisk = optional(object({
provisioned_iops = optional(number)
provisioned_throughput = optional(number) # in MiB/s
storage_pool = optional(string)
}), {})
}), {})
use_independent_disk = optional(bool, false)
source = optional(object({
attach = optional(string)
disk = optional(string)
image = optional(string)
# instant_snapshot = optional(string)
snapshot = optional(string)
}), { image = "debian-cloud/debian-13" })
use_independent_disk = optional(object({
name = optional(string)
}))
})
default = {
initialize_params = {}
}
default = {}
nullable = false
validation {
condition = var.boot_disk.source != null || var.boot_disk.initialize_params != null
error_message = "You can only have one of boot disk source or initialize params."
condition = (
var.boot_disk.initialize_params == null ||
(
var.boot_disk.source.attach == null &&
var.boot_disk.source.snapshot == null &&
var.boot_disk.source.disk == null
)
)
error_message = "Initialize params cannot be used when attaching an existing disk or creating from a snapshot."
}
validation {
condition = (
var.boot_disk.use_independent_disk != true
var.boot_disk.use_independent_disk == null
||
var.boot_disk.initialize_params != null
)
@@ -125,8 +103,8 @@ variable "boot_disk" {
}
validation {
condition = (
var.boot_disk.initialize_params.architecture == null ||
contains(["ARM64", "X86_64"], var.boot_disk.initialize_params.architecture)
var.boot_disk.architecture == null ||
contains(["ARM64", "X86_64"], var.boot_disk.architecture)
)
error_message = "Architecture can be null, 'X86_64' or 'ARM64'."
}
@@ -139,9 +117,13 @@ variable "can_ip_forward" {
}
variable "confidential_compute" {
description = "Enable Confidential Compute for these instances."
type = bool
default = false
description = "Confidential Compute configuration. Set to 'SEV' or 'SEV_SNP' to enable."
type = string
default = null
validation {
condition = var.confidential_compute == null || contains(["SEV", "SEV_SNP"], var.confidential_compute)
error_message = "Allowed values are 'SEV' or 'SEV_SNP'."
}
}
variable "context" {
@@ -184,6 +166,7 @@ variable "enable_display" {
variable "encryption" {
description = "Encryption options. Only one of kms_key_self_link and disk_encryption_key_raw may be set. If needed, you can specify to encrypt or not the boot disk."
# TODO: Add validation to enforce exclusivity of kms_key_self_link and disk_encryption_key_raw
type = object({
encrypt_boot = optional(bool, false)
disk_encryption_key_raw = optional(string)
@@ -228,9 +211,10 @@ variable "gpu" {
}
variable "group" {
description = "Define this variable to create an instance group for instances. Disabled for template use."
description = "Instance group configuration. Set 'named_ports' to create a new unmanaged instance group, or provide an existing group self_link/id in 'membership' to join one."
type = object({
named_ports = map(number)
membership = optional(string) # ID of an existing unmanaged group to join
named_ports = optional(map(number), {})
})
default = null
}
@@ -248,7 +232,7 @@ variable "iam" {
}
variable "instance_schedule" {
description = "Assign or create and assign an instance schedule policy. Either resource policy id or create_config must be specified if not null. Set active to null to dtach a policy from vm before destroying."
description = "Assign or create and assign an instance schedule policy. Set active to null to detach a policy from vm before destroying."
type = object({
active = optional(bool, true)
description = optional(string)
@@ -271,12 +255,6 @@ variable "instance_schedule" {
}
}
variable "instance_type" {
description = "Instance type."
type = string
default = "e2-micro"
}
variable "kms_autokeys" {
description = "KMS Autokey key handles. If location is not specified it will be inferred from the zone. Key handle names will be added to the kms_keys context with an `autokeys/` prefix."
type = map(object({
@@ -301,6 +279,58 @@ variable "labels" {
default = {}
}
variable "lifecycle_config" {
description = "Instance lifecycle and operational configurations."
type = object({
allow_stopping_for_update = optional(bool, true)
deletion_protection = optional(bool, false)
key_revocation_action_type = optional(string, "NONE")
graceful_shutdown = optional(object({
enabled = optional(bool, false)
max_duration_secs = optional(number)
}))
})
default = {}
validation {
condition = (
var.lifecycle_config.key_revocation_action_type == null || contains(
["NONE", "STOP"], var.lifecycle_config.key_revocation_action_type
)
)
error_message = "Allowed values for key_revocation_action_type are 'NONE' or 'STOP'."
}
}
variable "machine_features_config" {
description = "Machine-level configuration."
type = object({
enable_nested_virtualization = optional(bool)
enable_turbo_mode = optional(bool)
enable_uefi_networking = optional(bool)
performance_monitoring_unit = optional(string)
threads_per_core = optional(number)
visible_core_count = optional(number)
})
nullable = false
default = {}
validation {
condition = (
try(var.machine_features_config.performance_monitoring_unit, null) == null ||
contains(
["ARCHITECTURAL", "ENHANCED", "STANDARD"],
coalesce(try(var.machine_features_config.performance_monitoring_unit, null), "-")
)
)
error_message = "Allowed values for performance_monitoring_unit are ARCHITECTURAL', 'ENHANCED', 'STANDARD' and null."
}
}
variable "machine_type" {
description = "Machine type."
type = string
default = "e2-micro"
}
variable "metadata" {
description = "Instance metadata."
type = map(string)
@@ -335,17 +365,19 @@ variable "network_attached_interfaces" {
variable "network_interfaces" {
description = "Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed."
type = list(object({
network = string
subnetwork = string
alias_ips = optional(map(string), {})
nat = optional(bool, false)
nic_type = optional(string)
stack_type = optional(string)
network = string
subnetwork = string
alias_ips = optional(map(string), {})
nat = optional(bool, false)
network_tier = optional(string)
nic_type = optional(string)
stack_type = optional(string)
queue_count = optional(number) # NEW
internal_ipv6_prefix_length = optional(number) # NEW
addresses = optional(object({
internal = optional(string)
external = optional(string)
}), null)
network_tier = optional(string)
}))
validation {
condition = alltrue([for v in var.network_interfaces : contains(["STANDARD", "PREMIUM"], coalesce(v.network_tier, "PREMIUM"))])
@@ -353,6 +385,16 @@ variable "network_interfaces" {
}
}
variable "network_performance_tier" {
description = "Network performance total egress bandwidth tier."
type = string
default = null
validation {
condition = var.network_performance_tier == null || contains(["DEFAULT", "TIER_1"], coalesce(var.network_performance_tier, "-"))
error_message = "Allowed values are 'DEFAULT' or 'TIER_1'."
}
}
variable "network_tag_bindings" {
description = "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."
type = map(string)
@@ -360,73 +402,6 @@ variable "network_tag_bindings" {
default = {}
}
variable "options" {
description = "Instance options."
type = object({
advanced_machine_features = optional(object({
enable_nested_virtualization = optional(bool)
enable_turbo_mode = optional(bool)
enable_uefi_networking = optional(bool)
performance_monitoring_unit = optional(string)
threads_per_core = optional(number)
visible_core_count = optional(number)
}))
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)
}))
max_run_duration = optional(object({
nanos = optional(number)
seconds = number
}))
node_affinities = optional(map(object({
values = list(string)
in = optional(bool, true)
})), {})
spot = optional(bool, false)
termination_action = optional(string)
})
default = {
allow_stopping_for_update = true
deletion_protection = false
spot = false
termination_action = null
key_revocation_action_type = "NONE"
}
validation {
condition = (
var.options.termination_action == null
||
contains(["STOP", "DELETE"], coalesce(var.options.termination_action, "1"))
)
error_message = "Allowed values for options.termination_action are 'STOP', 'DELETE' and null."
}
validation {
condition = (
try(var.options.advanced_machine_features.performance_monitoring_unit, null) == null
||
contains(["ARCHITECTURAL", "ENHANCED", "STANDARD"], coalesce(
try(
var.options.advanced_machine_features.performance_monitoring_unit, null
), "-"
)
)
)
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" {
description = "Project id."
type = string
@@ -445,6 +420,41 @@ variable "resource_policies" {
default = null
}
variable "scheduling_config" {
description = "Scheduling configuration for the instance."
type = object({
automatic_restart = optional(bool) # Defaults to !spot
maintenance_interval = optional(string) # NEW
min_node_cpus = optional(number) # NEW
on_host_maintenance = optional(string) # Defaults to MIGRATE or TERMINATE based on GPU/Spot
provisioning_model = optional(string) # "SPOT" or "STANDARD"
termination_action = optional(string)
local_ssd_recovery_timeout = optional(object({ # NEW
nanos = optional(number)
seconds = number
}))
max_run_duration = optional(object({
nanos = optional(number)
seconds = number
}))
node_affinities = optional(map(object({
values = list(string)
in = optional(bool, true)
})), {})
})
nullable = false
default = {}
validation {
condition = (
var.scheduling_config.termination_action == null || contains(
["STOP", "DELETE"], coalesce(var.scheduling_config.termination_action, "1"
)
)
)
error_message = "Allowed values for termination_action are 'STOP', 'DELETE' and null."
}
}
variable "scratch_disks" {
description = "Scratch disks configuration."
type = object({
@@ -457,6 +467,7 @@ variable "scratch_disks" {
}
}
variable "service_account" {
description = "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."
type = object({
@@ -467,6 +478,7 @@ variable "service_account" {
default = {}
}
variable "shielded_config" {
description = "Shielded VM configuration of the instances."
type = object({