diff --git a/google/node_config.go b/google/node_config.go index 57cf387b..cdbfcb21 100644 --- a/google/node_config.go +++ b/google/node_config.go @@ -131,6 +131,32 @@ var schemaNodeConfig = &schema.Schema{ Elem: &schema.Schema{Type: schema.TypeString}, }, + "taint": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "effect": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{"NO_SCHEDULE", "PREFER_NO_SCHEDULE", "NO_EXECUTE"}, false), + }, + }, + }, + }, + "workload_metadata_config": { Type: schema.TypeList, Optional: true, @@ -240,6 +266,21 @@ func expandNodeConfig(v interface{}) *containerBeta.NodeConfig { nc.MinCpuPlatform = v.(string) } + if v, ok := nodeConfig["taint"]; ok && len(v.([]interface{})) > 0 { + taints := v.([]interface{}) + nodeTaints := make([]*containerBeta.NodeTaint, 0, len(taints)) + for _, raw := range taints { + data := raw.(map[string]interface{}) + taint := &containerBeta.NodeTaint{ + Key: data["key"].(string), + Value: data["value"].(string), + Effect: data["effect"].(string), + } + nodeTaints = append(nodeTaints, taint) + } + nc.Taints = nodeTaints + } + if v, ok := nodeConfig["workload_metadata_config"]; ok && len(v.([]interface{})) > 0 { conf := v.([]interface{})[0].(map[string]interface{}) nc.WorkloadMetadataConfig = &containerBeta.WorkloadMetadataConfig{ @@ -269,6 +310,7 @@ func flattenNodeConfig(c *containerBeta.NodeConfig) []map[string]interface{} { "tags": c.Tags, "preemptible": c.Preemptible, "min_cpu_platform": c.MinCpuPlatform, + "taint": flattenTaints(c.Taints), "workload_metadata_config": flattenWorkloadMetadataConfig(c.WorkloadMetadataConfig), }) @@ -290,6 +332,18 @@ func flattenContainerGuestAccelerators(c []*containerBeta.AcceleratorConfig) []m return result } +func flattenTaints(c []*containerBeta.NodeTaint) []map[string]interface{} { + result := []map[string]interface{}{} + for _, taint := range c { + result = append(result, map[string]interface{}{ + "key": taint.Key, + "value": taint.Value, + "effect": taint.Effect, + }) + } + return result +} + func flattenWorkloadMetadataConfig(c *containerBeta.WorkloadMetadataConfig) []map[string]interface{} { result := []map[string]interface{}{} if c != nil { diff --git a/google/resource_container_cluster.go b/google/resource_container_cluster.go index af69956c..ff39db1b 100644 --- a/google/resource_container_cluster.go +++ b/google/resource_container_cluster.go @@ -21,6 +21,7 @@ var ( ContainerClusterBaseApiVersion = v1 ContainerClusterVersionedFeatures = []Feature{ {Version: v1beta1, Item: "pod_security_policy_config"}, + {Version: v1beta1, Item: "node_config.*.taint"}, {Version: v1beta1, Item: "node_config.*.workload_metadata_config"}, } diff --git a/google/resource_container_cluster_test.go b/google/resource_container_cluster_test.go index 8daae15a..7b1b4eac 100644 --- a/google/resource_container_cluster_test.go +++ b/google/resource_container_cluster_test.go @@ -439,6 +439,26 @@ func TestAccContainerCluster_withNodeConfigScopeAlias(t *testing.T) { }) } +func TestAccContainerCluster_withNodeConfigTaints(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckContainerClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccContainerCluster_withNodeConfigTaints(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_container_cluster.with_node_config", "node_config.0.taint.#", "2"), + ), + }, + // Don't include an import step because beta features can't yet be imported. + // Once taints are in GA, consider merging this test with the _withNodeConfig test. + }, + }) +} + func TestAccContainerCluster_withWorkloadMetadataConfig(t *testing.T) { t.Parallel() @@ -1377,6 +1397,28 @@ resource "google_container_cluster" "with_node_config_scope_alias" { }`, acctest.RandString(10)) } +func testAccContainerCluster_withNodeConfigTaints() string { + return fmt.Sprintf(` +resource "google_container_cluster" "with_node_config" { + name = "cluster-test-%s" + zone = "us-central1-f" + initial_node_count = 1 + + node_config { + taint { + key = "taint_key" + value = "taint_value" + effect = "PREFER_NO_SCHEDULE" + } + taint { + key = "taint_key2" + value = "taint_value2" + effect = "NO_EXECUTE" + } + } +}`, acctest.RandString(10)) +} + func testAccContainerCluster_withWorkloadMetadataConfig() string { return fmt.Sprintf(` data "google_container_engine_versions" "central1a" { diff --git a/google/resource_container_node_pool.go b/google/resource_container_node_pool.go index da1a001c..ac157610 100644 --- a/google/resource_container_node_pool.go +++ b/google/resource_container_node_pool.go @@ -16,6 +16,7 @@ import ( var ( ContainerNodePoolBaseApiVersion = v1 ContainerNodePoolVersionedFeatures = []Feature{ + {Version: v1beta1, Item: "node_config.*.taint"}, {Version: v1beta1, Item: "node_config.*.workload_metadata_config"}, } ) diff --git a/google/resource_container_node_pool_test.go b/google/resource_container_node_pool_test.go index 28edce62..c1649957 100644 --- a/google/resource_container_node_pool_test.go +++ b/google/resource_container_node_pool_test.go @@ -100,6 +100,26 @@ func TestAccContainerNodePool_withNodeConfig(t *testing.T) { }) } +func TestAccContainerNodePool_withNodeConfigTaints(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckContainerNodePoolDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccContainerNodePool_withNodeConfigTaints(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("google_container_node_pool.np_with_node_config", "node_config.0.taint.#", "2"), + ), + }, + // Don't include an import step because beta features can't yet be imported. + // Once taints are in GA, consider merging this test with the _withNodeConfig test. + }, + }) +} + func TestAccContainerNodePool_withWorkloadMetadataConfig(t *testing.T) { t.Parallel() @@ -511,6 +531,33 @@ resource "google_container_node_pool" "np_with_node_config" { }`, acctest.RandString(10), acctest.RandString(10)) } +func testAccContainerNodePool_withNodeConfigTaints() string { + return fmt.Sprintf(` +resource "google_container_cluster" "cluster" { + name = "tf-cluster-nodepool-test-%s" + zone = "us-central1-a" + initial_node_count = 1 +} +resource "google_container_node_pool" "np_with_node_config" { + name = "tf-nodepool-test-%s" + zone = "us-central1-a" + cluster = "${google_container_cluster.cluster.name}" + initial_node_count = 1 + node_config { + taint { + key = "taint_key" + value = "taint_value" + effect = "PREFER_NO_SCHEDULE" + } + taint { + key = "taint_key2" + value = "taint_value2" + effect = "NO_EXECUTE" + } + } +}`, acctest.RandString(10), acctest.RandString(10)) +} + func testAccContainerNodePool_withWorkloadMetadataConfig() string { return fmt.Sprintf(` data "google_container_engine_versions" "central1a" { diff --git a/website/docs/r/container_cluster.html.markdown b/website/docs/r/container_cluster.html.markdown index 42fc3c78..6218b0a7 100644 --- a/website/docs/r/container_cluster.html.markdown +++ b/website/docs/r/container_cluster.html.markdown @@ -295,6 +295,10 @@ The `node_config` block supports: * `tags` - (Optional) The list of instance tags applied to all nodes. Tags are used to identify valid sources or targets for network firewalls. +* `taint` - (Optional, [Beta](/docs/providers/google/index.html#beta-features)) List of + [kubernetes taints](https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/) + to apply to each node. Structure is documented below. + * `workload_metadata_config` - (Optional) Metadata configuration to expose to workloads on the node pool. Structure is documented below. @@ -309,6 +313,14 @@ The `pod_security_policy_config` block supports: * `enabled` (Required) - Enable the PodSecurityPolicy controller for this cluster. If enabled, pods must be valid under a PodSecurityPolicy to be created. +The `taint` block supports: + +* `key` (Required) Key for taint. + +* `value` (Required) Value for taint. + +* `effect` (Required) Effect for taint. Accepted values are `NO_SCHEDULE`, `PREFER_NO_SCHEDULE`, and `NO_EXECUTE`. + The `workload_metadata_config` block supports: * `node_metadata` (Required) How to expose the node metadata to the workload running on the node.