Creates a single legacy external L4 Network Load Balancing target pool (
google_compute_target_pool). Targetshashicorp/google ~> 7.0, Terraform>= 1.12.0.
⚠️ This is the LEGACY external L4 (Network) Load Balancing mechanism. A NEW composition should preferterraform-google-backend-service+terraform-google-http-load-balancerunless there is a specific reason — a non-HTTP(S) protocol this legacy Network Load Balancer handles, or an existing legacy migration a caller has not yet moved off of — to reach for a target pool instead.
- 🎯 Creates one
google_compute_target_pool— GCE's collection of instances used as the target of a Network Load Balancer'sgoogle_compute_forwarding_rule. - 🧱 Standalone, single keystone, no children:
instancesis a plainlist(string)argument on this same resource, not a nested block and not a second top-level resource. - 🌎 Regional resource — unlike
terraform-google-health-check's global resource, this resource'sidformat (projects/{{project}}/regions/{{region}}/targetPools/{{name}}) confirms it is scoped to a region.regionis modeled as a real module variable (a deliberate, documented exception to the general "no region variable" rule — see Design Principles). ⚠️ CRITICAL — health check incompatibility.health_checksaccepts ONLY a legacygoogle_compute_http_health_checkname/self_link — it is INCOMPATIBLE withterraform-google-health-check's moderngoogle_compute_health_checkkeystone. No module in this catalog creates the legacy resource this argument actually wants — a genuine, unfilled catalog gap. See Architecture Notes and Troubleshooting.- 🔒 Secure by default:
deletion_policy = "PREVENT"(a deliberate departure from the provider's own"DELETE"default) — a target pool is directly referenced by a forwarding rule'stargetargument, making it a production load balancer's actual traffic-routing front door. - ⏱️ Shortest timeout default in this catalog — create/update/delete all default to 4 minutes.
- 🚫 No
labelsargument exists on this resource at all — a genuine, schema-driven omission.
💡 Why it matters: target pools still back real, in-production Network Load Balancers — particularly for non-HTTP(S) TCP/UDP workloads and legacy migrations not yet moved to the modern backend-service stack. Getting the health-check compatibility and deletion-guard defaults right here prevents both a silent apply-time rejection and an accidental destroy of a live load balancer's traffic-routing front door.
If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:
- ⭐ Star this repository to help others discover this Terraform module.
- 🤝 Connect with me on LinkedIn: linkedin.com/in/microsoftexpert
- ☕ Buy me a coffee: buymeacoffee.com/microsoftexpert
Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!
graph LR
CI["terraform-google-compute-instance"]:::neutral
HC["terraform-google-health-check\n(modern google_compute_health_check)"]:::incompatible
LHC["google_compute_http_health_check\n(external, NOT in this catalog — real gap)"]:::gap
THIS["terraform-google-compute-target-pool"]:::thisModule
FR["google_compute_forwarding_rule\n(external, NOT in this catalog)"]:::gap
CI -- "self_link consumed as instances[*] (optional, caller-supplied string)" --> THIS
LHC -. "name/self_link consumed as var.health_checks (optional)".-> THIS
HC -. "❌ INCOMPATIBLE — do NOT wire self_link here (legacy-only argument)".-> THIS
THIS -- "self_link consumed as target" --> FR
classDef thisModule fill:#4285F4,color:#ffffff,stroke:#174EA6,stroke-width:1px;
classDef neutral fill:#E8EAED,color:#202124,stroke:#9AA0A6,stroke-width:1px;
classDef gap fill:#fff3cd,color:#7a5b00,stroke:#c9a227,stroke-dasharray: 3 3;
classDef incompatible fill:#fce8e6,color:#c5221f,stroke:#c5221f,stroke-dasharray: 2 2;
Validated via the Mermaid Chart MCP before embedding. Read the red dashed edge carefully: it is
drawn deliberately to show what a reader must not do — terraform-google-health-check's self_link
output is schema-legal as var.health_checks (both are plain strings) but is rejected only at
apply time as an incompatible resource type. The only value var.health_checks actually wants is
the name/self_link of a legacy google_compute_http_health_check resource (yellow dashed node) that
the caller's own composition must create inline — no module in this catalog provides it.
terraform-google-compute-instance's self_link output is an optional input via instances[*]. This
module's own self_link output feeds an external, not-in-this-catalog
google_compute_forwarding_rule's target argument.
graph LR
subgraph Inputs
A["var.name"]
B["var.region"]
C["var.description"]
D["var.health_checks"]
E["var.instances"]
F["var.backup_pool / var.failover_ratio"]
G["var.session_affinity"]
H["var.deletion_policy"]
I["var.timeouts"]
end
R["google_compute_target_pool.this"]:::thisModule
A --> R
B --> R
C --> R
D --> R
E --> R
F --> R
G --> R
H --> R
I --> R
R --> O1["output: id"]
R --> O2["output: self_link"]
R --> O3["output: name"]
classDef thisModule fill:#4285F4,color:#ffffff,stroke:#174EA6,stroke-width:1px;
Validated via the Mermaid Chart MCP before embedding.
Resource inventory:
| Resource | Cardinality | Notes |
|---|---|---|
google_compute_target_pool.this |
Exactly 1 | Keystone; no nested blocks other than dynamic "timeouts" |
| Requirement | Value |
|---|---|
| Terraform | >= 1.12.0 |
hashicorp/google provider |
~> 7.0 |
| Provider block | None — the caller configures google (project, region/zone, auth) |
Schema notes that bite (verified against hashicorp/google v7.39.0 via terraform-registry,
providerDocID 12683524, independently re-confirmed against the live provider schema):
⚠️ health_checksis legacy-only — the single most important schema note in this module. The live Argument Reference states, verbatim: "List of zero or one health check name or self_link. Only legacygoogle_compute_http_health_checkis supported." This module's ownterraform-google-health-check(keystonegoogle_compute_health_check, the modern health check type used by the backend-service/forwarding-rule stack) is incompatible with this argument. The value is schema-legal either way (both are plain strings), soterraform validate/plancannot catch a caller mistakenly wiring the wrong resource type in — it is rejected only atapply. No module in the current catalog createsgoogle_compute_http_health_check— a genuine, currently-unfilled catalog gap, the same class of finding asterraform-google-service-networking-connection's own documentedgoogle_compute_global_addressgap.
namecarries an EXPLICIT, docs-stated ForceNew annotation — "Changing this forces a new resource to be created" — unusually direct for this provider's handwritten docs (most force-new behavior on this provider is inferred from schema flags, not stated in prose).security_policyis EXPLICITLY marked "(Beta)" in the live docs for this resource — excluded from this v1.0.0 per this module suite's GA-only provider-specific tail note. A real, schema-confirmed, deliberately deferred field, not silently dropped.- Timeouts default to 4 minutes — create/update/delete all default to 4 minutes, the shortest default seen anywhere in this catalog's authoring so far. Do not assume the common 20-minute pattern.
backup_poolrequiresfailover_ratioto also be set — "Must also set failover_ratio," enforced here as a plan-time, cross-variablevalidation {}.- Recreating a target pool that a
google_compute_forwarding_rulestill references likely raises aresourceInUseByAnotherResourceerror, mirroring the directly-documented behavior onterraform-google-compute-instance-groupandterraform-google-backend-service— but this resource's own doc page does not explicitly state that risk for itself.main.tfaddslifecycle { create_before_destroy = true }defensively regardless. - No
labelsargument exists anywhere in the live Argument Reference — confirmed by a full scan (name,backup_pool,description,failover_ratio,health_checks,instances,project,region,session_affinity,security_policy,deletion_policy— nothing resembling a label map).
roles/compute.networkAdminon the target project — create, update, and delete target pools.
compute.googleapis.comenabled on the target project (viaterraform-google-project-services, applied before this module).- If
var.health_checksis supplied, the referenced legacygoogle_compute_http_health_checkresource must already exist — this module does not create it, and no sibling module in this catalog does either (see the CRITICAL finding above). - If
var.instancesentries reference instances by URL, thosegoogle_compute_instanceresources should exist by apply time for the pool to have live members — not required at target-pool creation time per the live docs.
terraform-google-compute-target-pool/
├── providers.tf # required_providers (hashicorp/google ~> 7.0) + required_version — no provider {} block
├── variables.tf # name, region, description, health_checks, instances, backup_pool, failover_ratio,
│ # session_affinity, deletion_policy, timeouts (no labels — see Architecture Notes)
├── main.tf # google_compute_target_pool.this + dynamic timeouts + create_before_destroy
├── outputs.tf # id, self_link, name
├── README.md # this file
├── SCOPE.md # lightweight cross-module contract
└── examples/ # runnable example matching the Quick Start below
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "legacy-tcp-pool"
region = "us-east1"
}The caller's root module configures the google provider (project, region/zone, and authentication
via ADC, Workload Identity Federation, or a service account key supplied out-of-band) — this module
accepts none of those as variables.
Consumes
| Input | Type | Source module |
|---|---|---|
instances[*] (optional) |
string (self_link or "zone/name") |
terraform-google-compute-instance |
health_checks (optional) |
string (name or self_link of a legacy google_compute_http_health_check) |
None — no module in this catalog provides this value; the caller's own composition must create the legacy resource inline |
Emits
| Output | Description | Consumed by |
|---|---|---|
id |
Terraform-internal resource identifier, projects/{{project}}/regions/{{region}}/targetPools/{{name}} |
Reference only |
self_link |
Target pool self-link (URL form) | An external, not-in-this-catalog google_compute_forwarding_rule's target argument |
name |
Target pool name | Reference / gcloud lookups |
1 · Minimal target pool
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "legacy-tcp-pool"
region = "us-east1"
}💡 The empty-beyond-required call is a valid, complete target pool with no health check and no member instances yet — useful as a placeholder a later apply can extend.
deletion_policydefaults to"PREVENT"andsession_affinityto"NONE".
2 · Instances given as "zone/name" strings
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "legacy-tcp-pool"
region = "us-east1"
instances = [
"us-east1-b/app-instance-1",
"us-east1-c/app-instance-2",
]
}ℹ️ The live docs accept either the
"zone/name"short form or a fully-qualified URL perinstances[*]entry — both forms are shown in this example library (see entry 3). Instances need not exist at target-pool creation time.
3 · Instances given as full self_link URLs from terraform-google-compute-instance
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "legacy-tcp-pool"
region = "us-east1"
instances = [
module.app_instance_1.self_link,
module.app_instance_2.self_link,
]
}💡 Sourcing
instances[*]fromterraform-google-compute-instance'sself_linkoutput is the house pattern when the instances are managed by this catalog — no live Terraform dependency is created either way (the live docs note instances need not exist at target-pool creation time), so this is a plain string reference, not a resource-graph edge.
4 · Legacy health check wired via health_checks
resource "google_compute_http_health_check" "legacy" {
name = "legacy-tcp-pool-hc"
port = 80
request_path = "/healthz"
}
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "legacy-tcp-pool"
region = "us-east1"
health_checks = google_compute_http_health_check.legacy.self_link
instances = [
module.app_instance_1.self_link,
]
}
⚠️ health_checksaccepts ONLY a legacygoogle_compute_http_health_checkname/self_link — this is NOTterraform-google-health-check. That sibling module's keystone isgoogle_compute_health_check(the modern health check type built for the backend-service/forwarding-rule stack); wiring itsself_linkoutput intohealth_checkshere is schema-legal (both are plain strings) but is rejected only atapplytime as an incompatible resource type —terraform validate/plancannot catch the mistake. No module in this catalog createsgoogle_compute_http_health_check— this example creates it inline, in the caller's own root module, because this is a genuine, currently-unfilled catalog gap.
5 · backup_pool + failover_ratio pairing
module "backup_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "legacy-tcp-pool-backup"
region = "us-east1"
instances = [module.standby_instance.self_link]
}
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "legacy-tcp-pool"
region = "us-east1"
instances = [module.app_instance_1.self_link]
backup_pool = module.backup_pool.self_link
failover_ratio = 0.5
}ℹ️
backup_poolandfailover_ratioMUST be set together — the live docs state "Must also set failover_ratio." This module enforces the pairing as a plan-time, cross-variablevalidation {}onvar.backup_pool; omittingfailover_ratiowhile settingbackup_poolfails atplan, notapply.
6 · session_affinity = CLIENT_IP
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "sticky-tcp-pool"
region = "us-east1"
session_affinity = "CLIENT_IP"
instances = [module.app_instance_1.self_link]
}ℹ️
session_affinityis left at the provider's own default ("NONE") unless set — a workload-shape decision, not a security posture (see Design Principles).CLIENT_IPhashes the source/destination addresses and ports to route a given client consistently to the same instance.
7 · session_affinity = CLIENT_IP_PROTO
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "sticky-tcp-pool"
region = "us-east1"
session_affinity = "CLIENT_IP_PROTO"
instances = [module.app_instance_1.self_link]
}ℹ️
CLIENT_IP_PROTOextendsCLIENT_IP's hash to also include the protocol — useful when the same client may reach this pool over more than one protocol and each should be able to land on a different instance.
8 · Explicit region override
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "legacy-tcp-pool-use1"
region = "us-east1"
instances = [module.app_instance_use1.self_link]
}🔒
regiondefaults tonull(inherits the provider's own "project region" default per the live docs). Set it explicitly only to target a region different from the caller's provider configuration — e.g. a root module managing target pools across multiple regions from one provider block. Force-new: changing this value destroys and recreates the target pool.
9 · deletion_policy = "DELETE" (opt-out from the PREVENT default)
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "decommissioning-legacy-pool"
region = "us-east1"
deletion_policy = "DELETE"
instances = [module.legacy_instance.self_link]
}🔒 This module defaults
deletion_policyto"PREVENT"(a deliberate departure from the provider's own"DELETE"default — see Design Principles). Set"DELETE"explicitly to accept the provider's native destroy semantics — appropriate for a target pool a caller genuinely churns casually, such as this actively-being-decommissioned legacy migration.
10 · deletion_policy = "ABANDON"
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "unmanaged-going-forward-pool"
region = "us-east1"
deletion_policy = "ABANDON"
}
⚠️ "ABANDON"removes the target pool from Terraform state without calling the delete API on the next destroy — the resource keeps running in GCP, unmanaged. Use this when handing a target pool off to be managed outside Terraform (e.g.gcloud) rather than destroying it.
11 · Custom timeouts
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "legacy-tcp-pool"
region = "us-east1"
timeouts = {
create = "8m"
update = "8m"
delete = "8m"
}
instances = [module.app_instance_1.self_link]
}ℹ️ All three of create/update/delete default to 4 minutes on this resource — the shortest default in this catalog's authoring so far. This example doubles them; raise further only if a real apply has actually timed out, since a longer timeout only changes how long Terraform waits before giving up, not the underlying API operation's actual duration.
12 · description set
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "legacy-tcp-pool"
region = "us-east1"
description = "Legacy TCP load balancer target pool — retained for the payments-gateway migration, tracked in JIRA-4821."
instances = [module.app_instance_1.self_link]
}💡
descriptionis a free-text field with no format constraint from the API — use it to record the migration/decommission context a legacy resource like this benefits from, since a target pool carries nolabelsmap to hold that metadata instead.
13 · Full legacy Network Load Balancer shape — health check, backup pool, and sticky sessions together
resource "google_compute_http_health_check" "legacy" {
name = "prod-tcp-pool-hc"
port = 443
request_path = "/healthz"
}
module "prod_backup_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "prod-tcp-pool-backup"
region = "us-east1"
instances = [module.standby_instance.self_link]
}
module "prod_target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "prod-tcp-pool"
region = "us-east1"
session_affinity = "CLIENT_IP"
health_checks = google_compute_http_health_check.legacy.self_link
backup_pool = module.prod_backup_pool.self_link
failover_ratio = 0.5
instances = [
module.app_instance_1.self_link,
module.app_instance_2.self_link,
]
}
⚠️ This is the realistic shape of a production legacy Network Load Balancer: a health check gating traffic, sticky sessions, and a backup pool for failover — all three of this module's most significant gotchas (health-check compatibility, thebackup_pool/failover_ratiopairing, and a second target pool instance for backup) shown together in one composition.
14 · deletion_policy left at the secure PREVENT default alongside a live forwarding rule
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "prod-tcp-pool"
region = "us-east1"
instances = [module.app_instance_1.self_link]
}
resource "google_compute_forwarding_rule" "legacy_lb" {
name = "prod-tcp-lb"
region = "us-east1"
port_range = "443"
target = module.target_pool.self_link
}🔒
deletion_policydefaults to"PREVENT"— oncegoogle_compute_forwarding_rule.legacy_lbabove referencesmodule.target_pool.self_linkas itstarget, an accidentalterraform destroy/applythat would remove the target pool fails outright instead of silently taking down this production Network Load Balancer's front door.
15 · 🏗️ End-to-end composition
module "project_services" {
source = "git::https://github.com/microsoftexpert/terraform-google-project-services.git?ref=v1.0.0"
# Enables compute.googleapis.com (and any other APIs the composition needs)
# — applied before every other module in this composition.
}
module "app_instance_1" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-instance.git?ref=v1.0.0"
name = "legacy-app-1"
zone = "us-east1-b"
machine_type = "e2-medium"
boot_disk = {
initialize_params = {
image = "debian-cloud/debian-12"
}
}
network_interfaces = [
{ network = module.vpc_network.self_link }
]
depends_on = [module.project_services]
}
module "app_instance_2" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-instance.git?ref=v1.0.0"
name = "legacy-app-2"
zone = "us-east1-c"
machine_type = "e2-medium"
boot_disk = {
initialize_params = {
image = "debian-cloud/debian-12"
}
}
network_interfaces = [
{ network = module.vpc_network.self_link }
]
depends_on = [module.project_services]
}
# The legacy health check this module's own health_checks argument requires.
# No module in this catalog creates google_compute_http_health_check — this
# is the genuine, currently-unfilled catalog gap documented throughout this
# README. Created inline, in the caller's own composition.
resource "google_compute_http_health_check" "legacy" {
name = "prod-tcp-pool-hc"
port = 80
request_path = "/healthz"
}
module "target_pool" {
source = "git::https://github.com/microsoftexpert/terraform-google-compute-target-pool.git?ref=v1.0.0"
name = "prod-tcp-pool"
region = "us-east1"
session_affinity = "CLIENT_IP"
health_checks = google_compute_http_health_check.legacy.self_link
instances = [
module.app_instance_1.self_link,
module.app_instance_2.self_link,
]
}
# External, not-in-this-catalog resource: the forwarding rule that turns this
# target pool into an actual Network Load Balancer front door.
resource "google_compute_forwarding_rule" "legacy_lb" {
name = "prod-tcp-lb"
region = "us-east1"
port_range = "80"
target = module.target_pool.self_link
}💡 This shows the realistic legacy-stack chain — distinct from the modern
terraform-google-health-check->terraform-google-backend-service->terraform-google-http-load-balancerchain shown in those modules' own end-to-end examples:terraform-google-compute-instance'sself_linkoutputs feed this module'sinstanceslist; a caller-managedgoogle_compute_http_health_check(neverterraform-google-health-check) feedshealth_checks; and this module's ownself_linkoutput feeds an externalgoogle_compute_forwarding_rule'stargetargument, itself not a standalone module in this catalog.
⚠️ Do not substitutemodule.health_check(a hypotheticalterraform-google-health-checkinstance) forgoogle_compute_http_health_check.legacyabove — see the CRITICAL health-check-compatibility finding throughout this README.
| Variable | Type | Required | Default | Notes |
|---|---|---|---|---|
name |
string |
Yes | — | Force-new (explicitly docs-stated); RFC1035, 1-63 chars |
region |
string |
No | null |
Inherits provider's project-region default when unset; force-new |
description |
string |
No | null |
Free-text |
health_checks |
string |
No | null |
google_compute_http_health_check only — see Architecture Notes |
instances |
list(string) |
No | [] |
Self_link URLs or "zone/name" strings |
backup_pool |
string |
No | null |
Requires failover_ratio to also be set |
failover_ratio |
number |
No | null |
[0.0, 1.0]; required alongside backup_pool |
session_affinity |
string |
No | "NONE" |
NONE | CLIENT_IP | CLIENT_IP_PROTO |
deletion_policy |
string |
No | "PREVENT" |
🔒 Departs from the provider's own "DELETE" default |
timeouts |
object({ create, update, delete = optional(string) }) |
No | null |
All three default to 4 minutes |
No labels variable exists on this module — see Architecture Notes for why. security_policy is
deliberately not modeled (Beta) — see Architecture Notes.
Full variable schemas
variable "name" {
type = string
# RFC1035, 1-63 chars, enforced via validation {}
}
variable "region" {
type = string
default = null
}
variable "description" {
type = string
default = null
}
variable "health_checks" {
type = string
default = null
}
variable "instances" {
type = list(string)
default = []
}
variable "backup_pool" {
type = string
default = null
# validation {}: backup_pool != null => failover_ratio != null
}
variable "failover_ratio" {
type = number
default = null
# validation {}: 0.0 <= failover_ratio <= 1.0
}
variable "session_affinity" {
type = string
default = "NONE"
}
variable "deletion_policy" {
type = string
default = "PREVENT"
}
variable "timeouts" {
type = object({
create = optional(string)
update = optional(string)
delete = optional(string)
})
default = null
}| Output | Description |
|---|---|
id |
projects/{{project}}/regions/{{region}}/targetPools/{{name}} |
self_link |
Target pool self-link (URL form) |
name |
Target pool name |
None of these outputs are secret-bearing; no sensitive = true is applied to any of them.
- HEALTH CHECK COMPATIBILITY — read this first.
health_checksaccepts ONLY a legacygoogle_compute_http_health_checkname/self_link, per the live schema's own verbatim text ("Only legacy google_compute_http_health_check is supported"). It is INCOMPATIBLE withterraform-google-health-check's moderngoogle_compute_health_checkkeystone — that value is schema-legal here (both are plain strings) but is rejected only atapplytime as an incompatible resource type. No module in the current catalog creates the legacy resource this argument actually wants — a genuine, currently-unfilled catalog gap, the same class of finding asterraform-google-service-networking-connection's own documentedgoogle_compute_global_addressgap.var.health_checksis modeled as a single plain string (never a list variable, and never a live cross-module reference toterraform-google-health-check);main.tfwraps it in a one-element list only at the point it sets the underlying argument. backup_poolrequiresfailover_ratio. Enforced as a plan-time, cross-variablevalidation {}onvar.backup_pool(Terraform >= 1.9 supports a variable'svalidation {}referencing another input variable in the same module — this house'srequired_version >= 1.12.0floor comfortably covers it, mirroringterraform-google-log-sink's identicalbigquery_options/unique_writer_identitypairing pattern).- Recreate risk is an inference, not a directly-confirmed fact for this resource. Recreating a
target pool that a
google_compute_forwarding_rulestill references likely raises aresourceInUseByAnotherResourceerror — the same class of error directly documented forterraform-google-compute-instance-groupandterraform-google-backend-service— but this resource's own live doc page does not explicitly state that risk.nameis the only explicitly-confirmed force-new field.main.tfaddslifecycle { create_before_destroy = true }as a defensive measure regardless; because anamechange always produces a genuinely different name, this introduces no duplicate-name collision risk. - Timeouts default to 4 minutes — the shortest default in this catalog's authoring so far. Create/update/delete all default to 4 minutes per the live schema; do not assume the common 20-minute pattern seen on most other resources in this library.
- No
labelsvariable — confirmed schema-driven omission. The full live argument reference forgoogle_compute_target_poolwas scanned and contains nolabelsargument at all (name, backup_pool, description, failover_ratio, health_checks, instances, project, region, session_affinity, security_policy, deletion_policy — nothing resembling a label map). security_policyis EXPLICITLY marked "(Beta)" in the live provider docs — excluded from this v1.0.0 per this module suite's GA-only provider-specific tail note (mixing launch stages inside one module quietly couples a production module's stability to a preview feature's churn). A future minor version could add it without a breaking change.regionIS modeled as a real variable — a deliberate, documented exception to the general "no region variable" rule, per this module suite's authentication-model exception (the same exceptionterraform-google-cloud-router's andterraform-google-managed-instance-group's ownregionvariables rely on). This resource'sidformat confirms it is regional, unliketerraform-google-health-check's global resource.instancesrequires no dependency ordering. The live docs explicitly state instances need not exist at target-pool creation time; this module makes no attempt to construct one.
| Concern | Secure default | Opt-out (explicit) |
|---|---|---|
Deletion guard (deletion_policy) |
"PREVENT" — a deliberate departure from the provider's own "DELETE" default. A target pool is directly referenced by a forwarding rule's target argument, making it a production load balancer's actual traffic-routing front door; mirrors terraform-google-server-tls-policy's identical reasoning |
Caller sets "DELETE" explicitly (appropriate for a target pool genuinely churned casually, e.g. an actively-being-decommissioned legacy migration), or "ABANDON" |
Session affinity (session_affinity) |
"NONE" — the provider's own default, left as-is: a workload-shape decision, not a security posture, mirroring terraform-google-backend-service's identical reasoning |
Caller supplies "CLIENT_IP" or "CLIENT_IP_PROTO" |
Health check reference (health_checks) |
null — no health check attached by default; a valid, common configuration since the underlying argument is genuinely optional ("zero or one") |
Caller supplies a legacy google_compute_http_health_check name/self_link (never terraform-google-health-check's output) |
| Recreate safety | lifecycle { create_before_destroy = true } on the keystone resource, added by this authoring session as a defensive measure |
Not overridable by a module variable; remove the block in a fork if genuinely undesired |
Beta surface area (security_policy) |
Not modeled in v1.0.0 — GA-only per this module suite's provider-specific tail note | N/A — a future minor version may add it |
| Labels | Not applicable — no labels argument exists on this resource's live schema |
N/A |
cd terraform-google-compute-target-pool
terraform init -backend=false
terraform validate
terraform fmt -checkPin the module source to ?ref=v1.0.0 — never a branch. This library is plan-only from an
authoring session; a human applies from CI with valid Workload Identity Federation or ADC
credentials.
terraform validate confirms internal type and reference consistency (e.g. name's RFC1035
validation {} block, the backup_pool/failover_ratio pairing validation, deletion_policy's and
session_affinity's closed value sets, correct resource/output wiring). terraform fmt -check
confirms canonical formatting. Neither can catch GCP API-level rejections — most importantly,
terraform validate cannot catch a caller mistakenly wiring a modern
google_compute_health_check's self_link into health_checks, since that value is schema-legal
as a plain string and is rejected only at apply time as an incompatible resource type. Only a real
terraform plan/apply against a live project, with valid credentials, exercises that path — that
step belongs to the consuming CI pipeline, not this authoring session.
$ terraform output
id = "projects/casey-prod-networking/regions/us-east1/targetPools/prod-tcp-pool"
name = "prod-tcp-pool"
self_link = "https://www.googleapis.com/compute/v1/projects/casey-prod-networking/regions/us-east1/targetPools/prod-tcp-pool"
| Symptom | Cause | Fix |
|---|---|---|
apply rejects health_checks with an incompatible resource type |
A modern google_compute_health_check (e.g. terraform-google-health-check's self_link output) was wired into var.health_checks, which accepts only a legacy google_compute_http_health_check |
Create a google_compute_http_health_check resource inline in the caller's own composition (see Example Library entry 4) and pass its name/self_link instead — see the CRITICAL finding in Overview and Architecture Notes |
apply fails because backup_pool was set without failover_ratio |
The live API requires both to be set together | This module enforces the pairing at plan time via a validation {} block on var.backup_pool — supply failover_ratio alongside backup_pool |
resourceInUseByAnotherResource on rename/recreate |
A google_compute_forwarding_rule still references this target pool's self_link/target while a name change (the only confirmed force-new field) recreates it |
main.tf's lifecycle { create_before_destroy = true } mitigates this; if it still occurs, re-point the referencing forwarding rule to the new target pool in the same apply |
destroy/apply fails outright when trying to remove the target pool |
deletion_policy defaults to "PREVENT" |
Set deletion_policy = "DELETE" explicitly (or "ABANDON" to detach from Terraform state without deleting) before the destroy will succeed |
plan fails with a failover_ratio validation error |
Value outside [0.0, 1.0] |
Supply a value between 0.0 and 1.0 inclusive, or omit both backup_pool and failover_ratio |
No labels variable in variables.tf — looks incomplete compared to other modules |
Deliberate: google_compute_target_pool exposes no labels argument in the live schema |
Confirmed against the live provider schema; see Architecture Notes |
security_policy not exposed as a variable |
Deliberate: EXPLICITLY marked "(Beta)" in the live docs; excluded from this GA-only v1.0.0 | Wait for a future minor version, or manage a google_compute_target_pool outside this module if the Beta feature is required now |
google_compute_target_poolprovider resource referenceterraform-google-compute-instance(upstream, optional — suppliesinstances[*]self_link entries)terraform-google-health-check— NOT compatible with this module'shealth_checksargument; see the CRITICAL finding throughout this READMEterraform-google-backend-service/terraform-google-http-load-balancer— the modern stack a new composition should prefer over this legacy mechanismterraform-google-project-services(must enablecompute.googleapis.combefore this module applies)- This module's
SCOPE.md