Skip to content

Commit bf90594

Browse files
Update active folder to support both LIST and SEARCH methods (#10439) (#7248)
[upstream:4a01535b88d69b9923e9006b0e287bd07ad789b5] Signed-off-by: Modular Magician <[email protected]>
1 parent 33ea4b6 commit bf90594

File tree

4 files changed

+89
-11
lines changed

4 files changed

+89
-11
lines changed

.changelog/10439.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
resourcemanager: added the field `api_method` to datasource `google_active_folder` so you can use either `SEARCH` or `LIST` to find your folder
3+
```

google-beta/services/resourcemanager/data_source_google_active_folder.go

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
99
"github.com/hashicorp/terraform-provider-google-beta/google-beta/tpgresource"
1010
transport_tpg "github.com/hashicorp/terraform-provider-google-beta/google-beta/transport"
11+
"github.com/hashicorp/terraform-provider-google-beta/google-beta/verify"
1112
resourceManagerV3 "google.golang.org/api/cloudresourcemanager/v3"
1213
)
1314

@@ -28,6 +29,13 @@ func DataSourceGoogleActiveFolder() *schema.Resource {
2829
Type: schema.TypeString,
2930
Computed: true,
3031
},
32+
"api_method": {
33+
Type: schema.TypeString,
34+
Optional: true,
35+
Description: "Provides the REST method through which to find the folder. LIST is recommended as it is strongly consistent.",
36+
Default: "LIST",
37+
ValidateFunc: verify.ValidateEnum([]string{"LIST", "SEARCH"}),
38+
},
3139
},
3240
}
3341
}
@@ -42,24 +50,43 @@ func dataSourceGoogleActiveFolderRead(d *schema.ResourceData, meta interface{})
4250
var folderMatch *resourceManagerV3.Folder
4351
parent := d.Get("parent").(string)
4452
displayName := d.Get("display_name").(string)
45-
token := ""
53+
apiMethod := d.Get("api_method").(string)
54+
55+
if apiMethod == "LIST" {
56+
token := ""
57+
58+
for paginate := true; paginate; {
59+
resp, err := config.NewResourceManagerV3Client(userAgent).Folders.List().Parent(parent).PageSize(300).PageToken(token).Do()
60+
if err != nil {
61+
return fmt.Errorf("error reading folder list: %s", err)
62+
}
4663

47-
for paginate := true; paginate; {
48-
resp, err := config.NewResourceManagerV3Client(userAgent).Folders.List().Parent(parent).PageSize(300).PageToken(token).Do()
64+
for _, folder := range resp.Folders {
65+
if folder.DisplayName == displayName && folder.State == "ACTIVE" {
66+
if folderMatch != nil {
67+
return fmt.Errorf("more than one matching folder found")
68+
}
69+
folderMatch = folder
70+
}
71+
}
72+
token = resp.NextPageToken
73+
paginate = token != ""
74+
}
75+
} else {
76+
queryString := fmt.Sprintf("lifecycleState=ACTIVE AND parent=%s AND displayName=\"%s\"", parent, displayName)
77+
searchRequest := config.NewResourceManagerV3Client(userAgent).Folders.Search()
78+
searchRequest.Query(queryString)
79+
searchResponse, err := searchRequest.Do()
4980
if err != nil {
50-
return fmt.Errorf("error reading folder list: %s", err)
81+
return transport_tpg.HandleNotFoundError(err, d, fmt.Sprintf("Folder Not Found : %s", displayName))
5182
}
5283

53-
for _, folder := range resp.Folders {
54-
if folder.DisplayName == displayName && folder.State == "ACTIVE" {
55-
if folderMatch != nil {
56-
return fmt.Errorf("more than one matching folder found")
57-
}
84+
for _, folder := range searchResponse.Folders {
85+
if folder.DisplayName == displayName {
5886
folderMatch = folder
87+
break
5988
}
6089
}
61-
token = resp.NextPageToken
62-
paginate = token != ""
6390
}
6491

6592
if folderMatch == nil {

google-beta/services/resourcemanager/data_source_google_active_folder_test.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,29 @@ func TestAccDataSourceGoogleActiveFolder_default(t *testing.T) {
3232
})
3333
}
3434

35+
func TestAccDataSourceGoogleActiveFolder_Search(t *testing.T) {
36+
org := envvar.GetTestOrgFromEnv(t)
37+
38+
parent := fmt.Sprintf("organizations/%s", org)
39+
displayName := "tf-test-" + acctest.RandString(t, 10)
40+
41+
acctest.VcrTest(t, resource.TestCase{
42+
PreCheck: func() { acctest.AccTestPreCheck(t) },
43+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
44+
ExternalProviders: map[string]resource.ExternalProvider{
45+
"time": {},
46+
},
47+
Steps: []resource.TestStep{
48+
{
49+
Config: testAccDataSourceGoogleActiveFolderConfig_Search(parent, displayName),
50+
Check: resource.ComposeTestCheckFunc(
51+
testAccDataSourceGoogleActiveFolderCheck("data.google_active_folder.my_folder", "google_folder.foobar"),
52+
),
53+
},
54+
},
55+
})
56+
}
57+
3558
func TestAccDataSourceGoogleActiveFolder_space(t *testing.T) {
3659
org := envvar.GetTestOrgFromEnv(t)
3760

@@ -115,3 +138,26 @@ data "google_active_folder" "my_folder" {
115138
}
116139
`, parent, displayName)
117140
}
141+
142+
func testAccDataSourceGoogleActiveFolderConfig_Search(parent string, displayName string) string {
143+
return fmt.Sprintf(`
144+
resource "google_folder" "foobar" {
145+
parent = "%s"
146+
display_name = "%s"
147+
}
148+
149+
# Wait after folder creation to limit eventual consistency errors.
150+
resource "time_sleep" "wait_120_seconds" {
151+
depends_on = [google_folder.foobar]
152+
create_duration = "120s"
153+
}
154+
155+
156+
data "google_active_folder" "my_folder" {
157+
depends_on = [time_sleep.wait_120_seconds]
158+
parent = google_folder.foobar.parent
159+
display_name = google_folder.foobar.display_name
160+
api_method = "SEARCH"
161+
}
162+
`, parent, displayName)
163+
}

website/docs/d/active_folder.html.markdown

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ The following arguments are supported:
2525

2626
* `parent` - (Required) The resource name of the parent Folder or Organization.
2727

28+
* `api_method` - (Optional) The API method to use to search for the folder. Valid values are `LIST` and `SEARCH`. Default Value is `LIST`. `LIST` is [strongly consistent](https://cloud.google.com/resource-manager/reference/rest/v3/folders/list#:~:text=list()%20provides%20a-,strongly%20consistent,-view%20of%20the) and requires `resourcemanager.folders.list` on the parent folder, while `SEARCH` is [eventually consistent](https://cloud.google.com/resource-manager/reference/rest/v3/folders/search#:~:text=eventually%20consistent) and only returns folders that the user has `resourcemanager.folders.get` permission on.
29+
2830
## Attributes Reference
2931

3032
In addition to the arguments listed above, the following attributes are exported:

0 commit comments

Comments
 (0)