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

Adds Direct VPC egress support for Cloud Run V2 resources #15870

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
6 changes: 6 additions & 0 deletions .changelog/8932.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
```release-note:enhancement
cloudrunv2: added fields `network_interfaces` to resource `google_cloud_run_v2_job` to support Direct VPC egress.
```
```release-note:enhancement
cloudrunv2: added fields `network_interfaces` to resource `google_cloud_run_v2_service` to support Direct VPC egress.
```
123 changes: 123 additions & 0 deletions google/services/cloudrunv2/resource_cloud_run_v2_job.go
Original file line number Diff line number Diff line change
Expand Up @@ -515,10 +515,44 @@ A duration in seconds with up to nine fractional digits, ending with 's'. Exampl
},
"egress": {
Type: schema.TypeString,
Computed: true,
Optional: true,
ValidateFunc: verify.ValidateEnum([]string{"ALL_TRAFFIC", "PRIVATE_RANGES_ONLY", ""}),
Description: `Traffic VPC egress settings. Possible values: ["ALL_TRAFFIC", "PRIVATE_RANGES_ONLY"]`,
},
"network_interfaces": {
Type: schema.TypeList,
Optional: true,
Description: `Direct VPC egress settings. Currently only single network interface is supported.`,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"network": {
Type: schema.TypeString,
Computed: true,
Optional: true,
Description: `The VPC network that the Cloud Run resource will be able to send traffic to. At least one of network or subnetwork must be specified. If both
network and subnetwork are specified, the given VPC subnetwork must belong to the given VPC network. If network is not specified, it will be
looked up from the subnetwork.`,
},
"subnetwork": {
Type: schema.TypeString,
Computed: true,
Optional: true,
Description: `The VPC subnetwork that the Cloud Run resource will get IPs from. At least one of network or subnetwork must be specified. If both
network and subnetwork are specified, the given VPC subnetwork must belong to the given VPC network. If subnetwork is not specified, the
subnetwork with the same name with the network will be used.`,
},
"tags": {
Type: schema.TypeList,
Optional: true,
Description: `Network tags applied to this Cloud Run job.`,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
},
},
},
},
},
Expand Down Expand Up @@ -2068,6 +2102,8 @@ func flattenCloudRunV2JobTemplateTemplateVpcAccess(v interface{}, d *schema.Reso
flattenCloudRunV2JobTemplateTemplateVpcAccessConnector(original["connector"], d, config)
transformed["egress"] =
flattenCloudRunV2JobTemplateTemplateVpcAccessEgress(original["egress"], d, config)
transformed["network_interfaces"] =
flattenCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfaces(original["networkInterfaces"], d, config)
return []interface{}{transformed}
}
func flattenCloudRunV2JobTemplateTemplateVpcAccessConnector(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
Expand All @@ -2078,6 +2114,38 @@ func flattenCloudRunV2JobTemplateTemplateVpcAccessEgress(v interface{}, d *schem
return v
}

func flattenCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfaces(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
if v == nil {
return v
}
l := v.([]interface{})
transformed := make([]interface{}, 0, len(l))
for _, raw := range l {
original := raw.(map[string]interface{})
if len(original) < 1 {
// Do not include empty json objects coming back from the api
continue
}
transformed = append(transformed, map[string]interface{}{
"network": flattenCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesNetwork(original["network"], d, config),
"subnetwork": flattenCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesSubnetwork(original["subnetwork"], d, config),
"tags": flattenCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesTags(original["tags"], d, config),
})
}
return transformed
}
func flattenCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesNetwork(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesSubnetwork(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesTags(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
return v
}

func flattenCloudRunV2JobTemplateTemplateMaxRetries(v interface{}, d *schema.ResourceData, config *transport_tpg.Config) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
Expand Down Expand Up @@ -3326,6 +3394,13 @@ func expandCloudRunV2JobTemplateTemplateVpcAccess(v interface{}, d tpgresource.T
transformed["egress"] = transformedEgress
}

transformedNetworkInterfaces, err := expandCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfaces(original["network_interfaces"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedNetworkInterfaces); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["networkInterfaces"] = transformedNetworkInterfaces
}

return transformed, nil
}

Expand All @@ -3337,6 +3412,54 @@ func expandCloudRunV2JobTemplateTemplateVpcAccessEgress(v interface{}, d tpgreso
return v, nil
}

func expandCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfaces(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
l := v.([]interface{})
req := make([]interface{}, 0, len(l))
for _, raw := range l {
if raw == nil {
continue
}
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedNetwork, err := expandCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesNetwork(original["network"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedNetwork); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["network"] = transformedNetwork
}

transformedSubnetwork, err := expandCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesSubnetwork(original["subnetwork"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedSubnetwork); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["subnetwork"] = transformedSubnetwork
}

transformedTags, err := expandCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesTags(original["tags"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedTags); val.IsValid() && !tpgresource.IsEmptyValue(val) {
transformed["tags"] = transformedTags
}

req = append(req, transformed)
}
return req, nil
}

func expandCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesNetwork(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesSubnetwork(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandCloudRunV2JobTemplateTemplateVpcAccessNetworkInterfacesTags(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}

func expandCloudRunV2JobTemplateTemplateMaxRetries(v interface{}, d tpgresource.TerraformResourceData, config *transport_tpg.Config) (interface{}, error) {
return v, nil
}
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,62 @@ resource "google_compute_network" "custom_test" {
`, context)
}

func TestAccCloudRunV2Job_cloudrunv2JobDirectvpcExample(t *testing.T) {
t.Parallel()

context := map[string]interface{}{
"random_suffix": acctest.RandString(t, 10),
}

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckCloudRunV2JobDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccCloudRunV2Job_cloudrunv2JobDirectvpcExample(context),
},
{
ResourceName: "google_cloud_run_v2_job.default",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"name", "location"},
},
},
})
}

func testAccCloudRunV2Job_cloudrunv2JobDirectvpcExample(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_cloud_run_v2_job" "default" {
name = "tf-test-cloudrun-job%{random_suffix}"
location = "us-central1"
launch_stage = "BETA"
template {
template{
containers {
image = "us-docker.pkg.dev/cloudrun/container/job"
}
vpc_access {
network_interfaces {
network = "default"
subnetwork = "default"
tags = ["tag1", "tag2", "tag3"]
}
egress = "ALL_TRAFFIC"
}
}
}

lifecycle {
ignore_changes = [
launch_stage,
]
}
}
`, context)
}

func TestAccCloudRunV2Job_cloudrunv2JobSecretExample(t *testing.T) {
t.Parallel()

Expand Down
94 changes: 94 additions & 0 deletions google/services/cloudrunv2/resource_cloud_run_v2_job_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
package cloudrunv2_test

import (
"fmt"
"testing"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
Expand Down Expand Up @@ -206,3 +207,96 @@ resource "google_compute_network" "custom_test" {
}
`, context)
}

func TestAccCloudRunV2Job_cloudrunv2JobWithDirectVPCUpdate(t *testing.T) {
t.Parallel()

jobName := fmt.Sprintf("tf-test-cloudrun-service%s", acctest.RandString(t, 10))
context := map[string]interface{}{
"job_name": jobName,
}

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckCloudRunV2JobDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccCloudRunV2Job_cloudrunv2JobWithDirectVPC(context),
},
{
ResourceName: "google_cloud_run_v2_job.default",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"location", "launch_stage"},
},
{
Config: testAccCloudRunV2Job_cloudrunv2JobWithDirectVPCUpdate(context),
},
{
ResourceName: "google_cloud_run_v2_job.default",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"location", "launch_stage"},
},
},
})
}

func testAccCloudRunV2Job_cloudrunv2JobWithDirectVPC(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_cloud_run_v2_job" "default" {
name = "%{job_name}"
location = "us-central1"
launch_stage = "BETA"
template {
template {
containers {
image = "us-docker.pkg.dev/cloudrun/container/job"
}
vpc_access {
network_interfaces {
network = "default"
}
}
}
}

lifecycle {
ignore_changes = [
launch_stage,
]
}
}
`, context)
}

func testAccCloudRunV2Job_cloudrunv2JobWithDirectVPCUpdate(context map[string]interface{}) string {
return acctest.Nprintf(`
resource "google_cloud_run_v2_job" "default" {
name = "%{job_name}"
location = "us-central1"
launch_stage = "BETA"
template {
template {
containers {
image = "us-docker.pkg.dev/cloudrun/container/job"
}
vpc_access {
network_interfaces {
network = "my-network"
subnetwork = "my-network"
tags = ["tag1", "tag2", "tag3"]
}
}
}
}

lifecycle {
ignore_changes = [
launch_stage,
]
}
}
`, context)
}
Loading