Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

☁️ Google Cloud Compute Target Pool Terraform Module

Creates a single legacy external L4 Network Load Balancing target pool (google_compute_target_pool). Targets hashicorp/google ~> 7.0, Terraform >= 1.12.0.

Terraform Google Provider Module Version Module Type Resources Posture


🧩 Overview

⚠️ This is the LEGACY external L4 (Network) Load Balancing mechanism. A NEW composition should prefer terraform-google-backend-service + terraform-google-http-load-balancer unless 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's google_compute_forwarding_rule.
  • 🧱 Standalone, single keystone, no children: instances is a plain list(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's id format (projects/{{project}}/regions/{{region}}/targetPools/{{name}}) confirms it is scoped to a region. region is 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_checks accepts ONLY a legacy google_compute_http_health_check name/self_link — it is INCOMPATIBLE with terraform-google-health-check's modern google_compute_health_check keystone. 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's target argument, 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 labels argument 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.


❤️ Support this project

If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:

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!


🗺️ Where this fits

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;
Loading

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.


🧬 What this builds

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;
Loading

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"

✅ Provider / Versions

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_checks is 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 legacy google_compute_http_health_check is supported." This module's own terraform-google-health-check (keystone google_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), so terraform validate/plan cannot catch a caller mistakenly wiring the wrong resource type in — it is rejected only at apply. No module in the current catalog creates google_compute_http_health_check — a genuine, currently-unfilled catalog gap, the same class of finding as terraform-google-service-networking-connection's own documented google_compute_global_address gap.

  • name carries 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_policy is 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_pool requires failover_ratio to also be set — "Must also set failover_ratio," enforced here as a plan-time, cross-variable validation {}.
  • Recreating a target pool that a google_compute_forwarding_rule still references likely raises a resourceInUseByAnotherResource error, mirroring the directly-documented behavior on terraform-google-compute-instance-group and terraform-google-backend-service — but this resource's own doc page does not explicitly state that risk for itself. main.tf adds lifecycle { create_before_destroy = true } defensively regardless.
  • No labels argument 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).

🔑 Required IAM Roles

  • roles/compute.networkAdmin on the target project — create, update, and delete target pools.

☁️ GCP Prerequisites

  • compute.googleapis.com enabled on the target project (via terraform-google-project-services, applied before this module).
  • If var.health_checks is supplied, the referenced legacy google_compute_http_health_check resource 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.instances entries reference instances by URL, those google_compute_instance resources should exist by apply time for the pool to have live members — not required at target-pool creation time per the live docs.

📁 Module Structure

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

⚙️ Quick Start

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.


🔌 Cross-Module Contract

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

📚 Example Library

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_policy defaults to "PREVENT" and session_affinity to "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 per instances[*] 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[*] from terraform-google-compute-instance's self_link output 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_checks accepts ONLY a legacy google_compute_http_health_check name/self_link — this is NOT terraform-google-health-check. That sibling module's keystone is google_compute_health_check (the modern health check type built for the backend-service/forwarding-rule stack); wiring its self_link output into health_checks here is schema-legal (both are plain strings) but is rejected only at apply time as an incompatible resource type — terraform validate/plan cannot catch the mistake. No module in this catalog creates google_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_pool and failover_ratio MUST be set together — the live docs state "Must also set failover_ratio." This module enforces the pairing as a plan-time, cross-variable validation {} on var.backup_pool; omitting failover_ratio while setting backup_pool fails at plan, not apply.

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_affinity is left at the provider's own default ("NONE") unless set — a workload-shape decision, not a security posture (see Design Principles). CLIENT_IP hashes 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_PROTO extends CLIENT_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]
}

🔒 region defaults to null (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_policy to "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]
}

💡 description is 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 no labels map 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, the backup_pool/failover_ratio pairing, 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_policy defaults to "PREVENT" — once google_compute_forwarding_rule.legacy_lb above references module.target_pool.self_link as its target, an accidental terraform destroy/apply that 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-balancer chain shown in those modules' own end-to-end examples: terraform-google-compute-instance's self_link outputs feed this module's instances list; a caller-managed google_compute_http_health_check (never terraform-google-health-check) feeds health_checks; and this module's own self_link output feeds an external google_compute_forwarding_rule's target argument, itself not a standalone module in this catalog.

⚠️ Do not substitute module.health_check (a hypothetical terraform-google-health-check instance) for google_compute_http_health_check.legacy above — see the CRITICAL health-check-compatibility finding throughout this README.


📥 Inputs

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 ⚠️ Legacy 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
}

🧾 Outputs

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.


🧠 Architecture Notes

  • HEALTH CHECK COMPATIBILITY — read this first. health_checks accepts ONLY a legacy google_compute_http_health_check name/self_link, per the live schema's own verbatim text ("Only legacy google_compute_http_health_check is supported"). It is INCOMPATIBLE with terraform-google-health-check's modern google_compute_health_check keystone — that value is schema-legal here (both are plain strings) but is rejected only at apply time 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 as terraform-google-service-networking-connection's own documented google_compute_global_address gap. var.health_checks is modeled as a single plain string (never a list variable, and never a live cross-module reference to terraform-google-health-check); main.tf wraps it in a one-element list only at the point it sets the underlying argument.
  • backup_pool requires failover_ratio. Enforced as a plan-time, cross-variable validation {} on var.backup_pool (Terraform >= 1.9 supports a variable's validation {} referencing another input variable in the same module — this house's required_version >= 1.12.0 floor comfortably covers it, mirroring terraform-google-log-sink's identical bigquery_options/unique_writer_identity pairing pattern).
  • Recreate risk is an inference, not a directly-confirmed fact for this resource. Recreating a target pool that a google_compute_forwarding_rule still references likely raises a resourceInUseByAnotherResource error — the same class of error directly documented for terraform-google-compute-instance-group and terraform-google-backend-service — but this resource's own live doc page does not explicitly state that risk. name is the only explicitly-confirmed force-new field. main.tf adds lifecycle { create_before_destroy = true } as a defensive measure regardless; because a name change 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 labels variable — confirmed schema-driven omission. The full live argument reference for google_compute_target_pool was scanned and contains no labels argument 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_policy is 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.
  • region IS 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 exception terraform-google-cloud-router's and terraform-google-managed-instance-group's own region variables rely on). This resource's id format confirms it is regional, unlike terraform-google-health-check's global resource.
  • instances requires 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.

🧱 Design Principles

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

🚀 Runbook

cd terraform-google-compute-target-pool
terraform init -backend=false
terraform validate
terraform fmt -check

Pin 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.


🧪 Testing

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.


💬 Example Output

$ 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"

🔍 Troubleshooting

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

🔗 Related Docs

  • google_compute_target_pool provider resource reference
  • terraform-google-compute-instance (upstream, optional — supplies instances[*] self_link entries)
  • terraform-google-health-checkNOT compatible with this module's health_checks argument; see the CRITICAL finding throughout this README
  • terraform-google-backend-service / terraform-google-http-load-balancer — the modern stack a new composition should prefer over this legacy mechanism
  • terraform-google-project-services (must enable compute.googleapis.com before this module applies)
  • This module's SCOPE.md

About

Terraform module: terraform-google-compute-target-pool

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages