Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions autogen/main/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ The implications of this are that:
- You will indeed need sufficient IP space (and compute capacity) to create both node pools

{% endif %}

## Kubernetes version lookup

When `kubernetes_version` is set to `"latest"`, the module resolves the version via the `google_container_engine_versions` data source. For **regional** clusters only a region-level lookup is performed. For **zonal** clusters a zone-level lookup is used. This allows the module to work in environments where the Container API accepts only region-level `location` (e.g. some sovereign or partner clouds).

## Compatibility

This module is meant for use with Terraform 1.3+ and tested using Terraform 1.10+.
Expand Down
4 changes: 2 additions & 2 deletions autogen/main/cluster.tf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ resource "google_container_cluster" "primary" {
project = var.project_id
resource_labels = var.cluster_resource_labels

location = local.location
node_locations = local.node_locations
location = local.cluster_location_input
node_locations = local.cluster_node_locations
cluster_ipv4_cidr = var.cluster_ipv4_cidr
network = "projects/${local.network_project_id}/global/networks/${var.network}"
deletion_protection = var.deletion_protection
Expand Down
16 changes: 10 additions & 6 deletions autogen/main/main.tf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,14 @@ locals {
region = var.regional ? var.region : join("-", slice(split("-", var.zones[0]), 0, 2))
// for regional cluster - use var.zones if provided, use available otherwise, for zonal cluster use var.zones with first element extracted
node_locations = var.regional ? coalescelist(compact(var.zones), try(sort(random_shuffle.available_zones[0].result),[])) : slice(var.zones, 1, length(var.zones))
// Kubernetes version
// when cluster_location_override is set, use it for the cluster resource; when override equals first zone (regional), use remaining zones for node_locations so the cluster is created as zonal
cluster_location_input = coalesce(var.cluster_location_override, local.location)
use_zone_location = var.cluster_location_override != null && var.regional && length(var.zones) > 0 && var.cluster_location_override == var.zones[0]
// when omit_node_locations_for_regional is true, use var.zones so config matches API-populated node_locations and avoids drift on subsequent apply
cluster_node_locations = var.omit_node_locations_for_regional && var.regional ? var.zones : (local.use_zone_location ? slice(var.zones, 1, length(var.zones)) : local.node_locations)
// Kubernetes version: for regional clusters only region-level lookup is used; zone-level lookup is skipped to support environments where the API accepts only region-level location.
master_version_regional = var.kubernetes_version != "latest" ? var.kubernetes_version : data.google_container_engine_versions.region.latest_master_version
master_version_zonal = var.kubernetes_version != "latest" ? var.kubernetes_version : data.google_container_engine_versions.zone.latest_master_version
master_version_zonal = var.kubernetes_version != "latest" ? var.kubernetes_version : (var.regional ? local.master_version_regional : data.google_container_engine_versions.zone[0].latest_master_version)
master_version = var.regional ? local.master_version_regional : local.master_version_zonal
{% if autopilot_cluster != true %}
// Build a map of maps of node pools from a list of objects
Expand Down Expand Up @@ -255,11 +260,10 @@ data "google_container_engine_versions" "region" {
project = var.project_id
}

// Only created for zonal clusters; regional clusters use region-level version lookup only (avoids zone-level API calls in environments that support only region-level location).
data "google_container_engine_versions" "zone" {
// Work around to prevent a lack of zone declaration from causing regional cluster creation from erroring out due to error
//
// data.google_container_engine_versions.zone: Cannot determine zone: set in this resource, or set provider-level zone.
//
count = var.regional ? 0 : 1

location = local.zone_count == 0 ? data.google_compute_zones.available[0].names[0] : var.zones[0]
project = var.project_id
}
12 changes: 12 additions & 0 deletions autogen/main/variables.tf.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ variable "zones" {
default = []
}

variable "cluster_location_override" {
type = string
description = "Optional override for the cluster's location attribute. When set, this value is used as the cluster location instead of the default (region for regional, first zone for zonal). Use when the API rejects the default location (e.g. backends that validate location as a zone). When set to the first zone while regional=true, node_locations are set to the remaining zones so the cluster is created as zonal."
default = null
}

variable "omit_node_locations_for_regional" {
type = bool
description = "When true and regional=true, node_locations is set from var.zones so Terraform config matches the API-populated zones and avoids drift on subsequent apply. Use when the API only accepts region-level location at create and populates zones automatically; set var.zones to the region's zones so desired state matches the cluster after create."
default = false
}

variable "network" {
type = string
description = "The VPC network to host the cluster in (required)"
Expand Down
11 changes: 5 additions & 6 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ locals {
region = var.regional ? var.region : join("-", slice(split("-", var.zones[0]), 0, 2))
// for regional cluster - use var.zones if provided, use available otherwise, for zonal cluster use var.zones with first element extracted
node_locations = var.regional ? coalescelist(compact(var.zones), try(sort(random_shuffle.available_zones[0].result), [])) : slice(var.zones, 1, length(var.zones))
// Kubernetes version
// Kubernetes version: for regional clusters only region-level lookup is used; zone-level lookup is skipped to support environments where the API accepts only region-level location.
master_version_regional = var.kubernetes_version != "latest" ? var.kubernetes_version : data.google_container_engine_versions.region.latest_master_version
master_version_zonal = var.kubernetes_version != "latest" ? var.kubernetes_version : data.google_container_engine_versions.zone.latest_master_version
master_version_zonal = var.kubernetes_version != "latest" ? var.kubernetes_version : (var.regional ? local.master_version_regional : data.google_container_engine_versions.zone[0].latest_master_version)
master_version = var.regional ? local.master_version_regional : local.master_version_zonal
// Build a map of maps of node pools from a list of objects
node_pools = { for np in var.node_pools : np.name => np }
Expand Down Expand Up @@ -186,11 +186,10 @@ data "google_container_engine_versions" "region" {
project = var.project_id
}

// Only created for zonal clusters; regional clusters use region-level version lookup only (avoids zone-level API calls in environments that support only region-level location).
data "google_container_engine_versions" "zone" {
// Work around to prevent a lack of zone declaration from causing regional cluster creation from erroring out due to error
//
// data.google_container_engine_versions.zone: Cannot determine zone: set in this resource, or set provider-level zone.
//
count = var.regional ? 0 : 1

location = local.zone_count == 0 ? data.google_compute_zones.available[0].names[0] : var.zones[0]
project = var.project_id
}
10 changes: 10 additions & 0 deletions modules/beta-autopilot-private-cluster/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,16 @@ Sub modules are provided for creating private clusters, beta private clusters, a

For details on configuring private clusters with this module, check the [troubleshooting guide](https://github.com/terraform-google-modules/terraform-google-kubernetes-engine/blob/master/docs/private_clusters.md).

## Kubernetes version lookup

When `kubernetes_version` is set to `"latest"`, the module resolves the version via the `google_container_engine_versions` data source. For **regional** clusters only a region-level lookup is performed. For **zonal** clusters a zone-level lookup is used. This allows the module to work in environments where the Container API accepts only region-level `location` (e.g. some sovereign or partner clouds).

## Cluster location override

When the API rejects the default cluster location (e.g. backends that validate `location` as a zone and reject a region), set `cluster_location_override` to the value the API accepts. For regional clusters, setting it to the first zone (e.g. `var.zones[0]`) creates the cluster as zonal from the API’s perspective; `node_locations` is then set to the remaining zones so nodes can still span multiple zones.

When the API accepts the region as `location` but rejects explicit zone names at create (e.g. "Specified location is not a valid zone"), set `omit_node_locations_for_regional = true`. The module then creates the cluster with `node_locations = []` so the API accepts the request; the API populates zones automatically. A dedicated cluster resource variant with `lifecycle { ignore_changes = [node_locations] }` is used so subsequent applies do not drift and destroy/recreate works (create again sends `[]`, no update is attempted on node_locations).

## Compatibility

This module is meant for use with Terraform 1.3+ and tested using Terraform 1.10+.
Expand Down
Loading