From b5d11fcc8fc761a01b09b6f81897ebbaa7a25431 Mon Sep 17 00:00:00 2001 From: Philbrook Date: Tue, 17 May 2022 12:15:15 -0400 Subject: [PATCH 1/5] Created branch tag-data-sources from main From 29f40cb38fe4083ff4b96497cfeed6aaaaceb15e Mon Sep 17 00:00:00 2001 From: Philbrook Date: Tue, 17 May 2022 12:15:54 -0400 Subject: [PATCH 2/5] initial commit of data sources for IAM tags --- .../data_sources/data_source_tags_tag_key.go | 106 ++++++++++++++++++ .../data_source_tags_tag_value.go | 106 ++++++++++++++++++ .../terraform/utils/provider.go.erb | 2 + 3 files changed, 214 insertions(+) create mode 100644 mmv1/third_party/terraform/data_sources/data_source_tags_tag_key.go create mode 100644 mmv1/third_party/terraform/data_sources/data_source_tags_tag_value.go diff --git a/mmv1/third_party/terraform/data_sources/data_source_tags_tag_key.go b/mmv1/third_party/terraform/data_sources/data_source_tags_tag_key.go new file mode 100644 index 000000000000..d278dd3f0fde --- /dev/null +++ b/mmv1/third_party/terraform/data_sources/data_source_tags_tag_key.go @@ -0,0 +1,106 @@ +package google + +import ( + "errors" + "fmt" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + resourceManagerV3 "google.golang.org/api/cloudresourcemanager/v3" +) + +func dataSourceGoogleTagsTagKey() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGoogleTagsTagKeyRead, + + Schema: map[string]*schema.Schema{ + "parent": { + Type: schema.TypeString, + Required: true, + }, + "short_name": { + Type: schema.TypeString, + Required: true, + }, + "namespaced_name": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceGoogleTagsTagKeyRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + var tagKeyMatch *resourceManagerV3.TagKey + parent := d.Get("parent").(string) + shortName := d.Get("short_name").(string) + token := "" + + for paginate := true; paginate; { + resp, err := config.NewResourceManagerV3Client(userAgent).TagKeys.List().Parent(parent).PageSize(300).PageToken(token).Do() + if err != nil { + return fmt.Errorf("error reading tag key list: %s", err) + } + + for _, tagKey := range resp.TagKeys { + if tagKey.ShortName == shortName { + if tagKeyMatch != nil { + return errors.New("more than one matching tag key found") + } + tagKeyMatch = tagKey + } + } + token = resp.NextPageToken + paginate = token != "" + } + + if tagKeyMatch == nil { + return fmt.Errorf("tag key not found: %s/%s", parent, shortName) + } + + d.SetId(tagKeyMatch.Name) + nameParts := strings.Split(tagKeyMatch.Name, "/") + if err := d.Set("name", nameParts[1]); err != nil { + return fmt.Errorf("Error setting tag key name: %s", err) + } + if err := d.Set("namespaced_name", tagKeyMatch.NamespacedName); err != nil { + return fmt.Errorf("Error setting tag key namespaced_name: %s", err) + } + if err := d.Set("create_time", tagKeyMatch.CreateTime); err != nil { + return fmt.Errorf("Error setting tag key create_time: %s", err) + } + if err := d.Set("update_time", tagKeyMatch.UpdateTime); err != nil { + return fmt.Errorf("Error setting tag key update_time: %s", err) + } + if err := d.Set("description", tagKeyMatch.Description); err != nil { + return fmt.Errorf("Error setting tag key description: %s", err) + } + + return nil +} diff --git a/mmv1/third_party/terraform/data_sources/data_source_tags_tag_value.go b/mmv1/third_party/terraform/data_sources/data_source_tags_tag_value.go new file mode 100644 index 000000000000..5e6503c88636 --- /dev/null +++ b/mmv1/third_party/terraform/data_sources/data_source_tags_tag_value.go @@ -0,0 +1,106 @@ +package google + +import ( + "errors" + "fmt" + "strings" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + resourceManagerV3 "google.golang.org/api/cloudresourcemanager/v3" +) + +func dataSourceGoogleTagsTagValue() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGoogleTagsTagValueRead, + + Schema: map[string]*schema.Schema{ + "parent": { + Type: schema.TypeString, + Required: true, + }, + "short_name": { + Type: schema.TypeString, + Required: true, + }, + "namespaced_name": { + Type: schema.TypeString, + Computed: true, + }, + "description": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Computed: true, + }, + "id": { + Type: schema.TypeString, + Computed: true, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceGoogleTagsTagValueRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + var tagValueMatch *resourceManagerV3.TagValue + parent := d.Get("parent").(string) + shortName := d.Get("short_name").(string) + token := "" + + for paginate := true; paginate; { + resp, err := config.NewResourceManagerV3Client(userAgent).TagValues.List().Parent(parent).PageSize(300).PageToken(token).Do() + if err != nil { + return fmt.Errorf("error reading tag value list: %s", err) + } + + for _, tagValue := range resp.TagValues { + if tagValue.ShortName == shortName { + if tagValueMatch != nil { + return errors.New("more than one matching tag value found") + } + tagValueMatch = tagValue + } + } + token = resp.NextPageToken + paginate = token != "" + } + + if tagValueMatch == nil { + return fmt.Errorf("tag value not found: %s/%s", parent, shortName) + } + + d.SetId(tagValueMatch.Name) + nameParts := strings.Split(tagValueMatch.Name, "/") + if err := d.Set("name", nameParts[1]); err != nil { + return fmt.Errorf("Error setting tag value name: %s", err) + } + if err := d.Set("namespaced_name", tagValueMatch.NamespacedName); err != nil { + return fmt.Errorf("Error setting tag value namespaced_name: %s", err) + } + if err := d.Set("create_time", tagValueMatch.CreateTime); err != nil { + return fmt.Errorf("Error setting tag value create_time: %s", err) + } + if err := d.Set("update_time", tagValueMatch.UpdateTime); err != nil { + return fmt.Errorf("Error setting tag value update_time: %s", err) + } + if err := d.Set("description", tagValueMatch.Description); err != nil { + return fmt.Errorf("Error setting tag value description: %s", err) + } + + return nil +} diff --git a/mmv1/third_party/terraform/utils/provider.go.erb b/mmv1/third_party/terraform/utils/provider.go.erb index 235a6be224fe..967a98da98a8 100644 --- a/mmv1/third_party/terraform/utils/provider.go.erb +++ b/mmv1/third_party/terraform/utils/provider.go.erb @@ -324,6 +324,8 @@ func Provider() *schema.Provider { "google_storage_object_signed_url": dataSourceGoogleSignedUrl(), "google_storage_project_service_account": dataSourceGoogleStorageProjectServiceAccount(), "google_storage_transfer_project_service_account": dataSourceGoogleStorageTransferProjectServiceAccount(), + "google_tags_tag_key": dataSourceGoogleTagsTagKey(), + "google_tags_tag_value": dataSourceGoogleTagsTagValue(), "google_tpu_tensorflow_versions": dataSourceTpuTensorflowVersions(), "google_redis_instance": dataSourceGoogleRedisInstance(), // ####### END datasources ########### From 8d05ac927124216ce2fb4d8287dcb952fffd3792 Mon Sep 17 00:00:00 2001 From: Philbrook Date: Tue, 17 May 2022 14:24:33 -0400 Subject: [PATCH 3/5] Tests for tags data sources --- .../tests/data_source_tags_tag_key_test.go | 93 ++++++++++++++++ .../tests/data_source_tags_tag_value_test.go | 100 ++++++++++++++++++ 2 files changed, 193 insertions(+) create mode 100644 mmv1/third_party/terraform/tests/data_source_tags_tag_key_test.go create mode 100644 mmv1/third_party/terraform/tests/data_source_tags_tag_value_test.go diff --git a/mmv1/third_party/terraform/tests/data_source_tags_tag_key_test.go b/mmv1/third_party/terraform/tests/data_source_tags_tag_key_test.go new file mode 100644 index 000000000000..034b4ff0b866 --- /dev/null +++ b/mmv1/third_party/terraform/tests/data_source_tags_tag_key_test.go @@ -0,0 +1,93 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccDataSourceGoogleTagsTagKey_default(t *testing.T) { + org := getTestOrgFromEnv(t) + + parent := fmt.Sprintf("organizations/%s", org) + shortName := "tf-test-" + randString(t, 10) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceGoogleTagsTagKeyConfig(parent, shortName), + Check: resource.ComposeTestCheckFunc( + testAccDataSourceGoogleTagsTagKeyCheck("data.google_tags_tag_key.my_tag_key", "google_tags_tag_key.foobar"), + ), + }, + }, + }) +} + +func TestAccDataSourceGoogleTagsTagKey_dot(t *testing.T) { + org := getTestOrgFromEnv(t) + + parent := fmt.Sprintf("organizations/%s", org) + shortName := "terraform.test." + randString(t, 10) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceGoogleTagsTagKeyConfig(parent, shortName), + Check: resource.ComposeTestCheckFunc( + testAccDataSourceGoogleTagsTagKeyCheck("data.google_tags_tag_key.my_tag_key", "google_tags_tag_key.foobar"), + ), + }, + }, + }) +} + +func testAccDataSourceGoogleTagsTagKeyCheck(data_source_name string, resource_name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + ds, ok := s.RootModule().Resources[data_source_name] + if !ok { + return fmt.Errorf("root module has no resource called %s", data_source_name) + } + + rs, ok := s.RootModule().Resources[resource_name] + if !ok { + return fmt.Errorf("can't find %s in state", resource_name) + } + + ds_attr := ds.Primary.Attributes + rs_attr := rs.Primary.Attributes + tag_key_attrs_to_test := []string{"parent", "short_name", "name", "namespaced_name", "create_time", "update_time", "description"} + + for _, attr_to_check := range tag_key_attrs_to_test { + if ds_attr[attr_to_check] != rs_attr[attr_to_check] { + return fmt.Errorf( + "%s is %s; want %s", + attr_to_check, + ds_attr[attr_to_check], + rs_attr[attr_to_check], + ) + } + } + return nil + } +} + +func testAccDataSourceGoogleTagsTagKeyConfig(parent string, shortName string) string { + return fmt.Sprintf(` +resource "google_tags_tag_key" "foobar" { + parent = "%s" + short_name = "%s" +} + +data "google_tags_tag_key" "my_tag_key" { + parent = google_tags_tag_key.foobar.parent + short_name = google_tags_tag_key.foobar.short_name +} +`, parent, shortName) +} diff --git a/mmv1/third_party/terraform/tests/data_source_tags_tag_value_test.go b/mmv1/third_party/terraform/tests/data_source_tags_tag_value_test.go new file mode 100644 index 000000000000..5a10cbca30bd --- /dev/null +++ b/mmv1/third_party/terraform/tests/data_source_tags_tag_value_test.go @@ -0,0 +1,100 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" +) + +func TestAccDataSourceGoogleTagsTagValue_default(t *testing.T) { + org := getTestOrgFromEnv(t) + + parent := fmt.Sprintf("organizations/%s", org) + keyShortName := "tf-testkey-" + randString(t, 10) + shortName := "tf-test-" + randString(t, 10) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceGoogleTagsTagValueConfig(parent, keyShortName, shortName), + Check: resource.ComposeTestCheckFunc( + testAccDataSourceGoogleTagsTagValueCheck("data.google_tags_tag_value.my_tag_value", "google_tags_tag_value.norfqux"), + ), + }, + }, + }) +} + +func TestAccDataSourceGoogleTagsTagValue_dot(t *testing.T) { + org := getTestOrgFromEnv(t) + + parent := fmt.Sprintf("organizations/%s", org) + keyShortName := "tf-testkey-" + randString(t, 10) + shortName := "terraform.test." + randString(t, 10) + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccDataSourceGoogleTagsTagValueConfig(parent, keyShortName, shortName), + Check: resource.ComposeTestCheckFunc( + testAccDataSourceGoogleTagsTagValueCheck("data.google_tags_tag_value.my_tag_value", "google_tags_tag_value.norfqux"), + ), + }, + }, + }) +} + +func testAccDataSourceGoogleTagsTagValueCheck(data_source_name string, resource_name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + ds, ok := s.RootModule().Resources[data_source_name] + if !ok { + return fmt.Errorf("root module has no resource called %s", data_source_name) + } + + rs, ok := s.RootModule().Resources[resource_name] + if !ok { + return fmt.Errorf("can't find %s in state", resource_name) + } + + ds_attr := ds.Primary.Attributes + rs_attr := rs.Primary.Attributes + tag_value_attrs_to_test := []string{"parent", "short_name", "name", "namespaced_name", "create_time", "update_time", "description"} + + for _, attr_to_check := range tag_value_attrs_to_test { + if ds_attr[attr_to_check] != rs_attr[attr_to_check] { + return fmt.Errorf( + "%s is %s; want %s", + attr_to_check, + ds_attr[attr_to_check], + rs_attr[attr_to_check], + ) + } + } + return nil + } +} + +func testAccDataSourceGoogleTagsTagValueConfig(parent string, keyShortName string, shortName string) string { + return fmt.Sprintf(` +resource "google_tags_tag_key" "foobar" { + parent = "%s" + short_name = "%s" +} + +resource "google_tags_tag_value" "norfqux" { + parent = google_tags_tag_key.foobar.id + short_name = "%s" +} + +data "google_tags_tag_value" "my_tag_value" { + parent = google_tags_tag_value.norfqux.parent + short_name = google_tags_tag_value.norfqux.short_name +} +`, parent, keyShortName, shortName) +} From 17910ba517c59334410f71dcde3c81800a720380 Mon Sep 17 00:00:00 2001 From: Philbrook Date: Tue, 17 May 2022 15:03:08 -0400 Subject: [PATCH 4/5] Added documentation --- .../website/docs/d/tags_tag_key.html.markdown | 49 +++++++++++++++++++ .../docs/d/tags_tag_value.html.markdown | 49 +++++++++++++++++++ 2 files changed, 98 insertions(+) create mode 100644 mmv1/third_party/terraform/website/docs/d/tags_tag_key.html.markdown create mode 100644 mmv1/third_party/terraform/website/docs/d/tags_tag_value.html.markdown diff --git a/mmv1/third_party/terraform/website/docs/d/tags_tag_key.html.markdown b/mmv1/third_party/terraform/website/docs/d/tags_tag_key.html.markdown new file mode 100644 index 000000000000..8c0e1be6dd24 --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/d/tags_tag_key.html.markdown @@ -0,0 +1,49 @@ +--- +subcategory: "Tags" +layout: "google" +page_title: "Google: google_tags_tag_key" +sidebar_current: "docs-google-datasource-tags-tag-key" +description: |- + Get a tag key within a GCP organization. +--- + +# google\_tags\_tag\_key + +Get a tag key within a GCP org by `parent` and `short_name`. + +## Example Usage + +```tf +data "google_tags_tag_key" "environment_tag_key"{ + parent = "organizations/12345" + short_name = "environment" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `short_name` - (Required) The tag key's short_name. + +* `parent` - (Required) The resource name of the parent organization in format `organizations/{org_id}`. + +## Attributes Reference + +In addition to the arguments listed above, the following attributes are exported: + +* `id` - an identifier for the resource with format `tagKeys/{{name}}` + +* `name` - + The generated numeric id for the TagKey. + +* `namespaced_name` - + Namespaced name of the TagKey. + +* `create_time` - + Creation time. + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". + +* `update_time` - + Update time. + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". diff --git a/mmv1/third_party/terraform/website/docs/d/tags_tag_value.html.markdown b/mmv1/third_party/terraform/website/docs/d/tags_tag_value.html.markdown new file mode 100644 index 000000000000..4d0f7374b240 --- /dev/null +++ b/mmv1/third_party/terraform/website/docs/d/tags_tag_value.html.markdown @@ -0,0 +1,49 @@ +--- +subcategory: "Tags" +layout: "google" +page_title: "Google: google_tags_tag_value" +sidebar_current: "docs-google-datasource-tags-tag-value" +description: |- + Get a tag value from the parent key and short_name. +--- + +# google\_tags\_tag\_value + +Get a tag value by `parent` key and `short_name`. + +## Example Usage + +```tf +data "google_tags_tag_value" "environment_prod_tag_value"{ + parent = "tagKeys/56789" + short_name = "production" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `short_name` - (Required) The tag value's short_name. + +* `parent` - (Required) The resource name of the parent tagKey in format `tagKey/{name}`. + +## Attributes Reference + +In addition to the arguments listed above, the following attributes are exported: + +* `id` - an identifier for the resource with format `tagValues/{{name}}` + +* `name` - + The generated numeric id for the TagValue. + +* `namespaced_name` - + Namespaced name of the TagValue. + +* `create_time` - + Creation time. + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". + +* `update_time` - + Update time. + A timestamp in RFC3339 UTC "Zulu" format, with nanosecond resolution and up to nine fractional digits. Examples: "2014-10-02T15:01:23Z" and "2014-10-02T15:01:23.045123456Z". From f072664a1f8e2472b8f7317660c657e60e6c5937 Mon Sep 17 00:00:00 2001 From: Philbrook Date: Fri, 20 May 2022 05:38:37 -0400 Subject: [PATCH 5/5] Making error messages better --- .../terraform/data_sources/data_source_tags_tag_key.go | 2 +- .../terraform/data_sources/data_source_tags_tag_value.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/mmv1/third_party/terraform/data_sources/data_source_tags_tag_key.go b/mmv1/third_party/terraform/data_sources/data_source_tags_tag_key.go index d278dd3f0fde..2282e26803c4 100644 --- a/mmv1/third_party/terraform/data_sources/data_source_tags_tag_key.go +++ b/mmv1/third_party/terraform/data_sources/data_source_tags_tag_key.go @@ -81,7 +81,7 @@ func dataSourceGoogleTagsTagKeyRead(d *schema.ResourceData, meta interface{}) er } if tagKeyMatch == nil { - return fmt.Errorf("tag key not found: %s/%s", parent, shortName) + return fmt.Errorf("tag key with short_name %s not found under parent %s", shortName, parent) } d.SetId(tagKeyMatch.Name) diff --git a/mmv1/third_party/terraform/data_sources/data_source_tags_tag_value.go b/mmv1/third_party/terraform/data_sources/data_source_tags_tag_value.go index 5e6503c88636..7c14fdd53792 100644 --- a/mmv1/third_party/terraform/data_sources/data_source_tags_tag_value.go +++ b/mmv1/third_party/terraform/data_sources/data_source_tags_tag_value.go @@ -81,7 +81,7 @@ func dataSourceGoogleTagsTagValueRead(d *schema.ResourceData, meta interface{}) } if tagValueMatch == nil { - return fmt.Errorf("tag value not found: %s/%s", parent, shortName) + return fmt.Errorf("tag value with short_name %s not found under parent %s", shortName, parent) } d.SetId(tagValueMatch.Name)