Skip to content

Commit

Permalink
New Datasource for list Tag Keys and Tag Values (#10209)
Browse files Browse the repository at this point in the history
  • Loading branch information
jesse-l authored Apr 5, 2024
1 parent 475f70d commit d37b826
Show file tree
Hide file tree
Showing 7 changed files with 484 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,9 @@ var handwrittenDatasources = map[string]*schema.Resource{
"google_storage_project_service_account": storage.DataSourceGoogleStorageProjectServiceAccount(),
"google_storage_transfer_project_service_account": storagetransfer.DataSourceGoogleStorageTransferProjectServiceAccount(),
"google_tags_tag_key": tags.DataSourceGoogleTagsTagKey(),
"google_tags_tag_keys": tags.DataSourceGoogleTagsTagKeys(),
"google_tags_tag_value": tags.DataSourceGoogleTagsTagValue(),
"google_tags_tag_values": tags.DataSourceGoogleTagsTagValues(),
"google_tpu_tensorflow_versions": tpu.DataSourceTpuTensorflowVersions(),
<% unless version == 'ga' -%>
"google_tpu_v2_runtime_versions": tpuv2.DataSourceTpuV2RuntimeVersions(),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package tags

import (
"fmt"

"github.com/hashicorp/terraform-provider-google/google/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func DataSourceGoogleTagsTagKeys() *schema.Resource {
return &schema.Resource{
Read: dataSourceGoogleTagsTagKeysRead,

Schema: map[string]*schema.Schema{
"parent": {
Type: schema.TypeString,
Required: true,
},
"keys": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: tpgresource.DatasourceSchemaFromResourceSchema(ResourceTagsTagKey().Schema),
},
},
},
}
}

func dataSourceGoogleTagsTagKeysRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*transport_tpg.Config)
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
if err != nil {
return err
}

parent := d.Get("parent").(string)
token := ""

tagKeys := make([]map[string]interface{}, 0)

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 {

mappedData := map[string]interface{}{
"name": tagKey.Name,
"namespaced_name": tagKey.NamespacedName,
"short_name": tagKey.ShortName,
"parent": tagKey.Parent,
"create_time": tagKey.CreateTime,
"update_time": tagKey.UpdateTime,
"description": tagKey.Description,
"purpose": tagKey.Purpose,
"purpose_data": tagKey.PurposeData,
}
tagKeys = append(tagKeys, mappedData)
}
token = resp.NextPageToken
paginate = token != ""
}

d.SetId(parent)
if err := d.Set("keys", tagKeys); err != nil {
return fmt.Errorf("Error setting tag key name: %s", err)
}

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
package tags_test

import (
"fmt"
"regexp"
"strings"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/hashicorp/terraform-provider-google/google/acctest"
"github.com/hashicorp/terraform-provider-google/google/envvar"
)

func TestAccDataSourceGoogleTagsTagKeys_default(t *testing.T) {
org := envvar.GetTestOrgFromEnv(t)

parent := fmt.Sprintf("organizations/%s", org)
shortName := "tf-test-" + acctest.RandString(t, 10)

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
Steps: []resource.TestStep{
{
Config: testAccDataSourceGoogleTagsTagKeysConfig(parent, shortName),
Check: resource.ComposeTestCheckFunc(
testAccDataSourceGoogleTagsTagKeysCheck("data.google_tags_tag_keys.my_tag_keys", "google_tags_tag_key.foobar"),
),
},
},
})
}

func TestAccDataSourceGoogleTagsTagKeys_dot(t *testing.T) {
org := envvar.GetTestOrgFromEnv(t)

parent := fmt.Sprintf("organizations/%s", org)
shortName := "terraform.test." + acctest.RandString(t, 10)

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
Steps: []resource.TestStep{
{
Config: testAccDataSourceGoogleTagsTagKeysConfig(parent, shortName),
Check: resource.ComposeTestCheckFunc(
testAccDataSourceGoogleTagsTagKeysCheck("data.google_tags_tag_keys.my_tag_keys", "google_tags_tag_key.foobar"),
),
},
},
})
}

func testAccDataSourceGoogleTagsTagKeysCheck(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"}
re := regexp.MustCompile("[0-9]+")
index := ""

for k := range ds_attr {
ds_a := fmt.Sprintf("keys.%s.%s", re.FindString(k), tag_key_attrs_to_test[1])
if ds_attr[ds_a] == rs_attr[tag_key_attrs_to_test[1]] {
index = re.FindString(k)
break
}
}

for _, attr_to_check := range tag_key_attrs_to_test {
data := ""
if attr_to_check == "name" {
data = strings.Split(ds_attr[fmt.Sprintf("keys.%s.%s", index, attr_to_check)], "/")[1]
} else {
data = ds_attr[fmt.Sprintf("keys.%s.%s", index, attr_to_check)]
}
if data != rs_attr[attr_to_check] {
return fmt.Errorf(
"%s is %s; want %s",
attr_to_check,
data,
rs_attr[attr_to_check],
)
}
}

return nil
}
}

