Skip to content

Commit 707ee8f

Browse files
Support for Tags in google_dataproc_metastore_service resource (#14620)
1 parent cb2e8a2 commit 707ee8f

File tree

4 files changed

+357
-2
lines changed

4 files changed

+357
-2
lines changed

mmv1/products/metastore/Federation.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,3 +154,11 @@ properties:
154154
- 'METASTORE_TYPE_UNSPECIFIED'
155155
- 'DATAPROC_METASTORE'
156156
- 'BIGQUERY'
157+
- name: 'tags'
158+
type: KeyValuePairs
159+
description: |
160+
A map of resource manager tags.
161+
Resource manager tag keys and values have the same definition as resource manager tags.
162+
Keys must be in the format tagKeys/{tag_key_id}, and values are in the format tagValues/{tag_value_id}.
163+
immutable: true
164+
ignore_read: true

mmv1/products/metastore/Service.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,3 +521,11 @@ properties:
521521
enum_values:
522522
- 'LEGACY'
523523
- 'JSON'
524+
- name: 'tags'
525+
type: KeyValuePairs
526+
description: |
527+
A map of resource manager tags.
528+
Resource manager tag keys and values have the same definition as resource manager tags.
529+
Keys must be in the format tagKeys/{tag_key_id}, and values are in the format tagValues/{tag_value_id}.
530+
immutable: true
531+
ignore_read: true

mmv1/third_party/terraform/services/dataprocmetastore/resource_dataproc_metastore_federation_test.go

Lines changed: 170 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,16 @@ package dataprocmetastore_test
44

55
import (
66
"fmt"
7-
"github.com/hashicorp/terraform-provider-google/google/acctest"
7+
"net/url"
88
"regexp"
99
"testing"
1010

1111
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
12+
"github.com/hashicorp/terraform-plugin-testing/terraform"
13+
"github.com/hashicorp/terraform-provider-google/google/acctest"
14+
"github.com/hashicorp/terraform-provider-google/google/envvar"
15+
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"
16+
"strings"
1217
)
1318

1419
func TestAccMetastoreFederation_deletionprotection(t *testing.T) {
@@ -46,6 +51,37 @@ func TestAccMetastoreFederation_deletionprotection(t *testing.T) {
4651
})
4752
}
4853

