Refactor compute-vm to remove multiple instance support (#314)

* first iteration, largely untested

* basic tests pass

* basic tests pass

* nic test

* disk tests, refactor

* fix tests

* update README

* update gcs to bq example

* fix README examples, do not create disks for template

* fix data solutions examples

* update cloud operations examples

* update networking examples, mig and ilb modules examples

* update default image to debian 11

* update README table
This commit is contained in:
Ludovico Magnocavallo 2021-10-04 10:46:44 +02:00 committed by GitHub
parent 0bceb328d4
commit 262f823464
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
40 changed files with 500 additions and 618 deletions

View File

@ -102,7 +102,7 @@ module "cf" {
module "simple-vm-example" {
source = "../../modules/compute-vm"
project_id = module.project.project_id
region = var.region
zone = "${var.region}-b"
name = var.name
network_interfaces = [{
network = module.vpc.self_link
@ -111,8 +111,7 @@ module "simple-vm-example" {
addresses = null
alias_ips = null
}]
tags = ["${var.project_id}-test-feed", "shared-test-feed"]
instance_count = 1
tags = ["${var.project_id}-test-feed", "shared-test-feed"]
}
resource "random_pet" "random" {

View File

@ -104,7 +104,7 @@ module "service-directory" {
module "vm-ns-editor" {
source = "../../modules/compute-vm"
project_id = module.project.project_id
region = var.region
zone = "${var.region}-b"
name = "${var.name}-ns"
network_interfaces = [{
network = module.vpc.self_link
@ -116,13 +116,12 @@ module "vm-ns-editor" {
metadata = { startup-script = local.startup-script }
service_account_create = true
tags = ["ssh"]
instance_count = 1
}
module "vm-svc-editor" {
source = "../../modules/compute-vm"
project_id = module.project.project_id
region = var.region
zone = "${var.region}-b"
name = "${var.name}-svc"
network_interfaces = [{
network = module.vpc.self_link
@ -134,5 +133,4 @@ module "vm-svc-editor" {
metadata = { startup-script = local.startup-script }
service_account_create = true
tags = ["ssh"]
instance_count = 1
}

View File

@ -17,15 +17,15 @@
output "vms" {
description = "VM names."
value = {
ns-editor = module.vm-ns-editor.names.0
svc-editor = module.vm-svc-editor.names.0
ns-editor = module.vm-ns-editor.instance.name
svc-editor = module.vm-svc-editor.instance.name
}
}
output "gcloud_commands" {
description = "Commands used to SSH to the VMs."
value = {
ns-editor = "gcloud compute ssh ${module.vm-ns-editor.names.0} --zone ${var.region}-b --tunnel-through-iap"
svc-editor = "gcloud compute ssh ${module.vm-svc-editor.names.0} --zone ${var.region}-b --tunnel-through-iap"
ns-editor = "gcloud compute ssh ${module.vm-ns-editor.instance.name} --zone ${var.region}-b --tunnel-through-iap"
svc-editor = "gcloud compute ssh ${module.vm-svc-editor.instance.name} --zone ${var.region}-b --tunnel-through-iap"
}
}

View File

@ -52,6 +52,6 @@ This sample creates several distinct groups of resources:
| bucket | GCS Bucket URL. | |
| bucket_keys | GCS Bucket Cloud KMS crypto keys. | |
| projects | Project ids. | |
| vm | GCE VMs. | |
| vm | GCE VM. | |
| vm_keys | GCE VM Cloud KMS crypto keys. | |
<!-- END TFDOC -->

View File

@ -97,10 +97,10 @@ module "kms" {
# GCE #
###############################################################################
module "kms_vm_example" {
module "vm_example" {
source = "../../modules/compute-vm"
project_id = module.project-service.project_id
region = var.region
zone = "${var.region}-b"
name = "kms-vm"
network_interfaces = [{
network = module.vpc.self_link,
@ -111,14 +111,13 @@ module "kms_vm_example" {
}]
attached_disks = [
{
name = "attacheddisk"
name = "data"
size = 10
source = null
source_type = null
options = null
}
]
instance_count = 1
boot_disk = {
image = "projects/debian-cloud/global/images/family/debian-10"
type = "pd-ssd"

View File

@ -31,17 +31,17 @@ output "projects" {
}
output "vm" {
description = "GCE VMs."
description = "GCE VM."
value = {
for instance in module.kms_vm_example.instances :
instance.name => instance.network_interface.0.network_ip
name = module.vm_example.instance.name
address = module.vm_example.internal_ip
}
}
output "vm_keys" {
description = "GCE VM Cloud KMS crypto keys."
value = {
for instance in module.kms_vm_example.instances :
instance.name => instance.boot_disk.0.kms_key_self_link
name = module.vm_example.instance.name
key = module.vm_example.instance.boot_disk.0.kms_key_self_link
}
}

View File

@ -46,7 +46,7 @@ This sample creates several distinct groups of resources:
You can now connect to the GCE instance with the following command:
```hcl
gcloud compute ssh vm-example-1
gcloud compute ssh vm-example
```
You can run now the simple pipeline you can find [here](./script/data_ingestion/). Once you have installed required packages and copied a file into the GCS bucket, you can trigger the pipeline using internal ips with a command simila to:
@ -95,7 +95,7 @@ You can check data imported into Google BigQuery from the Google Cloud Console U
You can now connect to the GCE instance with the following command:
```hcl
gcloud compute ssh vm-example-1
gcloud compute ssh vm-example
```
You can run now a simple 'bq load' command to import data into Bigquery. Below an example command:
@ -133,5 +133,5 @@ You can check data imported into Google BigQuery from the Google Cloud Console U
| bq_tables | Bigquery Tables. | |
| buckets | GCS Bucket Cloud KMS crypto keys. | |
| projects | Project ids. | |
| vm | GCE VMs. | |
| vm | GCE VM. | |
<!-- END TFDOC -->

View File

@ -200,7 +200,7 @@ module "nat" {
module "vm_example" {
source = "../../modules/compute-vm"
project_id = module.project-service.project_id
region = var.region
zone = "${var.region}-b"
name = "vm-example"
network_interfaces = [{
network = module.vpc.self_link,
@ -211,14 +211,13 @@ module "vm_example" {
}]
attached_disks = [
{
name = "attacheddisk"
name = "data"
size = 10
source = null
source_type = null
options = null
}
]
instance_count = 2
boot_disk = {
image = "projects/debian-cloud/global/images/family/debian-10"
type = "pd-ssd"
@ -230,7 +229,9 @@ module "vm_example" {
disk_encryption_key_raw = null
kms_key_self_link = module.kms.key_self_links.key-gce
}
metadata = { startup-script = local.vm-startup-script }
metadata = {
startup-script = local.vm-startup-script
}
service_account = module.service-account-gce.email
service_account_scopes = ["https://www.googleapis.com/auth/cloud-platform"]
tags = ["ssh"]

View File

@ -34,9 +34,9 @@ output "projects" {
}
output "vm" {
description = "GCE VMs."
description = "GCE VM."
value = {
for instance in module.vm_example.instances :
instance.name => instance.network_interface.0.network_ip
name = module.vm_example.instance.name
address = module.vm_example.internal_ip
}
}

View File

@ -17,8 +17,7 @@ module "nginx-template" {
source = "./modules/compute-vm"
project_id = var.project_id
name = "nginx-template"
region = "europe-west1"
zones = ["europe-west1-b", "europe-west1-d"]
zone = "europe-west1-b"
tags = ["http-server", "ssh"]
network_interfaces = [{
network = var.vpc.self_link
@ -32,7 +31,7 @@ module "nginx-template" {
type = "pd-ssd"
size = 10
}
use_instance_template = true
create_template = true
metadata = {
user-data = module.cos-nginx.cloud_config
}
@ -65,8 +64,7 @@ module "nginx-template" {
source = "./modules/compute-vm"
project_id = var.project_id
name = "nginx-template"
region = "europe-west1"
zones = ["europe-west1-b", "europe-west1-d"]
zone = "europe-west1-b"
tags = ["http-server", "ssh"]
network_interfaces = [{
network = var.vpc.self_link
@ -80,7 +78,7 @@ module "nginx-template" {
type = "pd-ssd"
size = 10
}
use_instance_template = true
create_template = true
metadata = {
user-data = module.cos-nginx.cloud_config
}
@ -120,8 +118,7 @@ module "nginx-template" {
source = "./modules/compute-vm"
project_id = var.project_id
name = "nginx-template"
region = "europe-west1"
zones = ["europe-west1-b", "europe-west1-d"]
zone = "europe-west1-b"
tags = ["http-server", "ssh"]
network_interfaces = [{
network = var.vpc.self_link,
@ -135,7 +132,7 @@ module "nginx-template" {
type = "pd-ssd"
size = 10
}
use_instance_template = true
create_template = true
metadata = {
user-data = module.cos-nginx.cloud_config
}
@ -178,8 +175,7 @@ module "nginx-template" {
source = "./modules/compute-vm"
project_id = var.project_id
name = "nginx-template"
region = "europe-west1"
zones = ["europe-west1-b", "europe-west1-d"]
zone = "europe-west1-b"
tags = ["http-server", "ssh"]
network_interfaces = [{
network = var.vpc.self_link
@ -193,7 +189,7 @@ module "nginx-template" {
type = "pd-ssd"
size = 10
}
use_instance_template = true
create_template = true
metadata = {
user-data = module.cos-nginx.cloud_config
}
@ -232,8 +228,7 @@ module "nginx-template" {
source = "./modules/compute-vm"
project_id = var.project_id
name = "nginx-template"
region = "europe-west1"
zones = ["europe-west1-b", "europe-west1-d"]
zone = "europe-west1-b"
tags = ["http-server", "ssh"]
network_interfaces = [{
network = var.vpc.self_link
@ -247,7 +242,7 @@ module "nginx-template" {
type = "pd-ssd"
size = 10
}
use_instance_template = true
create_template = true
metadata = {
user-data = module.cos-nginx.cloud_config
}

View File

@ -17,7 +17,7 @@ The simplest example leverages defaults for the boot disk image and size, and us
module "simple-vm-example" {
source = "./modules/compute-vm"
project_id = var.project_id
region = var.region
zone = "europe-west1-b"
name = "test"
network_interfaces = [{
network = var.vpc.self_link
@ -27,7 +27,6 @@ module "simple-vm-example" {
alias_ips = null
}]
service_account_create = true
instance_count = 1
}
# tftest:modules=1:resources=2
@ -48,7 +47,7 @@ This is an example of attaching a pre-existing regional PD to a new instance:
module "simple-vm-example" {
source = "./modules/compute-vm"
project_id = var.project_id
region = var.region
zone = "${var.region}-b"
name = "test"
network_interfaces = [{
network = var.vpc.self_link
@ -63,10 +62,9 @@ module "simple-vm-example" {
source_type = "attach"
source = "regions/${var.region}/disks/repd-test-1"
options = {
auto_delete = false
mode = null
regional = true
type = null
mode = null
replica_zone = "${var.region}-c"
type = null
}
}]
service_account_create = true
@ -80,7 +78,7 @@ And the same example for an instance template (where not using the full self lin
module "simple-vm-example" {
source = "./modules/compute-vm"
project_id = var.project_id
region = var.region
zone = "${var.region}-b"
name = "test"
network_interfaces = [{
network = var.vpc.self_link
@ -95,14 +93,13 @@ module "simple-vm-example" {
source_type = "attach"
source = "https://www.googleapis.com/compute/v1/projects/${var.project_id}/regions/${var.region}/disks/repd-test-1"
options = {
auto_delete = false
mode = null
regional = true
replica_zone = "${var.region}-c"
type = null
}
}]
service_account_create = true
use_instance_template = true
create_template = true
}
# tftest:modules=1:resources=2
```
@ -115,7 +112,7 @@ This example shows how to control disk encryption via the the `encryption` varia
module "kms-vm-example" {
source = "./modules/compute-vm"
project_id = var.project_id
region = var.region
zone = "europe-west1-b"
name = "kms-test"
network_interfaces = [{
network = var.vpc.self_link
@ -134,7 +131,6 @@ module "kms-vm-example" {
}
]
service_account_create = true
instance_count = 1
boot_disk = {
image = "projects/debian-cloud/global/images/family/debian-10"
type = "pd-ssd"
@ -157,7 +153,7 @@ This example shows how add additional [Alias IPs](https://cloud.google.com/vpc/d
module "vm-with-alias-ips" {
source = "./modules/compute-vm"
project_id = "my-project"
region = "europe-west1"
zone = "europe-west1-b"
name = "test"
network_interfaces = [{
network = var.vpc.self_link
@ -165,17 +161,12 @@ module "vm-with-alias-ips" {
nat = false
addresses = null
alias_ips = {
alias1 = [
"10.16.0.10/32", # alias1 IP for first instance
"10.16.0.11/32", # alias1 IP for second instance
"10.16.0.12/32", # alias1 IP for third instance
]
alias1 = "10.16.0.10/32"
}
}]
service_account_create = true
instance_count = 3
}
# tftest:modules=1:resources=4
# tftest:modules=1:resources=2
```
### Instance template
@ -186,7 +177,7 @@ This example shows how to use the module to manage an instance template that def
module "cos-test" {
source = "./modules/compute-vm"
project_id = "my-project"
region = "europe-west1"
zone = "europe-west1-b"
name = "test"
network_interfaces = [{
network = var.vpc.self_link
@ -195,7 +186,6 @@ module "cos-test" {
addresses = null
alias_ips = null
}]
instance_count = 1
boot_disk = {
image = "projects/cos-cloud/global/images/family/cos-stable"
type = "pd-ssd"
@ -211,7 +201,7 @@ module "cos-test" {
}
]
service_account = "vm-default@my-project.iam.gserviceaccount.com"
use_instance_template = true
create_template = true
}
# tftest:modules=1:resources=1
```
@ -228,7 +218,7 @@ locals {
module "instance-group" {
source = "./modules/compute-vm"
project_id = "my-project"
region = "europe-west1"
zone = "europe-west1-b"
name = "ilb-test"
network_interfaces = [{
network = var.vpc.self_link
@ -257,25 +247,25 @@ module "instance-group" {
| name | description | type | required | default |
|---|---|:---: |:---:|:---:|
| name | Instances base name. | <code title="">string</code> | ✓ | |
| network_interfaces | Network interfaces configuration. Use self links for Shared VPC, set addresses and alias_ips to null if not needed. | <code title="list&#40;object&#40;&#123;&#10;nat &#61; bool&#10;network &#61; string&#10;subnetwork &#61; string&#10;addresses &#61; object&#40;&#123;&#10;internal &#61; list&#40;string&#41;&#10;external &#61; list&#40;string&#41;&#10;&#125;&#41;&#10;alias_ips &#61; map&#40;list&#40;string&#41;&#41;&#10;&#125;&#41;&#41;">list(object({...}))</code> | ✓ | |
| name | Instance name. | <code title="">string</code> | ✓ | |
| network_interfaces | Network interfaces configuration. Use self links for Shared VPC, set addresses and alias_ips to null if not needed. | <code title="list&#40;object&#40;&#123;&#10;nat &#61; bool&#10;network &#61; string&#10;subnetwork &#61; string&#10;addresses &#61; object&#40;&#123;&#10;internal &#61; string&#10;external &#61; string&#10;&#125;&#41;&#10;alias_ips &#61; map&#40;string&#41;&#10;&#125;&#41;&#41;">list(object({...}))</code> | ✓ | |
| project_id | Project id. | <code title="">string</code> | ✓ | |
| region | Compute region. | <code title="">string</code> | ✓ | |
| *attached_disk_defaults* | Defaults for attached disks options. | <code title="object&#40;&#123;&#10;auto_delete &#61; bool&#10;mode &#61; string&#10;regional &#61; bool&#10;type &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;auto_delete &#61; true&#10;mode &#61; &#34;READ_WRITE&#34;&#10;regional &#61; false&#10;type &#61; &#34;pd-ssd&#34;&#10;&#125;">...</code> |
| *attached_disks* | 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; string&#10;size &#61; string&#10;source &#61; string&#10;source_type &#61; string&#10;options &#61; object&#40;&#123;&#10;auto_delete &#61; bool&#10;mode &#61; string&#10;regional &#61; bool&#10;type &#61; string&#10;&#125;&#41;&#10;&#125;&#41;&#41;">list(object({...}))</code> | | <code title="&#91;&#93;&#10;validation &#123;&#10;condition &#61; length&#40;&#91;&#10;for d in var.attached_disks : d if&#40;&#10;d.source_type &#61;&#61; null&#10;&#124;&#124;&#10;contains&#40;&#91;&#34;image&#34;, &#34;snapshot&#34;, &#34;attach&#34;&#93;, coalesce&#40;d.source_type, &#34;1&#34;&#41;&#41;&#10;&#41;&#10;&#93;&#41; &#61;&#61; length&#40;var.attached_disks&#41;&#10;error_message &#61; &#34;Source type must be one of &#39;image&#39;, &#39;snapshot&#39;, &#39;attach&#39;, null.&#34;&#10;&#125;">...</code> |
| *boot_disk* | Boot disk properties. | <code title="object&#40;&#123;&#10;image &#61; string&#10;size &#61; number&#10;type &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;image &#61; &#34;projects&#47;debian-cloud&#47;global&#47;images&#47;family&#47;debian-10&#34;&#10;type &#61; &#34;pd-ssd&#34;&#10;size &#61; 10&#10;&#125;">...</code> |
| zone | Compute zone. | <code title="">string</code> | ✓ | |
| *attached_disk_defaults* | Defaults for attached disks options. | <code title="object&#40;&#123;&#10;mode &#61; string&#10;replica_zone &#61; string&#10;type &#61; string&#10;&#125;&#41;">object({...})</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;">...</code> |
| *attached_disks* | 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; string&#10;size &#61; string&#10;source &#61; string&#10;source_type &#61; string&#10;options &#61; object&#40;&#123;&#10;mode &#61; string&#10;replica_zone &#61; string&#10;type &#61; string&#10;&#125;&#41;&#10;&#125;&#41;&#41;">list(object({...}))</code> | | <code title="&#91;&#93;&#10;validation &#123;&#10;condition &#61; length&#40;&#91;&#10;for d in var.attached_disks : d if&#40;&#10;d.source_type &#61;&#61; null&#10;&#124;&#124;&#10;contains&#40;&#91;&#34;image&#34;, &#34;snapshot&#34;, &#34;attach&#34;&#93;, coalesce&#40;d.source_type, &#34;1&#34;&#41;&#41;&#10;&#41;&#10;&#93;&#41; &#61;&#61; length&#40;var.attached_disks&#41;&#10;error_message &#61; &#34;Source type must be one of &#39;image&#39;, &#39;snapshot&#39;, &#39;attach&#39;, null.&#34;&#10;&#125;">...</code> |
| *boot_disk* | Boot disk properties. | <code title="object&#40;&#123;&#10;image &#61; string&#10;size &#61; number&#10;type &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;image &#61; &#34;projects&#47;debian-cloud&#47;global&#47;images&#47;family&#47;debian-11&#34;&#10;type &#61; &#34;pd-balanced&#34;&#10;size &#61; 10&#10;&#125;">...</code> |
| *boot_disk_delete* | Auto delete boot disk. | <code title="">bool</code> | | <code title="">true</code> |
| *can_ip_forward* | Enable IP forwarding. | <code title="">bool</code> | | <code title="">false</code> |
| *confidential_compute* | Enable Confidential Compute for these instances. | <code title="">bool</code> | | <code title="">false</code> |
| *create_template* | Create instance template instead of instances. | <code title="">bool</code> | | <code title="">false</code> |
| *enable_display* | Enable virtual display on the instances | <code title="">bool</code> | | <code title="">false</code> |
| *encryption* | 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; bool&#10;disk_encryption_key_raw &#61; string&#10;kms_key_self_link &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *group* | 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({...})</code> | | <code title="">null</code> |
| *hostname* | Instance FQDN name. | <code title="">string</code> | | <code title="">null</code> |
| *iam* | IAM bindings in {ROLE => [MEMBERS]} format. | <code title="map&#40;list&#40;string&#41;&#41;">map(list(string))</code> | | <code title="">{}</code> |
| *instance_count* | Number of instances to create (only for non-template usage). | <code title="">number</code> | | <code title="">1</code> |
| *instance_type* | Instance type. | <code title="">string</code> | | <code title="">f1-micro</code> |
| *labels* | Instance labels. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *metadata* | Instance metadata. | <code title="map&#40;string&#41;">map(string)</code> | | <code title="">{}</code> |
| *metadata_list* | List of instance metadata that will be cycled through. Ignored for template use. | <code title="list&#40;map&#40;string&#41;&#41;">list(map(string))</code> | | <code title="">[]</code> |
| *min_cpu_platform* | Minimum CPU platform. | <code title="">string</code> | | <code title="">null</code> |
| *options* | Instance options. | <code title="object&#40;&#123;&#10;allow_stopping_for_update &#61; bool&#10;deletion_protection &#61; bool&#10;preemptible &#61; bool&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;allow_stopping_for_update &#61; true&#10;deletion_protection &#61; false&#10;preemptible &#61; false&#10;&#125;">...</code> |
| *scratch_disks* | Scratch disks configuration. | <code title="object&#40;&#123;&#10;count &#61; number&#10;interface &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;count &#61; 0&#10;interface &#61; &#34;NVME&#34;&#10;&#125;">...</code> |
@ -283,21 +273,17 @@ module "instance-group" {
| *service_account_create* | Auto-create service account. | <code title="">bool</code> | | <code title="">false</code> |
| *service_account_scopes* | Scopes applied to service account. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *shielded_config* | Shielded VM configuration of the instances. | <code title="object&#40;&#123;&#10;enable_secure_boot &#61; bool&#10;enable_vtpm &#61; bool&#10;enable_integrity_monitoring &#61; bool&#10;&#125;&#41;">object({...})</code> | | <code title="">null</code> |
| *single_name* | Do not append progressive count to instance name. | <code title="">bool</code> | | <code title="">false</code> |
| *tags* | Instance tags. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
| *use_instance_template* | Create instance template instead of instances. | <code title="">bool</code> | | <code title="">false</code> |
| *zones* | Compute zone, instance will cycle through the list, defaults to the 'b' zone in the region. | <code title="list&#40;string&#41;">list(string)</code> | | <code title="">[]</code> |
## Outputs
| name | description | sensitive |
|---|---|:---:|
| external_ips | Instance main interface external IP addresses. | |
| groups | Instance group resources. | |
| instances | Instance resources. | |
| internal_ips | Instance main interface internal IP addresses. | |
| names | Instance names. | |
| self_links | Instance self links. | |
| external_ip | Instance main interface external IP addresses. | |
| group | Instance group resource. | |
| instance | Instance resource. | |
| internal_ip | Instance main interface internal IP address. | |
| self_link | Instance self links. | |
| service_account | Service account resource. | |
| service_account_email | Service account email. | |
| service_account_iam_email | Service account email. | |

View File

@ -21,36 +21,20 @@ locals {
options = disk.options == null ? var.attached_disk_defaults : disk.options
})
}
attached_disks_pairs = {
for pair in setproduct(keys(local.names), keys(local.attached_disks)) :
"${pair[0]}-${pair[1]}" => { disk_name = pair[1], name = pair[0] }
attached_disks_regional = {
for k, v in local.attached_disks :
k => v if try(v.options.replica_zone, null) != null
}
attached_region_disks_pairs = {
for k, v in local.attached_disks_pairs :
k => v if local.attached_disks[v.disk_name].options.regional
}
attached_zone_disks_pairs = {
for k, v in local.attached_disks_pairs :
k => v if !local.attached_disks[v.disk_name].options.regional
attached_disks_zonal = {
for k, v in local.attached_disks :
k => v if try(v.options.replica_zone, null) == null
}
on_host_maintenance = (
var.options.preemptible || var.confidential_compute
? "TERMINATE"
: "MIGRATE"
)
iam_members = var.use_instance_template ? {} : {
for pair in setproduct(keys(var.iam), keys(local.names)) :
"${pair.0}/${pair.1}" => { role = pair.0, name = pair.1, members = var.iam[pair.0] }
}
names = (
var.use_instance_template
? { (var.name) = 0 }
: (
var.single_name && var.instance_count == 1
? { (var.name) = 0 }
: { for i in range(0, var.instance_count) : "${var.name}-${i + 1}" => i }
)
)
region = join("-", slice(split("-", var.zone), 0, 2))
service_account_email = (
var.service_account_create
? (
@ -76,38 +60,23 @@ locals {
]
)
)
zones_list = length(var.zones) == 0 ? ["${var.region}-b"] : var.zones
zones = {
for name, i in local.names : name => element(local.zones_list, i)
}
}
resource "google_compute_disk" "disks" {
for_each = var.use_instance_template ? {} : {
for k, v in local.attached_zone_disks_pairs :
k => v if local.attached_disks[v.disk_name].source_type != "attach"
for_each = var.create_template ? {} : {
for k, v in local.attached_disks_zonal :
k => v if v.source_type != "attach"
}
project = var.project_id
zone = local.zones[each.value.name]
name = each.key
type = local.attached_disks[each.value.disk_name].options.type
size = local.attached_disks[each.value.disk_name].size
image = (
local.attached_disks[each.value.disk_name].source_type == "image"
? local.attached_disks[each.value.disk_name].source
: null
)
snapshot = (
local.attached_disks[each.value.disk_name].source_type == "snapshot"
? local.attached_disks[each.value.disk_name].source
: null
)
project = var.project_id
zone = var.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 = local.attached_disks[each.value.disk_name].name
disk_type = local.attached_disks[each.value.disk_name].options.type
# Disk images usually have slashes, which is against label
# restrictions
# image = local.attached_disks[each.value.disk_name].image
disk_name = each.value.name
disk_type = each.value.options.type
})
dynamic "disk_encryption_key" {
for_each = var.encryption != null ? [""] : []
@ -120,29 +89,27 @@ resource "google_compute_disk" "disks" {
resource "google_compute_region_disk" "disks" {
provider = google-beta
for_each = var.use_instance_template ? {} : {
for k, v in local.attached_region_disks_pairs :
k => v if local.attached_disks[v.disk_name].source_type != "attach"
for_each = var.create_template ? {} : {
for k, v in local.attached_disks_regional :
k => v if v.source_type != "attach"
}
project = var.project_id
region = var.region
replica_zones = var.zones
name = each.key
type = local.attached_disks[each.value.disk_name].options.type
size = local.attached_disks[each.value.disk_name].size
snapshot = (
local.attached_disks[each.value.disk_name].source_type == "snapshot"
? local.attached_disks[each.value.disk_name].source
: null
)
region = local.region
replica_zones = [var.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 = local.attached_disks[each.value.disk_name].name
disk_type = local.attached_disks[each.value.disk_name].options.type
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
raw_key = var.encryption.disk_encryption_key_raw
# TODO: check if self link works here
kms_key_name = var.encryption.kms_key_self_link
}
}
@ -150,10 +117,10 @@ resource "google_compute_region_disk" "disks" {
resource "google_compute_instance" "default" {
provider = google-beta
for_each = var.use_instance_template ? {} : local.names
count = var.create_template ? 0 : 1
project = var.project_id
zone = local.zones[each.key]
name = each.key
zone = var.zone
name = var.name
hostname = var.hostname
description = "Managed by the compute-vm Terraform module."
tags = var.tags
@ -164,16 +131,10 @@ resource "google_compute_instance" "default" {
deletion_protection = var.options.deletion_protection
enable_display = var.enable_display
labels = var.labels
metadata = merge(
var.metadata, try(element(var.metadata_list, each.value), {})
)
metadata = var.metadata
dynamic "attached_disk" {
for_each = {
for resource_name, pair in local.attached_disks_pairs :
resource_name => local.attached_disks[pair.disk_name]
if pair.name == each.key
}
for_each = local.attached_disks_zonal
iterator = config
content {
device_name = config.value.name
@ -181,16 +142,27 @@ resource "google_compute_instance" "default" {
source = (
config.value.source_type == "attach"
? config.value.source
: (
config.value.options.regional
? google_compute_region_disk.disks[config.key].id
: google_compute_disk.disks[config.key].name
)
: google_compute_disk.disks[config.key].name
)
}
}
dynamic "attached_disk" {
for_each = local.attached_disks_regional
iterator = config
content {
device_name = config.value.name
mode = config.value.options.mode
source = (
config.value.source_type == "attach"
? config.value.source
: google_compute_region_disk.disks[config.key].name
)
}
}
boot_disk {
auto_delete = var.boot_disk_delete
initialize_params {
type = var.boot_disk.type
image = var.boot_disk.image
@ -213,26 +185,19 @@ resource "google_compute_instance" "default" {
content {
network = config.value.network
subnetwork = config.value.subnetwork
network_ip = config.value.addresses == null ? null : (
length(config.value.addresses.internal) == 0
? null
: config.value.addresses.internal[each.value]
)
network_ip = try(config.value.addresses.internal, null)
dynamic "access_config" {
for_each = config.value.nat ? [config.value.addresses] : []
iterator = addresses
for_each = config.value.nat ? [""] : []
content {
nat_ip = addresses.value == null ? null : (
length(addresses.value.external) == 0 ? null : addresses.value.external[each.value]
)
nat_ip = try(config.value.addresses.external, null)
}
}
dynamic "alias_ip_range" {
for_each = config.value.alias_ips != null ? config.value.alias_ips : {}
iterator = alias_ips
iterator = config_alias
content {
subnetwork_range_name = alias_ips.key
ip_cidr_range = alias_ips.value[each.value]
subnetwork_range_name = config_alias.key
ip_cidr_range = config_alias.value
}
}
}
@ -273,20 +238,20 @@ resource "google_compute_instance" "default" {
}
resource "google_compute_instance_iam_binding" "default" {
for_each = local.iam_members
project = var.project_id
zone = local.zones[each.value.name]
instance_name = each.value.name
role = each.value.role
members = each.value.members
for_each = var.iam
zone = var.zone
instance_name = var.name
role = each.key
members = each.value
depends_on = [google_compute_instance.default]
}
resource "google_compute_instance_template" "default" {
provider = google-beta
count = var.use_instance_template ? 1 : 0
count = var.create_template ? 1 : 0
project = var.project_id
region = var.region
region = local.region
name_prefix = "${var.name}-"
description = "Managed by the compute-vm Terraform module."
tags = var.tags
@ -297,10 +262,11 @@ resource "google_compute_instance_template" "default" {
labels = var.labels
disk {
source_image = var.boot_disk.image
disk_type = var.boot_disk.type
disk_size_gb = var.boot_disk.size
auto_delete = var.boot_disk_delete
boot = true
disk_size_gb = var.boot_disk.size
disk_type = var.boot_disk.type
source_image = var.boot_disk.image
}
dynamic "confidential_instance_config" {
@ -314,7 +280,7 @@ resource "google_compute_instance_template" "default" {
for_each = local.attached_disks
iterator = config
content {
auto_delete = config.value.options.auto_delete
# auto_delete = config.value.options.auto_delete
device_name = config.value.name
# Cannot use `source` with any of the fields in
# [disk_size_gb disk_name disk_type source_image labels]
@ -344,9 +310,20 @@ resource "google_compute_instance_template" "default" {
content {
network = config.value.network
subnetwork = config.value.subnetwork
network_ip = try(config.value.addresses.internal, null)
dynamic "access_config" {
for_each = config.value.nat ? [""] : []
content {}
content {
nat_ip = try(config.value.addresses.external, null)
}
}
dynamic "alias_ip_range" {
for_each = config.value.alias_ips != null ? config.value.alias_ips : {}
iterator = config_alias
content {
subnetwork_range_name = config_alias.key
ip_cidr_range = config_alias.value
}
}
}
}
@ -368,24 +345,17 @@ resource "google_compute_instance_template" "default" {
}
resource "google_compute_instance_group" "unmanaged" {
for_each = toset(
var.group != null && !var.use_instance_template
? local.zones_list
: []
)
count = var.group != null && !var.create_template ? 1 : 0
project = var.project_id
network = (
length(var.network_interfaces) > 0
? var.network_interfaces.0.network
: ""
)
zone = each.key
name = "${var.name}-${each.key}"
zone = var.zone
name = var.name
description = "Terraform-managed."
instances = [
for name, instance in google_compute_instance.default :
instance.self_link if instance.zone == each.key
]
instances = [google_compute_instance.default.0.self_link]
dynamic "named_port" {
for_each = var.group.named_ports != null ? var.group.named_ports : {}
iterator = config

View File

@ -14,50 +14,42 @@
* limitations under the License.
*/
output "external_ips" {
output "external_ip" {
description = "Instance main interface external IP addresses."
value = (
var.network_interfaces[0].nat
? [
for name, instance in google_compute_instance.default :
try(instance.network_interface.0.access_config.0.nat_ip, null)
]
: []
? try(google_compute_instance.default.0.network_interface.0.access_config.0.nat_ip, null)
: null
)
}
output "groups" {
description = "Instance group resources."
value = google_compute_instance_group.unmanaged
output "group" {
description = "Instance group resource."
value = try(google_compute_instance_group.unmanaged.0, null)
}
output "instances" {
description = "Instance resources."
value = [for name, instance in google_compute_instance.default : instance]
output "instance" {
description = "Instance resource."
value = try(google_compute_instance.default.0, null)
}
output "internal_ips" {
description = "Instance main interface internal IP addresses."
value = [
for name, instance in google_compute_instance.default :
instance.network_interface.0.network_ip
]
output "internal_ip" {
description = "Instance main interface internal IP address."
value = try(
google_compute_instance.default.0.network_interface.0.network_ip,
null
)
}
output "names" {
description = "Instance names."
value = [for name, instance in google_compute_instance.default : instance.name]
}
output "self_links" {
output "self_link" {
description = "Instance self links."
value = [for name, instance in google_compute_instance.default : instance.self_link]
value = try(google_compute_instance.default.0.self_link, null)
}
output "service_account" {
description = "Service account resource."
value = (
var.service_account_create ? google_service_account.service_account[0] : null
var.service_account_create ? google_service_account.service_account.0 : null
)
}
@ -76,18 +68,10 @@ output "service_account_iam_email" {
output "template" {
description = "Template resource."
value = (
length(google_compute_instance_template.default) > 0
? google_compute_instance_template.default[0]
: null
)
value = try(google_compute_instance_template.default.0, null)
}
output "template_name" {
description = "Template name."
value = (
length(google_compute_instance_template.default) > 0
? google_compute_instance_template.default[0].name
: null
)
value = try(google_compute_instance_template.default.0.name, null)
}

View File

@ -22,10 +22,9 @@ variable "attached_disks" {
source = string
source_type = string
options = object({
auto_delete = bool
mode = string
regional = bool
type = string
mode = string
replica_zone = string
type = string
})
}))
default = []
@ -44,16 +43,15 @@ variable "attached_disks" {
variable "attached_disk_defaults" {
description = "Defaults for attached disks options."
type = object({
auto_delete = bool
mode = string
regional = bool
type = string
mode = string
replica_zone = string
type = string
})
default = {
auto_delete = true
mode = "READ_WRITE"
regional = false
type = "pd-ssd"
auto_delete = true
mode = "READ_WRITE"
replica_zone = null
type = "pd-balanced"
}
}
@ -65,12 +63,18 @@ variable "boot_disk" {
type = string
})
default = {
image = "projects/debian-cloud/global/images/family/debian-10"
type = "pd-ssd"
image = "projects/debian-cloud/global/images/family/debian-11"
type = "pd-balanced"
size = 10
}
}
variable "boot_disk_delete" {
description = "Auto delete boot disk."
type = bool
default = true
}
variable "can_ip_forward" {
description = "Enable IP forwarding."
type = bool
@ -83,6 +87,12 @@ variable "confidential_compute" {
default = false
}
variable "create_template" {
description = "Create instance template instead of instances."
type = bool
default = false
}
variable "enable_display" {
description = "Enable virtual display on the instances"
type = bool
@ -119,12 +129,6 @@ variable "iam" {
default = {}
}
variable "instance_count" {
description = "Number of instances to create (only for non-template usage)."
type = number
default = 1
}
variable "instance_type" {
description = "Instance type."
type = string
@ -143,12 +147,6 @@ variable "metadata" {
default = {}
}
variable "metadata_list" {
description = "List of instance metadata that will be cycled through. Ignored for template use."
type = list(map(string))
default = []
}
variable "min_cpu_platform" {
description = "Minimum CPU platform."
type = string
@ -156,7 +154,7 @@ variable "min_cpu_platform" {
}
variable "name" {
description = "Instances base name."
description = "Instance name."
type = string
}
@ -167,10 +165,10 @@ variable "network_interfaces" {
network = string
subnetwork = string
addresses = object({
internal = list(string)
external = list(string)
internal = string
external = string
})
alias_ips = map(list(string))
alias_ips = map(string)
}))
}
@ -193,11 +191,6 @@ variable "project_id" {
type = string
}
variable "region" {
description = "Compute region."
type = string
}
variable "scratch_disks" {
description = "Scratch disks configuration."
type = object({
@ -230,30 +223,6 @@ variable "service_account_scopes" {
default = []
}
variable "single_name" {
description = "Do not append progressive count to instance name."
type = bool
default = false
}
variable "tags" {
description = "Instance tags."
type = list(string)
default = []
}
variable "use_instance_template" {
description = "Create instance template instead of instances."
type = bool
default = false
}
variable "zones" {
description = "Compute zone, instance will cycle through the list, defaults to the 'b' zone in the region."
type = list(string)
default = []
}
variable "shielded_config" {
description = "Shielded VM configuration of the instances."
type = object({
@ -263,3 +232,14 @@ variable "shielded_config" {
})
default = null
}
variable "tags" {
description = "Instance tags."
type = list(string)
default = []
}
variable "zone" {
description = "Compute zone."
type = string
}

View File

@ -67,10 +67,10 @@ module "cos-nginx" {
module "instance-group" {
source = "./modules/compute-vm"
for_each = toset(["b", "c"])
project_id = var.project_id
region = "europe-west1"
zones = ["europe-west1-b", "europe-west1-c"]
name = "ilb-test"
zone = "europe-west1-${each.key}"
name = "ilb-test-${each.key}"
network_interfaces = [{
network = var.vpc.self_link
subnetwork = var.subnet.self_link
@ -100,9 +100,9 @@ module "ilb" {
subnetwork = var.subnet.self_link
ports = [80]
backends = [
for name, group in module.instance-group.groups : {
for z, mod in module.instance-group : {
failover = false
group = group.self_link
group = mod.group.self_link
balancing_mode = "CONNECTION"
}
]
@ -110,7 +110,7 @@ module "ilb" {
type = "http", check = { port = 80 }, config = {}, logging = true
}
}
# tftest:modules=2:resources=6
# tftest:modules=3:resources=7
```
<!-- BEGIN TFDOC -->

View File

@ -18,7 +18,7 @@ locals {
squid_address = (
var.mig
? module.squid-ilb.0.forwarding_rule_address
: module.squid-vm.internal_ips.0
: module.squid-vm.internal_ip
)
}
@ -147,11 +147,12 @@ module "cos-squid" {
}
module "squid-vm" {
source = "../../modules/compute-vm"
project_id = module.project-host.project_id
region = var.region
name = "squid-vm"
instance_type = "e2-medium"
source = "../../modules/compute-vm"
project_id = module.project-host.project_id
zone = "${var.region}-b"
name = "squid-vm"
instance_type = "e2-medium"
create_template = var.mig
network_interfaces = [{
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["${var.region}/proxy"]
@ -166,7 +167,6 @@ module "squid-vm" {
}
service_account = module.service-account-squid.email
service_account_scopes = ["https://www.googleapis.com/auth/cloud-platform"]
use_instance_template = var.mig
metadata = {
user-data = module.cos-squid.cloud_config
}
@ -261,7 +261,7 @@ module "project-app" {
module "test-vm" {
source = "../../modules/compute-vm"
project_id = module.project-app.project_id
region = var.region
zone = "${var.region}-b"
name = "test-vm"
instance_type = "e2-micro"
tags = ["ssh"]

View File

@ -14,11 +14,11 @@
locals {
prefix = var.prefix != null && var.prefix != "" ? "${var.prefix}-" : ""
vm-instances = concat(
module.vm-hub.instances,
module.vm-spoke-1.instances,
module.vm-spoke-2.instances
)
vm-instances = [
module.vm-hub.instance,
module.vm-spoke-1.instance,
module.vm-spoke-2.instance
]
vm-startup-script = join("\n", [
"#! /bin/bash",
"apt-get update && apt-get install -y bash-completion dnsutils kubectl"
@ -178,7 +178,7 @@ module "hub-to-spoke-2-peering" {
module "vm-hub" {
source = "../../modules/compute-vm"
project_id = module.project.project_id
region = var.region
zone = "${var.region}-b"
name = "${local.prefix}hub"
network_interfaces = [{
network = module.vpc-hub.self_link
@ -196,7 +196,7 @@ module "vm-hub" {
module "vm-spoke-1" {
source = "../../modules/compute-vm"
project_id = module.project.project_id
region = var.region
zone = "${var.region}-b"
name = "${local.prefix}spoke-1"
network_interfaces = [{
network = module.vpc-spoke-1.self_link
@ -214,7 +214,7 @@ module "vm-spoke-1" {
module "vm-spoke-2" {
source = "../../modules/compute-vm"
project_id = module.project.project_id
region = var.region
zone = "${var.region}-b"
name = "${local.prefix}spoke-2"
network_interfaces = [{
network = module.vpc-spoke-2.self_link

View File

@ -13,10 +13,10 @@
# limitations under the License.
locals {
vm-instances = concat(
module.vm-spoke-1.instances,
module.vm-spoke-2.instances
)
vm-instances = [
module.vm-spoke-1.instance,
module.vm-spoke-2.instance
]
vm-startup-script = join("\n", [
"#! /bin/bash",
"apt-get update && apt-get install -y dnsutils"
@ -250,7 +250,7 @@ module "nat-spoke-2" {
module "vm-spoke-1" {
source = "../../modules/compute-vm"
project_id = var.project_id
region = var.regions.b
zone = "${var.regions.b}-b"
name = "spoke-1-test"
network_interfaces = [{
network = module.vpc-spoke-1.self_link
@ -266,7 +266,7 @@ module "vm-spoke-1" {
module "vm-spoke-2" {
source = "../../modules/compute-vm"
project_id = var.project_id
region = var.regions.b
zone = "${var.regions.b}-b"
name = "spoke-2-test"
network_interfaces = [{
network = module.vpc-spoke-2.self_link
@ -290,11 +290,13 @@ module "dns-host" {
name = "example"
domain = "example.com."
client_networks = [module.vpc-hub.self_link]
# setting instance IPs at first apply fails due to dynamic values
recordsets = [
for instance in local.vm-instances : {
name = instance.name, type = "A", ttl = 300,
records = [instance.network_interface.0.network_ip]
}
{ name = "localhost", type = "A", ttl = 300, records = ["127.0.0.1"] }
# for instance in local.vm-instances : {
# name = instance.name, type = "A", ttl = 300,
# records = [instance.network_interface.0.network_ip]
# }
]
}

View File

@ -16,10 +16,10 @@
module "gw" {
source = "../../modules/compute-vm"
for_each = local.zones
project_id = module.project.project_id
region = var.region
zones = local.zones
name = "${local.prefix}gw"
zone = each.value
name = "${local.prefix}gw-${each.key}"
instance_type = "f1-micro"
boot_disk = {
@ -56,7 +56,6 @@ module "gw" {
module.service-accounts.emails["${local.prefix}gce-vm"], null
)
service_account_scopes = ["https://www.googleapis.com/auth/cloud-platform"]
instance_count = 2
group = { named_ports = null }
}
@ -74,9 +73,9 @@ module "ilb-left" {
timeout_sec = null
connection_draining_timeout_sec = null
}
backends = [for zone, group in module.gw.groups : {
backends = [for z, mod in module.gw : {
failover = false
group = group.self_link
group = mod.group.self_link
balancing_mode = "CONNECTION"
}]
health_check_config = {
@ -98,9 +97,9 @@ module "ilb-right" {
timeout_sec = null
connection_draining_timeout_sec = null
}
backends = [for zone, group in module.gw.groups : {
backends = [for z, mod in module.gw : {
failover = false
group = group.self_link
group = mod.group.self_link
balancing_mode = "CONNECTION"
}]
health_check_config = {

View File

@ -20,7 +20,7 @@ locals {
trimprefix(k, local.prefix) => v.address
}
prefix = var.prefix == null || var.prefix == "" ? "" : "${var.prefix}-"
zones = [for z in var.zones : "${var.region}-${z}"]
zones = { for z in var.zones : z => "${var.region}-${z}" }
}
module "project" {

View File

@ -17,11 +17,11 @@
output "addresses" {
description = "IP addresses."
value = {
gw = module.gw.internal_ips
gw = [for z, mod in module.gw : mod.internal_ip]
ilb-left = module.ilb-left.forwarding_rule_address
ilb-right = module.ilb-right.forwarding_rule_address
vm-left = module.vm-left.internal_ips
vm-right = module.vm-right.internal_ips
vm-left = [for z, mod in module.vm-left : mod.internal_ip]
vm-right = [for z, mod in module.vm-right : mod.internal_ip]
}
}
@ -48,23 +48,23 @@ output "backend_health_right" {
output "ssh_gw" {
description = "Command-line login to gateway VMs."
value = [
for name, instance in module.gw.instances :
"gcloud compute ssh ${instance.name} --project ${var.project_id} --zone ${instance.zone}"
for z, mod in module.gw :
"gcloud compute ssh ${mod.instance.name} --project ${var.project_id} --zone ${mod.instance.zone}"
]
}
output "ssh_vm_left" {
description = "Command-line login to left VMs."
value = [
for name, instance in module.vm-left.instances :
"gcloud compute ssh ${instance.name} --project ${var.project_id} --zone ${instance.zone}"
for z, mod in module.vm-left :
"gcloud compute ssh ${mod.instance.name} --project ${var.project_id} --zone ${mod.instance.zone}"
]
}
output "ssh_vm_right" {
description = "Command-line login to right VMs."
value = [
for name, instance in module.vm-right.instances :
"gcloud compute ssh ${instance.name} --project ${var.project_id} --zone ${instance.zone}"
for z, mod in module.vm-right :
"gcloud compute ssh ${mod.instance.name} --project ${var.project_id} --zone ${mod.instance.zone}"
]
}

View File

@ -24,10 +24,10 @@ END
module "vm-left" {
source = "../../modules/compute-vm"
for_each = local.zones
project_id = module.project.project_id
region = var.region
zones = local.zones
name = "${local.prefix}vm-left"
zone = each.value
name = "${local.prefix}vm-left-${each.key}"
instance_type = "f1-micro"
network_interfaces = [
{
@ -46,15 +46,14 @@ module "vm-left" {
module.service-accounts.email, null
)
service_account_scopes = ["https://www.googleapis.com/auth/cloud-platform"]
instance_count = 2
}
module "vm-right" {
source = "../../modules/compute-vm"
for_each = local.zones
project_id = module.project.project_id
region = var.region
name = "${local.prefix}vm-right"
zones = local.zones
zone = each.value
name = "${local.prefix}vm-right-${each.key}"
instance_type = "f1-micro"
network_interfaces = [
{
@ -73,5 +72,4 @@ module "vm-right" {
module.service-accounts.email, null
)
service_account_scopes = ["https://www.googleapis.com/auth/cloud-platform"]
instance_count = 2
}

View File

@ -39,14 +39,14 @@ module "vpc-right" {
priority = null
tags = null
next_hop_type = "instance"
next_hop = module.gw.instances.0.self_link
next_hop = module.gw[var.zones[0]].self_link
}
to-left-gw-2 = {
dest_range = var.ip_ranges.left
priority = null
tags = null
next_hop_type = "instance"
next_hop = module.gw.instances.1.self_link
next_hop = module.gw[var.zones[1]].self_link
}
}
}

View File

@ -104,7 +104,7 @@ module "vpn1" {
}
bgp_session_range = "${local.bgp_interface_gcp1}/30"
ike_version = 2
peer_ip = module.vm-onprem.external_ips.0
peer_ip = module.vm-onprem.external_ip
router = null
shared_secret = ""
}
@ -136,7 +136,7 @@ module "vpn2" {
}
bgp_session_range = "${local.bgp_interface_gcp2}/30"
ike_version = 2
peer_ip = module.vm-onprem.external_ips.0
peer_ip = module.vm-onprem.external_ip
router = null
shared_secret = ""
}
@ -173,14 +173,17 @@ module "dns-gcp" {
client_networks = [module.vpc.self_link]
recordsets = concat(
[{ name = "localhost", type = "A", ttl = 300, records = ["127.0.0.1"] }],
[
for name, ip in zipmap(module.vm-test1.names, module.vm-test1.internal_ips) :
{ name = name, type = "A", ttl = 300, records = [ip] }
],
[
for name, ip in zipmap(module.vm-test2.names, module.vm-test2.internal_ips) :
{ name = name, type = "A", ttl = 300, records = [ip] }
]
# setting addresses during first apply triggers a dynamic value error
# [
# {
# name = module.vm-test1.instance.name, type = "A", ttl = 300,
# records = [module.vm-test1.internal_ip]
# },
# {
# name = module.vm-test2.instance.name, type = "A", ttl = 300,
# records = [module.vm-test2.internal_ip]
# }
# ]
)
}
@ -239,7 +242,7 @@ module "service-account-gce" {
module "vm-test1" {
source = "../../modules/compute-vm"
project_id = var.project_id
region = var.region.gcp1
zone = "${var.region.gcp1}-b"
name = "test-1"
network_interfaces = [{
network = module.vpc.self_link
@ -257,7 +260,7 @@ module "vm-test1" {
module "vm-test2" {
source = "../../modules/compute-vm"
project_id = var.project_id
region = var.region.gcp2
zone = "${var.region.gcp2}-b"
name = "test-2"
network_interfaces = [{
network = module.vpc.self_link
@ -316,7 +319,7 @@ module "service-account-onprem" {
module "vm-onprem" {
source = "../../modules/compute-vm"
project_id = var.project_id
region = var.region.gcp1
zone = "${var.region.gcp1}-b"
instance_type = "f1-micro"
name = "onprem"
boot_disk = {

View File

@ -17,23 +17,23 @@
output "onprem-instance" {
description = "Onprem instance details."
value = {
external_ip = module.vm-onprem.external_ips.0
internal_ip = module.vm-onprem.internal_ips.0
name = module.vm-onprem.names.0
external_ip = module.vm-onprem.external_ip
internal_ip = module.vm-onprem.internal_ip
name = module.vm-onprem.instance.name
}
}
output "test-instance1" {
description = "Test instance details."
value = join(" ", [
module.vm-test1.names[0],
module.vm-test1.internal_ips[0]
module.vm-test1.instance.name,
module.vm-test1.internal_ip
])
}
output "test-instance2" {
description = "Test instance details."
value = join(" ", [
module.vm-test2.names[0],
module.vm-test2.internal_ips[0]
module.vm-test2.instance.name,
module.vm-test2.internal_ip
])
}

View File

@ -177,7 +177,7 @@ module "vpn-hub" {
module "test-vm" {
source = "../../modules/compute-vm"
project_id = module.project.project_id
region = var.region
zone = "${var.region}-b"
name = "${var.name}-test"
instance_type = "e2-micro"
boot_disk = {
@ -192,8 +192,7 @@ module "test-vm" {
network = module.vpc-onprem.self_link
subnetwork = module.vpc-onprem.subnet_self_links["${var.region}/${var.name}-onprem"]
}]
single_name = true
tags = ["ssh"]
tags = ["ssh"]
}
###############################################################################

View File

@ -159,7 +159,7 @@ module "host-dns" {
client_networks = [module.vpc-shared.self_link]
recordsets = [
{ name = "localhost", type = "A", ttl = 300, records = ["127.0.0.1"] },
{ name = "bastion", type = "A", ttl = 300, records = module.vm-bastion.internal_ips },
# { name = "bastion", type = "A", ttl = 300, records = [module.vm-bastion.internal_ip] },
]
}
@ -170,7 +170,7 @@ module "host-dns" {
module "vm-bastion" {
source = "../../modules/compute-vm"
project_id = module.project-svc-gce.project_id
region = var.region
zone = "${var.region}-b"
name = "bastion"
network_interfaces = [{
network = module.vpc-shared.self_link
@ -179,8 +179,7 @@ module "vm-bastion" {
addresses = null
alias_ips = null
}]
instance_count = 1
tags = ["ssh"]
tags = ["ssh"]
metadata = {
startup-script = join("\n", [
"#! /bin/bash",

View File

@ -41,8 +41,7 @@ output "vpc" {
output "vms" {
description = "GCE VMs."
value = {
for instance in concat(module.vm-bastion.instances) :
instance.name => instance.network_interface.0.network_ip
(module.vm-bastion.instance.name) = module.vm-bastion.internal_ip
}
}

View File

@ -24,4 +24,4 @@ def test_resources(e2e_plan_runner):
"Test that plan works and the numbers of resources is as expected."
modules, resources = e2e_plan_runner(FIXTURES_DIR)
assert len(modules) == 14
assert len(resources) == 62
assert len(resources) == 60

View File

@ -17,17 +17,15 @@
module "test" {
source = "../../../../modules/compute-vm"
project_id = "my-project"
region = "europe-west1"
zones = var.zones
zone = "europe-west1-b"
name = "test"
network_interfaces = var.network_interfaces
service_account_create = var.service_account_create
instance_count = var.instance_count
use_instance_template = var.use_instance_template
attached_disks = var.attached_disks
attached_disk_defaults = var.attached_disk_defaults
create_template = var.create_template
confidential_compute = var.confidential_compute
group = var.group
iam = var.iam
metadata = var.metadata
metadata_list = var.metadata_list
single_name = var.single_name
network_interfaces = var.network_interfaces
service_account_create = var.service_account_create
}

View File

@ -14,11 +14,46 @@
* limitations under the License.
*/
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 = string
size = string
source = string
source_type = string
options = object({
mode = string
replica_zone = string
type = string
})
}))
default = []
}
variable "attached_disk_defaults" {
description = "Defaults for attached disks options."
type = object({
mode = string
replica_zone = string
type = string
})
default = {
mode = "READ_WRITE"
replica_zone = null
type = "pd-balanced"
}
}
variable "confidential_compute" {
type = bool
default = false
}
variable "create_template" {
type = bool
default = false
}
variable "group" {
type = any
default = null
@ -29,31 +64,21 @@ variable "iam" {
default = {}
}
variable "instance_count" {
type = number
default = 1
}
variable "metadata" {
type = map(string)
default = {}
}
variable "metadata_list" {
type = list(map(string))
default = []
}
variable "network_interfaces" {
type = list(object({
nat = bool
network = string
subnetwork = string
addresses = object({
internal = list(string)
external = list(string)
internal = string
external = string
})
alias_ips = map(list(string))
alias_ips = map(string)
}))
default = [{
network = "https://www.googleapis.com/compute/v1/projects/my-project/global/networks/default",
@ -68,18 +93,3 @@ variable "service_account_create" {
type = bool
default = false
}
variable "single_name" {
type = bool
default = false
}
variable "use_instance_template" {
type = bool
default = false
}
variable "zones" {
type = list(string)
default = []
}

View File

@ -20,53 +20,30 @@ import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_single_instance(plan_runner):
def test_defaults(plan_runner):
_, resources = plan_runner(FIXTURES_DIR)
assert len(resources) == 1
assert resources[0]['type'] == 'google_compute_instance'
def test_single_instance_single_name(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, single_name=1)
assert len(resources) == 1
assert resources[0]['type'] == 'google_compute_instance'
assert resources[0]['values']['name'] == 'test'
def test_multiple_instances(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, instance_count=2)
assert len(resources) == 2
assert set(r['type'] for r in resources) == set(['google_compute_instance'])
def test_service_account(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, instance_count=2,
service_account_create='true')
assert len(resources) == 3
assert 'google_service_account' in [r['type'] for r in resources]
_, resources = plan_runner(FIXTURES_DIR, service_account_create='true')
assert len(resources) == 2
assert set(r['type'] for r in resources) == set([
'google_compute_instance', 'google_service_account'
])
def test_template(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, use_instance_template='true')
_, resources = plan_runner(FIXTURES_DIR, create_template='true')
assert len(resources) == 1
assert resources[0]['type'] == 'google_compute_instance_template'
assert resources[0]['values']['name_prefix'] == 'test-'
def test_group(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, instance_count=2,
group='{named_ports={}}')
assert len(resources) == 3
assert set(r['type'] for r in resources) == set([
'google_compute_instance_group', 'google_compute_instance'
])
def test_group_zones(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, instance_count=2,
group='{named_ports={}}',
zones='["europe-west1-b", "europe-west1-c"]')
assert len(resources) == 4
_, resources = plan_runner(FIXTURES_DIR, group='{named_ports={}}')
assert len(resources) == 2
assert set(r['type'] for r in resources) == set([
'google_compute_instance_group', 'google_compute_instance'
])
@ -77,9 +54,8 @@ def test_iam(plan_runner):
'{"roles/compute.instanceAdmin" = ["user:a@a.com", "user:b@a.com"],'
'"roles/iam.serviceAccountUser" = ["user:a@a.com"]}'
)
_, resources = plan_runner(
FIXTURES_DIR, instance_count=2, iam=iam)
assert len(resources) == 6
_, resources = plan_runner(FIXTURES_DIR, iam=iam)
assert len(resources) == 3
assert set(r['type'] for r in resources) == set([
'google_compute_instance', 'google_compute_instance_iam_binding'])
iam_bindings = dict(
@ -87,16 +63,13 @@ def test_iam(plan_runner):
== 'google_compute_instance_iam_binding'
)
assert iam_bindings == {
'roles/compute.instanceAdmin/test-1': ['user:a@a.com', 'user:b@a.com'],
'roles/compute.instanceAdmin/test-2': ['user:a@a.com', 'user:b@a.com'],
'roles/iam.serviceAccountUser/test-1': ['user:a@a.com'],
'roles/iam.serviceAccountUser/test-2': ['user:a@a.com'],
'roles/compute.instanceAdmin': ['user:a@a.com', 'user:b@a.com'],
'roles/iam.serviceAccountUser': ['user:a@a.com'],
}
def test_confidential_compute(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, instance_count=1,
confidential_compute='true')
_, resources = plan_runner(FIXTURES_DIR, confidential_compute='true')
assert len(resources) == 1
assert resources[0]['values']['confidential_instance_config'] == [
{'enable_confidential_compute': True}]
@ -104,9 +77,8 @@ def test_confidential_compute(plan_runner):
def test_confidential_compute_template(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, instance_count=1,
confidential_compute='true',
use_instance_template='true')
_, resources = plan_runner(FIXTURES_DIR, confidential_compute='true',
create_template='true')
assert len(resources) == 1
assert resources[0]['values']['confidential_instance_config'] == [
{'enable_confidential_compute': True}]

View File

@ -0,0 +1,118 @@
# Copyright 2021 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_types(plan_runner):
_disks = '''[{
name = "data1"
size = "10"
source_type = "image"
source = "image-1"
options = null
}, {
name = "data2"
size = "20"
source_type = "snapshot"
source = "snapshot-2"
options = null
}, {
name = "data3"
size = null
source_type = "attach"
source = "disk-3"
options = null
}]
'''
_, resources = plan_runner(FIXTURES_DIR, attached_disks=_disks)
assert len(resources) == 3
disks = {r['values']['name']: r['values']
for r in resources if r['type'] == 'google_compute_disk'}
assert disks['test-data1']['size'] == 10
assert disks['test-data2']['size'] == 20
assert disks['test-data1']['image'] == 'image-1'
assert disks['test-data1']['snapshot'] is None
assert disks['test-data2']['snapshot'] == 'snapshot-2'
assert disks['test-data2']['image'] is None
instance = [r['values']
for r in resources if r['type'] == 'google_compute_instance'][0]
instance_disks = {d['source']: d['device_name']
for d in instance['attached_disk']}
assert instance_disks == {'test-data1': 'data1',
'test-data2': 'data2', 'disk-3': 'data3'}
def test_options(plan_runner):
_disks = '''[{
name = "data1"
size = "10"
source_type = "image"
source = "image-1"
options = {
mode = null, replica_zone = null, type = "pd-standard"
}
}, {
name = "data2"
size = "20"
source_type = null
source = null
options = {
mode = null, replica_zone = "europe-west1-c", type = "pd-ssd"
}
}]
'''
_, resources = plan_runner(FIXTURES_DIR, attached_disks=_disks)
assert len(resources) == 3
disks_z = [r['values']
for r in resources if r['type'] == 'google_compute_disk']
disks_r = [r['values']
for r in resources if r['type'] == 'google_compute_region_disk']
assert len(disks_z) == len(disks_r) == 1
instance = [r['values']
for r in resources if r['type'] == 'google_compute_instance'][0]
instance_disks = [d['device_name'] for d in instance['attached_disk']]
assert instance_disks == ['data1', 'data2']
def test_template(plan_runner):
_disks = '''[{
name = "data1"
size = "10"
source_type = "image"
source = "image-1"
options = {
mode = null, replica_zone = null, type = "pd-standard"
}
}, {
name = "data2"
size = "20"
source_type = null
source = null
options = {
mode = null, replica_zone = "europe-west1-c", type = "pd-ssd"
}
}]
'''
_, resources = plan_runner(
FIXTURES_DIR, attached_disks=_disks, create_template="true")
assert len(resources) == 1
template = [r['values'] for r in resources if r['type']
== 'google_compute_instance_template'][0]
assert len(template['disk']) == 3

View File

@ -20,60 +20,33 @@ import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_no_addresses(plan_runner):
network_interfaces = '''[{
def test_address(plan_runner):
nics = '''[{
network = "https://www.googleapis.com/compute/v1/projects/my-project/global/networks/default",
subnetwork = "https://www.googleapis.com/compute/v1/projects/my-project/regions/europe-west1/subnetworks/default-default",
nat = false,
addresses = {external=[], internal=[]}
addresses = {external=null, internal="10.0.0.2"}
alias_ips = null
}]
'''
_, resources = plan_runner(
FIXTURES_DIR, instance_count=2, network_interfaces=network_interfaces)
assert len(resources) == 2
_, resources = plan_runner(FIXTURES_DIR, network_interfaces=nics)
assert len(resources) == 1
n = resources[0]['values']['network_interface'][0]
assert n['network_ip'] == "10.0.0.2"
assert n['access_config'] == []
def test_internal_addresses(plan_runner):
network_interfaces = '''[{
network = "https://www.googleapis.com/compute/v1/projects/my-project/global/networks/default",
subnetwork = "https://www.googleapis.com/compute/v1/projects/my-project/regions/europe-west1/subnetworks/default-default",
nat = false,
addresses = {external=[], internal=["1.1.1.2", "1.1.1.3"]}
alias_ips = null
}]
'''
_, resources = plan_runner(
FIXTURES_DIR, instance_count=2, network_interfaces=network_interfaces)
assert [r['values']['network_interface'][0]['network_ip']
for r in resources] == ["1.1.1.2", "1.1.1.3"]
def test_internal_addresses_nat(plan_runner):
network_interfaces = '''[{
def test_nat_address(plan_runner):
nics = '''[{
network = "https://www.googleapis.com/compute/v1/projects/my-project/global/networks/default",
subnetwork = "https://www.googleapis.com/compute/v1/projects/my-project/regions/europe-west1/subnetworks/default-default",
nat = true,
addresses = {external=[], internal=["1.1.1.2", "1.1.1.3"]}
addresses = {external="8.8.8.8", internal=null}
alias_ips = null
}]
'''
_, resources = plan_runner(
FIXTURES_DIR, instance_count=2, network_interfaces=network_interfaces)
assert [r['values']['network_interface'][0]['network_ip']
for r in resources] == ["1.1.1.2", "1.1.1.3"]
def test_all_addresses(plan_runner):
network_interfaces = '''[{
network = "https://www.googleapis.com/compute/v1/projects/my-project/global/networks/default",
subnetwork = "https://www.googleapis.com/compute/v1/projects/my-project/regions/europe-west1/subnetworks/default-default",
nat = true,
addresses = {external=["2.2.2.2", "2.2.2.3"], internal=["1.1.1.2", "1.1.1.3"]}
alias_ips = null
}]
'''
_, resources = plan_runner(
FIXTURES_DIR, instance_count=2, network_interfaces=network_interfaces)
assert [r['values']['network_interface'][0]['access_config'][0]['nat_ip']
for r in resources] == ["2.2.2.2", "2.2.2.3"]
_, resources = plan_runner(FIXTURES_DIR, network_interfaces=nics)
assert len(resources) == 1
n = resources[0]['values']['network_interface'][0]
assert 'network_ip' not in n
assert n['access_config'][0]['nat_ip'] == '8.8.8.8'

View File

@ -1,34 +0,0 @@
# Copyright 2021 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_default(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, metadata='{a=1, b=2}')
assert resources[0]['values']['metadata'] == {'a': '1', 'b': '2'}
def test_multi(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, instance_count=3,
metadata='{a=1, b=2}',
metadata_list='[{c=3}, {c=4}]')
assert resources[0]['values']['metadata'] == {'a': '1', 'b': '2', 'c': '3'}
assert resources[1]['values']['metadata'] == {'a': '1', 'b': '2', 'c': '4'}
assert resources[2]['values']['metadata'] == {'a': '1', 'b': '2', 'c': '3'}

View File

@ -1,66 +0,0 @@
# Copyright 2021 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.
import os
import pytest
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_default(plan_runner):
_, resources = plan_runner(FIXTURES_DIR)
assert resources[0]['values']['zone'] == 'europe-west1-b'
def test_multiple_default(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, instance_count=2)
assert set(r['values']['zone'] for r in resources) == set(['europe-west1-b'])
def test_custom(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, zones='["a", "b"]')
assert resources[0]['values']['zone'] == 'a'
def test_custom_default(plan_runner):
_, resources = plan_runner(
FIXTURES_DIR, instance_count=3, zones='["a", "b"]')
assert [r['values']['zone'] for r in resources] == ['a', 'b', 'a']
def test_group(plan_runner):
_, resources = plan_runner(FIXTURES_DIR, instance_count=2,
group='{named_ports={}}', zones='["a", "b"]')
assert resources[2]['type'] == 'google_compute_instance_group'
assert resources[2]['values']['zone'] == 'a'
def test_iam(plan_runner):
iam = '{"roles/a" = ["user:a@a.com"], "roles/b" = ["user:a@a.com"]}'
_, resources = plan_runner(FIXTURES_DIR, instance_count=3,
iam=iam, zones='["a", "b"]')
iam_bindings = dict(
(r['index'], r['values']['zone']) for r in resources if r['type']
== 'google_compute_instance_iam_binding'
)
assert iam_bindings == {
'roles/a/test-1': 'a',
'roles/a/test-2': 'b',
'roles/a/test-3': 'a',
'roles/b/test-1': 'a',
'roles/b/test-2': 'b',
'roles/b/test-3': 'a',
}

View File

@ -24,4 +24,4 @@ def test_resources(e2e_plan_runner):
"Test that plan works and the numbers of resources is as expected."
modules, resources = e2e_plan_runner(FIXTURES_DIR)
assert len(modules) == 17
assert len(resources) == 70
assert len(resources) == 69

View File

@ -23,5 +23,5 @@ FIXTURES_DIR = os.path.join(os.path.dirname(__file__), 'fixture')
def test_resources(e2e_plan_runner):
"Test that plan works and the numbers of resources is as expected."
modules, resources = e2e_plan_runner(FIXTURES_DIR)
assert len(modules) == 14
assert len(modules) == 17
assert len(resources) == 42

View File

@ -24,4 +24,4 @@ def test_resources(e2e_plan_runner):
"Test that plan works and the numbers of resources is as expected."
modules, resources = e2e_plan_runner(FIXTURES_DIR)
assert len(modules) == 14
assert len(resources) == 48
assert len(resources) == 46

View File

@ -24,4 +24,4 @@ def test_resources(e2e_plan_runner):
"Test that plan works and the numbers of resources is as expected."
modules, resources = e2e_plan_runner(FIXTURES_DIR)
assert len(modules) == 10
assert len(resources) == 41
assert len(resources) == 40