Add alias IP support in `compute-vm` (#127)

* Add alias IP support in `compute-vm`

* Fix tests

* add end to end tests for data solutions examples and fix example errors

* update changelog

* add missing boilerplate

Co-authored-by: Ludovico Magnocavallo <ludomagno@google.com>
This commit is contained in:
Julio Castillo 2020-08-29 10:12:30 +02:00 committed by GitHub
parent 59f99872d8
commit 5ae489f50d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 300 additions and 82 deletions

View File

@ -4,7 +4,12 @@ All notable changes to this project will be documented in this file.
## [Unreleased]
- add alias IP support in `cloud-vm` module
- add tests for `data-solutions` examples
- fix apply errors on dynamic resources in dataflow example
## [3.1.1] - 2020-08-26
- fix error in `project` module
## [3.1.0] - 2020-08-16

View File

@ -108,10 +108,11 @@ module "simple-vm-example" {
region = var.region
name = var.name
network_interfaces = [{
network = module.vpc.self_link,
subnetwork = try(module.vpc.subnet_self_links["${var.region}/${var.name}-default"], ""),
nat = false,
network = module.vpc.self_link
subnetwork = try(module.vpc.subnet_self_links["${var.region}/${var.name}-default"], "")
nat = false
addresses = null
alias_ips = null
}]
tags = ["${var.project_id}-test-feed", "shared-test-feed"]
instance_count = 1

View File

@ -111,10 +111,11 @@ module "vm-ns-editor" {
region = var.region
name = "${var.name}-ns"
network_interfaces = [{
network = module.vpc.self_link,
subnetwork = module.vpc.subnet_self_links["${var.region}/${var.name}-default"],
nat = false,
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["${var.region}/${var.name}-default"]
nat = false
addresses = null
alias_ips = null
}]
metadata = { startup-script = local.startup-script }
service_account_create = true
@ -128,10 +129,11 @@ module "vm-svc-editor" {
region = var.region
name = "${var.name}-svc"
network_interfaces = [{
network = module.vpc.self_link,
subnetwork = module.vpc.subnet_self_links["${var.region}/${var.name}-default"],
nat = false,
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["${var.region}/${var.name}-default"]
nat = false
addresses = null
alias_ips = null
}]
metadata = { startup-script = local.startup-script }
service_account_create = true

View File

@ -104,13 +104,13 @@ module "kms_vm_example" {
source = "../../modules/compute-vm"
project_id = module.project-service.project_id
region = var.region
zone = var.zone
name = "kms-vm"
network_interfaces = [{
network = module.vpc.self_link,
subnetwork = module.vpc.subnet_self_links["${var.region}/subnet"],
nat = false,
addresses = null
alias_ips = null
}]
attached_disks = [
{

View File

@ -64,9 +64,3 @@ variable "vpc_ip_cidr_range" {
type = string
default = "10.0.0.0/20"
}
variable "zone" {
description = "The zone where resources will be deployed."
type = string
default = "europe-west1-b"
}

View File

@ -61,9 +61,9 @@ module "service-account-bq" {
project_id = module.project-service.project_id
names = ["bq-test"]
iam_project_roles = {
(module.project-service.project_id) = [
(var.project_service_name) = [
"roles/logging.logWriter",
"roles/monitoring.metricWriter",
"roles/monitoring.metricWriter",
"roles/bigquery.admin"
]
}
@ -74,12 +74,12 @@ module "service-account-gce" {
project_id = module.project-service.project_id
names = ["gce-test"]
iam_project_roles = {
(module.project-service.project_id) = [
(var.project_service_name) = [
"roles/logging.logWriter",
"roles/monitoring.metricWriter",
"roles/dataflow.admin",
"roles/iam.serviceAccountUser",
"roles/bigquery.dataOwner",
"roles/bigquery.dataOwner",
"roles/bigquery.jobUser" # Needed to import data using 'bq' command
]
}
@ -90,7 +90,7 @@ module "service-account-df" {
project_id = module.project-service.project_id
names = ["df-test"]
iam_project_roles = {
(module.project-service.project_id) = [
(var.project_service_name) = [
"roles/dataflow.worker",
"roles/bigquery.dataOwner",
"roles/bigquery.metadataViewer",
@ -143,7 +143,7 @@ module "kms" {
#"serviceAccount:${module.project-service.service_accounts.default.bq}",
"serviceAccount:${data.google_bigquery_default_service_account.bq_sa.email}",
]
},
},
}
}
@ -156,7 +156,7 @@ module "kms-regional" {
}
keys = { key-df = null }
key_iam_roles = {
key-df = ["roles/cloudkms.cryptoKeyEncrypterDecrypter"]
key-df = ["roles/cloudkms.cryptoKeyEncrypterDecrypter"]
}
key_iam_members = {
key-df = {
@ -164,7 +164,7 @@ module "kms-regional" {
"serviceAccount:${module.project-service.service_accounts.robots.dataflow}",
"serviceAccount:${module.project-service.service_accounts.robots.compute}",
]
}
}
}
}
@ -210,13 +210,13 @@ module "vm_example" {
source = "../../modules/compute-vm"
project_id = module.project-service.project_id
region = var.region
zone = var.zone
name = "vm-example"
network_interfaces = [{
network = module.vpc.self_link,
subnetwork = module.vpc.subnet_self_links["${var.region}/${var.vpc_subnet_name}"],
nat = false,
addresses = null
alias_ips = null
}]
attached_disks = [
{
@ -259,9 +259,9 @@ module "kms-gcs" {
prefix = module.project-service.project_id
names = ["data", "df-tmplocation"]
iam_roles = {
data = ["roles/storage.admin","roles/storage.objectViewer"],
data = ["roles/storage.admin", "roles/storage.objectViewer"],
df-tmplocation = ["roles/storage.admin"]
}
}
iam_members = {
data = {
"roles/storage.admin" = [
@ -269,22 +269,22 @@ module "kms-gcs" {
],
"roles/storage.viewer" = [
"serviceAccount:${module.service-account-df.email}",
],
],
},
df-tmplocation = {
"roles/storage.admin" = [
"serviceAccount:${module.service-account-gce.email}",
"serviceAccount:${module.service-account-df.email}",
]
}
}
}
}
encryption_keys = {
data = module.kms.keys.key-gcs.self_link,
df-tmplocation = module.kms.keys.key-gcs.self_link,
}
force_destroy = {
data = true,
df-tmplocation = true,
df-tmplocation = true,
}
}
@ -293,9 +293,9 @@ module "kms-gcs" {
###############################################################################
module "bigquery-dataset" {
source = "../../modules/bigquery-dataset"
project_id = module.project-service.project_id
id = "bq_dataset"
source = "../../modules/bigquery-dataset"
project_id = module.project-service.project_id
id = "bq_dataset"
access_roles = {
reader-group = { role = "READER", type = "domain" }
owner = { role = "OWNER", type = "user_by_email" }
@ -315,11 +315,11 @@ module "bigquery-dataset" {
range = null # use start/end/interval for range
time = null
}
schema = file("schema_bq_import.json")
schema = file("${path.module}/schema_bq_import.json")
options = {
clustering = null
expiration_time = null
encryption_key = module.kms.keys.key-bq.self_link
clustering = null
expiration_time = null
encryption_key = module.kms.keys.key-bq.self_link
}
},
df_import = {
@ -331,11 +331,11 @@ module "bigquery-dataset" {
range = null # use start/end/interval for range
time = null
}
schema = file("schema_df_import.json")
schema = file("${path.module}/schema_df_import.json")
options = {
clustering = null
clustering = null
expiration_time = null
encryption_key = module.kms.keys.key-bq.self_link
encryption_key = module.kms.keys.key-bq.self_link
}
}
}

View File

@ -63,12 +63,6 @@ variable "vpc_ip_cidr_range" {
default = "10.0.0.0/20"
}
variable "zone" {
description = "The zone where resources will be deployed."
type = string
default = "europe-west1-b"
}
variable "ssh_source_ranges" {
description = "IP CIDR ranges that will be allowed to connect via SSH to the onprem instance."
type = list(string)

View File

@ -20,10 +20,11 @@ module "simple-vm-example" {
region = "europe-west1"
name = "test"
network_interfaces = [{
network = local.network_self_link,
subnetwork = local.subnet_self_link,
nat = false,
network = local.network_self_link
subnetwork = local.subnet_self_link
nat = false
addresses = null
alias_ips = null
}]
service_account_create = true
instance_count = 1
@ -41,10 +42,11 @@ module "kms-vm-example" {
region = local.region
name = "kms-test"
network_interfaces = [{
network = local.network_self_link,
subnetwork = local.subnet_self_link,
nat = false,
network = local.network_self_link
subnetwork = local.subnet_self_link
nat = false
addresses = null
alias_ips = null
}]
attached_disks = [
{
@ -85,10 +87,11 @@ module "cos-test" {
region = "europe-west1"
name = "test"
network_interfaces = [{
network = local.network_self_link,
subnetwork = local.subnet_self_link,
nat = false,
network = local.network_self_link
subnetwork = local.subnet_self_link
nat = false
addresses = null
alias_ips = null
}]
instance_count = 1
boot_disk = {
@ -115,10 +118,11 @@ module "instance-group" {
region = "europe-west1"
name = "ilb-test"
network_interfaces = [{
network = local.network_self_link,
subnetwork = local.subnetwork_self_link,
nat = false,
network = local.network_self_link
subnetwork = local.subnetwork_self_link
nat = false
addresses = null
alias_ips = null
}]
boot_disk = {
image = "projects/cos-cloud/global/images/family/cos-stable"
@ -141,7 +145,7 @@ 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 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;&#125;&#41;&#41;">list(object({...}))</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; list&#40;object&#40;&#123;&#10;ip_cidr_range &#61; string&#10;subnetwork_range_name &#61; string&#10;&#125;&#41;&#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;type &#61; string&#10;source &#61; string&#10;&#125;&#41;">object({...})</code> | | <code title="&#123;&#10;auto_delete &#61; true&#10;source &#61; null&#10;mode &#61; &#34;READ_WRITE&#34;&#10;type &#61; &#34;pd-ssd&#34;&#10;&#125;">...</code> |

View File

@ -145,6 +145,14 @@ resource "google_compute_instance" "default" {
)
}
}
dynamic alias_ip_range {
for_each = config.value.alias_ips != null ? config.value.alias_ips : []
iterator = alias_ips
content {
ip_cidr_range = alias_ips.value.ip_cidr_range
subnetwork_range_name = alias_ips.value.subnetwork_range_name
}
}
}
}

View File

@ -144,7 +144,7 @@ variable "name" {
}
variable "network_interfaces" {
description = "Network interfaces configuration. Use self links for Shared VPC, set addresses to null if not needed."
description = "Network interfaces configuration. Use self links for Shared VPC, set addresses and alias_ips to null if not needed."
type = list(object({
nat = bool
network = string
@ -153,6 +153,10 @@ variable "network_interfaces" {
internal = list(string)
external = list(string)
})
alias_ips = list(object({
ip_cidr_range = string
subnetwork_range_name = string
}))
}))
}

View File

@ -149,10 +149,11 @@ module "vm-spoke-1" {
region = var.region
name = "spoke-1-test"
network_interfaces = [{
network = module.vpc-spoke-1.self_link,
network = module.vpc-spoke-1.self_link
subnetwork = module.vpc-spoke-1.subnet_self_links["${var.region}/spoke-1-default"]
nat = false,
nat = false
addresses = null
alias_ips = null
}]
metadata = { startup-script = local.vm-startup-script }
service_account = module.service-account-gce.email
@ -166,10 +167,11 @@ module "vm-spoke-2" {
region = var.region
name = "spoke-2-test"
network_interfaces = [{
network = module.vpc-spoke-2.self_link,
network = module.vpc-spoke-2.self_link
subnetwork = module.vpc-spoke-2.subnet_self_links["${var.region}/spoke-2-default"]
nat = false,
nat = false
addresses = null
alias_ips = null
}]
metadata = { startup-script = local.vm-startup-script }
service_account = module.service-account-gce.email

View File

@ -249,10 +249,11 @@ module "vm-spoke-1" {
region = var.regions.b
name = "spoke-1-test"
network_interfaces = [{
network = module.vpc-spoke-1.self_link,
network = module.vpc-spoke-1.self_link
subnetwork = module.vpc-spoke-1.subnet_self_links["${var.regions.b}/spoke-1-b"]
nat = false,
nat = false
addresses = null
alias_ips = null
}]
tags = ["ssh"]
metadata = { startup-script = local.vm-startup-script }
@ -264,10 +265,11 @@ module "vm-spoke-2" {
region = var.regions.b
name = "spoke-2-test"
network_interfaces = [{
network = module.vpc-spoke-2.self_link,
subnetwork = module.vpc-spoke-2.subnet_self_links["${var.regions.b}/spoke-2-b"],
nat = false,
network = module.vpc-spoke-2.self_link
subnetwork = module.vpc-spoke-2.subnet_self_links["${var.regions.b}/spoke-2-b"]
nat = false
addresses = null
alias_ips = null
}]
tags = ["ssh"]
metadata = { startup-script = local.vm-startup-script }

View File

@ -32,13 +32,15 @@ module "gw" {
network = module.vpc-left.self_link
subnetwork = values(module.vpc-left.subnet_self_links)[0],
nat = false,
addresses = null
addresses = null,
alias_ips = null
},
{
network = module.vpc-right.self_link
subnetwork = values(module.vpc-right.subnet_self_links)[0],
nat = false,
addresses = null
addresses = null,
alias_ips = null
}
]
tags = ["ssh"]

View File

@ -31,9 +31,10 @@ module "vm-left" {
network_interfaces = [
{
network = module.vpc-left.self_link
subnetwork = values(module.vpc-left.subnet_self_links)[0],
nat = false,
subnetwork = values(module.vpc-left.subnet_self_links)[0]
nat = false
addresses = null
alias_ips = null
}
]
tags = ["ssh"]
@ -56,9 +57,10 @@ module "vm-right" {
network_interfaces = [
{
network = module.vpc-right.self_link
subnetwork = values(module.vpc-right.subnet_self_links)[0],
nat = false,
subnetwork = values(module.vpc-right.subnet_self_links)[0]
nat = false
addresses = null
alias_ips = null
}
]
tags = ["ssh"]

View File

@ -187,10 +187,11 @@ module "vm-test" {
region = var.region
name = "test"
network_interfaces = [{
network = module.vpc.self_link,
network = module.vpc.self_link
subnetwork = module.vpc.subnet_self_links["${var.region}/subnet"]
nat = false,
nat = false
addresses = null
alias_ips = null
}]
metadata = { startup-script = local.vm-startup-script }
service_account = module.service-account-gce.email
@ -250,8 +251,9 @@ module "vm-onprem" {
network_interfaces = [{
network = module.vpc.name
subnetwork = module.vpc.subnet_self_links["${var.region}/subnet"]
nat = true,
nat = true
addresses = null
alias_ips = null
}]
service_account = module.service-account-onprem.email
service_account_scopes = ["https://www.googleapis.com/auth/cloud-platform"]

View File

@ -182,10 +182,11 @@ module "vm-bastion" {
region = var.region
name = "bastion"
network_interfaces = [{
network = module.vpc-shared.self_link,
subnetwork = lookup(module.vpc-shared.subnet_self_links, "${var.region}/gce", null),
nat = false,
network = module.vpc-shared.self_link
subnetwork = lookup(module.vpc-shared.subnet_self_links, "${var.region}/gce", null)
nat = false
addresses = null
alias_ips = null
}]
instance_count = 1
tags = ["ssh"]

View File

@ -0,0 +1,13 @@
# Copyright 2020 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.

View File

@ -0,0 +1,21 @@
/**
* Copyright 2020 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 "test" {
source = "../../../../data-solutions/cmek-via-centralized-kms/"
billing_account = var.billing_account
root_node = var.root_node
}

View File

@ -0,0 +1,26 @@
/**
* Copyright 2020 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.
*/
variable "billing_account" {
type = string
default = "123456-123456-123456"
}
variable "root_node" {
description = "The resource name of the parent Folder or Organization. Must be of the form folders/folder_id or organizations/org_id."
type = string
default = "folders/12345678"
}

View File

@ -0,0 +1,27 @@
# Copyright 2020 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_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) == 7
assert len(resources) == 22

View File

@ -0,0 +1,13 @@
# Copyright 2020 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.

View File

@ -0,0 +1,23 @@
/**
* Copyright 2020 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 "test" {
source = "../../../../data-solutions/gcs-to-bq-with-dataflow/"
billing_account = var.billing_account
project_kms_name = var.project_kms_name
project_service_name = var.project_service_name
root_node = var.root_node
}

View File

@ -0,0 +1,36 @@
/**
* Copyright 2020 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.
*/
variable "billing_account" {
type = string
default = "123456-123456-123456"
}
variable "root_node" {
description = "The resource name of the parent Folder or Organization. Must be of the form folders/folder_id or organizations/org_id."
type = string
default = "folders/12345678"
}
variable "project_service_name" {
type = string
default = "project-srv"
}
variable "project_kms_name" {
type = string
default = "project-kms"
}

View File

@ -0,0 +1,27 @@
# Copyright 2020 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_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) == 13
assert len(resources) == 61

View File

@ -53,12 +53,17 @@ variable "network_interfaces" {
internal = list(string)
external = list(string)
})
alias_ips = list(object({
ip_cidr_range = string
subnetwork_range_name = string
}))
}))
default = [{
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 = null
alias_ips = null
}]
}

View File

@ -26,6 +26,7 @@ def test_no_addresses(plan_runner):
subnetwork = "https://www.googleapis.com/compute/v1/projects/my-project/regions/europe-west1/subnetworks/default-default",
nat = false,
addresses = {external=[], internal=[]}
alias_ips = null
}]
'''
_, resources = plan_runner(
@ -39,6 +40,7 @@ def test_internal_addresses(plan_runner):
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(
@ -53,6 +55,7 @@ def test_internal_addresses_nat(plan_runner):
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"]}
alias_ips = null
}]
'''
_, resources = plan_runner(
@ -67,6 +70,7 @@ def test_all_addresses(plan_runner):
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(