54+
func TestAccMetastoreFederation_tags(t *testing.T) {
55+
t.Parallel()
56+
tagKey := acctest.BootstrapSharedTestOrganizationTagKey(t, "metastore-fed-tagkey", map[string]interface{}{})
57+
context := map[string]interface{}{
58+
"random_suffix": acctest.RandString(t, 10),
59+
"org": envvar.GetTestOrgFromEnv(t),
60+
"tagKey": tagKey,
61+
"tagValue": acctest.BootstrapSharedTestOrganizationTagValue(t, "metastore-fed-tagvalue", tagKey),
62+
}
63+
acctest.VcrTest(t, resource.TestCase{
64+
PreCheck: func() { acctest.AccTestPreCheck(t) },
65+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
66+
CheckDestroy: testAccCheckDataprocMetastoreFederationDestroyProducer(t),
67+
Steps: []resource.TestStep{
68+
{
69+
Config: testAccMetastoreFederationTags(context),
70+
Check: resource.ComposeTestCheckFunc(
71+
resource.TestCheckResourceAttrSet("google_dataproc_metastore_federation.default", "tags.%"),
72+
testAccCheckMetastoreFederationHasTagBindings(t),
73+
),
74+
},
75+
{
76+
ResourceName: "google_dataproc_metastore_federation.default",
77+
ImportState: true,
78+
ImportStateVerify: true,
79+
ImportStateVerifyIgnore: []string{"federation_id", "location", "tags"},
80+
},
81+
},
82+
})
83+
}
84+
4985
func testAccMetastoreFederationDeletionProtection(name string, location string) string {
5086

5187
return fmt.Sprintf(`
@@ -97,3 +133,136 @@ func testAccMetastoreFederationDeletionProtectionFalse(name string, location str
97133
}
98134
`, name, name, location)
99135
}
136+
137+
func testAccCheckMetastoreFederationHasTagBindings(t *testing.T) func(s *terraform.State) error {
138+
return func(s *terraform.State) error {
139+
for name, rs := range s.RootModule().Resources {
140+
if rs.Type != "google_dataproc_metastore_federation" {
141+
continue
142+
}
143+
if strings.HasPrefix(name, "data.") {
144+
continue
145+
}
146+
147+
config := acctest.GoogleProviderConfig(t)
148+
149+
var configuredTagValueNamespacedName string
150+
var tagKeyNamespacedName, tagValueShortName string
151+
for key, val := range rs.Primary.Attributes {
152+
if strings.HasPrefix(key, "tags.") && key != "tags.%" {
153+
tagKeyNamespacedName = strings.TrimPrefix(key, "tags.")
154+
tagValueShortName = val
155+
if tagValueShortName != "" {
156+
configuredTagValueNamespacedName = fmt.Sprintf("%s/%s", tagKeyNamespacedName, tagValueShortName)
157+
break
158+
}
159+
}
160+
}
161+
162+
if configuredTagValueNamespacedName == "" {
163+
return fmt.Errorf("could not find a configured tag value in the state for resource %s", rs.Primary.ID)
164+
}
165+
166+
if strings.Contains(configuredTagValueNamespacedName, "%{") {
167+
return fmt.Errorf("tag namespaced name contains unsubstituted variables: %q. Ensure the context map in the test step is populated", configuredTagValueNamespacedName)
168+
}
169+
170+
safeNamespacedName := url.QueryEscape(configuredTagValueNamespacedName)
171+
describeTagValueURL := fmt.Sprintf("https://cloudresourcemanager.googleapis.com/v3/tagValues/namespaced?name=%s", safeNamespacedName)
172+
173+
respDescribe, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
174+
Config: config,
175+
Method: "GET",
176+
RawURL: describeTagValueURL,
177+
UserAgent: config.UserAgent,
178+
})
179+
180+
if err != nil {
181+
return fmt.Errorf("error describing tag value using namespaced name %q: %v", configuredTagValueNamespacedName, err)
182+
}
183+
184+
fullTagValueName, ok := respDescribe["name"].(string)
185+
if !ok || fullTagValueName == "" {
186+
return fmt.Errorf("tag value details (name) not found in response for namespaced name: %q, response: %v", configuredTagValueNamespacedName, respDescribe)
187+
}
188+
189+
parts := strings.Split(rs.Primary.ID, "/")
190+
if len(parts) != 6 {
191+
return fmt.Errorf("invalid resource ID format: %s", rs.Primary.ID)
192+
}
193+
project := parts[1]
194+
location := parts[3]
195+
federation_id := parts[5]
196+
197+
parentURL := fmt.Sprintf("//metastore.googleapis.com/projects/%s/locations/%s/federations/%s", project, location, federation_id)
198+
listBindingsURL := fmt.Sprintf("https://%s-cloudresourcemanager.googleapis.com/v3/tagBindings?parent=%s", location, url.QueryEscape(parentURL))
199+
200+
resp, err := transport_tpg.SendRequest(transport_tpg.SendRequestOptions{
201+
Config: config,
202+
Method: "GET",
203+
RawURL: listBindingsURL,
204+
UserAgent: config.UserAgent,
205+
})
206+
207+
if err != nil {
208+
return fmt.Errorf("error calling TagBindings API: %v", err)
209+
}
210+
211+
tagBindingsVal, exists := resp["tagBindings"]
212+
if !exists {
213+
tagBindingsVal = []interface{}{}
214+
}
215+
216+
tagBindings, ok := tagBindingsVal.([]interface{})
217+
if !ok {
218+
return fmt.Errorf("'tagBindings' is not a slice in response for resource %s. Response: %v", rs.Primary.ID, resp)
219+
}
220+
221+
foundMatch := false
222+
for _, binding := range tagBindings {
223+
bindingMap, ok := binding.(map[string]interface{})
224+
if !ok {
225+
continue
226+
}
227+
if bindingMap["tagValue"] == fullTagValueName {
228+
foundMatch = true
229+
break
230+
}
231+
}
232+
233+
if !foundMatch {
234+
return fmt.Errorf("expected tag value %s (from namespaced %q) not found in tag bindings for resource %s. Bindings: %v", fullTagValueName, configuredTagValueNamespacedName, rs.Primary.ID, tagBindings)
235+
}
236+
237+
t.Logf("Successfully found matching tag binding for %s with tagValue %s", rs.Primary.ID, fullTagValueName)
238+
}
239+
240+
return nil
241+
}
242+
}
243+
244+
func testAccMetastoreFederationTags(context map[string]interface{}) string {
245+
return acctest.Nprintf(`
246+
resource "google_dataproc_metastore_service" "backend" {
247+
service_id = "tf-test-service-%{random_suffix}"
248+
location = "us-east1"
249+
tier = "DEVELOPER"
250+
hive_metastore_config {
251+
version = "3.1.2"
252+
endpoint_protocol = "GRPC"
253+
}
254+
}
255+
resource "google_dataproc_metastore_federation" "default" {
256+
federation_id = "tf-test-federation-%{random_suffix}"
257+
location = "us-east1"
258+
version = "3.1.2"
259+
backend_metastores {
260+
name = google_dataproc_metastore_service.backend.id
261+
metastore_type = "DATAPROC_METASTORE"
262+
rank = "1"
263+
}
264+
tags = {
265+
"%{org}/%{tagKey}" = "%{tagValue}"
266+
}
267+
}`, context)
268+
}

0 commit comments

Comments
 (0)