From e14aa8bf39498fa944942fc9a9b28999a1862ee3 Mon Sep 17 00:00:00 2001 From: Gareth Evans Date: Fri, 15 Jun 2018 11:10:25 +0100 Subject: [PATCH 1/3] Added ability to configure resource labels on a GKE cluster --- google/resource_container_cluster.go | 36 +++++++++++++++++++ google/resource_container_cluster_test.go | 36 +++++++++++++++++++ .../docs/r/container_cluster.html.markdown | 2 ++ 3 files changed, 74 insertions(+) diff --git a/google/resource_container_cluster.go b/google/resource_container_cluster.go index 54adaaf4..3f6feb60 100644 --- a/google/resource_container_cluster.go +++ b/google/resource_container_cluster.go @@ -461,6 +461,12 @@ func resourceContainerCluster() *schema.Resource { ForceNew: true, ValidateFunc: validation.CIDRNetwork(28, 28), }, + + "resource_labels": { + Type: schema.TypeMap, + Optional: true, + Elem: schema.TypeString, + }, }, } } @@ -638,6 +644,10 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er } } + if v, ok := d.GetOk("resource_labels"); ok { + cluster.ResourceLabels = v.(map[string]string) + } + req := &containerBeta.CreateClusterRequest{ Cluster: cluster, } @@ -787,6 +797,7 @@ func resourceContainerClusterRead(d *schema.ResourceData, meta interface{}) erro d.Set("private_cluster", cluster.PrivateCluster) d.Set("master_ipv4_cidr_block", cluster.MasterIpv4CidrBlock) + d.Set("resource_labels", cluster.ResourceLabels) return nil } @@ -1143,6 +1154,31 @@ func resourceContainerClusterUpdate(d *schema.ResourceData, meta interface{}) er d.SetPartial("pod_security_policy_config") } + if d.HasChange("resource_labels") { + resourceLabels := d.Get("resource_labels").(map[string]string) + + req := &containerBeta.SetLabelsRequest{ + ResourceLabels: resourceLabels, + } + updateF := func() error { + name := containerClusterFullName(project, location, clusterName) + op, err := config.clientContainerBeta.Projects.Locations.Clusters.SetResourceLabels(name, req).Do() + if err != nil { + return err + } + + // Wait until it's updated + return containerSharedOperationWait(config, op, project, location, "updating GKE resource labels", timeoutInMinutes, 2) + } + + // Call update serially. + if err := lockedCall(lockKey, updateF); err != nil { + return err + } + + d.SetPartial("resource_labels") + } + if d.HasChange("remove_default_node_pool") && d.Get("remove_default_node_pool").(bool) { name := fmt.Sprintf("%s/nodePools/%s", containerClusterFullName(project, location, clusterName), "default-pool") op, err := config.clientContainerBeta.Projects.Locations.Clusters.NodePools.Delete(name).Do() diff --git a/google/resource_container_cluster_test.go b/google/resource_container_cluster_test.go index 6632e359..06e118c8 100644 --- a/google/resource_container_cluster_test.go +++ b/google/resource_container_cluster_test.go @@ -1160,6 +1160,27 @@ func TestAccContainerCluster_sharedVpc(t *testing.T) { }) } +func TestAccContainerCluster_withResourceLabels(t *testing.T) { + t.Parallel() + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckContainerClusterDestroy, + Steps: []resource.TestStep{ + { + Config: testAccContainerCluster_withResourceLabels(), + }, + { + ResourceName: "google_container_cluster.with_resource_labels", + ImportStateIdPrefix: "us-central1-a/", + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + func testAccCheckContainerClusterDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) @@ -2229,3 +2250,18 @@ resource "google_container_cluster" "shared_vpc_cluster" { ] }`, projectName, org, billingId, projectName, org, billingId, acctest.RandString(10), acctest.RandString(10), name) } + +func testAccContainerCluster_withResourceLabels() string { + testId := acctest.RandString(10) + return fmt.Sprintf(` +resource "google_container_cluster" "with_resource_labels" { + name = "tf-cluster-resourcelabel-test-%s" + zone = "us-central1-a" + initial_node_count = 1 + + resource_labels { + created-by = "terraform" + } +} +`, testId) +} diff --git a/website/docs/r/container_cluster.html.markdown b/website/docs/r/container_cluster.html.markdown index 72fdc59b..56b03354 100644 --- a/website/docs/r/container_cluster.html.markdown +++ b/website/docs/r/container_cluster.html.markdown @@ -172,6 +172,8 @@ output "cluster_ca_certificate" { * `remove_default_node_pool` - (Optional) If true, deletes the default node pool upon cluster creation. +* `resource_labels` - (Optional) The GCE resource labels (key/value pairs) to be applied to the cluster. + * `subnetwork` - (Optional) The name or self_link of the Google Compute Engine subnetwork in which the cluster's instances are launched. From fee1c7f682a74dd4648d85861eab8fc992591c82 Mon Sep 17 00:00:00 2001 From: Gareth Evans Date: Fri, 15 Jun 2018 11:39:08 +0100 Subject: [PATCH 2/3] Type conversion issue --- google/resource_container_cluster.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/google/resource_container_cluster.go b/google/resource_container_cluster.go index 3f6feb60..e5337aa7 100644 --- a/google/resource_container_cluster.go +++ b/google/resource_container_cluster.go @@ -645,7 +645,11 @@ func resourceContainerClusterCreate(d *schema.ResourceData, meta interface{}) er } if v, ok := d.GetOk("resource_labels"); ok { - cluster.ResourceLabels = v.(map[string]string) + m := make(map[string]string) + for k, val := range v.(map[string]interface{}) { + m[k] = val.(string) + } + cluster.ResourceLabels = m } req := &containerBeta.CreateClusterRequest{ From bf7c70b392fb77d3482ff407bf5394eec067fb1d Mon Sep 17 00:00:00 2001 From: Gareth Evans Date: Mon, 25 Jun 2018 09:55:27 +0100 Subject: [PATCH 3/3] Minor code changes as requested --- google/resource_container_cluster_test.go | 21 ++++++++++--------- .../docs/r/container_cluster.html.markdown | 2 +- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/google/resource_container_cluster_test.go b/google/resource_container_cluster_test.go index 06e118c8..1c879a55 100644 --- a/google/resource_container_cluster_test.go +++ b/google/resource_container_cluster_test.go @@ -1163,13 +1163,15 @@ func TestAccContainerCluster_sharedVpc(t *testing.T) { func TestAccContainerCluster_withResourceLabels(t *testing.T) { t.Parallel() + clusterName := fmt.Sprintf("cluster-test-%s", acctest.RandString(10)) + resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, CheckDestroy: testAccCheckContainerClusterDestroy, Steps: []resource.TestStep{ { - Config: testAccContainerCluster_withResourceLabels(), + Config: testAccContainerCluster_withResourceLabels(clusterName), }, { ResourceName: "google_container_cluster.with_resource_labels", @@ -2251,17 +2253,16 @@ resource "google_container_cluster" "shared_vpc_cluster" { }`, projectName, org, billingId, projectName, org, billingId, acctest.RandString(10), acctest.RandString(10), name) } -func testAccContainerCluster_withResourceLabels() string { - testId := acctest.RandString(10) +func testAccContainerCluster_withResourceLabels(clusterName string) string { return fmt.Sprintf(` resource "google_container_cluster" "with_resource_labels" { - name = "tf-cluster-resourcelabel-test-%s" + name = "%s" zone = "us-central1-a" - initial_node_count = 1 - - resource_labels { - created-by = "terraform" - } + initial_node_count = 1 + + resource_labels { + created-by = "terraform" + } } -`, testId) +`, clusterName) } diff --git a/website/docs/r/container_cluster.html.markdown b/website/docs/r/container_cluster.html.markdown index 56b03354..19939254 100644 --- a/website/docs/r/container_cluster.html.markdown +++ b/website/docs/r/container_cluster.html.markdown @@ -172,7 +172,7 @@ output "cluster_ca_certificate" { * `remove_default_node_pool` - (Optional) If true, deletes the default node pool upon cluster creation. -* `resource_labels` - (Optional) The GCE resource labels (key/value pairs) to be applied to the cluster. +* `resource_labels` - (Optional) The GCE resource labels (a map of key/value pairs) to be applied to the cluster. * `subnetwork` - (Optional) The name or self_link of the Google Compute Engine subnetwork in which the cluster's instances are launched.