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

Backfill support for user_project_override and billing_project for google_service_networking_connection #9668

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/4995.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
servicenetworking: added support for `user_project_override` and `billing_project ` to `google_service_networking_connection`
```
71 changes: 64 additions & 7 deletions google/resource_service_networking_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ func resourceServiceNetworkingConnectionCreate(d *schema.ResourceData, meta inte
ReservedPeeringRanges: convertStringArr(d.Get("reserved_peering_ranges").([]interface{})),
}

networkFieldValue, err := ParseNetworkFieldValue(network, d, config)
if err != nil {
return errwrap.Wrapf("Failed to retrieve network field value, err: {{err}}", err)
}
project := networkFieldValue.Project

parentService := formatParentService(d.Get("service").(string))
// We use Patch instead of Create, because we're getting
// "Error waiting for Create Service Networking Connection:
Expand All @@ -98,12 +104,22 @@ func resourceServiceNetworkingConnectionCreate(d *schema.ResourceData, meta inte
// The API docs don't specify that you can do connections/-,
// but that's what gcloud does, and it's easier than grabbing
// the connection name.
op, err := config.NewServiceNetworkingClient(userAgent).Services.Connections.Patch(parentService+"/connections/-", connection).UpdateMask("reservedPeeringRanges").Force(true).Do()

// err == nil indicates that the billing_project value was found
if bp, err := getBillingProject(d, config); err == nil {
project = bp
}

createCall := config.NewServiceNetworkingClient(userAgent).Services.Connections.Patch(parentService+"/connections/-", connection).UpdateMask("reservedPeeringRanges").Force(true)
if config.UserProjectOverride {
createCall.Header().Add("X-Goog-User-Project", project)
}
op, err := createCall.Do()
if err != nil {
return err
}

if err := serviceNetworkingOperationWaitTime(config, op, "Create Service Networking Connection", userAgent, d.Timeout(schema.TimeoutCreate)); err != nil {
if err := serviceNetworkingOperationWaitTime(config, op, "Create Service Networking Connection", userAgent, project, d.Timeout(schema.TimeoutCreate)); err != nil {
return err
}

Expand Down Expand Up @@ -133,9 +149,24 @@ func resourceServiceNetworkingConnectionRead(d *schema.ResourceData, meta interf
return errwrap.Wrapf("Failed to find Service Networking Connection, err: {{err}}", err)
}

network := d.Get("network").(string)
networkFieldValue, err := ParseNetworkFieldValue(network, d, config)
if err != nil {
return errwrap.Wrapf("Failed to retrieve network field value, err: {{err}}", err)
}
project := networkFieldValue.Project

// err == nil indicates that the billing_project value was found
if bp, err := getBillingProject(d, config); err == nil {
project = bp
}

parentService := formatParentService(connectionId.Service)
response, err := config.NewServiceNetworkingClient(userAgent).Services.Connections.List(parentService).
Network(serviceNetworkingNetworkName).Do()
readCall := config.NewServiceNetworkingClient(userAgent).Services.Connections.List(parentService).Network(serviceNetworkingNetworkName)
if config.UserProjectOverride {
readCall.Header().Add("X-Goog-User-Project", project)
}
response, err := readCall.Do()
if err != nil {
return err
}
Expand Down Expand Up @@ -195,13 +226,29 @@ func resourceServiceNetworkingConnectionUpdate(d *schema.ResourceData, meta inte
ReservedPeeringRanges: convertStringArr(d.Get("reserved_peering_ranges").([]interface{})),
}

networkFieldValue, err := ParseNetworkFieldValue(network, d, config)
if err != nil {
return errwrap.Wrapf("Failed to retrieve network field value, err: {{err}}", err)
}
project := networkFieldValue.Project

// The API docs don't specify that you can do connections/-, but that's what gcloud does,
// and it's easier than grabbing the connection name.
op, err := config.NewServiceNetworkingClient(userAgent).Services.Connections.Patch(parentService+"/connections/-", connection).UpdateMask("reservedPeeringRanges").Force(true).Do()

// err == nil indicates that the billing_project value was found
if bp, err := getBillingProject(d, config); err == nil {
project = bp
}

patchCall := config.NewServiceNetworkingClient(userAgent).Services.Connections.Patch(parentService+"/connections/-", connection).UpdateMask("reservedPeeringRanges").Force(true)
if config.UserProjectOverride {
patchCall.Header().Add("X-Goog-User-Project", project)
}
op, err := patchCall.Do()
if err != nil {
return err
}
if err := serviceNetworkingOperationWaitTime(config, op, "Update Service Networking Connection", userAgent, d.Timeout(schema.TimeoutUpdate)); err != nil {
if err := serviceNetworkingOperationWaitTime(config, op, "Update Service Networking Connection", userAgent, project, d.Timeout(schema.TimeoutUpdate)); err != nil {
return err
}
}
Expand Down Expand Up @@ -322,7 +369,17 @@ func retrieveServiceNetworkingNetworkName(d *schema.ResourceData, config *Config
return "", fmt.Errorf("Could not determine project")
}
log.Printf("[DEBUG] Retrieving project number by doing a GET with the project id, as required by service networking")
project, err := config.NewResourceManagerClient(userAgent).Projects.Get(pid).Do()
// err == nil indicates that the billing_project value was found
billingProject := pid
if bp, err := getBillingProject(d, config); err == nil {
billingProject = bp
}

getProjectCall := config.NewResourceManagerClient(userAgent).Projects.Get(pid)
if config.UserProjectOverride {
getProjectCall.Header().Add("X-Goog-User-Project", billingProject)
}
project, err := getProjectCall.Do()
if err != nil {
// note: returning a wrapped error is part of this method's contract!
// https://blog.golang.org/go1.13-errors
Expand Down
8 changes: 5 additions & 3 deletions google/resource_service_networking_connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ func testServiceNetworkingConnectionDestroy(t *testing.T, parent, network string
config := googleProviderConfig(t)
parentService := "services/" + parent
networkName := fmt.Sprintf("projects/%s/global/networks/%s", getTestProjectFromEnv(), network)

response, err := config.NewServiceNetworkingClient(config.userAgent).Services.Connections.List(parentService).
Network(networkName).Do()
listCall := config.NewServiceNetworkingClient(config.userAgent).Services.Connections.List(parentService).Network(networkName)
if config.UserProjectOverride {
listCall.Header().Add("X-Goog-User-Project", getTestProjectFromEnv())
}
response, err := listCall.Do()
if err != nil {
return err
}
Expand Down
16 changes: 12 additions & 4 deletions google/service_networking_operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,25 @@ import (
)

type ServiceNetworkingOperationWaiter struct {
Service *servicenetworking.APIService
Service *servicenetworking.APIService
Project string
UserProjectOverride bool
CommonOperationWaiter
}

func (w *ServiceNetworkingOperationWaiter) QueryOp() (interface{}, error) {
return w.Service.Operations.Get(w.Op.Name).Do()
opGetCall := w.Service.Operations.Get(w.Op.Name)
if w.UserProjectOverride {
opGetCall.Header().Add("X-Goog-User-Project", w.Project)
}
return opGetCall.Do()
}

func serviceNetworkingOperationWaitTime(config *Config, op *servicenetworking.Operation, activity, userAgent string, timeout time.Duration) error {
func serviceNetworkingOperationWaitTime(config *Config, op *servicenetworking.Operation, activity, userAgent, project string, timeout time.Duration) error {
w := &ServiceNetworkingOperationWaiter{
Service: config.NewServiceNetworkingClient(userAgent),
Service: config.NewServiceNetworkingClient(userAgent),
Project: project,
UserProjectOverride: config.UserProjectOverride,
}

if err := w.SetOp(op); err != nil {
Expand Down
5 changes: 5 additions & 0 deletions website/docs/r/service_networking_connection.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,8 @@ ServiceNetworkingConnection can be imported using any of these accepted formats
* terraform import google_service_networking_connection.peering_connection {{peering-network}}:{{service}}

* terraform import google_service_networking_connection.peering_connection /projects/{{project}}/global/networks/{{peering-network}}:{{service}}


## User Project Overrides

This resource supports [User Project Overrides](https://www.terraform.io/docs/providers/google/guides/provider_reference.html#user_project_override).