From f9dc4098aced445bde0a871bc0f87e1ed352ff6d Mon Sep 17 00:00:00 2001 From: Mike Laramie Date: Tue, 5 Oct 2021 22:59:56 -0400 Subject: [PATCH 1/4] resourcemanager: adding "folders" data source --- google/data_source_google_folders.go | 153 ++++++++++++++++++++++ google/data_source_google_folders_test.go | 44 +++++++ google/provider.go | 1 + website/docs/d/folders.html.markdown | 51 ++++++++ 4 files changed, 249 insertions(+) create mode 100644 google/data_source_google_folders.go create mode 100644 google/data_source_google_folders_test.go create mode 100644 website/docs/d/folders.html.markdown diff --git a/google/data_source_google_folders.go b/google/data_source_google_folders.go new file mode 100644 index 00000000000..cec3124dec2 --- /dev/null +++ b/google/data_source_google_folders.go @@ -0,0 +1,153 @@ +package google + +import ( + "fmt" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" +) + +func dataSourceGoogleFolders() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGoogleFoldersRead, + Schema: map[string]*schema.Schema{ + "parent_id": { + Type: schema.TypeString, + Required: true, + }, + "folders": { + Type: schema.TypeList, + Computed: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Computed: true, + }, + "parent": { + Type: schema.TypeString, + Computed: true, + }, + "display_name": { + Type: schema.TypeString, + Computed: true, + }, + "state": { + Type: schema.TypeString, + Computed: true, + }, + "create_time": { + Type: schema.TypeString, + Computed: true, + }, + "update_time": { + Type: schema.TypeString, + Computed: true, + }, + "delete_time": { + Type: schema.TypeString, + Computed: true, + }, + "etag": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + }, + } +} + +func dataSourceGoogleFoldersRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + userAgent, err := generateUserAgentString(d, config.userAgent) + if err != nil { + return err + } + + params := make(map[string]string) + folders := make([]map[string]interface{}, 0) + + for { + params["parent"] = d.Get("parent_id").(string) + url := "https://cloudresourcemanager.googleapis.com/v3/folders" + + url, err := addQueryParams(url, params) + if err != nil { + return err + } + + res, err := sendRequest(config, "GET", "", url, userAgent, nil) + if err != nil { + return fmt.Errorf("Error retrieving folders: %s", err) + } + + pageFolders := flattenDataSourceGoogleFoldersList(res["folders"]) + folders = append(folders, pageFolders...) + + pToken, ok := res["nextPageToken"] + if ok && pToken != nil && pToken.(string) != "" { + params["pageToken"] = pToken.(string) + } else { + break + } + } + + if err := d.Set("folders", folders); err != nil { + return fmt.Errorf("Error retrieving folders: %s", err) + } + + d.SetId(d.Get("parent_id").(string)) + + return nil +} + +func flattenDataSourceGoogleFoldersList(v interface{}) []map[string]interface{} { + if v == nil { + return make([]map[string]interface{}, 0) + } + + ls := v.([]interface{}) + folders := make([]map[string]interface{}, 0, len(ls)) + for _, raw := range ls { + f := raw.(map[string]interface{}) + + var mState, mName, mCreateTime, mUpdateTime, mDeleteTime, mParent, mDisplayName, mEtag interface{} + if fName, ok := f["name"]; ok { + mName = fName + } + if fState, ok := f["state"]; ok { + mState = fState + } + if fCreateTime, ok := f["createTime"]; ok { + mCreateTime = fCreateTime + } + if fUpdateTime, ok := f["updateTime"]; ok { + mUpdateTime = fUpdateTime + } + if fDeleteTime, ok := f["deleteTime"]; ok { + mDeleteTime = fDeleteTime + } + if fParent, ok := f["parent"]; ok { + mParent = fParent + } + if fDisplayName, ok := f["displayName"]; ok { + mDisplayName = fDisplayName + } + if fEtag, ok := f["etag"]; ok { + mEtag = fEtag + } + folders = append(folders, map[string]interface{}{ + "name": mName, + "state": mState, + "create_time": mCreateTime, + "update_time": mUpdateTime, + "delete_time": mDeleteTime, + "parent": mParent, + "display_name": mDisplayName, + "etag": mEtag, + }) + } + + return folders +} diff --git a/google/data_source_google_folders_test.go b/google/data_source_google_folders_test.go new file mode 100644 index 00000000000..8c732ef7280 --- /dev/null +++ b/google/data_source_google_folders_test.go @@ -0,0 +1,44 @@ +package google + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" +) + +func TestAccDataSourceGoogleFolders_basic(t *testing.T) { + t.Parallel() + + org_id := getTestOrgFromEnv() + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + { + Config: testAccCheckGoogleFoldersConfig(org_id), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.name"), + resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.display_name"), + resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.state"), + resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.parent.id"), + resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.parent.type"), + resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.create_time"), + resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.update_time"), + // resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.delete_time"), + // deleteTime will only be set on a deleted folder + resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.etag"), + ), + }, + }, + }) +} + +func testAccCheckGoogleFoldersConfig(org_id string) string { + return fmt.Sprintf(` +data "google_folders" "my-folder" { + parent_id = "organizations/%s" +} +`, org_id) +} diff --git a/google/provider.go b/google/provider.go index 279d0e5942c..89640fca96a 100644 --- a/google/provider.go +++ b/google/provider.go @@ -768,6 +768,7 @@ func Provider() *schema.Provider { "google_kms_secret": dataSourceGoogleKmsSecret(), "google_kms_secret_ciphertext": dataSourceGoogleKmsSecretCiphertext(), "google_folder": dataSourceGoogleFolder(), + "google_folders": dataSourceGoogleFolders(), "google_folder_organization_policy": dataSourceGoogleFolderOrganizationPolicy(), "google_monitoring_notification_channel": dataSourceMonitoringNotificationChannel(), "google_monitoring_cluster_istio_service": dataSourceMonitoringServiceClusterIstio(), diff --git a/website/docs/d/folders.html.markdown b/website/docs/d/folders.html.markdown new file mode 100644 index 00000000000..74e64edb26a --- /dev/null +++ b/website/docs/d/folders.html.markdown @@ -0,0 +1,51 @@ +--- +subcategory: "Cloud Platform" +layout: "google" +page_title: "Google: google_folders" +sidebar_current: "docs-google-datasource-folders" +description: |- + Retrieve a set of folders based on a parent ID. +--- + +# google\_folders + +Retrieve information about a set of folders based on a parent ID. See the +[REST API](https://cloud.google.com/resource-manager/reference/rest/v3/folders/list) +for more details. + +## Example Usage - searching for folders at the root of an org + +```hcl +data "google_folders" "my-org-folders" { + parent_id = "organizations/${var.organization_id}" +} + +data "google_folder" "first-folder" { + folder = data.google_folders.my-org-folders.folders[0].name +} +``` + +## Argument Reference + +The following arguments are supported: + +* `parent_id` - (Required) A string parent as defined in the [REST API](https://cloud.google.com/resource-manager/reference/rest/v3/folders/list#query-parameters). + + +## Attributes Reference + +The following attributes are exported: + +* `folders` - A list of projects matching the provided filter. Structure is defined below. + +The `folders` block supports: + +* `name` - The id of the folder +* `parent` - The parent id of the folder +* `displayName` - The display name of the folder +* `state` - The lifecycle state of the folder +* `createTime` - The timestamp of when the folder was created +* `updateTime` - The timestamp of when the folder was last modified +* `deleteTime` - The timestamp of when the folder was requested to be deleted (if applicable) +* `etag` - Entity tag identifier of the folder + From 37d64619fa58269d0fd44bb5f6bcebe364602bf6 Mon Sep 17 00:00:00 2001 From: Mike Laramie Date: Tue, 5 Oct 2021 23:35:22 -0400 Subject: [PATCH 2/4] docs: updated docs to fix attribute typos --- website/docs/d/folders.html.markdown | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/website/docs/d/folders.html.markdown b/website/docs/d/folders.html.markdown index 74e64edb26a..a9290915626 100644 --- a/website/docs/d/folders.html.markdown +++ b/website/docs/d/folders.html.markdown @@ -42,10 +42,10 @@ The `folders` block supports: * `name` - The id of the folder * `parent` - The parent id of the folder -* `displayName` - The display name of the folder +* `display_name` - The display name of the folder * `state` - The lifecycle state of the folder -* `createTime` - The timestamp of when the folder was created -* `updateTime` - The timestamp of when the folder was last modified -* `deleteTime` - The timestamp of when the folder was requested to be deleted (if applicable) +* `create_time` - The timestamp of when the folder was created +* `update_time` - The timestamp of when the folder was last modified +* `delete_time` - The timestamp of when the folder was requested to be deleted (if applicable) * `etag` - Entity tag identifier of the folder From 27d0e0162ec57337084c6c8f38854f75d9f91269 Mon Sep 17 00:00:00 2001 From: Mike Laramie Date: Thu, 7 Oct 2021 13:21:54 -0400 Subject: [PATCH 3/4] updated google_folders test --- google/data_source_google_folders_test.go | 19 +++++++++++++------ website/google.erb | 4 ++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/google/data_source_google_folders_test.go b/google/data_source_google_folders_test.go index 8c732ef7280..fa338210ba8 100644 --- a/google/data_source_google_folders_test.go +++ b/google/data_source_google_folders_test.go @@ -10,14 +10,16 @@ import ( func TestAccDataSourceGoogleFolders_basic(t *testing.T) { t.Parallel() - org_id := getTestOrgFromEnv() + org := getTestOrgFromEnv(t) + parent := fmt.Sprintf("organizations/%s", org) + displayName := "terraform-test-" + randString(t, 10) vcrTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, Providers: testAccProviders, Steps: []resource.TestStep{ { - Config: testAccCheckGoogleFoldersConfig(org_id), + Config: testAccCheckGoogleFoldersConfig(parent, displayName), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.name"), resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.display_name"), @@ -35,10 +37,15 @@ func TestAccDataSourceGoogleFolders_basic(t *testing.T) { }) } -func testAccCheckGoogleFoldersConfig(org_id string) string { +func testAccCheckGoogleFoldersConfig(parent string, displayName string) string { return fmt.Sprintf(` -data "google_folders" "my-folder" { - parent_id = "organizations/%s" +resource "google_folder" "foobar" { + parent = "%s" + display_name = "%s" } -`, org_id) + +data "google_folders" "root-test" { + parent_id = "%s" +} +`, parent, displayName, parent) } diff --git a/website/google.erb b/website/google.erb index b79256fda2f..896d5094f25 100644 --- a/website/google.erb +++ b/website/google.erb @@ -1085,6 +1085,10 @@ google_folder_organization_policy +
  • + google_folders +
  • +
  • google_iam_policy
  • From d90f7975c6fe7e8b47ef935462a16a3ee4e12bf1 Mon Sep 17 00:00:00 2001 From: Mike Laramie Date: Wed, 10 Nov 2021 16:58:51 -0500 Subject: [PATCH 4/4] fix: updated test to reference correct object --- google/data_source_google_folders_test.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/google/data_source_google_folders_test.go b/google/data_source_google_folders_test.go index fa338210ba8..2c017f014a8 100644 --- a/google/data_source_google_folders_test.go +++ b/google/data_source_google_folders_test.go @@ -21,16 +21,15 @@ func TestAccDataSourceGoogleFolders_basic(t *testing.T) { { Config: testAccCheckGoogleFoldersConfig(parent, displayName), Check: resource.ComposeTestCheckFunc( - resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.name"), - resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.display_name"), - resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.state"), - resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.parent.id"), - resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.parent.type"), - resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.create_time"), - resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.update_time"), - // resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.delete_time"), + resource.TestCheckResourceAttrSet("data.google_folders.root-test", "folders.0.name"), + resource.TestCheckResourceAttrSet("data.google_folders.root-test", "folders.0.display_name"), + resource.TestCheckResourceAttrSet("data.google_folders.root-test", "folders.0.state"), + resource.TestCheckResourceAttrSet("data.google_folders.root-test", "folders.0.parent"), + resource.TestCheckResourceAttrSet("data.google_folders.root-test", "folders.0.create_time"), + resource.TestCheckResourceAttrSet("data.google_folders.root-test", "folders.0.update_time"), + // resource.TestCheckResourceAttrSet("data.google_folders.root-test", "folders.0.delete_time"), // deleteTime will only be set on a deleted folder - resource.TestCheckResourceAttrSet("data.google_folders.my-folder", "folders.0.etag"), + resource.TestCheckResourceAttrSet("data.google_folders.root-test", "folders.0.etag"), ), }, },