Skip to content

Commit 22da542

Browse files
Add Resource Manager Tags support to 'google_container_cluster' (#9531) (#7001)
* resourceManagerTags added to Cluster Node Config schema * update beta tag * add cluster and node proto tests * add expand and flatten proto * removed beta tag * added to documentation * added resource manager tags to auto pilot * migrating resourceManagerTags tests * migrating node_pools test * migrating additional tests * minor fixes * fixing tests * add in-place update support * fixed tests * fixed annotations * validated clusters and node pools tests. Isolated node pool auto config * isolated resource manager tags from docs * fixed permission issue * fixed spaces * fixed non determinism on tag keys * removed auto_pilot rmts * fixed time_sleep * add depends_on to IAM policies [upstream:343ff46df5008cc457392c3baafd0acc6dc97633] Signed-off-by: Modular Magician <[email protected]>
1 parent 123b05e commit 22da542

File tree

8 files changed

+618
-11
lines changed

8 files changed

+618
-11
lines changed

.changelog/9531.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
```release-note:enhancement
2+
container: added `node_config.resource_manager_tags` field to `google_container_cluster` resource
3+
```
4+
```release-note:enhancement
5+
container: added `node_config.resource_manager_tags` field to `google_container_node_pool` resource
6+
```

google-beta/services/compute/resource_compute_instance.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -660,7 +660,7 @@ func ResourceComputeInstance() *schema.Resource {
660660
Optional: true,
661661
Elem: &schema.Schema{Type: schema.TypeString},
662662
Description: `A set of key/value label pairs assigned to the instance.
663-
663+
664664
**Note**: This field is non-authoritative, and will only manage the labels present in your configuration.
665665
Please refer to the field 'effective_labels' for all of the labels present on the resource.`,
666666
},

google-beta/services/container/node_config.go

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -664,6 +664,11 @@ func schemaNodeConfig() *schema.Schema {
664664
},
665665
},
666666
},
667+
"resource_manager_tags": {
668+
Type: schema.TypeMap,
669+
Optional: true,
670+
Description: `A map of resource manager tags. Resource manager tag keys and values have the same definition as resource manager tags. Keys must be in the format tagKeys/{tag_key_id}, and values are in the format tagValues/456. The field is ignored (both PUT & PATCH) when empty.`,
671+
},
667672
"enable_confidential_storage": {
668673
Type: schema.TypeBool,
669674
Optional: true,
@@ -867,6 +872,10 @@ func expandNodeConfig(v interface{}) *container.NodeConfig {
867872
nc.ResourceLabels = m
868873
}
869874

875+
if v, ok := nodeConfig["resource_manager_tags"]; ok && len(v.(map[string]interface{})) > 0 {
876+
nc.ResourceManagerTags = expandResourceManagerTags(v)
877+
}
878+
870879
if v, ok := nodeConfig["tags"]; ok {
871880
tagsList := v.([]interface{})
872881
tags := []string{}
@@ -965,6 +974,19 @@ func expandNodeConfig(v interface{}) *container.NodeConfig {
965974
return nc
966975
}
967976

977+
func expandResourceManagerTags(v interface{}) *container.ResourceManagerTags {
978+
rmts := make(map[string]string)
979+
980+
if v != nil {
981+
rmts = tpgresource.ConvertStringMap(v.(map[string]interface{}))
982+
}
983+
984+
return &container.ResourceManagerTags{
985+
Tags: rmts,
986+
ForceSendFields: []string{"Tags"},
987+
}
988+
}
989+
968990
func expandWorkloadMetadataConfig(v interface{}) *container.WorkloadMetadataConfig {
969991
if v == nil {
970992
return nil
@@ -1182,8 +1204,8 @@ func flattenNodeConfig(c *container.NodeConfig, v interface{}) []map[string]inte
11821204
"advanced_machine_features": flattenAdvancedMachineFeaturesConfig(c.AdvancedMachineFeatures),
11831205
"sole_tenant_config": flattenSoleTenantConfig(c.SoleTenantConfig),
11841206
"fast_socket": flattenFastSocket(c.FastSocket),
1185-
1186-
"enable_confidential_storage": c.EnableConfidentialStorage,
1207+
"resource_manager_tags": flattenResourceManagerTags(c.ResourceManagerTags),
1208+
"enable_confidential_storage": c.EnableConfidentialStorage,
11871209
})
11881210

11891211
if len(c.OauthScopes) > 0 {
@@ -1193,6 +1215,19 @@ func flattenNodeConfig(c *container.NodeConfig, v interface{}) []map[string]inte
11931215
return config
11941216
}
11951217

1218+
func flattenResourceManagerTags(c *container.ResourceManagerTags) map[string]interface{} {
1219+
rmt := make(map[string]interface{})
1220+
1221+
if c != nil {
1222+
for k, v := range c.Tags {
1223+
rmt[k] = v
1224+
}
1225+
1226+
}
1227+
1228+
return rmt
1229+
}
1230+
11961231
func flattenAdvancedMachineFeaturesConfig(c *container.AdvancedMachineFeatures) []map[string]interface{} {
11971232
result := []map[string]interface{}{}
11981233
if c != nil {

google-beta/services/container/resource_container_cluster.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ var (
9292
forceNewClusterNodeConfigFields = []string{
9393
"labels",
9494
"workload_metadata_config",
95+
"resource_manager_tags",
9596
}
9697

9798
suppressDiffForAutopilot = schema.SchemaDiffSuppressFunc(func(k, oldValue, newValue string, d *schema.ResourceData) bool {
@@ -5349,6 +5350,7 @@ func expandNodePoolAutoConfig(configured interface{}) *container.NodePoolAutoCon
53495350
if v, ok := config["network_tags"]; ok && len(v.([]interface{})) > 0 {
53505351
npac.NetworkTags = expandNodePoolAutoConfigNetworkTags(v)
53515352
}
5353+
53525354
return npac
53535355
}
53545356

google-beta/services/container/resource_container_cluster_test.go

Lines changed: 124 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,43 @@ func TestAccContainerCluster_basic(t *testing.T) {
5757
})
5858
}
5959

60+
func TestAccContainerCluster_resourceManagerTags(t *testing.T) {
61+
t.Parallel()
62+
63+
pid := envvar.GetTestProjectFromEnv()
64+
65+
randomSuffix := acctest.RandString(t, 10)
66+
clusterName := fmt.Sprintf("tf-test-cluster-%s", randomSuffix)
67+
68+
networkName := acctest.BootstrapSharedTestNetwork(t, "gke-cluster")
69+
subnetworkName := acctest.BootstrapSubnet(t, "gke-cluster", networkName)
70+
71+
acctest.VcrTest(t, resource.TestCase{
72+
PreCheck: func() { acctest.AccTestPreCheck(t) },
73+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
74+
ExternalProviders: map[string]resource.ExternalProvider{
75+
"time": {},
76+
},
77+
CheckDestroy: testAccCheckContainerClusterDestroyProducer(t),
78+
Steps: []resource.TestStep{
79+
{
80+
Config: testAccContainerCluster_resourceManagerTags(pid, clusterName, networkName, subnetworkName, randomSuffix),
81+
Check: resource.ComposeTestCheckFunc(
82+
resource.TestCheckResourceAttrSet("google_container_cluster.primary", "self_link"),
83+
resource.TestCheckResourceAttrSet("google_container_cluster.primary", "node_config.0.resource_manager_tags.%"),
84+
),
85+
},
86+
{
87+
ResourceName: "google_container_cluster.primary",
88+
ImportStateId: fmt.Sprintf("us-central1-a/%s", clusterName),
89+
ImportState: true,
90+
ImportStateVerify: true,
91+
ImportStateVerifyIgnore: []string{"min_master_version", "deletion_protection"},
92+
},
93+
},
94+
})
95+
}
96+
6097
func TestAccContainerCluster_networkingModeRoutes(t *testing.T) {
6198
t.Parallel()
6299

@@ -4418,11 +4455,11 @@ func testAccContainerCluster_withIncompatibleMasterVersionNodeVersion(name strin
44184455
resource "google_container_cluster" "gke_cluster" {
44194456
name = "%s"
44204457
location = "us-central1"
4421-
4458+
44224459
min_master_version = "1.10.9-gke.5"
44234460
node_version = "1.10.6-gke.11"
44244461
initial_node_count = 1
4425-
4462+
44264463
}
44274464
`, name)
44284465
}
@@ -6631,7 +6668,7 @@ resource "google_container_cluster" "with_autoprovisioning" {
66316668
min_master_version = data.google_container_engine_versions.central1a.latest_master_version
66326669
initial_node_count = 1
66336670
deletion_protection = false
6634-
6671+
66356672
network = "%s"
66366673
subnetwork = "%s"
66376674
@@ -9197,7 +9234,7 @@ resource "google_compute_resource_policy" "policy" {
91979234
resource "google_container_cluster" "cluster" {
91989235
name = "%s"
91999236
location = "us-central1-a"
9200-
9237+
92019238
node_pool {
92029239
name = "%s"
92039240
initial_node_count = 2
@@ -9504,3 +9541,86 @@ func testAccContainerCluster_withWorkloadALTSConfig(projectID, name, networkName
95049541
}
95059542
`, projectID, networkName, subnetworkName, name, enable)
95069543
}
9544+
9545+
func testAccContainerCluster_resourceManagerTags(projectID, clusterName, networkName, subnetworkName, randomSuffix string) string {
9546+
return fmt.Sprintf(`
9547+
data "google_project" "project" {
9548+
project_id = "%[1]s"
9549+
}
9550+
9551+
resource "google_project_iam_binding" "tagHoldAdmin" {
9552+
project = "%[1]s"
9553+
role = "roles/resourcemanager.tagHoldAdmin"
9554+
members = [
9555+
"serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com",
9556+
]
9557+
}
9558+
9559+
resource "google_project_iam_binding" "tagUser" {
9560+
project = "%[1]s"
9561+
role = "roles/resourcemanager.tagUser"
9562+
members = [
9563+
"serviceAccount:service-${data.google_project.project.number}@container-engine-robot.iam.gserviceaccount.com",
9564+
"serviceAccount:${data.google_project.project.number}@cloudservices.gserviceaccount.com",
9565+
]
9566+
9567+
depends_on = [google_project_iam_binding.tagHoldAdmin]
9568+
}
9569+
9570+
resource "time_sleep" "wait_120_seconds" {
9571+
create_duration = "120s"
9572+
9573+
depends_on = [
9574+
google_project_iam_binding.tagHoldAdmin,
9575+
google_project_iam_binding.tagUser
9576+
]
9577+
}
9578+
9579+
resource "google_tags_tag_key" "key" {
9580+
parent = "projects/%[1]s"
9581+
short_name = "foobarbaz-%[2]s"
9582+
description = "For foo/bar resources"
9583+
purpose = "GCE_FIREWALL"
9584+
purpose_data = {
9585+
network = "%[1]s/%[4]s"
9586+
}
9587+
}
9588+
9589+
resource "google_tags_tag_value" "value" {
9590+
parent = "tagKeys/${google_tags_tag_key.key.name}"
9591+
short_name = "foo-%[2]s"
9592+
description = "For foo resources"
9593+
}
9594+
9595+
data "google_container_engine_versions" "uscentral1a" {
9596+
location = "us-central1-a"
9597+
}
9598+
9599+
resource "google_container_cluster" "primary" {
9600+
name = "%[3]s"
9601+
location = "us-central1-a"
9602+
min_master_version = data.google_container_engine_versions.uscentral1a.release_channel_latest_version["STABLE"]
9603+
initial_node_count = 1
9604+
9605+
node_config {
9606+
machine_type = "n1-standard-1" // can't be e2 because of local-ssd
9607+
disk_size_gb = 15
9608+
9609+
resource_manager_tags = {
9610+
"tagKeys/${google_tags_tag_key.key.name}" = "tagValues/${google_tags_tag_value.value.name}"
9611+
}
9612+
}
9613+
9614+
deletion_protection = false
9615+
network = "%[4]s"
9616+
subnetwork = "%[5]s"
9617+
9618+
timeouts {
9619+
create = "30m"
9620+
update = "40m"
9621+
}
9622+
9623+
depends_on = [time_sleep.wait_120_seconds]
9624+
}
9625+
`, projectID, randomSuffix, clusterName, networkName, subnetworkName)
9626+
}

google-beta/services/container/resource_container_node_pool.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,6 +1586,48 @@ func nodePoolUpdate(d *schema.ResourceData, meta interface{}, nodePoolInfo *Node
15861586
log.Printf("[INFO] Updated tags for node pool %s", name)
15871587
}
15881588

1589+
if d.HasChange(prefix + "node_config.0.resource_manager_tags") {
1590+
req := &container.UpdateNodePoolRequest{
1591+
Name: name,
1592+
}
1593+
if v, ok := d.GetOk(prefix + "node_config.0.resource_manager_tags"); ok {
1594+
req.ResourceManagerTags = expandResourceManagerTags(v)
1595+
}
1596+
1597+
// sets resource manager tags to the empty list when user removes a previously defined list of tags entriely
1598+
// aka the node pool goes from having tags to no longer having any
1599+
if req.ResourceManagerTags == nil {
1600+
tags := make(map[string]string)
1601+
rmTags := &container.ResourceManagerTags{
1602+
Tags: tags,
1603+
}
1604+
req.ResourceManagerTags = rmTags
1605+
}
1606+
1607+
updateF := func() error {
1608+
clusterNodePoolsUpdateCall := config.NewContainerClient(userAgent).Projects.Locations.Clusters.NodePools.Update(nodePoolInfo.fullyQualifiedName(name), req)
1609+
if config.UserProjectOverride {
1610+
clusterNodePoolsUpdateCall.Header().Add("X-Goog-User-Project", nodePoolInfo.project)
1611+
}
1612+
op, err := clusterNodePoolsUpdateCall.Do()
1613+
if err != nil {
1614+
return err
1615+
}
1616+
1617+
// Wait until it's updated
1618+
return ContainerOperationWait(config, op,
1619+
nodePoolInfo.project,
1620+
nodePoolInfo.location,
1621+
"updating GKE node pool resource manager tags", userAgent,
1622+
timeout)
1623+
}
1624+
1625+
if err := retryWhileIncompatibleOperation(timeout, npLockKey, updateF); err != nil {
1626+
return err
1627+
}
1628+
log.Printf("[INFO] Updated resource manager tags for node pool %s", name)
1629+
}
1630+
15891631
if d.HasChange(prefix + "node_config.0.resource_labels") {
15901632
req := &container.UpdateNodePoolRequest{
15911633
Name: name,

0 commit comments

Comments
 (0)