func testAccDataSourceGoogleTagsTagKeysConfig(parent string, shortName string) string {
return fmt.Sprintf(`
resource "google_tags_tag_key" "foobar" {
parent = "%s"
short_name = "%s"
}
data "google_tags_tag_keys" "my_tag_keys" {
parent = google_tags_tag_key.foobar.parent
}
`, parent, shortName)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package tags

import (
"fmt"

"github.com/hashicorp/terraform-provider-google/google/tpgresource"
transport_tpg "github.com/hashicorp/terraform-provider-google/google/transport"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func DataSourceGoogleTagsTagValues() *schema.Resource {
return &schema.Resource{
Read: dataSourceGoogleTagsTagValuesRead,

Schema: map[string]*schema.Schema{
"parent": {
Type: schema.TypeString,
Required: true,
},
"values": {
Type: schema.TypeList,
Computed: true,
Elem: &schema.Resource{
Schema: tpgresource.DatasourceSchemaFromResourceSchema(ResourceTagsTagValue().Schema),
},
},
},
}
}

func dataSourceGoogleTagsTagValuesRead(d *schema.ResourceData, meta interface{}) error {
config := meta.(*transport_tpg.Config)
userAgent, err := tpgresource.GenerateUserAgentString(d, config.UserAgent)
if err != nil {
return err
}

parent := d.Get("parent").(string)
token := ""

tagValues := make([]map[string]interface{}, 0)

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 {
mappedData := map[string]interface{}{
"name": tagValue.Name,
"namespaced_name": tagValue.NamespacedName,
"short_name": tagValue.ShortName,
"parent": tagValue.Parent,
"create_time": tagValue.CreateTime,
"update_time": tagValue.UpdateTime,
"description": tagValue.Description,
}

tagValues = append(tagValues, mappedData)
}
token = resp.NextPageToken
paginate = token != ""
}

d.SetId(parent)

if err := d.Set("values", tagValues); err != nil {
return fmt.Errorf("Error setting tag values: %s", err)
}

return nil
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package tags_test

import (
"fmt"
"strings"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/hashicorp/terraform-provider-google/google/acctest"
"github.com/hashicorp/terraform-provider-google/google/envvar"
)

func TestAccDataSourceGoogleTagsTagValues_default(t *testing.T) {
org := envvar.GetTestOrgFromEnv(t)

parent := fmt.Sprintf("organizations/%s", org)
keyShortName := "tf-testkey-" + acctest.RandString(t, 10)
shortName := "tf-test-" + acctest.RandString(t, 10)

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
Steps: []resource.TestStep{
{
Config: testAccDataSourceGoogleTagsTagValuesConfig(parent, keyShortName, shortName),
Check: resource.ComposeTestCheckFunc(
testAccDataSourceGoogleTagsTagValuesCheck("data.google_tags_tag_values.my_tag_values", "google_tags_tag_value.norfqux"),
),
},
},
})
}

func TestAccDataSourceGoogleTagsTagValues_dot(t *testing.T) {
org := envvar.GetTestOrgFromEnv(t)

parent := fmt.Sprintf("organizations/%s", org)
keyShortName := "tf-testkey-" + acctest.RandString(t, 10)
shortName := "terraform.test." + acctest.RandString(t, 10)

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
Steps: []resource.TestStep{
{
Config: testAccDataSourceGoogleTagsTagValuesConfig(parent, keyShortName, shortName),
Check: resource.ComposeTestCheckFunc(
testAccDataSourceGoogleTagsTagValuesCheck("data.google_tags_tag_values.my_tag_values", "google_tags_tag_value.norfqux"),
),
},
},
})
}

func testAccDataSourceGoogleTagsTagValuesCheck(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", "name", "namespaced_name", "create_time", "update_time", "description"}

for _, attr_to_check := range tag_value_attrs_to_test {
data := ""
if attr_to_check == "name" {
data = strings.Split(ds_attr[fmt.Sprintf("values.0.%s", attr_to_check)], "/")[1]
} else {
data = ds_attr[fmt.Sprintf("values.0.%s", attr_to_check)]
}
if data != rs_attr[attr_to_check] {
return fmt.Errorf(
"%s is %s; want %s",
attr_to_check,
data,
rs_attr[attr_to_check],
)
}
}

return nil
}
}

func testAccDataSourceGoogleTagsTagValuesConfig(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_values" "my_tag_values" {
parent = google_tags_tag_value.norfqux.parent
}
`, parent, keyShortName, shortName)
}
Loading

0 comments on commit d37b826

Please sign in to comment.