diff --git a/.changelog/6987.txt b/.changelog/6987.txt new file mode 100644 index 00000000000..647aad3540f --- /dev/null +++ b/.changelog/6987.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +added `template.0.containers0.liveness_probe.grpc`, `template.0.containers0.startup_probe.grpc` fields to `google_cloud_run_v2_service` resource +``` diff --git a/google/config.go b/google/config.go index 6d06f6faa3d..2533b8afa72 100644 --- a/google/config.go +++ b/google/config.go @@ -42,6 +42,7 @@ import ( iamcredentials "google.golang.org/api/iamcredentials/v1" cloudlogging "google.golang.org/api/logging/v2" "google.golang.org/api/pubsub/v1" + runadminv2 "google.golang.org/api/run/v2" "google.golang.org/api/servicemanagement/v1" "google.golang.org/api/servicenetworking/v1" "google.golang.org/api/serviceusage/v1" @@ -1146,6 +1147,20 @@ func (c *Config) NewBigTableProjectsInstancesTablesClient(userAgent string) *big return clientBigtableProjectsInstancesTables } +func (c *Config) NewCloudRunV2Client(userAgent string) *runadminv2.Service { + runAdminV2ClientBasePath := removeBasePathVersion(removeBasePathVersion(c.CloudRunV2BasePath)) + log.Printf("[INFO] Instantiating Google Cloud Run Admin v2 client for path %s", runAdminV2ClientBasePath) + clientRunAdminV2, err := runadminv2.NewService(c.context, option.WithHTTPClient(c.client)) + if err != nil { + log.Printf("[WARN] Error creating client run admin: %s", err) + return nil + } + clientRunAdminV2.UserAgent = userAgent + clientRunAdminV2.BasePath = runAdminV2ClientBasePath + + return clientRunAdminV2 +} + // staticTokenSource is used to be able to identify static token sources without reflection. type staticTokenSource struct { oauth2.TokenSource diff --git a/google/resource_cloud_run_v2_service.go b/google/resource_cloud_run_v2_service.go index ab774c77fe7..466b2fb6250 100644 --- a/google/resource_cloud_run_v2_service.go +++ b/google/resource_cloud_run_v2_service.go @@ -139,6 +139,7 @@ func ResourceCloudRunV2Service() *schema.Resource { }, "liveness_probe": { Type: schema.TypeList, + Computed: true, Optional: true, Description: `Periodic probe of container liveness. Container will be restarted if the probe fails. More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes`, MaxItems: 1, @@ -150,6 +151,29 @@ func ResourceCloudRunV2Service() *schema.Resource { Description: `Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1.`, Default: 3, }, + "grpc": { + Type: schema.TypeList, + Optional: true, + Description: `GRPC specifies an action involving a GRPC port.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + Description: `Port number to access on the container. Number must be in the range 1 to 65535. If not specified, defaults to the same value as container.ports[0].containerPort.`, + }, + "service": { + Type: schema.TypeString, + Optional: true, + Description: `The name of the service to place in the gRPC HealthCheckRequest +(see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). +If this is not specified, the default behavior is defined by gRPC.`, + }, + }, + }, + }, "http_get": { Type: schema.TypeList, Optional: true, @@ -288,6 +312,29 @@ If omitted, a port number will be chosen and passed to the container through the Description: `Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3. Minimum value is 1.`, Default: 3, }, + "grpc": { + Type: schema.TypeList, + Optional: true, + Description: `GRPC specifies an action involving a GRPC port.`, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Computed: true, + Optional: true, + Description: `Port number to access on the container. Number must be in the range 1 to 65535. If not specified, defaults to the same value as container.ports[0].containerPort.`, + }, + "service": { + Type: schema.TypeString, + Optional: true, + Description: `The name of the service to place in the gRPC HealthCheckRequest +(see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). +If this is not specified, the default behavior is defined by gRPC.`, + }, + }, + }, + }, "http_get": { Type: schema.TypeList, Optional: true, @@ -1649,6 +1696,8 @@ func flattenCloudRunV2ServiceTemplateContainersLivenessProbe(v interface{}, d *s flattenCloudRunV2ServiceTemplateContainersLivenessProbeHttpGet(original["httpGet"], d, config) transformed["tcp_socket"] = flattenCloudRunV2ServiceTemplateContainersLivenessProbeTcpSocket(original["tcpSocket"], d, config) + transformed["grpc"] = + flattenCloudRunV2ServiceTemplateContainersLivenessProbeGrpc(original["grpc"], d, config) return []interface{}{transformed} } func flattenCloudRunV2ServiceTemplateContainersLivenessProbeInitialDelaySeconds(v interface{}, d *schema.ResourceData, config *Config) interface{} { @@ -1789,6 +1838,39 @@ func flattenCloudRunV2ServiceTemplateContainersLivenessProbeTcpSocketPort(v inte return v // let terraform core handle it otherwise } +func flattenCloudRunV2ServiceTemplateContainersLivenessProbeGrpc(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + transformed := make(map[string]interface{}) + transformed["port"] = + flattenCloudRunV2ServiceTemplateContainersLivenessProbeGrpcPort(original["port"], d, config) + transformed["service"] = + flattenCloudRunV2ServiceTemplateContainersLivenessProbeGrpcService(original["service"], d, config) + return []interface{}{transformed} +} +func flattenCloudRunV2ServiceTemplateContainersLivenessProbeGrpcPort(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := stringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenCloudRunV2ServiceTemplateContainersLivenessProbeGrpcService(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func flattenCloudRunV2ServiceTemplateContainersStartupProbe(v interface{}, d *schema.ResourceData, config *Config) interface{} { if v == nil { return nil @@ -1810,6 +1892,8 @@ func flattenCloudRunV2ServiceTemplateContainersStartupProbe(v interface{}, d *sc flattenCloudRunV2ServiceTemplateContainersStartupProbeHttpGet(original["httpGet"], d, config) transformed["tcp_socket"] = flattenCloudRunV2ServiceTemplateContainersStartupProbeTcpSocket(original["tcpSocket"], d, config) + transformed["grpc"] = + flattenCloudRunV2ServiceTemplateContainersStartupProbeGrpc(original["grpc"], d, config) return []interface{}{transformed} } func flattenCloudRunV2ServiceTemplateContainersStartupProbeInitialDelaySeconds(v interface{}, d *schema.ResourceData, config *Config) interface{} { @@ -1950,6 +2034,39 @@ func flattenCloudRunV2ServiceTemplateContainersStartupProbeTcpSocketPort(v inter return v // let terraform core handle it otherwise } +func flattenCloudRunV2ServiceTemplateContainersStartupProbeGrpc(v interface{}, d *schema.ResourceData, config *Config) interface{} { + if v == nil { + return nil + } + original := v.(map[string]interface{}) + transformed := make(map[string]interface{}) + transformed["port"] = + flattenCloudRunV2ServiceTemplateContainersStartupProbeGrpcPort(original["port"], d, config) + transformed["service"] = + flattenCloudRunV2ServiceTemplateContainersStartupProbeGrpcService(original["service"], d, config) + return []interface{}{transformed} +} +func flattenCloudRunV2ServiceTemplateContainersStartupProbeGrpcPort(v interface{}, d *schema.ResourceData, config *Config) interface{} { + // Handles the string fixed64 format + if strVal, ok := v.(string); ok { + if intVal, err := stringToFixed64(strVal); err == nil { + return intVal + } + } + + // number values are represented as float64 + if floatVal, ok := v.(float64); ok { + intVal := int(floatVal) + return intVal + } + + return v // let terraform core handle it otherwise +} + +func flattenCloudRunV2ServiceTemplateContainersStartupProbeGrpcService(v interface{}, d *schema.ResourceData, config *Config) interface{} { + return v +} + func flattenCloudRunV2ServiceTemplateVolumes(v interface{}, d *schema.ResourceData, config *Config) interface{} { if v == nil { return v @@ -2993,6 +3110,13 @@ func expandCloudRunV2ServiceTemplateContainersLivenessProbe(v interface{}, d Ter transformed["tcpSocket"] = transformedTcpSocket } + transformedGrpc, err := expandCloudRunV2ServiceTemplateContainersLivenessProbeGrpc(original["grpc"], d, config) + if err != nil { + return nil, err + } else { + transformed["grpc"] = transformedGrpc + } + return transformed, nil } @@ -3112,6 +3236,45 @@ func expandCloudRunV2ServiceTemplateContainersLivenessProbeTcpSocketPort(v inter return v, nil } +func expandCloudRunV2ServiceTemplateContainersLivenessProbeGrpc(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 { + return nil, nil + } + + if l[0] == nil { + transformed := make(map[string]interface{}) + return transformed, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedPort, err := expandCloudRunV2ServiceTemplateContainersLivenessProbeGrpcPort(original["port"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPort); val.IsValid() && !isEmptyValue(val) { + transformed["port"] = transformedPort + } + + transformedService, err := expandCloudRunV2ServiceTemplateContainersLivenessProbeGrpcService(original["service"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedService); val.IsValid() && !isEmptyValue(val) { + transformed["service"] = transformedService + } + + return transformed, nil +} + +func expandCloudRunV2ServiceTemplateContainersLivenessProbeGrpcPort(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudRunV2ServiceTemplateContainersLivenessProbeGrpcService(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandCloudRunV2ServiceTemplateContainersStartupProbe(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { l := v.([]interface{}) if len(l) == 0 || l[0] == nil { @@ -3163,6 +3326,13 @@ func expandCloudRunV2ServiceTemplateContainersStartupProbe(v interface{}, d Terr transformed["tcpSocket"] = transformedTcpSocket } + transformedGrpc, err := expandCloudRunV2ServiceTemplateContainersStartupProbeGrpc(original["grpc"], d, config) + if err != nil { + return nil, err + } else { + transformed["grpc"] = transformedGrpc + } + return transformed, nil } @@ -3282,6 +3452,45 @@ func expandCloudRunV2ServiceTemplateContainersStartupProbeTcpSocketPort(v interf return v, nil } +func expandCloudRunV2ServiceTemplateContainersStartupProbeGrpc(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + l := v.([]interface{}) + if len(l) == 0 { + return nil, nil + } + + if l[0] == nil { + transformed := make(map[string]interface{}) + return transformed, nil + } + raw := l[0] + original := raw.(map[string]interface{}) + transformed := make(map[string]interface{}) + + transformedPort, err := expandCloudRunV2ServiceTemplateContainersStartupProbeGrpcPort(original["port"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedPort); val.IsValid() && !isEmptyValue(val) { + transformed["port"] = transformedPort + } + + transformedService, err := expandCloudRunV2ServiceTemplateContainersStartupProbeGrpcService(original["service"], d, config) + if err != nil { + return nil, err + } else if val := reflect.ValueOf(transformedService); val.IsValid() && !isEmptyValue(val) { + transformed["service"] = transformedService + } + + return transformed, nil +} + +func expandCloudRunV2ServiceTemplateContainersStartupProbeGrpcPort(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + +func expandCloudRunV2ServiceTemplateContainersStartupProbeGrpcService(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { + return v, nil +} + func expandCloudRunV2ServiceTemplateVolumes(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) { l := v.([]interface{}) req := make([]interface{}, 0, len(l)) diff --git a/google/resource_cloud_run_v2_service_test.go b/google/resource_cloud_run_v2_service_test.go index 24633dadd42..4241fcf27fe 100644 --- a/google/resource_cloud_run_v2_service_test.go +++ b/google/resource_cloud_run_v2_service_test.go @@ -1,7 +1,10 @@ package google import ( + "fmt" + "regexp" "testing" + "time" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" ) @@ -199,7 +202,7 @@ resource "google_compute_network" "custom_test" { `, context) } -func TestAccCloudRunV2Service_cloudrunv2ServiceProbesUpdate(t *testing.T) { +func TestAccCloudRunV2Service_cloudrunv2ServiceTCPProbesUpdate(t *testing.T) { t.Parallel() context := map[string]interface{}{ @@ -229,6 +232,22 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceProbesUpdate(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIgnore: []string{"name", "location"}, }, + }, + }) +} + +func TestAccCloudRunV2Service_cloudrunv2ServiceHTTPProbesUpdate(t *testing.T) { + t.Parallel() + + context := map[string]interface{}{ + "random_suffix": randString(t, 10), + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudRunV2ServiceDestroyProducer(t), + Steps: []resource.TestStep{ { Config: testAccCloudRunV2Service_cloudrunv2ServiceUpdateWithEmptyHTTPStartupProbe(context), }, @@ -251,12 +270,89 @@ func TestAccCloudRunV2Service_cloudrunv2ServiceProbesUpdate(t *testing.T) { }) } +func TestAccCloudRunV2Service_cloudrunv2ServiceGRPCProbesUpdate(t *testing.T) { + t.Parallel() + + serviceName := fmt.Sprintf("tf-test-cloudrun-service%s", randString(t, 10)) + context := map[string]interface{}{ + "service_name": serviceName, + } + + vcrTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckCloudRunV2ServiceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccCloudRunV2Service_cloudRunServiceUpdateWithEmptyGRPCLivenessProbe(context), + }, + { + ResourceName: "google_cloud_run_v2_service.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "location"}, + }, + { + Config: testAccCloudRunV2Service_cloudRunServiceUpdateWithGRPCLivenessProbe(context), + }, + { + ResourceName: "google_cloud_run_v2_service.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "location"}, + }, + // The following test steps of gRPC startup probe are expected to fail with startup probe check failures. + // This is because, due to the unavailability of ready-to-use container images of a gRPC service that + // implements the standard gRPC health check protocol, we compromise and use a container image of an + // ordinary HTTP service to deploy the gRPC service, which never passes startup probes. + // So we only check that the `startup.grpc {}` block and its properties are accepted by the APIs. + { + Config: testAccCloudRunV2Service_cloudRunServiceUpdateWithEmptyGRPCStartupProbe(context), + ExpectError: regexp.MustCompile(fmt.Sprintf(`Revision '%s-.*' is not ready and cannot serve traffic\. The user-provided container failed the configured startup probe checks\.`, serviceName)), + }, + { + PreConfig: testAccCheckCloudRunV2ServiceDestroyByNameProducer(t, serviceName), + Config: testAccCloudRunV2Service_cloudRunServiceUpdateWithGRPCStartupProbe(context), + ExpectError: regexp.MustCompile(fmt.Sprintf(`Revision '%s-.*' is not ready and cannot serve traffic\. The user-provided container failed the configured startup probe checks\.`, serviceName)), + }, + { + PreConfig: testAccCheckCloudRunV2ServiceDestroyByNameProducer(t, serviceName), + Config: testAccCloudRunV2Service_cloudRunServiceUpdateWithGRPCLivenessAndStartupProbes(context), + ExpectError: regexp.MustCompile(fmt.Sprintf(`Revision '%s-.*' is not ready and cannot serve traffic\. The user-provided container failed the configured startup probe checks\.`, serviceName)), + }, + { + PreConfig: testAccCheckCloudRunV2ServiceDestroyByNameProducer(t, serviceName), + Config: testAccCloudRunV2Service_cloudRunServiceUpdateWithGRPCLivenessAndStartupProbes(context), + PlanOnly: true, + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckCloudRunV2ServiceDestroyByNameProducer(t *testing.T, serviceName string) func() { + return func() { + config := googleProviderConfig(t) + service := config.NewCloudRunV2Client(config.userAgent).Projects.Locations.Services + qualifiedServiceName := fmt.Sprintf("projects/%s/locations/%s/services/%s", config.Project, config.Region, serviceName) + op, err := service.Delete(qualifiedServiceName).Do() + if err != nil { + t.Errorf("Error while deleting the Cloud Run service: %s", err) + return + } + err = runAdminV2OperationWaitTime(config, op, config.Project, "Waiting for Cloud Run service to be deleted", config.userAgent, 5*time.Minute) + if err != nil { + t.Errorf("Error while waiting for Cloud Run service delete operation to complete: %s", err.Error()) + } + } +} + func testAccCloudRunV2Service_cloudrunv2ServiceWithEmptyTCPStartupProbeAndHTTPLivenessProbe(context map[string]interface{}) string { return Nprintf(` resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" - + template { containers { image = "us-docker.pkg.dev/cloudrun/container/hello" @@ -280,7 +376,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceUpdateWithTCPStartupProbeAndHTTPL resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" - + template { containers { image = "us-docker.pkg.dev/cloudrun/container/hello" @@ -323,7 +419,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceUpdateWithEmptyHTTPStartupProbe(c resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" - + template { containers { image = "us-docker.pkg.dev/cloudrun/container/hello" @@ -341,7 +437,7 @@ func testAccCloudRunV2Service_cloudrunv2ServiceUpdateWithHTTPStartupProbe(contex resource "google_cloud_run_v2_service" "default" { name = "tf-test-cloudrun-service%{random_suffix}" location = "us-central1" - + template { containers { image = "us-docker.pkg.dev/cloudrun/container/hello" @@ -366,3 +462,123 @@ resource "google_cloud_run_v2_service" "default" { } `, context) } + +func testAccCloudRunV2Service_cloudRunServiceUpdateWithEmptyGRPCLivenessProbe(context map[string]interface{}) string { + return Nprintf(` +resource "google_cloud_run_v2_service" "default" { + name ="%{service_name}" + location = "us-central1" + + template { + containers { + image = "us-docker.pkg.dev/cloudrun/container/hello" + ports { + container_port = 8080 + } + liveness_probe { + grpc {} + } + } + } +} +`, context) +} + +func testAccCloudRunV2Service_cloudRunServiceUpdateWithGRPCLivenessProbe(context map[string]interface{}) string { + return Nprintf(` +resource "google_cloud_run_v2_service" "default" { + name = "%{service_name}" + location = "us-central1" + + template { + containers { + image = "us-docker.pkg.dev/cloudrun/container/hello" + ports { + container_port = 8080 + } + liveness_probe { + grpc { + port = 8080 + service = "grpc.health.v1.Health" + } + } + } + } +} +`, context) +} + +func testAccCloudRunV2Service_cloudRunServiceUpdateWithEmptyGRPCStartupProbe(context map[string]interface{}) string { + return Nprintf(` +resource "google_cloud_run_v2_service" "default" { + name = "%{service_name}" + location = "us-central1" + + template { + containers { + image = "us-docker.pkg.dev/cloudrun/container/hello" + ports { + container_port = 8080 + } + startup_probe { + grpc {} + } + } + } +} +`, context) +} + +func testAccCloudRunV2Service_cloudRunServiceUpdateWithGRPCStartupProbe(context map[string]interface{}) string { + return Nprintf(` +resource "google_cloud_run_v2_service" "default" { + name = "%{service_name}" + location = "us-central1" + + template { + containers { + image = "us-docker.pkg.dev/cloudrun/container/hello" + ports { + container_port = 8080 + } + startup_probe { + grpc { + port = 8080 + service = "grpc.health.v1.Health" + } + } + } + } +} +`, context) +} + +func testAccCloudRunV2Service_cloudRunServiceUpdateWithGRPCLivenessAndStartupProbes(context map[string]interface{}) string { + return Nprintf(` +resource "google_cloud_run_v2_service" "default" { + name = "%{service_name}" + location = "us-central1" + + template { + containers { + image = "us-docker.pkg.dev/cloudrun/container/hello" + ports { + container_port = 8080 + } + liveness_probe { + grpc { + port = 8080 + service = "grpc.health.v1.Health" + } + } + startup_probe { + grpc { + port = 8080 + service = "grpc.health.v1.Health" + } + } + } + } +} +`, context) +} diff --git a/google/runadminv3_operation.go b/google/runadminv3_operation.go new file mode 100644 index 00000000000..bf540c11c8c --- /dev/null +++ b/google/runadminv3_operation.go @@ -0,0 +1,59 @@ +package google + +import ( + "encoding/json" + "fmt" + "time" + + "google.golang.org/api/run/v2" +) + +type RunAdminV2OperationWaiter struct { + Config *Config + UserAgent string + Project string + CommonOperationWaiter +} + +func (w *RunAdminV2OperationWaiter) QueryOp() (interface{}, error) { + if w == nil { + return nil, fmt.Errorf("Cannot query operation, it's unset or nil.") + } + url := fmt.Sprintf("%s%s", w.Config.CloudRunV2BasePath, w.CommonOperationWaiter.Op.Name) + + return sendRequest(w.Config, "GET", w.Project, url, w.UserAgent, nil) +} + +func createRunAdminV2Waiter(config *Config, op *run.GoogleLongrunningOperation, project, activity, userAgent string) (*RunAdminV2OperationWaiter, error) { + w := &RunAdminV2OperationWaiter{ + Config: config, + UserAgent: userAgent, + Project: project, + } + if err := w.CommonOperationWaiter.SetOp(op); err != nil { + return nil, err + } + return w, nil +} + +func runAdminV2OperationWaitTimeWithResponse(config *Config, op *run.GoogleLongrunningOperation, response *map[string]interface{}, project, activity, userAgent string, timeout time.Duration) error { + w, err := createRunAdminV2Waiter(config, op, project, activity, userAgent) + if err != nil { + return err + } + if err := OperationWait(w, activity, timeout, config.PollInterval); err != nil { + return err + } + return json.Unmarshal([]byte(w.CommonOperationWaiter.Op.Response), response) +} + +func runAdminV2OperationWaitTime(config *Config, op *run.GoogleLongrunningOperation, project, activity, userAgent string, timeout time.Duration) error { + if op.Done { + return nil + } + w, err := createRunAdminV2Waiter(config, op, project, activity, userAgent) + if err != nil { + return err + } + return OperationWait(w, activity, timeout, config.PollInterval) +} diff --git a/website/docs/r/cloud_run_v2_service.html.markdown b/website/docs/r/cloud_run_v2_service.html.markdown index 3bc5597bc82..c6a2fa4ce4c 100644 --- a/website/docs/r/cloud_run_v2_service.html.markdown +++ b/website/docs/r/cloud_run_v2_service.html.markdown @@ -517,6 +517,11 @@ The following arguments are supported: TCPSocket specifies an action involving a TCP port. This field is not supported in liveness probe currently. Structure is [documented below](#nested_tcp_socket). +* `grpc` - + (Optional) + GRPC specifies an action involving a GRPC port. + Structure is [documented below](#nested_grpc). + The `http_get` block supports: @@ -546,6 +551,18 @@ The following arguments are supported: (Optional) Port number to access on the container. Must be in the range 1 to 65535. If not specified, defaults to 8080. +The `grpc` block supports: + +* `port` - + (Optional) + Port number to access on the container. Number must be in the range 1 to 65535. If not specified, defaults to the same value as container.ports[0].containerPort. + +* `service` - + (Optional) + The name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + If this is not specified, the default behavior is defined by gRPC. + The `startup_probe` block supports: * `initial_delay_seconds` - @@ -574,6 +591,11 @@ The following arguments are supported: TCPSocket specifies an action involving a TCP port. Exactly one of HTTPGet or TCPSocket must be specified. Structure is [documented below](#nested_tcp_socket). +* `grpc` - + (Optional) + GRPC specifies an action involving a GRPC port. + Structure is [documented below](#nested_grpc). + The `http_get` block supports: @@ -603,6 +625,18 @@ The following arguments are supported: (Optional) Port number to access on the container. Must be in the range 1 to 65535. If not specified, defaults to 8080. +The `grpc` block supports: + +* `port` - + (Optional) + Port number to access on the container. Number must be in the range 1 to 65535. If not specified, defaults to the same value as container.ports[0].containerPort. + +* `service` - + (Optional) + The name of the service to place in the gRPC HealthCheckRequest + (see https://github.com/grpc/grpc/blob/master/doc/health-checking.md). + If this is not specified, the default behavior is defined by gRPC. + The `volumes` block supports: * `name` -