Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .changelog/18094.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
container: added `ANY_RESERVATION_THEN_FAIL` option to `consume_reservation_type` field in `google_container_cluster` and `google_container_node_pool` resources
```
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ require (
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56
golang.org/x/net v0.56.0
golang.org/x/oauth2 v0.36.0
google.golang.org/api v0.285.0
google.golang.org/api v0.286.0
google.golang.org/genproto/googleapis/rpc v0.0.0-20260610212136-7ab31c22f7ad
google.golang.org/grpc v1.81.1
google.golang.org/protobuf v1.36.11
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,8 @@ golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da h1:noIWHXmPHxILtqtCOPIhS
golang.org/x/xerrors v0.0.0-20240903120638-7835f813f4da/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4=
gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E=
google.golang.org/api v0.285.0 h1:B7eHHoKGAX/LrPkQvhQqnGwjgWxofbdGwCTQvpm8FkM=
google.golang.org/api v0.285.0/go.mod h1:NlOlUIr8MPoIhT9Bb/oUnRuHbJOLwxb6JSYJM8Yz+jQ=
google.golang.org/api v0.286.0 h1:TdTXMvzYKnWV1/lPbCdbXRqBrkDqjPto22H2xeZZ8LI=
google.golang.org/api v0.286.0/go.mod h1:NlOlUIr8MPoIhT9Bb/oUnRuHbJOLwxb6JSYJM8Yz+jQ=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM=
Expand Down
2 changes: 1 addition & 1 deletion google/services/container/node_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -593,7 +593,7 @@ func schemaNodeConfig() *schema.Schema {
Required: true,
ForceNew: true,
Description: `Corresponds to the type of reservation consumption.`,
ValidateFunc: validation.StringInSlice([]string{"UNSPECIFIED", "NO_RESERVATION", "ANY_RESERVATION", "SPECIFIC_RESERVATION"}, false),
ValidateFunc: validation.StringInSlice([]string{"UNSPECIFIED", "NO_RESERVATION", "ANY_RESERVATION", "SPECIFIC_RESERVATION", "ANY_RESERVATION_THEN_FAIL"}, false),
},
"key": {
Type: schema.TypeString,
Expand Down
101 changes: 101 additions & 0 deletions google/services/container/resource_container_cluster_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2931,6 +2931,38 @@ func TestAccContainerCluster_withNodeConfigReservationAffinitySpecific(t *testin
})
}

func TestAccContainerCluster_withNodeConfigReservationAffinityAnyReservationThenFail(t *testing.T) {
t.Parallel()

reservationName := fmt.Sprintf("tf-test-reservation-%s", acctest.RandString(t, 10))
clusterName := fmt.Sprintf("tf-test-cluster-%s", acctest.RandString(t, 10))
networkName := tpgcompute.BootstrapSharedTestNetwork(t, "gke-cluster")
subnetworkName := tpgcompute.BootstrapSubnet(t, "gke-cluster", networkName)

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckContainerClusterDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccContainerCluster_withNodeConfigReservationAffinityAnyReservationThenFail(reservationName, clusterName, networkName, subnetworkName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("google_container_cluster.with_node_config",
"node_config.0.reservation_affinity.#", "1"),
resource.TestCheckResourceAttr("google_container_cluster.with_node_config",
"node_config.0.reservation_affinity.0.consume_reservation_type", "ANY_RESERVATION_THEN_FAIL"),
),
},
{
ResourceName: "google_container_cluster.with_node_config",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"deletion_protection"},
},
},
})
}

func TestAccContainerCluster_withNodeConfigNodeImageConfig(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -9721,6 +9753,75 @@ resource "google_container_cluster" "with_node_config" {
`, reservation, clusterName, networkName, subnetworkName)
}

func testAccContainerCluster_withNodeConfigReservationAffinityAnyReservationThenFail(reservation, clusterName, networkName, subnetworkName string) string {
return fmt.Sprintf(`

resource "google_project_service" "compute" {
service = "compute.googleapis.com"
}

resource "google_project_service" "container" {
service = "container.googleapis.com"
depends_on = [google_project_service.compute]
}


resource "google_compute_reservation" "gce_reservation" {
name = "%s"
zone = "us-central1-f"

specific_reservation {
count = 1
instance_properties {
machine_type = "n1-standard-1"
}
}

specific_reservation_required = false
depends_on = [google_project_service.compute]
}

resource "google_container_cluster" "with_node_config" {
name = "%s"
location = "us-central1-f"
initial_node_count = 1

node_config {
machine_type = "n1-standard-1"
disk_size_gb = 15
disk_type = "pd-ssd"
oauth_scopes = [
"https://www.googleapis.com/auth/monitoring",
"https://www.googleapis.com/auth/compute",
"https://www.googleapis.com/auth/devstorage.read_only",
"https://www.googleapis.com/auth/logging.write",
]
service_account = "default"
metadata = {
foo = "bar"
disable-legacy-endpoints = "true"
}
labels = {
foo = "bar"
}
tags = ["foo", "bar"]

// Updatable fields
image_type = "COS_CONTAINERD"

reservation_affinity {
consume_reservation_type = "ANY_RESERVATION_THEN_FAIL"
}
}
network = "%s"
subnetwork = "%s"

deletion_protection = false
depends_on = [google_project_service.container]
}
`, reservation, clusterName, networkName, subnetworkName)
}

