Skip to content

Commit 495ee1b

Browse files
Add support for dataproc cluster resource_manager_tags (#15634) (#11021)
[upstream:c3a208fae52af4fd93dd13a6259b956e7faf189d] Signed-off-by: Modular Magician <[email protected]>
1 parent ef988ee commit 495ee1b

File tree

5 files changed

+136
-5
lines changed

5 files changed

+136
-5
lines changed

.changelog/15634.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
dataproc: added `resource_manager_tags` to `google_dataproc_cluster` resource
3+
```

google-beta/services/dataproc/resource_dataproc_cluster.go

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ var (
7777
"cluster_config.0.gce_cluster_config.0.internal_ip_only",
7878
"cluster_config.0.gce_cluster_config.0.shielded_instance_config",
7979
"cluster_config.0.gce_cluster_config.0.metadata",
80+
"cluster_config.0.gce_cluster_config.0.resource_manager_tags",
8081
"cluster_config.0.gce_cluster_config.0.reservation_affinity",
8182
"cluster_config.0.gce_cluster_config.0.node_group_affinity",
8283
"cluster_config.0.gce_cluster_config.0.confidential_instance_config",
@@ -697,6 +698,16 @@ func ResourceDataprocCluster() *schema.Resource {
697698
Description: `A map of the Compute Engine metadata entries to add to all instances`,
698699
},
699700

701+
"resource_manager_tags": {
702+
Type: schema.TypeMap,
703+
Optional: true,
704+
Computed: true,
705+
AtLeastOneOf: gceClusterConfigKeys,
706+
Elem: &schema.Schema{Type: schema.TypeString},
707+
ForceNew: true,
708+
Description: `A map of resource manager tags to add to all instances. Keys must be in the format tagKeys/{tag_key_id} and values in the format tagValues/{tag_value_id}.`,
709+
},
710+
700711
"shielded_instance_config": {
701712
Type: schema.TypeList,
702713
Optional: true,
@@ -2293,6 +2304,9 @@ func expandGceClusterConfig(d *schema.ResourceData, config *transport_tpg.Config
22932304
if v, ok := cfg["metadata"]; ok {
22942305
conf.Metadata = tpgresource.ConvertStringMap(v.(map[string]interface{}))
22952306
}
2307+
if v, ok := cfg["resource_manager_tags"]; ok {
2308+
conf.ResourceManagerTags = tpgresource.ConvertStringMap(v.(map[string]interface{}))
2309+
}
22962310
if v, ok := d.GetOk("cluster_config.0.gce_cluster_config.0.shielded_instance_config"); ok {
22972311
cfgSic := v.([]interface{})[0].(map[string]interface{})
22982312
conf.ShieldedInstanceConfig = &dataproc.ShieldedInstanceConfig{}
@@ -3274,11 +3288,12 @@ func flattenGceClusterConfig(d *schema.ResourceData, gcc *dataproc.GceClusterCon
32743288
}
32753289

32763290
gceConfig := map[string]interface{}{
3277-
"tags": schema.NewSet(schema.HashString, tpgresource.ConvertStringArrToInterface(gcc.Tags)),
3278-
"service_account": gcc.ServiceAccount,
3279-
"zone": tpgresource.GetResourceNameFromSelfLink(gcc.ZoneUri),
3280-
"internal_ip_only": gcc.InternalIpOnly,
3281-
"metadata": gcc.Metadata,
3291+
"tags": schema.NewSet(schema.HashString, tpgresource.ConvertStringArrToInterface(gcc.Tags)),
3292+
"service_account": gcc.ServiceAccount,
3293+
"zone": tpgresource.GetResourceNameFromSelfLink(gcc.ZoneUri),
3294+
"internal_ip_only": gcc.InternalIpOnly,
3295+
"metadata": gcc.Metadata,
3296+
"resource_manager_tags": gcc.ResourceManagerTags,
32823297
}
32833298

32843299
if gcc.NetworkUri != "" {

google-beta/services/dataproc/resource_dataproc_cluster_meta.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ fields:
3232
- field: 'cluster_config.gce_cluster_config.reservation_affinity.consume_reservation_type'
3333
- field: 'cluster_config.gce_cluster_config.reservation_affinity.key'
3434
- field: 'cluster_config.gce_cluster_config.reservation_affinity.values'
35+
- field: 'cluster_config.gce_cluster_config.resource_manager_tags'
3536
- field: 'cluster_config.gce_cluster_config.service_account'
3637
- field: 'cluster_config.gce_cluster_config.service_account_scopes'
3738
- field: 'cluster_config.gce_cluster_config.shielded_instance_config.enable_integrity_monitoring'

google-beta/services/dataproc/resource_dataproc_cluster_test.go

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,41 @@ func TestAccDataprocCluster_withMetadataAndTags(t *testing.T) {
368368
})
369369
}
370370

371+
func TestAccDataprocCluster_withResourceManagerTags(t *testing.T) {
372+
t.Parallel()
373+
374+
var cluster dataproc.Cluster
375+
pid := envvar.GetTestProjectFromEnv()
376+
projectNumber := envvar.GetTestProjectNumberFromEnv()
377+
rnd := acctest.RandString(t, 10)
378+
networkName := acctest.BootstrapSharedTestNetwork(t, "dataproc-cluster")
379+
subnetworkName := acctest.BootstrapSubnet(t, "dataproc-cluster", networkName)
380+
acctest.BootstrapFirewallForDataprocSharedNetwork(t, "dataproc-cluster", networkName)
381+
// TODO: remove this IAM binding once tagUser permissions are present in Dataproc Service Agent role.
382+
acctest.BootstrapIamMembers(t, []acctest.IamMember{
383+
{
384+
Member: fmt.Sprintf("serviceAccount:service-%[email protected]", projectNumber),
385+
Role: "roles/resourcemanager.tagUser",
386+
},
387+
})
388+
389+
acctest.VcrTest(t, resource.TestCase{
390+
PreCheck: func() { acctest.AccTestPreCheck(t) },
391+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
392+
CheckDestroy: testAccCheckDataprocClusterDestroy(t),
393+
Steps: []resource.TestStep{
394+
{
395+
Config: testAccDataprocCluster_withResourceManagerTags(pid, rnd, subnetworkName),
396+
Check: resource.ComposeTestCheckFunc(
397+
testAccCheckDataprocClusterExists(t, "google_dataproc_cluster.basic", &cluster),
398+
399+
testAccCheckDataprocClusterResourceManagerTags(t, "google_dataproc_cluster.basic"),
400+
),
401+
},
402+
},
403+
})
404+
}
405+
371406
func TestAccDataprocCluster_withMinNumInstances(t *testing.T) {
372407
t.Parallel()
373408

@@ -1538,6 +1573,40 @@ func testAccCheckDataprocClusterExists(t *testing.T, n string, cluster *dataproc
15381573
}
15391574
}
15401575

1576+
func testAccCheckDataprocClusterResourceManagerTags(t *testing.T, n string) resource.TestCheckFunc {
1577+
return func(s *terraform.State) error {
1578+
rs, ok := s.RootModule().Resources[n]
1579+
if !ok {
1580+
return fmt.Errorf("Terraform resource Not found: %s", n)
1581+
}
1582+
1583+
// Find the tags and validate key/value formats.
1584+
tagPrefix := "cluster_config.0.gce_cluster_config.0.resource_manager_tags."
1585+
keyRegex := regexp.MustCompile(`^tagKeys/`)
1586+
valueRegex := regexp.MustCompile(`^tagValues/`)
1587+
1588+
foundTags := 0
1589+
for attr, value := range rs.Primary.Attributes {
1590+
if strings.HasPrefix(attr, tagPrefix) && !strings.HasSuffix(attr, ".#") && !strings.HasSuffix(attr, ".%") {
1591+
foundTags++
1592+
key := strings.TrimPrefix(attr, tagPrefix)
1593+
1594+
if !keyRegex.MatchString(key) {
1595+
return fmt.Errorf("resource manager tag key %q does not have expected prefix 'tagKeys/'", key)
1596+
}
1597+
if !valueRegex.MatchString(value) {
1598+
return fmt.Errorf("resource manager tag value %q for key %q does not have expected prefix 'tagValues/'", value, key)
1599+
}
1600+
}
1601+
}
1602+
1603+
if foundTags != 2 {
1604+
return fmt.Errorf("expected to find 2 resource manager tags, but found %d", foundTags)
1605+
}
1606+
1607+
return nil
1608+
}
1609+
}
15411610
func testAccCheckDataproc_missingZoneGlobalRegion1(rnd string) string {
15421611
return fmt.Sprintf(`
15431612
resource "google_dataproc_cluster" "basic" {
@@ -1822,6 +1891,45 @@ resource "google_dataproc_cluster" "basic" {
18221891
`, rnd, subnetworkName)
18231892
}
18241893

1894+
func testAccDataprocCluster_withResourceManagerTags(pid, rnd, subnetworkName string) string {
1895+
return fmt.Sprintf(`
1896+
resource "google_tags_tag_key" "tag_key" {
1897+
parent = "projects/%s"
1898+
short_name = "key-%s"
1899+
}
1900+
1901+
resource "google_tags_tag_value" "tag_value" {
1902+
parent = "tagKeys/${google_tags_tag_key.tag_key.name}"
1903+
short_name = "val-%s"
1904+
}
1905+
1906+
resource "google_tags_tag_key" "tag_key_2" {
1907+
parent = "projects/%s"
1908+
short_name = "key-2-%s"
1909+
}
1910+
1911+
resource "google_tags_tag_value" "tag_value_2" {
1912+
parent = "tagKeys/${google_tags_tag_key.tag_key_2.name}"
1913+
short_name = "val-2-%s"
1914+
}
1915+
1916+
resource "google_dataproc_cluster" "basic" {
1917+
name = "tf-test-dproc-%s"
1918+
region = "us-central1"
1919+
1920+
cluster_config {
1921+
gce_cluster_config {
1922+
subnetwork = "%s"
1923+
resource_manager_tags = {
1924+
"${google_tags_tag_key.tag_key.id}" = "${google_tags_tag_value.tag_value.id}",
1925+
"${google_tags_tag_key.tag_key_2.id}" = "${google_tags_tag_value.tag_value_2.id}"
1926+
}
1927+
}
1928+
}
1929+
}
1930+
`, pid, rnd, rnd, pid, rnd, rnd, rnd, subnetworkName)
1931+
}
1932+
18251933
func testAccDataprocCluster_withMinNumInstances(rnd, subnetworkName string) string {
18261934
return fmt.Sprintf(`
18271935
resource "google_dataproc_cluster" "with_min_num_instances" {

website/docs/r/dataproc_cluster.html.markdown

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,10 @@ resource "google_dataproc_cluster" "accelerated_cluster" {
458458
* `metadata` - (Optional) A map of the Compute Engine metadata entries to add to all instances
459459
(see [Project and instance metadata](https://cloud.google.com/compute/docs/storing-retrieving-metadata#project_and_instance_metadata)).
460460

461+
* `resource_manager_tags` - (Optional) A map of resource manager tags to add to all instances.
462+
Keys must be in the format `tagKeys/{tag_key_id}` and values in the format `tagValues/{tag_value_id}`
463+
(see [Secure tags](https://cloud.google.com/dataproc/docs/guides/use-secure-tags)).
464+
461465
* `reservation_affinity` - (Optional) Reservation Affinity for consuming zonal reservation.
462466
* `consume_reservation_type` - (Optional) Corresponds to the type of reservation consumption.
463467
* `key` - (Optional) Corresponds to the label key of reservation resource.

0 commit comments

Comments
 (0)