-
Notifications
You must be signed in to change notification settings - Fork 9.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
providers/google: google_project supports billing account #11653
Conversation
This one is really tricky to write an integration test for. We'd need to create two dummy Billing Accounts in the testing Organization, and give the service account that runs the integration test the proper permission in the Organization. Then introduce the two Billing Account IDs as env vars to the tests. Not impossible, but really raises the bar for someone running the integration tests locally. For now, I'm testing manually to verify create and update of a project with a billing account. Thoughts, @danawillow and @paddyforan? Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just a few nitpicks.
As for testing, I agree that it'll be tricky, especially for someone running locally (and I don't want another set of environment variables that have to be set for someone running it locally). If we had a way of using mocks (and then running non-mocks only via CI) that would probably be the ideal solution, but I don't see that happening anytime soon. For now my opinion is to just get the change in- I don't think that's too reckless (famous last words).
ba := cloudbilling.ProjectBillingInfo{ | ||
BillingAccountName: "billingAccounts/" + v.(string), | ||
} | ||
_, err = config.clientBilling.Projects.UpdateBillingInfo("projects/"+pid, &ba).Do() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: even though it's a teeny tiny thing, since you do "projects/" + pid a few times I wouldn't mind seeing that in a function
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a nit at all! Done.
return fmt.Errorf("Error reading billing account for project %q: %v", "projects/"+pid, err) | ||
} | ||
if ba.BillingAccountName != "" { | ||
_ba := strings.Split(ba.BillingAccountName, "billingAccounts/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TrimPrefix is probably cleaner than split
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way this is written, I don't actually know what the string is expected to be... it could be any one of these:
- projects/{PROJECT}/billingAccounts/{account name}
- billingAccounts/{account name}
- https://www.googlespis.com/projects/{PROJECT}/billingAccounts/{account name}
Honestly, would love some clarification (esp as a code comment) around what ba.BillingAccountName
is expected to be at this point. And agree strings.Split
may not be the most semantic function to use.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TIL TrimPrefix
. Done.
Have a few thoughts on this, let me circle around tomorrow. :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great, with just a few nitpicks here and there. For my part, though, I'd love to see some sort of tests here.
If I understand your explanation right, the problem is we would need to do some special setup on the project before we could run the tests, namely adding billing accounts, giving the service account permissions, and passing the billing accounts in as an environment variable.
My gut on this is that we've kind of crossed that bridge already:
- XPN requires our project to be whitelisted before the tests can be run, anyways.
- Projects requires the Org ID to be passed in as an environment variable.
- Projects requires the service account to have specific permissions.
On my end, I think "untested features" is more frightening than "painful to test features", and at least with the painful to test features, we have good examples to look at when rethinking our testing framework, and can potentially make them simpler to run. There are some ways I can think of to automate the stuff we've mentioned so Terraform could bootstrap testing environments, and having "here's why that's a good idea" is always good.
That said, I'm open to being convinced that increasing the difficulty of running tests on non-official projects is not worth it in this case. My general stance is that making testing on non-official projects harder is bad, and we should avoid it where possible, but if it's necessary for us to test functionality, let's do it.
_, err = config.clientBilling.Projects.UpdateBillingInfo("projects/"+pid, &ba).Do() | ||
if err != nil { | ||
d.Set("billing_account", "") | ||
if _err, ok := err.(*googleapi.Error); ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a difference between how *googleapi.Error
and error
get printed when using %v
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is. The former will unpack and print any nested errors.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair enough!
return fmt.Errorf("Error reading billing account for project %q: %v", "projects/"+pid, err) | ||
} | ||
if ba.BillingAccountName != "" { | ||
_ba := strings.Split(ba.BillingAccountName, "billingAccounts/") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way this is written, I don't actually know what the string is expected to be... it could be any one of these:
- projects/{PROJECT}/billingAccounts/{account name}
- billingAccounts/{account name}
- https://www.googlespis.com/projects/{PROJECT}/billingAccounts/{account name}
Honestly, would love some clarification (esp as a code comment) around what ba.BillingAccountName
is expected to be at this point. And agree strings.Split
may not be the most semantic function to use.
@@ -210,6 +231,18 @@ func resourceGoogleProjectRead(d *schema.ResourceData, meta interface{}) error { | |||
d.Set("policy_etag", pol.Etag) | |||
d.Set("policy_data", string(polBytes)) | |||
|
|||
// Read the billing account | |||
ba, err := config.clientBilling.Projects.GetBillingInfo("projects/" + pid).Do() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like it's possible to create projects without a billing account (now), and this line of code is causing any projects which do not have a billing account to return a 403 on read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I'm not seeing this. I've created a few projects (and just added tests that do the same) that don't have billing accounts but make it through read. GetBillingInfo should return an empty billing account if none is set. Possible to see your config?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@evandbrown it's sadder than that 😦 . Steps to repro:
- Compile Terraform without this PR
- Create project
- Compile Terraform with this PR
- Change a project attr
- Get error
This change allows a Terraform user to set and update the billing account associated with their project.
This change adds optional acceptance tests for project billing accounts. GOOGLE_PROJECT_BILLING_ACCOUNT and GOOGLE_PROJECT_BILLING_ACCOUNT_2 must be set in the environment for the tests to run; otherwise, they will be skipped. Also includes a few code cleanups per review.
9f3b76e
to
d49ab62
Compare
@paddyforan totally reasonable; tests are added. |
func testAccGoogleProject_createBilling(pid, name, org, billing string) string { | ||
return fmt.Sprintf(` | ||
resource "google_project" "acceptance" { | ||
project_id = "%s" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like tabs vs spaces happened here
Thanks for adding those tests, @evandbrown! This looks great. Looks like @sethvargo had a nit about tabs/spaces, don't know if you want to update that or not. Either is fine by me. But this has a 👍 from me. |
* Vendor google.golang.org/api/cloudbilling/v1 * providers/google: Add cloudbilling client * providers/google: google_project supports billing account This change allows a Terraform user to set and update the billing account associated with their project. * providers/google: Testing project billing account This change adds optional acceptance tests for project billing accounts. GOOGLE_PROJECT_BILLING_ACCOUNT and GOOGLE_PROJECT_BILLING_ACCOUNT_2 must be set in the environment for the tests to run; otherwise, they will be skipped. Also includes a few code cleanups per review. * providers/google: Improve project billing error message
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further. |
This change allows a Terraform user to set and update the billing account associated with their project.