func testAccContainerCluster_withNodeConfigNodeImageConfig(clusterName, networkName, subnetworkName, imageName, imageProject string) string {
return fmt.Sprintf(`

Expand Down
81 changes: 81 additions & 0 deletions google/services/container/resource_container_node_pool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,38 @@ func TestAccContainerNodePool_withReservationAffinitySpecific(t *testing.T) {
})
}

func TestAccContainerNodePool_withReservationAffinityAnyReservationThenFail(t *testing.T) {
t.Parallel()

cluster := fmt.Sprintf("tf-test-cluster-%s", acctest.RandString(t, 10))
reservation := fmt.Sprintf("tf-test-reservation-%s", acctest.RandString(t, 10))
np := fmt.Sprintf("tf-test-np-%s", acctest.RandString(t, 10))
networkName := tpgcompute.BootstrapSharedTestNetwork(t, "gke-cluster")
subnetworkName := tpgcompute.BootstrapSubnet(t, "gke-cluster", networkName)

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckContainerClusterDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccContainerNodePool_withReservationAffinityAnyReservationThenFail(cluster, reservation, np, networkName, subnetworkName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("google_container_node_pool.with_reservation_affinity",
"node_config.0.reservation_affinity.#", "1"),
resource.TestCheckResourceAttr("google_container_node_pool.with_reservation_affinity",
"node_config.0.reservation_affinity.0.consume_reservation_type", "ANY_RESERVATION_THEN_FAIL"),
),
},
{
ResourceName: "google_container_node_pool.with_reservation_affinity",
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccContainerNodePool_withWorkloadIdentityConfig(t *testing.T) {
t.Parallel()

Expand Down Expand Up @@ -3838,6 +3870,55 @@ resource "google_container_node_pool" "with_reservation_affinity" {
`, cluster, networkName, subnetworkName, reservation, np)
}

func testAccContainerNodePool_withReservationAffinityAnyReservationThenFail(cluster, reservation, np, networkName, subnetworkName string) string {
return fmt.Sprintf(`
data "google_container_engine_versions" "central1a" {
location = "us-central1-a"
}

resource "google_container_cluster" "cluster" {
name = "%s"
location = "us-central1-a"
initial_node_count = 1
min_master_version = data.google_container_engine_versions.central1a.latest_master_version
deletion_protection = false
network = "%s"
subnetwork = "%s"
}

resource "google_compute_reservation" "gce_reservation" {
name = "%s"
zone = "us-central1-a"

specific_reservation {
count = 1
instance_properties {
machine_type = "n1-standard-1"
}
}

specific_reservation_required = false
}

resource "google_container_node_pool" "with_reservation_affinity" {
name = "%s"
location = "us-central1-a"
cluster = google_container_cluster.cluster.name
initial_node_count = 1
node_config {
machine_type = "n1-standard-1"
oauth_scopes = [
"https://www.googleapis.com/auth/logging.write",
"https://www.googleapis.com/auth/monitoring",
]
reservation_affinity {
consume_reservation_type = "ANY_RESERVATION_THEN_FAIL"
}
}
}
`, cluster, networkName, subnetworkName, reservation, np)
}

func testAccContainerNodePool_withWorkloadMetadataConfig(cluster, np, networkName, subnetworkName string) string {
return fmt.Sprintf(`
data "google_container_engine_versions" "central1a" {
Expand Down
3 changes: 2 additions & 1 deletion website/docs/r/container_cluster.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -1521,8 +1521,9 @@ not.

* `"UNSPECIFIED"`: Default value. This should not be used.
* `"NO_RESERVATION"`: Do not consume from any reserved capacity.
* `"ANY_RESERVATION"`: Consume any reservation available.
* `"ANY_RESERVATION"`: Consume any non-specific reservation available, with a fallback to on-demand capacity in case of none reservaition being claimable.
* `"SPECIFIC_RESERVATION"`: Must consume from a specific reservation. Must specify key value fields for specifying the reservations.
* `"ANY_RESERVATION_THEN_FAIL"`: Consume any non-specific reservation available, without a fallback to on-demand capacity in case of none reservaition being claimable.
* `key` (Optional) The label key of a reservation resource. To target a SPECIFIC_RESERVATION by name, specify "compute.googleapis.com/reservation-name" as the key and specify the name of your reservation as its value.
* `values` (Optional) The list of label values of reservation resources. For example: the name of the specific reservation when using a key of "compute.googleapis.com/reservation-name"

Expand Down
3 changes: 2 additions & 1 deletion website/docs/r/container_node_pool.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -336,8 +336,9 @@ cluster.

* `"UNSPECIFIED"`: Default value. This should not be used.
* `"NO_RESERVATION"`: Do not consume from any reserved capacity.
* `"ANY_RESERVATION"`: Consume any reservation available.
* `"ANY_RESERVATION"`: Consume any non-specific reservation available, with a fallback to on-demand capacity in case of none reservaition being claimable.
* `"SPECIFIC_RESERVATION"`: Must consume from a specific reservation. Must specify key value fields for specifying the reservations.
* `"ANY_RESERVATION_THEN_FAIL"`: Consume any non-specific reservation available, without a fallback to on-demand capacity in case of none reservaition being claimable.
* `key` (Optional) The label key of a reservation resource. To target a SPECIFIC_RESERVATION by name, specify "compute.googleapis.com/reservation-name" as the key and specify the name of your reservation as its value.
* `values` (Optional) The list of label values of reservation resources. For example: the name of the specific reservation when using a key of "compute.googleapis.com/reservation-name"

Expand Down