From 83ca8d2a354b12eb836fee426316ab8583bcf4c1 Mon Sep 17 00:00:00 2001 From: Norberto Lopes Date: Tue, 14 Nov 2017 16:46:51 +0000 Subject: [PATCH 1/4] Add folder data source It is common to split infrastructure in GCP by environments, where all are under the same folder. You can think of it this way: you have a folder named "EnvA" that contains two different projects, each project managed by a filesystem folder in the terraform directory. Currently, one would have to hardcode the folder name in the variables file (as an option) after it had been created. With this data source it becomes possible to reference the folder with a given display name (this has to been unique within the same parent). --- google/data_source_google_folder.go | 59 ++++++++++++++++++ google/data_source_google_folder_test.go | 79 ++++++++++++++++++++++++ google/provider.go | 1 + 3 files changed, 139 insertions(+) create mode 100644 google/data_source_google_folder.go create mode 100644 google/data_source_google_folder_test.go diff --git a/google/data_source_google_folder.go b/google/data_source_google_folder.go new file mode 100644 index 00000000000..a83cabac51b --- /dev/null +++ b/google/data_source_google_folder.go @@ -0,0 +1,59 @@ +package google + +import ( + "fmt" + + "github.com/hashicorp/terraform/helper/schema" + resourceManagerV2Beta1 "google.golang.org/api/cloudresourcemanager/v2beta1" + "google.golang.org/api/googleapi" +) + +func dataSourceGoogleFolder() *schema.Resource { + return &schema.Resource{ + Read: dataSourceGoogleFolderRead, + + Schema: map[string]*schema.Schema{ + "parent": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "display_name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + "name": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func dataSourceGoogleFolderRead(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + parent := d.Get("parent").(string) + displayName := d.Get("display_name").(string) + + queryString := fmt.Sprintf("lifecycleState=ACTIVE AND parent=%s AND displayName=%s", parent, displayName) + searchRequest := &resourceManagerV2Beta1.SearchFoldersRequest{ + Query: queryString, + } + searchResponse, err := config.clientResourceManagerV2Beta1.Folders.Search(searchRequest).Do() + if err != nil { + if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { + return fmt.Errorf("Folder Not Found : %s", d.Get("name")) + } + + return fmt.Errorf("Error reading folders: %s", err) + } + + folders := searchResponse.Folders + if len(folders) != 1 { + return fmt.Errorf("More than one folder found") + } + + d.SetId(folders[0].Name) + d.Set("name", folders[0].Name) + return nil +} diff --git a/google/data_source_google_folder_test.go b/google/data_source_google_folder_test.go new file mode 100644 index 00000000000..2d1dd85a0f8 --- /dev/null +++ b/google/data_source_google_folder_test.go @@ -0,0 +1,79 @@ +package google + +import ( + "fmt" + "os" + "testing" + + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccDataSourceGoogleFolder(t *testing.T) { + skipIfEnvNotSet(t, + []string{ + "GOOGLE_ORG", + }..., + ) + + parent := fmt.Sprintf("organizations/%s", os.Getenv("GOOGLE_ORG")) + displayName := "terraform-test-" + acctest.RandString(10) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccDataSourceGoogleFolderConfig(parent, displayName), + Check: resource.ComposeTestCheckFunc( + testAccDataSourceGoogleFolderCheck("data.google_folder.my_folder", "google_folder.foobar"), + ), + }, + }, + }) +} + +func testAccDataSourceGoogleFolderCheck(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 + folder_attrs_to_test := []string{"parent", "display_name", "name"} + + for _, attr_to_check := range folder_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 testAccDataSourceGoogleFolderConfig(parent string, displayName string) string { + return fmt.Sprintf(` +resource "google_folder" "foobar" { + parent = "%s" + display_name = "%s" +} + +data "google_folder" "my_folder" { + parent = "${google_folder.foobar.parent}" + display_name = "${google_folder.foobar.display_name}" +} +`, parent, displayName) +} diff --git a/google/provider.go b/google/provider.go index 7977baeba7b..f238139b645 100644 --- a/google/provider.go +++ b/google/provider.go @@ -57,6 +57,7 @@ func Provider() terraform.ResourceProvider { "google_compute_zones": dataSourceGoogleComputeZones(), "google_compute_instance_group": dataSourceGoogleComputeInstanceGroup(), "google_container_engine_versions": dataSourceGoogleContainerEngineVersions(), + "google_folder": dataSourceGoogleFolder(), "google_iam_policy": dataSourceGoogleIamPolicy(), "google_storage_object_signed_url": dataSourceGoogleSignedUrl(), }, From fe7eec0db527fe9fb517f0161c2e8afabaa17698 Mon Sep 17 00:00:00 2001 From: Norberto Lopes Date: Tue, 14 Nov 2017 17:05:53 +0000 Subject: [PATCH 2/4] Add documentation for folder data source --- .../docs/d/datasource_folder.html.markdown | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 website/docs/d/datasource_folder.html.markdown diff --git a/website/docs/d/datasource_folder.html.markdown b/website/docs/d/datasource_folder.html.markdown new file mode 100644 index 00000000000..53bfdb8917e --- /dev/null +++ b/website/docs/d/datasource_folder.html.markdown @@ -0,0 +1,39 @@ +--- +layout: "google" +page_title: "Google: google_folder" +sidebar_current: "docs-google-datasource-folder" +description: |- + Get a folder within GCP. +--- + +# google\_folder + +Get a folder within GCP by display_name and parent. + +## Example Usage + +```tf +resource "google_folder" "new-folder" { + display_name = "new-folder" + parent = "folders/some-folder-id" +} + +data "google_folder" "new-folder" { + display_name = "${google_folder.new-folder.display_name}" + parent = "${google_folder.new-folder.parent}" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `display_name` - (Required) The folder's display name. + +* `parent` - (Required) The resource name of the parent Folder or Organization. + +## Attributes Reference + +In addition to the arguments listed above, the following attributes are exported: + +* `name` - The resource name of the Folder. This uniquely identifies the folder. From bce770a59487d9e11c4f26be457cff97b1521350 Mon Sep 17 00:00:00 2001 From: Norberto Lopes Date: Wed, 15 Nov 2017 18:11:19 +0000 Subject: [PATCH 3/4] Rename data source to google_active_folder --- google/data_source_google_folder_test.go | 13 ++++--------- google/provider.go | 2 +- website/docs/d/datasource_folder.html.markdown | 8 ++++---- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/google/data_source_google_folder_test.go b/google/data_source_google_folder_test.go index 2d1dd85a0f8..141125a2a78 100644 --- a/google/data_source_google_folder_test.go +++ b/google/data_source_google_folder_test.go @@ -2,7 +2,6 @@ package google import ( "fmt" - "os" "testing" "github.com/hashicorp/terraform/helper/acctest" @@ -11,13 +10,9 @@ import ( ) func TestAccDataSourceGoogleFolder(t *testing.T) { - skipIfEnvNotSet(t, - []string{ - "GOOGLE_ORG", - }..., - ) + skipIfEnvNotSet(t, "GOOGLE_ORG") - parent := fmt.Sprintf("organizations/%s", os.Getenv("GOOGLE_ORG")) + parent := fmt.Sprintf("organizations/%s", org) displayName := "terraform-test-" + acctest.RandString(10) resource.Test(t, resource.TestCase{ @@ -27,7 +22,7 @@ func TestAccDataSourceGoogleFolder(t *testing.T) { resource.TestStep{ Config: testAccDataSourceGoogleFolderConfig(parent, displayName), Check: resource.ComposeTestCheckFunc( - testAccDataSourceGoogleFolderCheck("data.google_folder.my_folder", "google_folder.foobar"), + testAccDataSourceGoogleFolderCheck("data.google_active_folder.my_folder", "google_folder.foobar"), ), }, }, @@ -71,7 +66,7 @@ resource "google_folder" "foobar" { display_name = "%s" } -data "google_folder" "my_folder" { +data "google_active_folder" "my_folder" { parent = "${google_folder.foobar.parent}" display_name = "${google_folder.foobar.display_name}" } diff --git a/google/provider.go b/google/provider.go index f238139b645..281845656e4 100644 --- a/google/provider.go +++ b/google/provider.go @@ -57,7 +57,7 @@ func Provider() terraform.ResourceProvider { "google_compute_zones": dataSourceGoogleComputeZones(), "google_compute_instance_group": dataSourceGoogleComputeInstanceGroup(), "google_container_engine_versions": dataSourceGoogleContainerEngineVersions(), - "google_folder": dataSourceGoogleFolder(), + "google_active_folder": dataSourceGoogleFolder(), "google_iam_policy": dataSourceGoogleIamPolicy(), "google_storage_object_signed_url": dataSourceGoogleSignedUrl(), }, diff --git a/website/docs/d/datasource_folder.html.markdown b/website/docs/d/datasource_folder.html.markdown index 53bfdb8917e..caa6ca25fe5 100644 --- a/website/docs/d/datasource_folder.html.markdown +++ b/website/docs/d/datasource_folder.html.markdown @@ -1,14 +1,14 @@ --- layout: "google" -page_title: "Google: google_folder" +page_title: "Google: google_active_folder" sidebar_current: "docs-google-datasource-folder" description: |- Get a folder within GCP. --- -# google\_folder +# google\_active\_folder -Get a folder within GCP by display_name and parent. +Get a folder within GCP by `display_name` and `parent`. ## Example Usage @@ -18,7 +18,7 @@ resource "google_folder" "new-folder" { parent = "folders/some-folder-id" } -data "google_folder" "new-folder" { +data "google_active_folder" "new-folder" { display_name = "${google_folder.new-folder.display_name}" parent = "${google_folder.new-folder.parent}" } From d7da495588796ebcd5f32042693de8a5083c634b Mon Sep 17 00:00:00 2001 From: Norberto Lopes Date: Wed, 15 Nov 2017 18:29:10 +0000 Subject: [PATCH 4/4] Rename methods to match data source name (GoogleActiveFolder) --- ...e_folder.go => data_source_google_active_folder.go} | 6 +++--- ...est.go => data_source_google_active_folder_test.go} | 10 +++++----- google/provider.go | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) rename google/{data_source_google_folder.go => data_source_google_active_folder.go} (87%) rename google/{data_source_google_folder_test.go => data_source_google_active_folder_test.go} (77%) diff --git a/google/data_source_google_folder.go b/google/data_source_google_active_folder.go similarity index 87% rename from google/data_source_google_folder.go rename to google/data_source_google_active_folder.go index a83cabac51b..a3bdfdbc852 100644 --- a/google/data_source_google_folder.go +++ b/google/data_source_google_active_folder.go @@ -8,9 +8,9 @@ import ( "google.golang.org/api/googleapi" ) -func dataSourceGoogleFolder() *schema.Resource { +func dataSourceGoogleActiveFolder() *schema.Resource { return &schema.Resource{ - Read: dataSourceGoogleFolderRead, + Read: dataSourceGoogleActiveFolderRead, Schema: map[string]*schema.Schema{ "parent": &schema.Schema{ @@ -29,7 +29,7 @@ func dataSourceGoogleFolder() *schema.Resource { } } -func dataSourceGoogleFolderRead(d *schema.ResourceData, meta interface{}) error { +func dataSourceGoogleActiveFolderRead(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) parent := d.Get("parent").(string) diff --git a/google/data_source_google_folder_test.go b/google/data_source_google_active_folder_test.go similarity index 77% rename from google/data_source_google_folder_test.go rename to google/data_source_google_active_folder_test.go index 141125a2a78..319d282a6af 100644 --- a/google/data_source_google_folder_test.go +++ b/google/data_source_google_active_folder_test.go @@ -9,7 +9,7 @@ import ( "github.com/hashicorp/terraform/terraform" ) -func TestAccDataSourceGoogleFolder(t *testing.T) { +func TestAccDataSourceGoogleActiveFolder(t *testing.T) { skipIfEnvNotSet(t, "GOOGLE_ORG") parent := fmt.Sprintf("organizations/%s", org) @@ -20,16 +20,16 @@ func TestAccDataSourceGoogleFolder(t *testing.T) { Providers: testAccProviders, Steps: []resource.TestStep{ resource.TestStep{ - Config: testAccDataSourceGoogleFolderConfig(parent, displayName), + Config: testAccDataSourceGoogleActiveFolderConfig(parent, displayName), Check: resource.ComposeTestCheckFunc( - testAccDataSourceGoogleFolderCheck("data.google_active_folder.my_folder", "google_folder.foobar"), + testAccDataSourceGoogleActiveFolderCheck("data.google_active_folder.my_folder", "google_folder.foobar"), ), }, }, }) } -func testAccDataSourceGoogleFolderCheck(data_source_name string, resource_name string) resource.TestCheckFunc { +func testAccDataSourceGoogleActiveFolderCheck(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 { @@ -59,7 +59,7 @@ func testAccDataSourceGoogleFolderCheck(data_source_name string, resource_name s } } -func testAccDataSourceGoogleFolderConfig(parent string, displayName string) string { +func testAccDataSourceGoogleActiveFolderConfig(parent string, displayName string) string { return fmt.Sprintf(` resource "google_folder" "foobar" { parent = "%s" diff --git a/google/provider.go b/google/provider.go index 281845656e4..0a6d20b5d37 100644 --- a/google/provider.go +++ b/google/provider.go @@ -57,7 +57,7 @@ func Provider() terraform.ResourceProvider { "google_compute_zones": dataSourceGoogleComputeZones(), "google_compute_instance_group": dataSourceGoogleComputeInstanceGroup(), "google_container_engine_versions": dataSourceGoogleContainerEngineVersions(), - "google_active_folder": dataSourceGoogleFolder(), + "google_active_folder": dataSourceGoogleActiveFolder(), "google_iam_policy": dataSourceGoogleIamPolicy(), "google_storage_object_signed_url": dataSourceGoogleSignedUrl(), },