-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add 'google_billing_account' data source (#889)
* Add 'google_billing_account' data source. * Use 'GetResourceNameFromSelfLink'. * Use 'ConflictsWith' in schema. * Use pagination for List() API call. * Add ability to filter by 'open' attribute. * Don't use 'ForceNew' for data sources. * Add 'billing_account' argument and make 'name' an output-only attribute. * Correct error message.
- Loading branch information
Showing
5 changed files
with
286 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"net/http" | ||
"strings" | ||
|
||
"github.com/hashicorp/terraform/helper/schema" | ||
|
||
"google.golang.org/api/cloudbilling/v1" | ||
"google.golang.org/api/googleapi" | ||
) | ||
|
||
func dataSourceGoogleBillingAccount() *schema.Resource { | ||
return &schema.Resource{ | ||
Read: dataSourceBillingAccountRead, | ||
Schema: map[string]*schema.Schema{ | ||
"billing_account": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
ConflictsWith: []string{"display_name"}, | ||
}, | ||
"display_name": { | ||
Type: schema.TypeString, | ||
Optional: true, | ||
Computed: true, | ||
ConflictsWith: []string{"billing_account"}, | ||
}, | ||
"open": { | ||
Type: schema.TypeBool, | ||
Optional: true, | ||
Computed: true, | ||
}, | ||
"name": { | ||
Type: schema.TypeString, | ||
Computed: true, | ||
}, | ||
"project_ids": { | ||
Type: schema.TypeSet, | ||
Computed: true, | ||
Elem: &schema.Schema{ | ||
Type: schema.TypeString, | ||
}, | ||
}, | ||
}, | ||
} | ||
} | ||
|
||
func dataSourceBillingAccountRead(d *schema.ResourceData, meta interface{}) error { | ||
config := meta.(*Config) | ||
|
||
open, openOk := d.GetOkExists("open") | ||
|
||
var billingAccount *cloudbilling.BillingAccount | ||
if v, ok := d.GetOk("billing_account"); ok { | ||
resp, err := config.clientBilling.BillingAccounts.Get(canonicalBillingAccountName(v.(string))).Do() | ||
if err != nil { | ||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == http.StatusNotFound { | ||
return fmt.Errorf("Billing account not found: %s", v) | ||
} | ||
|
||
return fmt.Errorf("Error reading billing account: %s", err) | ||
} | ||
|
||
if openOk && resp.Open != open.(bool) { | ||
return fmt.Errorf("Billing account not found: %s", v) | ||
} | ||
|
||
billingAccount = resp | ||
} else if v, ok := d.GetOk("display_name"); ok { | ||
token := "" | ||
for paginate := true; paginate; { | ||
resp, err := config.clientBilling.BillingAccounts.List().PageToken(token).Do() | ||
if err != nil { | ||
return fmt.Errorf("Error reading billing accounts: %s", err) | ||
} | ||
|
||
for _, ba := range resp.BillingAccounts { | ||
if ba.DisplayName == v.(string) { | ||
if openOk && ba.Open != open.(bool) { | ||
continue | ||
} | ||
if billingAccount != nil { | ||
return fmt.Errorf("More than one matching billing account found") | ||
} | ||
billingAccount = ba | ||
} | ||
} | ||
|
||
token = resp.NextPageToken | ||
paginate = token != "" | ||
} | ||
|
||
if billingAccount == nil { | ||
return fmt.Errorf("Billing account not found: %s", v) | ||
} | ||
} else { | ||
return fmt.Errorf("one of billing_account or display_name must be set") | ||
} | ||
|
||
resp, err := config.clientBilling.BillingAccounts.Projects.List(billingAccount.Name).Do() | ||
if err != nil { | ||
return fmt.Errorf("Error reading billing account projects: %s", err) | ||
} | ||
projectIds := flattenBillingProjects(resp.ProjectBillingInfo) | ||
|
||
d.SetId(GetResourceNameFromSelfLink(billingAccount.Name)) | ||
d.Set("name", billingAccount.Name) | ||
d.Set("display_name", billingAccount.DisplayName) | ||
d.Set("open", billingAccount.Open) | ||
d.Set("project_ids", projectIds) | ||
|
||
return nil | ||
} | ||
|
||
func canonicalBillingAccountName(ba string) string { | ||
if strings.HasPrefix(ba, "billingAccounts/") { | ||
return ba | ||
} | ||
|
||
return "billingAccounts/" + ba | ||
} | ||
|
||
func flattenBillingProjects(billingProjects []*cloudbilling.ProjectBillingInfo) []string { | ||
projectIds := make([]string, len(billingProjects)) | ||
for i, billingProject := range billingProjects { | ||
projectIds[i] = billingProject.ProjectId | ||
} | ||
|
||
return projectIds | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
package google | ||
|
||
import ( | ||
"fmt" | ||
"regexp" | ||
"testing" | ||
|
||
"github.com/hashicorp/terraform/helper/acctest" | ||
|
||
"github.com/hashicorp/terraform/helper/resource" | ||
) | ||
|
||
func TestAccDataSourceGoogleBillingAccount_byFullName(t *testing.T) { | ||
billingId := getTestBillingAccountFromEnv(t) | ||
name := "billingAccounts/" + billingId | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccCheckGoogleBillingAccount_byName(name), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("data.google_billing_account.acct", "id", billingId), | ||
resource.TestCheckResourceAttr("data.google_billing_account.acct", "name", name), | ||
resource.TestCheckResourceAttr("data.google_billing_account.acct", "open", "true"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccDataSourceGoogleBillingAccount_byShortName(t *testing.T) { | ||
billingId := getTestBillingAccountFromEnv(t) | ||
name := "billingAccounts/" + billingId | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccCheckGoogleBillingAccount_byName(billingId), | ||
Check: resource.ComposeTestCheckFunc( | ||
resource.TestCheckResourceAttr("data.google_billing_account.acct", "id", billingId), | ||
resource.TestCheckResourceAttr("data.google_billing_account.acct", "name", name), | ||
resource.TestCheckResourceAttr("data.google_billing_account.acct", "open", "true"), | ||
), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccDataSourceGoogleBillingAccount_byFullNameClosed(t *testing.T) { | ||
billingId := getTestBillingAccountFromEnv(t) | ||
name := "billingAccounts/" + billingId | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccCheckGoogleBillingAccount_byNameClosed(name), | ||
ExpectError: regexp.MustCompile("Billing account not found: " + name), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func TestAccDataSourceGoogleBillingAccount_byDisplayName(t *testing.T) { | ||
name := acctest.RandString(16) | ||
|
||
resource.Test(t, resource.TestCase{ | ||
PreCheck: func() { testAccPreCheck(t) }, | ||
Providers: testAccProviders, | ||
Steps: []resource.TestStep{ | ||
{ | ||
Config: testAccCheckGoogleBillingAccount_byDisplayName(name), | ||
ExpectError: regexp.MustCompile("Billing account not found: " + name), | ||
}, | ||
}, | ||
}) | ||
} | ||
|
||
func testAccCheckGoogleBillingAccount_byName(name string) string { | ||
return fmt.Sprintf(` | ||
data "google_billing_account" "acct" { | ||
billing_account = "%s" | ||
}`, name) | ||
} | ||
|
||
func testAccCheckGoogleBillingAccount_byNameClosed(name string) string { | ||
return fmt.Sprintf(` | ||
data "google_billing_account" "acct" { | ||
billing_account = "%s" | ||
open = false | ||
}`, name) | ||
} | ||
|
||
func testAccCheckGoogleBillingAccount_byDisplayName(name string) string { | ||
return fmt.Sprintf(` | ||
data "google_billing_account" "acct" { | ||
display_name = "%s" | ||
}`, name) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
--- | ||
layout: "google" | ||
page_title: "Google: google_billing_account" | ||
sidebar_current: "docs-google-datasource-billing-account" | ||
description: |- | ||
Get information about a Google Billing Account. | ||
--- | ||
|
||
# google\_billing\_account | ||
|
||
Use this data source to get information about a Google Billing Account. | ||
|
||
```hcl | ||
data "google_billing_account" "acct" { | ||
display_name = "My Billing Account" | ||
open = true | ||
} | ||
resource "google_project" "my_project" { | ||
name = "My Project" | ||
project_id = "your-project-id" | ||
org_id = "1234567" | ||
billing_account = "${data.google_billing_account.acct.id}" | ||
} | ||
``` | ||
|
||
## Argument Reference | ||
|
||
The arguments of this data source act as filters for querying the available billing accounts. | ||
The given filters must match exactly one billing account whose data will be exported as attributes. | ||
The following arguments are supported: | ||
|
||
* `billing_account` (Optional) - The name of the billing account in the form `{billing_account_id}` or `billingAccounts/{billing_account_id}`. | ||
* `display_name` (Optional) - The display name of the billing account. | ||
* `open` (Optional) - `true` if the billing account is open, `false` if the billing account is closed. | ||
|
||
~> **NOTE:** One of `billing_account` or `display_name` must be specified. | ||
|
||
## Attributes Reference | ||
|
||
The following additional attributes are exported: | ||
|
||
* `id` - The billing account ID. | ||
* `name` - The resource name of the billing account in the form `billingAccounts/{billing_account_id}`. | ||
* `project_ids` - The IDs of any projects associated with the billing account. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters