diff --git a/modules/compute-vm/README.md b/modules/compute-vm/README.md
index 0844c5997..b2f627fe5 100644
--- a/modules/compute-vm/README.md
+++ b/modules/compute-vm/README.md
@@ -937,41 +937,42 @@ module "sole-tenancy" {
| name | description | type | required | default |
|---|---|:---:|:---:|:---:|
-| [name](variables.tf#L266) | Instance name. | string | ✓ | |
-| [network_interfaces](variables.tf#L278) | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | list(object({…})) | ✓ | |
-| [project_id](variables.tf#L363) | Project id. | string | ✓ | |
-| [zone](variables.tf#L483) | Compute zone. | string | ✓ | |
+| [name](variables.tf#L283) | Instance name. | string | ✓ | |
+| [network_interfaces](variables.tf#L295) | Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed. | list(object({…})) | ✓ | |
+| [project_id](variables.tf#L380) | Project id. | string | ✓ | |
+| [zone](variables.tf#L500) | Compute zone. | string | ✓ | |
| [attached_disk_defaults](variables.tf#L17) | Defaults for attached disks options. | object({…}) | | {…} |
| [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. | list(object({…})) | | [] |
| [boot_disk](variables.tf#L82) | Boot disk properties. Initialize params are ignored when source is set. | object({…}) | | {…} |
| [can_ip_forward](variables.tf#L113) | Enable IP forwarding. | bool | | false |
| [confidential_compute](variables.tf#L119) | Enable Confidential Compute for these instances. | bool | | false |
-| [create_template](variables.tf#L125) | Create instance template instead of instances. Defaults to a global template. | object({…}) | | null |
-| [description](variables.tf#L134) | Description of a Compute Instance. | string | | "Managed by the compute-vm Terraform module." |
-| [enable_display](variables.tf#L140) | Enable virtual display on the instances. | bool | | false |
-| [encryption](variables.tf#L146) | 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. | object({…}) | | null |
-| [gpu](variables.tf#L156) | GPU information. Based on https://cloud.google.com/compute/docs/gpus. | object({…}) | | null |
-| [group](variables.tf#L191) | Define this variable to create an instance group for instances. Disabled for template use. | object({…}) | | null |
-| [hostname](variables.tf#L199) | Instance FQDN name. | string | | null |
-| [iam](variables.tf#L205) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} |
-| [instance_schedule](variables.tf#L211) | 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. | object({…}) | | null |
-| [instance_type](variables.tf#L235) | Instance type. | string | | "f1-micro" |
-| [labels](variables.tf#L241) | Instance labels. | map(string) | | {} |
-| [metadata](variables.tf#L247) | Instance metadata. | map(string) | | {} |
-| [metadata_startup_script](variables.tf#L253) | Instance startup script. Will trigger recreation on change, even after importing. | string | | null |
-| [min_cpu_platform](variables.tf#L260) | Minimum CPU platform. | string | | null |
-| [network_attached_interfaces](variables.tf#L271) | Network interfaces using network attachments. | list(string) | | [] |
-| [network_tag_bindings](variables.tf#L299) | 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. | map(string) | | {} |
-| [options](variables.tf#L306) | Instance options. | object({…}) | | {…} |
-| [project_number](variables.tf#L368) | Project number. Used in tag bindings to avoid a permadiff. | string | | null |
-| [resource_policies](variables.tf#L374) | Resource policies to attach to the instance or template. | list(string) | | null |
-| [scratch_disks](variables.tf#L381) | Scratch disks configuration. | object({…}) | | {…} |
-| [service_account](variables.tf#L393) | 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. | object({…}) | | {} |
-| [shielded_config](variables.tf#L403) | Shielded VM configuration of the instances. | object({…}) | | null |
-| [snapshot_schedules](variables.tf#L413) | Snapshot schedule resource policies that can be attached to disks. | map(object({…})) | | {} |
-| [tag_bindings](variables.tf#L456) | 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. | map(string) | | {} |
-| [tag_bindings_immutable](variables.tf#L463) | 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. | map(string) | | null |
-| [tags](variables.tf#L477) | Instance network tags for firewall rule targets. | list(string) | | [] |
+| [context](variables.tf#L125) | Context-specific interpolations. | object({…}) | | {} |
+| [create_template](variables.tf#L142) | Create instance template instead of instances. Defaults to a global template. | object({…}) | | null |
+| [description](variables.tf#L151) | Description of a Compute Instance. | string | | "Managed by the compute-vm Terraform module." |
+| [enable_display](variables.tf#L157) | Enable virtual display on the instances. | bool | | false |
+| [encryption](variables.tf#L163) | 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. | object({…}) | | null |
+| [gpu](variables.tf#L173) | GPU information. Based on https://cloud.google.com/compute/docs/gpus. | object({…}) | | null |
+| [group](variables.tf#L208) | Define this variable to create an instance group for instances. Disabled for template use. | object({…}) | | null |
+| [hostname](variables.tf#L216) | Instance FQDN name. | string | | null |
+| [iam](variables.tf#L222) | IAM bindings in {ROLE => [MEMBERS]} format. | map(list(string)) | | {} |
+| [instance_schedule](variables.tf#L228) | 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. | object({…}) | | null |
+| [instance_type](variables.tf#L252) | Instance type. | string | | "f1-micro" |
+| [labels](variables.tf#L258) | Instance labels. | map(string) | | {} |
+| [metadata](variables.tf#L264) | Instance metadata. | map(string) | | {} |
+| [metadata_startup_script](variables.tf#L270) | Instance startup script. Will trigger recreation on change, even after importing. | string | | null |
+| [min_cpu_platform](variables.tf#L277) | Minimum CPU platform. | string | | null |
+| [network_attached_interfaces](variables.tf#L288) | Network interfaces using network attachments. | list(string) | | [] |
+| [network_tag_bindings](variables.tf#L316) | 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. | map(string) | | {} |
+| [options](variables.tf#L323) | Instance options. | object({…}) | | {…} |
+| [project_number](variables.tf#L385) | Project number. Used in tag bindings to avoid a permadiff. | string | | null |
+| [resource_policies](variables.tf#L391) | Resource policies to attach to the instance or template. | list(string) | | null |
+| [scratch_disks](variables.tf#L398) | Scratch disks configuration. | object({…}) | | {…} |
+| [service_account](variables.tf#L410) | 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. | object({…}) | | {} |
+| [shielded_config](variables.tf#L420) | Shielded VM configuration of the instances. | object({…}) | | null |
+| [snapshot_schedules](variables.tf#L430) | Snapshot schedule resource policies that can be attached to disks. | map(object({…})) | | {} |
+| [tag_bindings](variables.tf#L473) | 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. | map(string) | | {} |
+| [tag_bindings_immutable](variables.tf#L480) | 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. | map(string) | | null |
+| [tags](variables.tf#L494) | Instance network tags for firewall rule targets. | list(string) | | [] |
## Outputs
diff --git a/modules/compute-vm/main.tf b/modules/compute-vm/main.tf
index 2880e47b9..4535cce8f 100644
--- a/modules/compute-vm/main.tf
+++ b/modules/compute-vm/main.tf
@@ -15,6 +15,7 @@
*/
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 :
@@ -30,18 +31,27 @@ locals {
for k, v in local.attached_disks :
k => v if try(v.options.replica_zone, null) == null
}
+ ctx = {
+ for k, v in var.context : k => {
+ for kk, vv in v : "${local.ctx_p}${k}:${kk}" => vv
+ }
+ }
+ ctx_p = "$"
+ gpu = var.gpu != null
on_host_maintenance = (
var.options.spot || var.confidential_compute || local.gpu
? "TERMINATE"
: "MIGRATE"
)
- region = join("-", slice(split("-", var.zone), 0, 2))
- gpu = var.gpu != null
+ project_id = lookup(local.ctx.project_ids, var.project_id, var.project_id)
+ region = lookup(local.ctx.locations, local._region, local._region)
service_account = var.service_account == null ? null : {
- email = (
- var.service_account.auto_create
+ email = (var.service_account.auto_create
? google_service_account.service_account[0].email
- : var.service_account.email
+ : try(
+ local.ctx.iam_principals[var.service_account.email],
+ var.service_account.email
+ )
)
scopes = (
var.service_account.scopes != null ? var.service_account.scopes : (
@@ -63,12 +73,13 @@ locals {
termination_action = (
var.options.spot || var.options.max_run_duration != null ? coalesce(var.options.termination_action, "STOP") : null
)
+ zone = lookup(local.ctx.locations, var.zone, var.zone)
}
resource "google_compute_disk" "boot" {
count = !local.template_create && var.boot_disk.use_independent_disk ? 1 : 0
- project = var.project_id
- zone = var.zone
+ 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 = "${var.name}-boot"
@@ -82,8 +93,12 @@ resource "google_compute_disk" "boot" {
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
- raw_key = var.encryption.disk_encryption_key_raw
- kms_key_self_link = var.encryption.kms_key_self_link
+ 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
+ )
}
}
}
@@ -93,8 +108,8 @@ resource "google_compute_disk" "disks" {
for k, v in local.attached_disks_zonal :
k => v if v.source_type != "attach"
}
- project = var.project_id
- zone = var.zone
+ project = local.project_id
+ zone = local.zone
name = "${var.name}-${each.key}"
type = each.value.options.type
size = each.value.size
@@ -107,8 +122,12 @@ resource "google_compute_disk" "disks" {
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
- raw_key = var.encryption.disk_encryption_key_raw
- kms_key_self_link = var.encryption.kms_key_self_link
+ 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
+ )
}
}
}
@@ -119,9 +138,9 @@ resource "google_compute_region_disk" "disks" {
for k, v in local.attached_disks_regional :
k => v if v.source_type != "attach"
}
- project = var.project_id
+ project = local.project_id
region = local.region
- replica_zones = [var.zone, each.value.options.replica_zone]
+ replica_zones = [local.zone, each.value.options.replica_zone]
name = "${var.name}-${each.key}"
type = each.value.options.type
size = each.value.size
@@ -136,7 +155,12 @@ resource "google_compute_region_disk" "disks" {
content {
raw_key = var.encryption.disk_encryption_key_raw
# TODO: check if self link works here
- kms_key_name = var.encryption.kms_key_self_link
+ kms_key_name = lookup(
+ local.ctx.kms_keys,
+ var.encryption.kms_key_self_link,
+ var.encryption.kms_key_self_link
+ )
+
}
}
}
@@ -144,8 +168,8 @@ resource "google_compute_region_disk" "disks" {
resource "google_compute_instance" "default" {
provider = google-beta
count = local.template_create ? 0 : 1
- project = var.project_id
- zone = var.zone
+ project = local.project_id
+ zone = local.zone
name = var.name
hostname = var.hostname
description = var.description
@@ -228,10 +252,20 @@ resource "google_compute_instance" "default" {
: var.boot_disk.source
)
disk_encryption_key_raw = (
- var.encryption != null ? var.encryption.disk_encryption_key_raw : null
+ 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 ? var.encryption.kms_key_self_link : null
+ 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 = (
@@ -263,15 +297,27 @@ resource "google_compute_instance" "default" {
for_each = var.network_interfaces
iterator = config
content {
- network = config.value.network
- subnetwork = config.value.subnetwork
- network_ip = try(config.value.addresses.internal, null)
+ 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(config.value.addresses.external, null)
+ nat_ip = try(
+ local.ctx.addresses[config.value.addresses.external],
+ config.value.addresses.external,
+ null
+ )
network_tier = try(config.value.network_tier, null)
}
}
@@ -378,24 +424,26 @@ resource "google_compute_instance" "default" {
}
resource "google_compute_instance_iam_binding" "default" {
- project = var.project_id
+ project = local.project_id
for_each = var.iam
- zone = var.zone
+ zone = local.zone
instance_name = var.name
- role = each.key
- members = each.value
- depends_on = [google_compute_instance.default]
+ role = lookup(local.ctx.custom_roles, each.key, each.key)
+ members = [
+ for m in each.value : lookup(local.ctx.iam_principals, m, m)
+ ]
+ depends_on = [google_compute_instance.default]
}
resource "google_compute_instance_group" "unmanaged" {
count = var.group != null && !local.template_create ? 1 : 0
- project = var.project_id
+ project = local.project_id
network = (
length(var.network_interfaces) > 0
? var.network_interfaces[0].network
: ""
)
- zone = var.zone
+ zone = local.zone
name = var.name
description = var.description
instances = [google_compute_instance.default[0].self_link]
@@ -411,7 +459,7 @@ resource "google_compute_instance_group" "unmanaged" {
resource "google_service_account" "service_account" {
count = try(var.service_account.auto_create, null) == true ? 1 : 0
- project = var.project_id
+ project = local.project_id
account_id = "tf-vm-${var.name}"
display_name = "Terraform VM ${var.name}."
}
diff --git a/modules/compute-vm/outputs.tf b/modules/compute-vm/outputs.tf
index 79551b84a..7e3b97e88 100644
--- a/modules/compute-vm/outputs.tf
+++ b/modules/compute-vm/outputs.tf
@@ -57,7 +57,7 @@ output "internal_ips" {
output "login_command" {
description = "Command to SSH into the machine."
- value = "gcloud compute ssh --project ${var.project_id} --zone ${var.zone} ${var.name}"
+ value = "gcloud compute ssh --project ${local.project_id} --zone ${local.zone} ${var.name}"
}
output "self_link" {
diff --git a/modules/compute-vm/resource-policies.tf b/modules/compute-vm/resource-policies.tf
index fbabd667f..e717ecd74 100644
--- a/modules/compute-vm/resource-policies.tf
+++ b/modules/compute-vm/resource-policies.tf
@@ -46,8 +46,8 @@ locals {
resource "google_compute_resource_policy" "schedule" {
count = var.instance_schedule != null ? 1 : 0
- project = var.project_id
- region = substr(var.zone, 0, length(var.zone) - 2)
+ project = local.project_id
+ region = substr(local.zone, 0, length(local.zone) - 2)
name = var.name
description = coalesce(
var.instance_schedule.description, "Schedule policy for ${var.name}."
@@ -73,8 +73,8 @@ resource "google_compute_resource_policy" "schedule" {
resource "google_compute_resource_policy" "snapshot" {
for_each = var.snapshot_schedules
- project = var.project_id
- region = substr(var.zone, 0, length(var.zone) - 2)
+ project = local.project_id
+ region = substr(local.zone, 0, length(local.zone) - 2)
name = "${var.name}-${each.key}"
description = coalesce(
each.value.description, "Schedule policy ${each.key} for ${var.name}."
@@ -132,8 +132,8 @@ resource "google_compute_resource_policy" "snapshot" {
resource "google_compute_disk_resource_policy_attachment" "boot" {
for_each = var.boot_disk.snapshot_schedule != null ? toset(var.boot_disk.snapshot_schedule) : []
- project = var.project_id
- zone = var.zone
+ project = local.project_id
+ zone = local.zone
name = try(
google_compute_resource_policy.snapshot[each.value].name,
each.value
@@ -153,8 +153,8 @@ resource "google_compute_disk_resource_policy_attachment" "attached" {
"${attachment.disk_key}-${attachment.snapshot_schedule}" => attachment
}
- project = var.project_id
- zone = var.zone
+ project = local.project_id
+ zone = local.zone
name = try(
google_compute_resource_policy.snapshot[each.value.snapshot_schedule].name,
each.value.snapshot_schedule
@@ -176,7 +176,7 @@ resource "google_compute_region_disk_resource_policy_attachment" "attached" {
"${attachment.disk_key}-${attachment.snapshot_schedule}" => attachment
}
- project = var.project_id
+ project = local.project_id
name = try(
google_compute_resource_policy.snapshot[each.value.snapshot_schedule].name,
each.value.snapshot_schedule
diff --git a/modules/compute-vm/tags.tf b/modules/compute-vm/tags.tf
index e06c9f8c0..d5a6a4fb7 100644
--- a/modules/compute-vm/tags.tf
+++ b/modules/compute-vm/tags.tf
@@ -46,7 +46,7 @@ locals {
])
tag_parent_base = format(
"//compute.googleapis.com/projects/%s",
- coalesce(var.project_number, var.project_id)
+ coalesce(var.project_number, local.project_id)
)
}
@@ -55,19 +55,19 @@ locals {
resource "google_tags_location_tag_binding" "network" {
for_each = local.template_create ? {} : var.network_tag_bindings
parent = (
- "${local.tag_parent_base}/zones/${var.zone}/instances/${google_compute_instance.default[0].instance_id}"
+ "${local.tag_parent_base}/zones/${local.zone}/instances/${google_compute_instance.default[0].instance_id}"
)
- tag_value = each.value
- location = var.zone
+ tag_value = lookup(local.ctx.tag_values, each.value, each.value)
+ location = local.zone
}
resource "google_tags_location_tag_binding" "instance" {
for_each = local.template_create ? {} : var.tag_bindings
parent = (
- "${local.tag_parent_base}/zones/${var.zone}/instances/${google_compute_instance.default[0].instance_id}"
+ "${local.tag_parent_base}/zones/${local.zone}/instances/${google_compute_instance.default[0].instance_id}"
)
- tag_value = each.value
- location = var.zone
+ tag_value = lookup(local.ctx.tag_values, each.value, each.value)
+ location = local.zone
}
resource "google_tags_location_tag_binding" "boot_disks" {
@@ -75,10 +75,10 @@ resource "google_tags_location_tag_binding" "boot_disks" {
local.template_create ? {} : { for v in local.boot_disk_tags : v.key => v }
)
parent = (
- "${local.tag_parent_base}/zones/${var.zone}/disks/${each.value.disk_id}"
+ "${local.tag_parent_base}/zones/${local.zone}/disks/${each.value.disk_id}"
)
- tag_value = each.value.tag_value
- location = var.zone
+ tag_value = lookup(local.ctx.tag_values, each.value.tag_value, each.value.tag_value)
+ location = local.zone
}
resource "google_tags_location_tag_binding" "disks" {
@@ -86,10 +86,10 @@ resource "google_tags_location_tag_binding" "disks" {
local.template_create ? {} : { for v in local.disk_tags : v.key => v }
)
parent = (
- "${local.tag_parent_base}/zones/${var.zone}/disks/${each.value.disk_id}"
+ "${local.tag_parent_base}/zones/${local.zone}/disks/${each.value.disk_id}"
)
- tag_value = each.value.tag_value
- location = var.zone
+ tag_value = lookup(local.ctx.tag_values, each.value.tag_value, each.value.tag_value)
+ location = local.zone
}
resource "google_tags_location_tag_binding" "disks_regional" {
@@ -99,7 +99,7 @@ resource "google_tags_location_tag_binding" "disks_regional" {
parent = (
"${local.tag_parent_base}/regions/${local.region}/disks/${each.value.disk_id}"
)
- tag_value = each.value.tag_value
+ tag_value = lookup(local.ctx.tag_values, each.value.tag_value, each.value.tag_value)
location = local.region
}
@@ -108,8 +108,8 @@ resource "google_tags_location_tag_binding" "disks_regional" {
# resource "google_tags_location_tag_binding" "template" {
# for_each = local.template_create ? var.tag_bindings : {}
# parent = (
-# "${local.tag_parent_base}/regions/${local.region}/instanceTemplates/${google_compute_instance.default[0].instance_id}"
+# "${local.tag_parent_base}/regions/${local.region}/instanceTemplates/${google_compute_instance_template.default[0].instance_id}"
# )
-# tag_value = each.value
+# tag_value = lookup(local.ctx.tag_values, each.value, each.value)
# location = local.region
# }
diff --git a/modules/compute-vm/template.tf b/modules/compute-vm/template.tf
index 4e06f9be5..4001d3e65 100644
--- a/modules/compute-vm/template.tf
+++ b/modules/compute-vm/template.tf
@@ -22,7 +22,7 @@ locals {
resource "google_compute_instance_template" "default" {
provider = google-beta
count = local.template_create && !local.template_regional ? 1 : 0
- project = var.project_id
+ project = local.project_id
region = local.region
name_prefix = "${var.name}-"
description = var.description
@@ -67,7 +67,11 @@ resource "google_compute_instance_template" "default" {
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
- kms_key_self_link = 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
+ )
}
}
}
@@ -117,7 +121,11 @@ resource "google_compute_instance_template" "default" {
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
- kms_key_self_link = 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
+ )
}
}
}
@@ -127,15 +135,27 @@ resource "google_compute_instance_template" "default" {
for_each = var.network_interfaces
iterator = config
content {
- network = config.value.network
- subnetwork = config.value.subnetwork
- network_ip = try(config.value.addresses.internal, null)
+ 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 ? [""] : []
content {
- nat_ip = try(config.value.addresses.external, null)
+ nat_ip = try(
+ local.ctx.addresses[config.value.addresses.external],
+ config.value.addresses.external,
+ null
+ )
}
}
dynamic "alias_ip_range" {
@@ -221,7 +241,7 @@ resource "google_compute_instance_template" "default" {
resource "google_compute_region_instance_template" "default" {
provider = google-beta
count = local.template_create && local.template_regional ? 1 : 0
- project = var.project_id
+ project = local.project_id
region = local.region
name_prefix = "${var.name}-"
description = var.description
@@ -266,7 +286,10 @@ resource "google_compute_region_instance_template" "default" {
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
- kms_key_self_link = var.encryption.kms_key_self_link
+ kms_key_self_link = try(
+ local.ctx.kms_keys[var.encryption.kms_key_self_link],
+ var.encryption.kms_key_self_link
+ )
}
}
}
@@ -316,7 +339,10 @@ resource "google_compute_region_instance_template" "default" {
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
content {
- kms_key_self_link = var.encryption.kms_key_self_link
+ kms_key_self_link = try(
+ local.ctx.kms_keys[var.encryption.kms_key_self_link],
+ var.encryption.kms_key_self_link
+ )
}
}
}
@@ -326,15 +352,27 @@ resource "google_compute_region_instance_template" "default" {
for_each = var.network_interfaces
iterator = config
content {
- network = config.value.network
- subnetwork = config.value.subnetwork
- network_ip = try(config.value.addresses.internal, null)
+ 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 ? [""] : []
content {
- nat_ip = try(config.value.addresses.external, null)
+ nat_ip = try(
+ local.ctx.addresses[config.value.addresses.external],
+ config.value.addresses.external,
+ null
+ )
}
}
dynamic "alias_ip_range" {
diff --git a/modules/compute-vm/variables.tf b/modules/compute-vm/variables.tf
index 2d502af73..6e6dfa9c9 100644
--- a/modules/compute-vm/variables.tf
+++ b/modules/compute-vm/variables.tf
@@ -122,6 +122,23 @@ variable "confidential_compute" {
default = false
}
+variable "context" {
+ description = "Context-specific interpolations."
+ type = object({
+ addresses = optional(map(string), {})
+ custom_roles = optional(map(string), {})
+ kms_keys = optional(map(string), {})
+ iam_principals = optional(map(string), {})
+ locations = optional(map(string), {})
+ networks = optional(map(string), {})
+ project_ids = optional(map(string), {})
+ subnets = optional(map(string), {})
+ tag_values = optional(map(string), {})
+ })
+ default = {}
+ nullable = false
+}
+
variable "create_template" {
description = "Create instance template instead of instances. Defaults to a global template."
type = object({
diff --git a/tests/modules/compute_vm/context-template-regional.tfvars b/tests/modules/compute_vm/context-template-regional.tfvars
new file mode 100644
index 000000000..fc11cce4f
--- /dev/null
+++ b/tests/modules/compute_vm/context-template-regional.tfvars
@@ -0,0 +1,62 @@
+attached_disks = [{
+ name = "data-0"
+ size = 10
+ }
+]
+context = {
+ addresses = {
+ ext-test-0 = "35.10.10.10"
+ int-test-0 = "10.0.0.10"
+ }
+ custom_roles = {
+ myrole_one = "organizations/366118655033/roles/myRoleOne"
+ }
+ iam_principals = {
+ mygroup = "group:test-group@example.com"
+ }
+ kms_keys = {
+ test = "projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute"
+ }
+ locations = {
+ ew8a = "europe-west8-a"
+ }
+ networks = {
+ test = "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
+ }
+ project_ids = {
+ test = "foo-test-0"
+ }
+ subnets = {
+ test = "projects/foo-dev-net-spoke-0/regions/europe-west1/subnetworks/gce"
+ }
+ tag_values = {
+ "test/one" = "tagValues/1234567890"
+ }
+}
+create_template = {
+ regional = true
+}
+encryption = {
+ encrypt_boot = true
+ kms_key_self_link = "$kms_keys:test"
+}
+iam = {
+ "$custom_roles:myrole_one" = [
+ "$iam_principals:mygroup"
+ ]
+}
+name = "test"
+network_interfaces = [{
+ network = "$networks:test"
+ subnetwork = "$subnets:test"
+ nat = true
+ addresses = {
+ external = "$addresses:ext-test-0"
+ internal = "$addresses:int-test-0"
+ }
+}]
+project_id = "$project_ids:test"
+tag_bindings = {
+ foo = "$tag_values:test/one"
+}
+zone = "$locations:ew8a"
diff --git a/tests/modules/compute_vm/context-template-regional.yaml b/tests/modules/compute_vm/context-template-regional.yaml
new file mode 100644
index 000000000..073ca8c5c
--- /dev/null
+++ b/tests/modules/compute_vm/context-template-regional.yaml
@@ -0,0 +1,122 @@
+# Copyright 2025 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.
+
+values:
+ google_compute_instance_iam_binding.default["$custom_roles:myrole_one"]:
+ condition: []
+ instance_name: test
+ members:
+ - group:test-group@example.com
+ project: foo-test-0
+ role: organizations/366118655033/roles/myRoleOne
+ zone: europe-west8-a
+ google_compute_region_instance_template.default[0]:
+ advanced_machine_features: []
+ can_ip_forward: false
+ description: Managed by the compute-vm Terraform module.
+ disk:
+ - auto_delete: true
+ boot: true
+ disk_encryption_key:
+ - kms_key_self_link: projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute
+ kms_key_service_account: null
+ disk_name: null
+ disk_size_gb: 10
+ disk_type: pd-balanced
+ guest_os_features: null
+ labels: null
+ resource_manager_tags: null
+ resource_policies: null
+ source: null
+ source_image: projects/debian-cloud/global/images/family/debian-11
+ source_image_encryption_key: []
+ source_snapshot: null
+ source_snapshot_encryption_key: []
+ - auto_delete: true
+ device_name: data-0
+ disk_encryption_key:
+ - kms_key_self_link: projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute
+ kms_key_service_account: null
+ disk_name: data-0
+ disk_size_gb: 10
+ disk_type: pd-balanced
+ guest_os_features: null
+ labels: null
+ mode: READ_WRITE
+ resource_manager_tags: null
+ resource_policies: null
+ source: null
+ source_image_encryption_key: []
+ source_snapshot: null
+ source_snapshot_encryption_key: []
+ type: PERSISTENT
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_display: null
+ guest_accelerator: []
+ instance_description: null
+ key_revocation_action_type: null
+ labels: null
+ machine_type: f1-micro
+ metadata: null
+ metadata_startup_script: null
+ min_cpu_platform: null
+ name_prefix: test-
+ network_interface:
+ - access_config:
+ - nat_ip: 35.10.10.10
+ alias_ip_range: []
+ network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
+ network_ip: 10.0.0.10
+ nic_type: null
+ queue_count: null
+ subnetwork: projects/foo-dev-net-spoke-0/regions/europe-west1/subnetworks/gce
+ network_performance_config: []
+ partner_metadata: null
+ project: foo-test-0
+ region: europe-west8
+ reservation_affinity: []
+ resource_manager_tags: null
+ resource_policies: null
+ scheduling:
+ - automatic_restart: true
+ availability_domain: null
+ graceful_shutdown: []
+ host_error_timeout_seconds: null
+ instance_termination_action: null
+ local_ssd_recovery_timeout: []
+ maintenance_interval: null
+ max_run_duration: []
+ min_node_cpus: null
+ node_affinities: []
+ on_host_maintenance: MIGRATE
+ on_instance_stop_action: []
+ preemptible: false
+ provisioning_model: STANDARD
+ termination_time: null
+ service_account:
+ - scopes:
+ - https://www.googleapis.com/auth/devstorage.read_only
+ - https://www.googleapis.com/auth/logging.write
+ - https://www.googleapis.com/auth/monitoring.write
+ shielded_instance_config: []
+ tags: null
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+counts:
+ google_compute_instance_iam_binding: 1
+ google_compute_region_instance_template: 1
+ modules: 0
+ resources: 2
diff --git a/tests/modules/compute_vm/context-template.tfvars b/tests/modules/compute_vm/context-template.tfvars
new file mode 100644
index 000000000..3ee07484a
--- /dev/null
+++ b/tests/modules/compute_vm/context-template.tfvars
@@ -0,0 +1,60 @@
+attached_disks = [{
+ name = "data-0"
+ size = 10
+ }
+]
+context = {
+ addresses = {
+ ext-test-0 = "35.10.10.10"
+ int-test-0 = "10.0.0.10"
+ }
+ custom_roles = {
+ myrole_one = "organizations/366118655033/roles/myRoleOne"
+ }
+ iam_principals = {
+ mygroup = "group:test-group@example.com"
+ }
+ kms_keys = {
+ test = "projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute"
+ }
+ locations = {
+ ew8a = "europe-west8-a"
+ }
+ networks = {
+ test = "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
+ }
+ project_ids = {
+ test = "foo-test-0"
+ }
+ subnets = {
+ test = "projects/foo-dev-net-spoke-0/regions/europe-west1/subnetworks/gce"
+ }
+ tag_values = {
+ "test/one" = "tagValues/1234567890"
+ }
+}
+create_template = {}
+encryption = {
+ encrypt_boot = true
+ kms_key_self_link = "$kms_keys:test"
+}
+iam = {
+ "$custom_roles:myrole_one" = [
+ "$iam_principals:mygroup"
+ ]
+}
+name = "test"
+network_interfaces = [{
+ network = "$networks:test"
+ subnetwork = "$subnets:test"
+ nat = true
+ addresses = {
+ external = "$addresses:ext-test-0"
+ internal = "$addresses:int-test-0"
+ }
+}]
+project_id = "$project_ids:test"
+tag_bindings = {
+ foo = "$tag_values:test/one"
+}
+zone = "$locations:ew8a"
diff --git a/tests/modules/compute_vm/context-template.yaml b/tests/modules/compute_vm/context-template.yaml
new file mode 100644
index 000000000..edd9a7003
--- /dev/null
+++ b/tests/modules/compute_vm/context-template.yaml
@@ -0,0 +1,123 @@
+# Copyright 2025 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.
+
+values:
+ google_compute_instance_iam_binding.default["$custom_roles:myrole_one"]:
+ condition: []
+ instance_name: test
+ members:
+ - group:test-group@example.com
+ project: foo-test-0
+ role: organizations/366118655033/roles/myRoleOne
+ zone: europe-west8-a
+ google_compute_instance_template.default[0]:
+ advanced_machine_features: []
+ can_ip_forward: false
+ description: Managed by the compute-vm Terraform module.
+ disk:
+ - auto_delete: true
+ boot: true
+ disk_encryption_key:
+ - kms_key_self_link: projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute
+ kms_key_service_account: null
+ disk_name: null
+ disk_size_gb: 10
+ disk_type: pd-balanced
+ guest_os_features: null
+ labels: null
+ resource_manager_tags: null
+ resource_policies: null
+ source: null
+ source_image: projects/debian-cloud/global/images/family/debian-11
+ source_image_encryption_key: []
+ source_snapshot: null
+ source_snapshot_encryption_key: []
+ - auto_delete: true
+ device_name: data-0
+ disk_encryption_key:
+ - kms_key_self_link: projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute
+ kms_key_service_account: null
+ disk_name: data-0
+ disk_size_gb: 10
+ disk_type: pd-balanced
+ guest_os_features: null
+ labels: null
+ mode: READ_WRITE
+ resource_manager_tags: null
+ resource_policies: null
+ source: null
+ source_image_encryption_key: []
+ source_snapshot: null
+ source_snapshot_encryption_key: []
+ type: PERSISTENT
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_display: null
+ guest_accelerator: []
+ instance_description: null
+ key_revocation_action_type: null
+ labels: null
+ machine_type: f1-micro
+ metadata: null
+ metadata_startup_script: null
+ min_cpu_platform: null
+ name_prefix: test-
+ network_interface:
+ - access_config:
+ - nat_ip: 35.10.10.10
+ alias_ip_range: []
+ ipv6_access_config: []
+ network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
+ network_ip: 10.0.0.10
+ nic_type: null
+ queue_count: null
+ subnetwork: projects/foo-dev-net-spoke-0/regions/europe-west1/subnetworks/gce
+ network_performance_config: []
+ partner_metadata: null
+ project: foo-test-0
+ region: europe-west8
+ reservation_affinity: []
+ resource_manager_tags: null
+ resource_policies: null
+ scheduling:
+ - automatic_restart: true
+ availability_domain: null
+ graceful_shutdown: []
+ host_error_timeout_seconds: null
+ instance_termination_action: null
+ local_ssd_recovery_timeout: []
+ maintenance_interval: null
+ max_run_duration: []
+ min_node_cpus: null
+ node_affinities: []
+ on_host_maintenance: MIGRATE
+ on_instance_stop_action: []
+ preemptible: false
+ provisioning_model: STANDARD
+ termination_time: null
+ service_account:
+ - scopes:
+ - https://www.googleapis.com/auth/devstorage.read_only
+ - https://www.googleapis.com/auth/logging.write
+ - https://www.googleapis.com/auth/monitoring.write
+ shielded_instance_config: []
+ tags: null
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+counts:
+ google_compute_instance_iam_binding: 1
+ google_compute_instance_template: 1
+ modules: 0
+ resources: 2
diff --git a/tests/modules/compute_vm/context-vm.tfvars b/tests/modules/compute_vm/context-vm.tfvars
new file mode 100644
index 000000000..91295c4d8
--- /dev/null
+++ b/tests/modules/compute_vm/context-vm.tfvars
@@ -0,0 +1,59 @@
+attached_disks = [{
+ name = "data-0"
+ size = 10
+ }
+]
+context = {
+ addresses = {
+ ext-test-0 = "35.10.10.10"
+ int-test-0 = "10.0.0.10"
+ }
+ custom_roles = {
+ myrole_one = "organizations/366118655033/roles/myRoleOne"
+ }
+ iam_principals = {
+ mygroup = "group:test-group@example.com"
+ }
+ kms_keys = {
+ test = "projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute"
+ }
+ locations = {
+ ew8a = "europe-west8-a"
+ }
+ networks = {
+ test = "projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0"
+ }
+ project_ids = {
+ test = "foo-test-0"
+ }
+ subnets = {
+ test = "projects/foo-dev-net-spoke-0/regions/europe-west1/subnetworks/gce"
+ }
+ tag_values = {
+ "test/one" = "tagValues/1234567890"
+ }
+}
+encryption = {
+ encrypt_boot = true
+ kms_key_self_link = "$kms_keys:test"
+}
+iam = {
+ "$custom_roles:myrole_one" = [
+ "$iam_principals:mygroup"
+ ]
+}
+name = "test"
+network_interfaces = [{
+ network = "$networks:test"
+ subnetwork = "$subnets:test"
+ nat = true
+ addresses = {
+ external = "$addresses:ext-test-0"
+ internal = "$addresses:int-test-0"
+ }
+}]
+project_id = "$project_ids:test"
+tag_bindings = {
+ foo = "$tag_values:test/one"
+}
+zone = "$locations:ew8a"
diff --git a/tests/modules/compute_vm/context-vm.yaml b/tests/modules/compute_vm/context-vm.yaml
new file mode 100644
index 000000000..252e886cf
--- /dev/null
+++ b/tests/modules/compute_vm/context-vm.yaml
@@ -0,0 +1,164 @@
+# Copyright 2025 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.
+
+values:
+ google_compute_disk.disks["data-0"]:
+ architecture: null
+ async_primary_disk: []
+ create_snapshot_before_destroy: false
+ create_snapshot_before_destroy_prefix: null
+ description: null
+ disk_encryption_key:
+ - kms_key_self_link: projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute
+ kms_key_service_account: null
+ raw_key: null
+ rsa_encrypted_key: null
+ effective_labels:
+ disk_name: data-0
+ disk_type: pd-balanced
+ goog-terraform-provisioned: 'true'
+ image: null
+ labels:
+ disk_name: data-0
+ disk_type: pd-balanced
+ name: test-data-0
+ params: []
+ project: foo-test-0
+ size: 10
+ snapshot: null
+ source_disk: null
+ source_image_encryption_key: []
+ source_instant_snapshot: null
+ source_snapshot_encryption_key: []
+ source_storage_object: null
+ storage_pool: null
+ terraform_labels:
+ disk_name: data-0
+ disk_type: pd-balanced
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ type: pd-balanced
+ zone: europe-west8-a
+ google_compute_instance.default[0]:
+ advanced_machine_features: []
+ allow_stopping_for_update: true
+ attached_disk:
+ - device_name: data-0
+ disk_encryption_key_raw: null
+ disk_encryption_key_rsa: null
+ disk_encryption_service_account: null
+ force_attach: null
+ mode: READ_WRITE
+ source: test-data-0
+ boot_disk:
+ - auto_delete: true
+ disk_encryption_key_raw: null
+ disk_encryption_key_rsa: null
+ disk_encryption_service_account: null
+ force_attach: null
+ initialize_params:
+ - enable_confidential_compute: null
+ image: projects/debian-cloud/global/images/family/debian-11
+ resource_manager_tags: null
+ size: 10
+ source_image_encryption_key: []
+ source_snapshot_encryption_key: []
+ storage_pool: null
+ type: pd-balanced
+ interface: null
+ kms_key_self_link: projects/foo-prod-sec-core/locations/global/keyRings/prod-global-default/cryptoKeys/compute
+ mode: READ_WRITE
+ can_ip_forward: false
+ deletion_protection: false
+ description: Managed by the compute-vm Terraform module.
+ desired_status: null
+ effective_labels:
+ goog-terraform-provisioned: 'true'
+ enable_display: false
+ hostname: null
+ instance_encryption_key: []
+ key_revocation_action_type: null
+ labels: null
+ machine_type: f1-micro
+ metadata: null
+ metadata_startup_script: null
+ name: test
+ network_interface:
+ - access_config:
+ - nat_ip: 35.10.10.10
+ public_ptr_domain_name: null
+ alias_ip_range: []
+ ipv6_access_config: []
+ network: projects/foo-dev-net-spoke-0/global/networks/dev-spoke-0
+ network_ip: 10.0.0.10
+ nic_type: null
+ queue_count: null
+ security_policy: null
+ subnetwork: projects/foo-dev-net-spoke-0/regions/europe-west1/subnetworks/gce
+ network_performance_config: []
+ params: []
+ partner_metadata: null
+ project: foo-test-0
+ resource_policies: null
+ scheduling:
+ - automatic_restart: true
+ availability_domain: null
+ graceful_shutdown: []
+ host_error_timeout_seconds: null
+ instance_termination_action: null
+ local_ssd_recovery_timeout: []
+ maintenance_interval: null
+ max_run_duration: []
+ min_node_cpus: null
+ node_affinities: []
+ on_host_maintenance: MIGRATE
+ on_instance_stop_action: []
+ preemptible: false
+ provisioning_model: STANDARD
+ termination_time: null
+ scratch_disk: []
+ service_account:
+ - scopes:
+ - https://www.googleapis.com/auth/devstorage.read_only
+ - https://www.googleapis.com/auth/logging.write
+ - https://www.googleapis.com/auth/monitoring.write
+ shielded_instance_config: []
+ tags: null
+ terraform_labels:
+ goog-terraform-provisioned: 'true'
+ timeouts: null
+ zone: europe-west8-a
+ google_compute_instance_iam_binding.default["$custom_roles:myrole_one"]:
+ condition: []
+ instance_name: test
+ members:
+ - group:test-group@example.com
+ project: foo-test-0
+ role: organizations/366118655033/roles/myRoleOne
+ zone: europe-west8-a
+ google_tags_location_tag_binding.disks["data-0/foo"]:
+ location: europe-west8-a
+ tag_value: tagValues/1234567890
+ timeouts: null
+ google_tags_location_tag_binding.instance["foo"]:
+ location: europe-west8-a
+ tag_value: tagValues/1234567890
+ timeouts: null
+counts:
+ google_compute_disk: 1
+ google_compute_instance: 1
+ google_compute_instance_iam_binding: 1
+ google_tags_location_tag_binding: 2
+ modules: 0
+ resources: 5
diff --git a/tests/modules/compute_vm/tftest.yaml b/tests/modules/compute_vm/tftest.yaml
new file mode 100644
index 000000000..61f5f1dd4
--- /dev/null
+++ b/tests/modules/compute_vm/tftest.yaml
@@ -0,0 +1,19 @@
+# Copyright 2025 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.
+
+module: modules/compute-vm
+tests:
+ context-template:
+ context-template-regional:
+ context-vm: