Skip to content
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

Add billing_project configuration to the provider #3886

Merged
4 changes: 4 additions & 0 deletions products/accesscontextmanager/terraform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
--- !ruby/object:Provider::Terraform::Config
overrides: !ruby/object:Overrides::ResourceOverrides
AccessPolicy: !ruby/object:Overrides::Terraform::ResourceOverride
supports_indirect_user_project_override: true
upodroid marked this conversation as resolved.
Show resolved Hide resolved
timeouts: !ruby/object:Api::Timeouts
insert_minutes: 6
update_minutes: 6
Expand All @@ -36,6 +37,7 @@ overrides: !ruby/object:Overrides::ResourceOverrides
custom_code: !ruby/object:Provider::Terraform::CustomCode
post_create: templates/terraform/post_create/accesspolicy.erb
AccessLevel: !ruby/object:Overrides::Terraform::ResourceOverride
supports_indirect_user_project_override: true
timeouts: !ruby/object:Api::Timeouts
insert_minutes: 6
update_minutes: 6
Expand All @@ -61,6 +63,7 @@ overrides: !ruby/object:Overrides::ResourceOverrides
encoder: templates/terraform/encoders/access_level_never_send_parent.go.erb
custom_import: templates/terraform/custom_import/set_access_policy_parent_from_self_link.go.erb
ServicePerimeter: !ruby/object:Overrides::Terraform::ResourceOverride
supports_indirect_user_project_override: true
timeouts: !ruby/object:Api::Timeouts
insert_minutes: 6
update_minutes: 6
Expand Down Expand Up @@ -99,6 +102,7 @@ overrides: !ruby/object:Overrides::ResourceOverrides
encoder: templates/terraform/encoders/access_level_never_send_parent.go.erb
custom_import: templates/terraform/custom_import/set_access_policy_parent_from_self_link.go.erb
ServicePerimeterResource: !ruby/object:Overrides::Terraform::ResourceOverride
supports_indirect_user_project_override: true
autogen_async: true
exclude_validator: true
# Skipping the sweeper due to the non-standard base_url and because this is fine-grained under ServicePerimeter
Expand Down
73 changes: 72 additions & 1 deletion templates/terraform/resource.erb
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,17 @@ func resource<%= resource_name -%>Create(d *schema.ResourceData, meta interface{
var project string
if parts := regexp.MustCompile(`projects\/([^\/]+)\/`).FindStringSubmatch(url); parts != nil {
project = parts[1]
}
} else {
upodroid marked this conversation as resolved.
Show resolved Hide resolved

// Send the billing_project ID in the X-Goog-User-Project header.
config.UserProjectOverride = true
upodroid marked this conversation as resolved.
Show resolved Hide resolved

billingProject, err := getBillingProject(d, config)
upodroid marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return err
}
project = billingProject
}
<% end -%>
<%= lines(compile(pwd + '/' + object.custom_code.pre_create)) if object.custom_code.pre_create -%>
res, err := sendRequestWithTimeout(config, "<%= object.create_verb.to_s.upcase -%>", <% if has_project || object.supports_indirect_user_project_override %>project<% else %>""<% end %>, url, obj, d.Timeout(schema.TimeoutCreate)<%= object.error_retry_predicates ? ", " + object.error_retry_predicates.join(',') : "" -%>)
Expand Down Expand Up @@ -345,6 +355,16 @@ func resource<%= resource_name -%>PollRead(d *schema.ResourceData, meta interfac
var project string
if parts := regexp.MustCompile(`projects\/([^\/]+)\/`).FindStringSubmatch(url); parts != nil {
project = parts[1]
} else {

// Send the billing_project ID in the X-Goog-User-Project header.
config.UserProjectOverride = true

billingProject, err := getBillingProject(d, config)
if err != nil {
return err
}
project = billingProject
}
<% end -%>
res, err := sendRequest(config, "<%= object.read_verb.to_s.upcase -%>", <% if has_project || object.supports_indirect_user_project_override %>project<% else %>""<% end %>, url, nil<%= object.error_retry_predicates ? ", " + object.error_retry_predicates.join(',') : "" -%>)
Expand Down Expand Up @@ -404,6 +424,16 @@ func resource<%= resource_name -%>Read(d *schema.ResourceData, meta interface{})
var project string
if parts := regexp.MustCompile(`projects\/([^\/]+)\/`).FindStringSubmatch(url); parts != nil {
project = parts[1]
} else {

// Send the billing_project ID in the X-Goog-User-Project header.
config.UserProjectOverride = true

billingProject, err := getBillingProject(d, config)
if err != nil {
return err
}
project = billingProject
}
<% end -%>
res, err := sendRequest(config, "<%= object.read_verb.to_s.upcase -%>", <% if has_project || object.supports_indirect_user_project_override %>project<% else %>""<% end %>, url, nil<%= object.error_retry_predicates ? ", " + object.error_retry_predicates.join(',') : "" -%>)
Expand Down Expand Up @@ -527,6 +557,16 @@ if <%= props.map { |prop| "d.HasChange(\"#{prop.name.underscore}\")" }.join ' ||
<% if object.supports_indirect_user_project_override -%>
if parts := regexp.MustCompile(`projects\/([^\/]+)\/`).FindStringSubmatch(url); parts != nil {
project = parts[1]
} else {

// Send the billing_project ID in the X-Goog-User-Project header.
config.UserProjectOverride = true

billingProject, err := getBillingProject(d, config)
if err != nil {
return err
}
project = billingProject
}
<% end -%>
getRes, err := sendRequest(config, "<%= object.read_verb.to_s.upcase -%>", <% if has_project || object.supports_indirect_user_project_override %>project<% else %>""<% end %>, getUrl, nil<%= object.error_retry_predicates ? ", " + object.error_retry_predicates.join(',') : "" -%>)
Expand Down Expand Up @@ -597,6 +637,16 @@ if <%= props.map { |prop| "d.HasChange(\"#{prop.name.underscore}\")" }.join ' ||
var project string
if parts := regexp.MustCompile(`projects\/([^\/]+)\/`).FindStringSubmatch(url); parts != nil {
project = parts[1]
} else {

// Send the billing_project ID in the X-Goog-User-Project header.
config.UserProjectOverride = true

billingProject, err := getBillingProject(d, config)
if err != nil {
return err
}
project = billingProject
}
<% end -%>
res, err := sendRequestWithTimeout(config, "<%= key[:update_verb] -%>", <% if has_project || object.supports_indirect_user_project_override %>project<% else %>""<% end %>, url, obj, d.Timeout(schema.TimeoutUpdate)<%= object.error_retry_predicates ? ", " + object.error_retry_predicates.join(',') : "" -%>)
Expand Down Expand Up @@ -693,7 +743,18 @@ if <%= props.map { |prop| "d.HasChange(\"#{prop.name.underscore}\")" }.join ' ||
var project string
if parts := regexp.MustCompile(`projects\/([^\/]+)\/`).FindStringSubmatch(url); parts != nil {
project = parts[1]
} else {

// Send the billing_project ID in the X-Goog-User-Project header.
config.UserProjectOverride = true

billingProject, err := getBillingProject(d, config)
if err != nil {
return err
}
project = billingProject
}

<% end -%>
res, err := sendRequestWithTimeout(config, "<%= object.update_verb -%>", <% if has_project || object.supports_indirect_user_project_override %>project<% else %>""<% end %>, url, obj, d.Timeout(schema.TimeoutUpdate)<%= object.error_retry_predicates ? ", " + object.error_retry_predicates.join(',') : "" -%>)

Expand Down Expand Up @@ -784,6 +845,16 @@ func resource<%= resource_name -%>Delete(d *schema.ResourceData, meta interface{
var project string
if parts := regexp.MustCompile(`projects\/([^\/]+)\/`).FindStringSubmatch(url); parts != nil {
project = parts[1]
} else {

// Send the billing_project ID in the X-Goog-User-Project header.
config.UserProjectOverride = true

billingProject, err := getBillingProject(d, config)
if err != nil {
return err
}
project = billingProject
}
<% end -%>
log.Printf("[DEBUG] Deleting <%= object.name -%> %q", d.Id())
Expand Down
1 change: 1 addition & 0 deletions third_party/terraform/utils/config.go.erb
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type Config struct {
Credentials string
AccessToken string
Project string
BillingProject string
Region string
Zone string
Scopes []string
Expand Down
11 changes: 11 additions & 0 deletions third_party/terraform/utils/field_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,17 @@ func getProjectFromSchema(projectSchemaField string, d TerraformResourceData, co
return "", fmt.Errorf("%s: required field is not set", projectSchemaField)
}

func getBillingProjectFromSchema(billingProjectSchemaField string, d TerraformResourceData, config *Config) (string, error) {
upodroid marked this conversation as resolved.
Show resolved Hide resolved
res, ok := d.GetOk(billingProjectSchemaField)
if ok && billingProjectSchemaField != "" {
return res.(string), nil
}
if config.BillingProject != "" {
return config.BillingProject, nil
}
return "", fmt.Errorf("%s: required field is not set", billingProjectSchemaField)
}

type OrganizationFieldValue struct {
OrgId string
Name string
Expand Down
8 changes: 8 additions & 0 deletions third_party/terraform/utils/provider.go.erb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ func Provider() terraform.ResourceProvider {
}, nil),
},

"billing_project": &schema.Schema{
upodroid marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Optional: true,
DefaultFunc: schema.MultiEnvDefaultFunc([]string{
"GOOGLE_BILLING_PROJECT",
}, nil),
},

"region": &schema.Schema{
Type: schema.TypeString,
Optional: true,
Expand Down
9 changes: 9 additions & 0 deletions third_party/terraform/utils/provider_test.go.erb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ var projectEnvVars = []string{
"CLOUDSDK_CORE_PROJECT",
}

var billingProjectEnvVars = []string{
upodroid marked this conversation as resolved.
Show resolved Hide resolved
"GOOGLE_BILLING_PROJECT",
}

var firestoreProjectEnvVars = []string{
"GOOGLE_FIRESTORE_PROJECT",
}
Expand Down Expand Up @@ -882,6 +886,11 @@ func getTestOrgDomainFromEnv(t *testing.T) string {
return multiEnvSearch(orgEnvDomainVars)
}

func getTestBillingProjectFromEnv(t *testing.T) string {
upodroid marked this conversation as resolved.
Show resolved Hide resolved
skipIfEnvNotSet(t, billingProjectEnvVars...)
return multiEnvSearch(billingProjectEnvVars)
}

func getTestOrgTargetFromEnv(t *testing.T) string {
skipIfEnvNotSet(t, orgTargetEnvVars...)
return multiEnvSearch(orgTargetEnvVars)
Expand Down
7 changes: 7 additions & 0 deletions third_party/terraform/utils/utils.go.erb
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ func getProject(d TerraformResourceData, config *Config) (string, error) {
return getProjectFromSchema("project", d, config)
}

// getBillingProject reads the "billing_project" field from the given resource data and falls
// back to the provider's value if not given. If the provider's value is not
upodroid marked this conversation as resolved.
Show resolved Hide resolved
// given, an error is returned.
func getBillingProject(d TerraformResourceData, config *Config) (string, error) {
return getBillingProjectFromSchema("billing_project", d, config)
}

// getProjectFromDiff reads the "project" field from the given diff and falls
// back to the provider's value if not given. If the provider's value is not
// given, an error is returned.
Expand Down