diff --git a/google/node_config.go b/google/node_config.go index 683242d58a2..4bac504b819 100644 --- a/google/node_config.go +++ b/google/node_config.go @@ -84,6 +84,13 @@ var schemaNodeConfig = &schema.Schema{ ForceNew: true, Elem: &schema.Schema{Type: schema.TypeString}, }, + + "preemptible": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Default: false, + }, }, }, } @@ -148,7 +155,30 @@ func expandNodeConfig(v interface{}) *container.NodeConfig { } nc.Tags = tags } + // Preemptible Is Optional+Default, so it always has a value + nc.Preemptible = nodeConfig["preemptible"].(bool) return nc +} + +func flattenNodeConfig(c *container.NodeConfig) []map[string]interface{} { + config := []map[string]interface{}{ + { + "machine_type": c.MachineType, + "disk_size_gb": c.DiskSizeGb, + "local_ssd_count": c.LocalSsdCount, + "service_account": c.ServiceAccount, + "metadata": c.Metadata, + "image_type": c.ImageType, + "labels": c.Labels, + "tags": c.Tags, + "preemptible": c.Preemptible, + }, + } + + if len(c.OauthScopes) > 0 { + config[0]["oauth_scopes"] = c.OauthScopes + } + return config } diff --git a/google/resource_container_cluster.go b/google/resource_container_cluster.go index 282470ac781..ad6924da3d3 100644 --- a/google/resource_container_cluster.go +++ b/google/resource_container_cluster.go @@ -494,7 +494,7 @@ func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) erro d.Set("monitoring_service", cluster.MonitoringService) d.Set("network", d.Get("network").(string)) d.Set("subnetwork", cluster.Subnetwork) - d.Set("node_config", flattenClusterNodeConfig(cluster.NodeConfig)) + d.Set("node_config", flattenNodeConfig(cluster.NodeConfig)) nps, err := flattenClusterNodePools(d, config, cluster.NodePools) if err != nil { return err @@ -733,27 +733,6 @@ func getInstanceGroupUrlsFromManagerUrls(config *Config, igmUrls []string) ([]st return instanceGroupURLs, nil } -func flattenClusterNodeConfig(c *container.NodeConfig) []map[string]interface{} { - config := []map[string]interface{}{ - { - "machine_type": c.MachineType, - "disk_size_gb": c.DiskSizeGb, - "local_ssd_count": c.LocalSsdCount, - "service_account": c.ServiceAccount, - "metadata": c.Metadata, - "image_type": c.ImageType, - "labels": c.Labels, - "tags": c.Tags, - }, - } - - if len(c.OauthScopes) > 0 { - config[0]["oauth_scopes"] = c.OauthScopes - } - - return config -} - func flattenClusterNodePools(d *schema.ResourceData, config *Config, c []*container.NodePool) ([]map[string]interface{}, error) { nodePools := make([]map[string]interface{}, 0, len(c)) @@ -776,7 +755,7 @@ func flattenClusterNodePools(d *schema.ResourceData, config *Config, c []*contai "name_prefix": d.Get(fmt.Sprintf("node_pool.%d.name_prefix", i)), "initial_node_count": np.InitialNodeCount, "node_count": size / len(np.InstanceGroupUrls), - "node_config": flattenClusterNodeConfig(np.Config), + "node_config": flattenNodeConfig(np.Config), } nodePools = append(nodePools, nodePool) } diff --git a/google/resource_container_cluster_test.go b/google/resource_container_cluster_test.go index d7df8d46f88..6ef551338af 100644 --- a/google/resource_container_cluster_test.go +++ b/google/resource_container_cluster_test.go @@ -449,6 +449,7 @@ func testAccCheckContainerCluster(n string) resource.TestCheckFunc { {"node_config.0.image_type", cluster.NodeConfig.ImageType}, {"node_config.0.labels", cluster.NodeConfig.Labels}, {"node_config.0.tags", cluster.NodeConfig.Tags}, + {"node_config.0.preemptible", cluster.NodeConfig.Preemptible}, {"node_version", cluster.CurrentNodeVersion}, } @@ -535,6 +536,10 @@ func checkMatch(attributes map[string]string, attr string, gcp interface{}) stri if gcpMap, ok := gcp.(map[string]string); ok { return checkMapMatch(attributes, attr, gcpMap) } + if gcpBool, ok := gcp.(bool); ok { + return checkBoolMatch(attributes, attr, gcpBool) + } + tf := attributes[attr] if tf != gcp { return matchError(attr, tf, gcp) @@ -602,6 +607,18 @@ func checkMapMatch(attributes map[string]string, attr string, gcpMap map[string] return "" } +func checkBoolMatch(attributes map[string]string, attr string, gcpBool bool) string { + tf, err := strconv.ParseBool(attributes[attr]) + if err != nil { + return fmt.Sprintf("Error converting attribute %s to boolean: value is %s", attr, attributes[attr]) + } + if tf != gcpBool { + return matchError(attr, tf, gcpBool) + } + + return "" +} + func matchError(attr, tf interface{}, gcp interface{}) string { return fmt.Sprintf("Cluster has mismatched %s.\nTF State: %+v\nGCP State: %+v", attr, tf, gcp) } @@ -762,11 +779,12 @@ resource "google_container_cluster" "with_node_config" { metadata { foo = "bar" } - image_type = "CONTAINER_VM" + image_type = "COS" labels { foo = "bar" } tags = ["foo", "bar"] + preemptible = true } }`, acctest.RandString(10)) @@ -1018,7 +1036,7 @@ resource "google_container_cluster" "with_node_pool_node_config" { metadata { foo = "bar" } - image_type = "CONTAINER_VM" + image_type = "COS" labels { foo = "bar" } diff --git a/google/resource_container_node_pool.go b/google/resource_container_node_pool.go index 015fef85bb8..5df38e81079 100644 --- a/google/resource_container_node_pool.go +++ b/google/resource_container_node_pool.go @@ -174,7 +174,7 @@ func resourceContainerNodePoolRead(d *schema.ResourceData, meta interface{}) err d.Set("name", nodePool.Name) d.Set("initial_node_count", nodePool.InitialNodeCount) - d.Set("node_config", flattenClusterNodeConfig(nodePool.Config)) + d.Set("node_config", flattenNodeConfig(nodePool.Config)) autoscaling := []map[string]interface{}{} if nodePool.Autoscaling != nil && nodePool.Autoscaling.Enabled { diff --git a/google/resource_container_node_pool_test.go b/google/resource_container_node_pool_test.go index 546f2448438..5ae5fa16b97 100644 --- a/google/resource_container_node_pool_test.go +++ b/google/resource_container_node_pool_test.go @@ -154,6 +154,7 @@ func testAccCheckContainerNodePoolMatches(n string) resource.TestCheckFunc { {"node_config.0.image_type", nodepool.Config.ImageType}, {"node_config.0.labels", nodepool.Config.Labels}, {"node_config.0.tags", nodepool.Config.Tags}, + {"node_config.0.preemptible", nodepool.Config.Preemptible}, } for _, attrs := range nodepoolTests { @@ -261,6 +262,9 @@ func nodepoolCheckMatch(attributes map[string]string, attr string, gcp interface if gcpMap, ok := gcp.(map[string]string); ok { return nodepoolCheckMapMatch(attributes, attr, gcpMap) } + if gcpBool, ok := gcp.(bool); ok { + return checkBoolMatch(attributes, attr, gcpBool) + } tf := attributes[attr] if tf != gcp { return nodepoolMatchError(attr, tf, gcp) @@ -356,6 +360,7 @@ resource "google_container_node_pool" "np_with_node_config" { "https://www.googleapis.com/auth/logging.write", "https://www.googleapis.com/auth/monitoring" ] + preemptible = true } }`, acctest.RandString(10), acctest.RandString(10)) diff --git a/website/docs/r/container_cluster.html.markdown b/website/docs/r/container_cluster.html.markdown index f683aca8533..c853c7efc17 100644 --- a/website/docs/r/container_cluster.html.markdown +++ b/website/docs/r/container_cluster.html.markdown @@ -153,6 +153,10 @@ which the cluster's instances are launched * `tags` - (Optional) The list of instance tags applied to all nodes. Tags are used to identify valid sources or targets for network firewalls. +* `preemptible` - (Optional) A boolean that represents whether or not the underlying node VMs + are preemptible. See the [official documentation](https://cloud.google.com/container-engine/docs/preemptible-vm) + for more information. Defaults to false. + **Addons Config** supports the following addons: * `http_load_balancing` - (Optional) The status of the HTTP Load Balancing diff --git a/website/docs/r/container_node_pool.html.markdown b/website/docs/r/container_node_pool.html.markdown index 631b99d6f22..3cfc095bf55 100644 --- a/website/docs/r/container_node_pool.html.markdown +++ b/website/docs/r/container_node_pool.html.markdown @@ -105,6 +105,10 @@ resource "google_container_cluster" "primary" { * `image_type` - (Optional) The image type to use for this node. +* `preemptible` - (Optional) A boolean that represents whether or not the underlying node VMs + are preemptible. See the [official documentation](https://cloud.google.com/container-engine/docs/preemptible-vm) + for more information. Defaults to false. + The `autoscaling` block supports: * `minNodeCount` - (Required) Minimum number of nodes in the NodePool. Must be >=1 and