Refactor subnets mgmt in net-vpc-factory (#3715)

Refactor subnets mgmt in net-vpc-factory

This commit removes the ability to define subnets inline within the VPC `.config.yaml` across `net-vpc-factory` and enforces file-based subnet definitions using the `subnets/` subdirectory pattern.

Key changes include:
- **Module Updates:** Removed standard and non-standard inline subnet arguments (`subnets`, `subnets_private_nat`, `subnets_proxy_only`, `subnets_psc`) from the factory module's internal `vpcs` instantiation.
- **Schema & Docs:** Renamed `vpc.schema.json` to `vpc-factory.schema.json`, stripping inline subnet definitions from the JSON schema, and updated the module `README.md` to reflect the new file-based only approach.
- **Stage 2 Networking Configs:** Refactored datasets to migrate inline `subnets_proxy_only` definitions into standalone files like `subnets/prod-proxy.yaml`. Added a new exported output `subnet_ips` for downstream usage.

<!--
**Breaking Changes**

```upgrade-note
`fast/stages/2-networking`: Proxy-only subnets have been renamed for consistency - unfortunately this results in a nasty create-before-destroy which needs to be handled manually (i.e. delete the existing proxy-only-subnet first, either manually or with a targeted apply, then apply again)
```
-->
This commit is contained in:
Simone Ruffilli
2026-02-09 11:51:43 +01:00
committed by GitHub
parent 6ca86ed94f
commit 494ecba511
16 changed files with 164 additions and 146 deletions

View File

@@ -334,10 +334,11 @@ Internally created resources are mapped to context namespaces, and use specific
| name | description | sensitive | | name | description | sensitive |
|---|---|:---:| |---|---|:---:|
| [host_project_ids](outputs.tf#L70) | Project IDs. | | | [host_project_ids](outputs.tf#L73) | Project IDs. | |
| [host_project_numbers](outputs.tf#L75) | Project numbers. | | | [host_project_numbers](outputs.tf#L78) | Project numbers. | |
| [subnet_proxy_only_self_links](outputs.tf#L80) | Subnet proxy-only self-links. | | | [subnet_ips](outputs.tf#L83) | Subnet IP ranges. | |
| [subnet_psc_self_links](outputs.tf#L85) | Subnet PSC self-links. | | | [subnet_proxy_only_self_links](outputs.tf#L88) | Subnet proxy-only self-links. | |
| [subnet_self_links](outputs.tf#L90) | Subnet self-links. | | | [subnet_psc_self_links](outputs.tf#L93) | Subnet PSC self-links. | |
| [vpc_self_links](outputs.tf#L95) | VPC self-links. | | | [subnet_self_links](outputs.tf#L98) | Subnet self-links. | |
| [vpc_self_links](outputs.tf#L103) | VPC self-links. | |
<!-- END TFDOC --> <!-- END TFDOC -->

View File

@@ -26,8 +26,3 @@ routes:
dest_range: 0.0.0.0/0 dest_range: 0.0.0.0/0
next_hop_type: "gateway" next_hop_type: "gateway"
next_hop: "default-internet-gateway" next_hop: "default-internet-gateway"
subnets_proxy_only:
- ip_cidr_range: 10.72.240.0/24
region: $locations:primary
name: primary-region-proxy-only
active: true

View File

@@ -0,0 +1,9 @@
# skip boilerplate check
# yaml-language-server: $schema=../../../../../schemas/subnet.schema.json
name: prod-proxy
region: $locations:primary
ip_cidr_range: 10.72.240.0/24
description: Primary-region proxy-only subnet for prod
proxy_only: true

View File

@@ -0,0 +1,9 @@
# skip boilerplate check
# yaml-language-server: $schema=../../../../../schemas/subnet.schema.json
name: prod-proxy
region: $locations:primary
ip_cidr_range: 10.72.240.0/24
description: Primary-region proxy-only subnet for prod
proxy_only: true

View File

@@ -26,10 +26,5 @@ routes:
dest_range: 0.0.0.0/0 dest_range: 0.0.0.0/0
next_hop_type: "gateway" next_hop_type: "gateway"
next_hop: "default-internet-gateway" next_hop: "default-internet-gateway"
subnets_proxy_only:
- ip_cidr_range: 10.72.240.0/24
region: $locations:primary
name: primary-region-proxy-only
active: true
# dns_policy: # dns_policy:
# logging: true # logging: true

View File

@@ -0,0 +1,9 @@
# skip boilerplate check
# yaml-language-server: $schema=../../../../../schemas/subnet.schema.json
name: prod-proxy
region: $locations:primary
ip_cidr_range: 10.72.240.0/24
description: Primary-region proxy-only subnet for prod
proxy_only: true

View File

@@ -0,0 +1,9 @@
# skip boilerplate check
# yaml-language-server: $schema=../../../../../schemas/subnet.schema.json
name: prod-proxy
region: $locations:primary
ip_cidr_range: 10.72.240.0/24
description: Primary-region proxy-only subnet for prod
proxy_only: true

View File

@@ -18,6 +18,9 @@ locals {
tfvars = { tfvars = {
host_project_ids = module.projects.project_ids host_project_ids = module.projects.project_ids
host_project_numbers = module.projects.project_numbers host_project_numbers = module.projects.project_numbers
subnet_ips = {
for vpc_key, vpc in module.vpc-factory.vpcs : vpc_key => vpc.subnet_ips
}
subnet_self_links = { subnet_self_links = {
for vpc_key, vpc in module.vpc-factory.vpcs : vpc_key => vpc.subnet_ids for vpc_key, vpc in module.vpc-factory.vpcs : vpc_key => vpc.subnet_ids
} }
@@ -77,6 +80,11 @@ output "host_project_numbers" {
value = local.tfvars.host_project_numbers value = local.tfvars.host_project_numbers
} }
output "subnet_ips" {
description = "Subnet IP ranges."
value = local.tfvars.subnet_ips
}
output "subnet_proxy_only_self_links" { output "subnet_proxy_only_self_links" {
description = "Subnet proxy-only self-links." description = "Subnet proxy-only self-links."
value = local.tfvars.subnet_proxy_only_self_links value = local.tfvars.subnet_proxy_only_self_links

View File

@@ -43,10 +43,6 @@ Each VPC directory contains a `.config.yaml` file. The structure of the YAML fil
project_id: $project_ids:my-project # Or use the project id directly project_id: $project_ids:my-project # Or use the project id directly
description: "My VPC" description: "My VPC"
routing_mode: GLOBAL routing_mode: GLOBAL
subnets:
- name: subnet-a
region: europe-west1
ip_cidr_range: 10.0.0.0/24
``` ```
### Defaults ### Defaults
@@ -71,7 +67,7 @@ module "net-vpc-factory" {
### Subnets ### Subnets
Subnets can be defined inline in the VPC `.config.yaml` file (as shown above) or in separate files within a `subnets` subdirectory in the VPC's folder. The factory automatically scans the `subnets` folder if it exists. Subnets can be defined in separate files within a `subnets` subdirectory in the VPC's folder.
```text ```text
data/vpcs/ data/vpcs/
@@ -150,18 +146,22 @@ module "net-vpc-factory" {
vpcs = "data/vpcs" vpcs = "data/vpcs"
} }
} }
# tftest files=vpc,fw modules=3 inventory=example.yaml # tftest files=vpc,fw,subnet modules=3 inventory=example.yaml
``` ```
**data/vpcs/shared-vpc/.config.yaml** **data/vpcs/shared-vpc/.config.yaml**
```yaml ```yaml
project_id: $project_ids:net-project project_id: $project_ids:net-project
name: data-vpc-0 name: data-vpc-0
subnets: # tftest-file id=vpc path=data/vpcs/data-vpc-0/.config.yaml schema=vpc-factory.schema.json
- name: primary-subnet ```
region: $locations:primary **data/vpcs/data-vpc-0/subnets/primary-subnet.yaml**
ip_cidr_range: 10.10.0.0/24 ```yaml
# tftest-file id=vpc path=data/vpcs/data-vpc-0/.config.yaml schema=vpc.schema.json name: primary-subnet
region: $locations:primary
ip_cidr_range: 10.10.0.0/24
description: Primary subnet for data-vpc-0
# tftest-file id=subnet path=data/vpcs/data-vpc-0/subnets/primary-subnet.yaml schema=subnet.schema.json
``` ```
**data/vpcs/data-vpc-0/firewall-rules/allow-iap.yaml** **data/vpcs/data-vpc-0/firewall-rules/allow-iap.yaml**

View File

@@ -2,7 +2,7 @@
--- ---
# start of document (---) avoids errors if the file only contains comments # start of document (---) avoids errors if the file only contains comments
# yaml-language-server: $schema=../../../schemas/vpc.schema.json # yaml-language-server: $schema=../../../schemas/vpc-factory.schema.json
name: example name: example
project_id: $project_ids:net project_id: $project_ids:net

View File

@@ -79,10 +79,6 @@ module "vpcs" {
network_attachments = try(each.value.network_attachments, {}) network_attachments = try(each.value.network_attachments, {})
psa_configs = try(each.value.psa_configs, []) psa_configs = try(each.value.psa_configs, [])
routing_mode = try(each.value.routing_mode, "GLOBAL") routing_mode = try(each.value.routing_mode, "GLOBAL")
subnets = try(each.value.subnets, [])
subnets_private_nat = try(each.value.subnets_private_nat, [])
subnets_proxy_only = try(each.value.subnets_proxy_only, [])
subnets_psc = try(each.value.subnets_psc, [])
context = local.context context = local.context
} }

View File

@@ -65,30 +65,6 @@
"$ref": "#/$defs/psa_config" "$ref": "#/$defs/psa_config"
} }
}, },
"subnets": {
"type": "array",
"items": {
"$ref": "#/$defs/subnet"
}
},
"subnets_private_nat": {
"type": "array",
"items": {
"$ref": "#/$defs/simple_subnet"
}
},
"subnets_proxy_only": {
"type": "array",
"items": {
"$ref": "#/$defs/proxy_only_subnet"
}
},
"subnets_psc": {
"type": "array",
"items": {
"$ref": "#/$defs/simple_subnet"
}
},
"nat_config": { "nat_config": {
"$ref": "#/$defs/nat_config" "$ref": "#/$defs/nat_config"
}, },
@@ -317,86 +293,6 @@
} }
} }
} }
},
"simple_subnet": {
"type": "object",
"required": [
"name",
"ip_cidr_range",
"region"
],
"properties": {
"name": {
"type": "string"
},
"ip_cidr_range": {
"type": "string"
},
"region": {
"type": "string"
},
"description": {
"type": "string"
}
}
},
"subnet": {
"type": "object",
"required": [
"name",
"region"
],
"properties": {
"name": {
"type": "string"
},
"ip_cidr_range": {
"type": "string"
},
"region": {
"type": "string"
},
"description": {
"type": "string"
},
"enable_private_access": {
"type": "boolean"
},
"allow_subnet_cidr_routes_overlap": {
"type": "boolean"
},
"reserved_internal_range": {
"type": "string"
}
}
},
"proxy_only_subnet": {
"type": "object",
"required": [
"name",
"ip_cidr_range",
"region"
],
"properties": {
"name": {
"type": "string"
},
"ip_cidr_range": {
"type": "string"
},
"region": {
"type": "string"
},
"description": {
"type": "string"
},
"active": {
"type": "boolean"
},
"global": {
"type": "boolean"
}
}
} }
} }
} }

View File

@@ -0,0 +1,91 @@
# VPC Configuration
<!-- markdownlint-disable MD036 -->
## Properties
*additional properties: false*
- ⁺**project_id**: *string*
- ⁺**name**: *string*
- **description**: *string*
- **auto_create_subnetworks**: *boolean*
- **delete_default_routes_on_create**: *boolean*
- **mtu**: *number*
- **routing_mode**: *string*
<br>*enum: ['GLOBAL', 'REGIONAL']*
- **firewall_policy_enforcement_order**: *string*
<br>*enum: ['BEFORE_CLASSIC_FIREWALL', 'AFTER_CLASSIC_FIREWALL']*
- **create_googleapis_routes**: *reference([create_googleapis_routes](#refs-create_googleapis_routes))*
- **dns_policy**: *reference([dns_policy](#refs-dns_policy))*
- **ipv6_config**: *reference([ipv6_config](#refs-ipv6_config))*
- **network_attachments**: *reference([network_attachments](#refs-network_attachments))*
- **routers**: *reference([routers](#refs-routers))*
- **peering_config**: *reference([peering_config](#refs-peering_config))*
- **psa_configs**: *array*
- items: *reference([psa_config](#refs-psa_config))*
- **nat_config**: *reference([nat_config](#refs-nat_config))*
- **ncc_config**: *reference([ncc_config](#refs-ncc_config))*
- **routes**: *object*
- **policy_based_routes**: *object*
- **vpn_config**: *object*
## Definitions
- **create_googleapis_routes**<a name="refs-create_googleapis_routes"></a>: *object*
- **directpath**: *boolean*
- **directpath-6**: *boolean*
- **private**: *boolean*
- **private-6**: *boolean*
- **restricted**: *boolean*
- **restricted-6**: *boolean*
- **dns_policy**<a name="refs-dns_policy"></a>: *object*
- **inbound**: *boolean*
- **logging**: *boolean*
- **outbound**: *object*
- **private_ns**: *array*
- items: *string*
- **public_ns**: *array*
- items: *string*
- **ipv6_config**<a name="refs-ipv6_config"></a>: *object*
- **enable_ula_internal**: *boolean*
- **internal_range**: *string*
- **nat_config**<a name="refs-nat_config"></a>: *object*
- **`^[a-z0-9-]+$`**: *object*
- ⁺**region**: *string*
- **ncc_config**<a name="refs-ncc_config"></a>: *object*
- ⁺**hub**: *string*
- **group**: *string*
- **network_attachments**<a name="refs-network_attachments"></a>: *object*
- **`^[a-z0-9-]+$`**: *object*
- **subnet**: *string*
- **automatic_connection**: *boolean*
- **description**: *string*
- **producer_accept_lists**: *array*
- items: *string*
- **producer_reject_lists**: *array*
- items: *string*
- **peering_config**<a name="refs-peering_config"></a>: *object*
- **peer_vpc_self_link**: *string*
- **create_remote_peer**: *boolean*
- **export_routes**: *boolean*
- **import_routes**: *boolean*
- **psa_config**<a name="refs-psa_config"></a>: *object*
- **deletion_policy**: *string*
- **ranges**: *object*
- **`^[a-z0-9-]+$`**: *string*
- **export_routes**: *boolean*
- **import_routes**: *boolean*
- **peered_domains**: *array*
- items: *string*
- **range_prefix**: *string*
- **service_producer**: *string*
- **routers**<a name="refs-routers"></a>: *object*
- **`^[a-z0-9-]+$`**: *object*
<br>*additional properties: false*
- ⁺**region**: *string*
- ⁺**asn**: *number*
- **custom_advertise**: *object*
- **all_subnets**: *boolean*
- **ip_ranges**: *object*
- **`.*`**: *string*

View File

@@ -31,7 +31,7 @@ counts:
google_compute_router_nat: 1 google_compute_router_nat: 1
google_compute_router_peer: 2 google_compute_router_peer: 2
google_compute_shared_vpc_host_project: 3 google_compute_shared_vpc_host_project: 3
google_compute_subnetwork: 4 google_compute_subnetwork: 5
google_compute_vpn_tunnel: 2 google_compute_vpn_tunnel: 2
google_dns_managed_zone: 5 google_dns_managed_zone: 5
google_dns_record_set: 3 google_dns_record_set: 3
@@ -44,5 +44,5 @@ counts:
google_storage_bucket_object: 2 google_storage_bucket_object: 2
modules: 36 modules: 36
random_id: 3 random_id: 3
resources: 199 resources: 200
terraform_data: 2 terraform_data: 2

View File

@@ -26,7 +26,7 @@ counts:
google_compute_router_nat: 1 google_compute_router_nat: 1
google_compute_router_peer: 10 google_compute_router_peer: 10
google_compute_shared_vpc_host_project: 3 google_compute_shared_vpc_host_project: 3
google_compute_subnetwork: 3 google_compute_subnetwork: 4
google_compute_vpn_tunnel: 10 google_compute_vpn_tunnel: 10
google_dns_managed_zone: 5 google_dns_managed_zone: 5
google_dns_record_set: 3 google_dns_record_set: 3
@@ -39,5 +39,5 @@ counts:
google_storage_bucket_object: 2 google_storage_bucket_object: 2
modules: 30 modules: 30
random_id: 15 random_id: 15
resources: 214 resources: 215
terraform_data: 2 terraform_data: 2

View File

@@ -15,9 +15,9 @@
values: values:
module.net-vpc-factory.module.firewall["data-vpc-0"].google_compute_firewall.custom-rules["allow-iap"]: module.net-vpc-factory.module.firewall["data-vpc-0"].google_compute_firewall.custom-rules["allow-iap"]:
allow: allow:
- ports: - ports:
- '22' - "22"
protocol: tcp protocol: tcp
deny: [] deny: []
description: Allow IAP for SSH description: Allow IAP for SSH
direction: INGRESS direction: INGRESS
@@ -29,12 +29,12 @@ values:
priority: 1000 priority: 1000
project: my-host-project-id project: my-host-project-id
source_ranges: source_ranges:
- 35.235.240.0/20 - 35.235.240.0/20
source_service_accounts: null source_service_accounts: null
source_tags: null source_tags: null
target_service_accounts: null target_service_accounts: null
target_tags: target_tags:
- ssh - ssh
timeouts: null timeouts: null
module.net-vpc-factory.module.vpcs["data-vpc-0"].google_compute_network.network[0]: module.net-vpc-factory.module.vpcs["data-vpc-0"].google_compute_network.network[0]:
auto_create_subnetworks: true auto_create_subnetworks: true
@@ -92,7 +92,7 @@ values:
tags: null tags: null
timeouts: null timeouts: null
module.net-vpc-factory.module.vpcs["data-vpc-0"].google_compute_subnetwork.subnetwork["europe-west1/primary-subnet"]: module.net-vpc-factory.module.vpcs["data-vpc-0"].google_compute_subnetwork.subnetwork["europe-west1/primary-subnet"]:
description: Terraform-managed. description: Primary subnet for data-vpc-0
ip_cidr_range: 10.10.0.0/24 ip_cidr_range: 10.10.0.0/24
ip_collection: null ip_collection: null
ipv6_access_type: null ipv6_access_type: null