From c0c09b232b256b72e84ed53db421b2015d7f55ad Mon Sep 17 00:00:00 2001 From: Thomas Shafer Date: Thu, 19 Sep 2024 08:26:41 -0700 Subject: [PATCH] Add support for GPU fields in Cloud Run Service v1 and v2 api (#11597) --- mmv1/products/cloudrun/Service.yaml | 19 ++- mmv1/products/cloudrunv2/Service.yaml | 21 +++- .../examples/cloud_run_service_gpu.tf.erb | 35 ++++++ .../examples/cloudrunv2_service_gpu.tf.erb | 28 +++++ .../resource_cloud_run_service_test.go.erb | 118 +++++++++++++++++ .../resource_cloud_run_v2_service_test.go.erb | 119 ++++++++++++++++++ 6 files changed, 338 insertions(+), 2 deletions(-) create mode 100644 mmv1/templates/terraform/examples/cloud_run_service_gpu.tf.erb create mode 100644 mmv1/templates/terraform/examples/cloudrunv2_service_gpu.tf.erb diff --git a/mmv1/products/cloudrun/Service.yaml b/mmv1/products/cloudrun/Service.yaml index 2a277edcd829..6f5ab65a8770 100644 --- a/mmv1/products/cloudrun/Service.yaml +++ b/mmv1/products/cloudrun/Service.yaml @@ -53,6 +53,17 @@ examples: cloud_run_service_name: 'cloudrun-srv' test_env_vars: project: :PROJECT_NAME + - !ruby/object:Provider::Terraform::Examples + name: 'cloud_run_service_gpu' + min_version: 'beta' + primary_resource_id: 'default' + primary_resource_name: "fmt.Sprintf(\"tf-test-cloudrun-srv%s\", + context[\"random_suffix\"\ + ])" + vars: + cloud_run_service_name: 'cloudrun-srv' + test_env_vars: + project: :PROJECT_NAME - !ruby/object:Provider::Terraform::Examples name: 'cloud_run_service_sql' primary_resource_id: 'default' @@ -743,7 +754,13 @@ properties: 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. - + - !ruby/object:Api::Type::KeyValuePairs + name: nodeSelector + min_version: beta + description: |- + Node Selector describes the hardware requirements of the resources. + Use the following node selector keys to configure features on a Revision: + - `run.googleapis.com/accelerator` sets the [type of GPU](https://cloud.google.com/run/docs/configuring/services/gpu) required by the Revision to run. - !ruby/object:Api::Type::Integer name: containerConcurrency description: |- diff --git a/mmv1/products/cloudrunv2/Service.yaml b/mmv1/products/cloudrunv2/Service.yaml index d6c36d475bbe..f770698be82f 100644 --- a/mmv1/products/cloudrunv2/Service.yaml +++ b/mmv1/products/cloudrunv2/Service.yaml @@ -112,6 +112,15 @@ examples: cloud_run_service_name: 'cloudrun-service' ignore_read_extra: - 'deletion_protection' + - !ruby/object:Provider::Terraform::Examples + name: 'cloudrunv2_service_gpu' + min_version: 'beta' + primary_resource_id: 'default' + primary_resource_name: "fmt.Sprintf(\"tf-test-cloudrun-srv%s\", context[\"random_suffix\"])" + vars: + cloud_run_service_name: 'cloudrun-service' + ignore_read_extra: + - 'deletion_protection' - !ruby/object:Provider::Terraform::Examples name: 'cloudrunv2_service_probes' primary_resource_id: 'default' @@ -498,7 +507,7 @@ properties: - !ruby/object:Api::Type::KeyValuePairs name: 'limits' description: |- - Only memory and CPU are supported. Use key `cpu` for CPU limit and `memory` for memory limit. Note: The only supported values for CPU are '1', '2', '4', and '8'. Setting 4 CPU requires at least 2Gi of memory. The values of the map is string form of the 'quantity' k8s type: https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity.go + Only memory, CPU, and nvidia.com/gpu are supported. Use key `cpu` for CPU limit, `memory` for memory limit, `nvidia.com/gpu` for gpu limit. Note: The only supported values for CPU are '1', '2', '4', and '8'. Setting 4 CPU requires at least 2Gi of memory. The values of the map is string form of the 'quantity' k8s type: https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/apimachinery/pkg/api/resource/quantity.go default_from_api: true - !ruby/object:Api::Type::Boolean name: 'cpuIdle' @@ -899,6 +908,16 @@ properties: name: 'mesh' description: |- The Mesh resource name. For more information see https://cloud.google.com/service-mesh/docs/reference/network-services/rest/v1/projects.locations.meshes#resource:-mesh. + - !ruby/object:Api::Type::NestedObject + name: 'nodeSelector' + min_version: beta + description: Node Selector describes the hardware requirements of the resources. + properties: + - !ruby/object:Api::Type::String + name: 'accelerator' + required: true + description: + The GPU to attach to an instance. See https://cloud.google.com/run/docs/configuring/services/gpu for configuring GPU. - !ruby/object:Api::Type::Array name: 'traffic' description: |- diff --git a/mmv1/templates/terraform/examples/cloud_run_service_gpu.tf.erb b/mmv1/templates/terraform/examples/cloud_run_service_gpu.tf.erb new file mode 100644 index 000000000000..bf1a942b0d97 --- /dev/null +++ b/mmv1/templates/terraform/examples/cloud_run_service_gpu.tf.erb @@ -0,0 +1,35 @@ +resource "google_cloud_run_service" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + name = "<%= ctx[:vars]['cloud_run_service_name'] %>" + location = "us-central1" + + metadata { + annotations = { + "run.googleapis.com/launch-stage" = "BETA" + } + } + + template { + metadata { + annotations = { + "autoscaling.knative.dev/maxScale": "1" + "run.googleapis.com/cpu-throttling": "false" + } + } + spec { + containers { + image = "gcr.io/cloudrun/hello" + resources { + limits = { + "cpu" = "4" + "memory" = "16Gi" + "nvidia.com/gpu" = "1" + } + } + } + node_selector = { + "run.googleapis.com/accelerator" = "nvidia-l4" + } + } + } +} diff --git a/mmv1/templates/terraform/examples/cloudrunv2_service_gpu.tf.erb b/mmv1/templates/terraform/examples/cloudrunv2_service_gpu.tf.erb new file mode 100644 index 000000000000..f0d83e17bd28 --- /dev/null +++ b/mmv1/templates/terraform/examples/cloudrunv2_service_gpu.tf.erb @@ -0,0 +1,28 @@ +resource "google_cloud_run_v2_service" "<%= ctx[:primary_resource_id] %>" { + provider = google-beta + name = "<%= ctx[:vars]['cloud_run_service_name'] %>" + location = "us-central1" + deletion_protection = false + ingress = "INGRESS_TRAFFIC_ALL" + launch_stage = "BETA" + + template { + containers { + image = "us-docker.pkg.dev/cloudrun/container/hello" + resources { + limits = { + "cpu" = "4" + "memory" = "16Gi" + "nvidia.com/gpu" = "1" + } + startup_cpu_boost = true + } + } + node_selector { + accelerator = "nvidia-l4" + } + scaling { + max_instance_count = 1 + } + } +} diff --git a/mmv1/third_party/terraform/services/cloudrun/resource_cloud_run_service_test.go.erb b/mmv1/third_party/terraform/services/cloudrun/resource_cloud_run_service_test.go.erb index dd99e80cb7db..0bf8003f33c9 100644 --- a/mmv1/third_party/terraform/services/cloudrun/resource_cloud_run_service_test.go.erb +++ b/mmv1/third_party/terraform/services/cloudrun/resource_cloud_run_service_test.go.erb @@ -1484,3 +1484,121 @@ resource "google_cloud_run_service" "default" { `, name, project) } <% end -%> + +<% unless version == 'ga' -%> +func TestAccCloudRunService_resourcesRequirements(t *testing.T) { + t.Parallel() + + project := envvar.GetTestProjectFromEnv() + name := "tftest-cloudrun-" + acctest.RandString(t, 6) + + acctest.VcrTest(t, resource.TestCase{ + PreCheck: func() { acctest.AccTestPreCheck(t) }, + ProtoV5ProviderFactories: acctest.ProtoV5ProviderBetaFactories(t), + Steps: []resource.TestStep{ + { + Config: testAccCloudRunV2Service_cloudrunServiceWithoutGpu(name, project), + }, + { + ResourceName: "google_cloud_run_service.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"metadata.0.resource_version", "metadata.0.annotations", "metadata.0.labels", "metadata.0.terraform_labels", "status.0.conditions"}, + }, + { + Config: testAccCloudRunV2Service_cloudrunServiceWithGpu(name, project), + }, + { + ResourceName: "google_cloud_run_service.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"metadata.0.resource_version", "metadata.0.annotations", "metadata.0.labels", "metadata.0.terraform_labels", "status.0.conditions"}, + }, + { + Config: testAccCloudRunV2Service_cloudrunServiceWithoutGpu(name, project), + }, + { + ResourceName: "google_cloud_run_service.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"metadata.0.resource_version", "metadata.0.annotations", "metadata.0.labels", "metadata.0.terraform_labels", "status.0.conditions"}, + }, + }, + }) +} + +func testAccCloudRunV2Service_cloudrunServiceWithoutGpu(name, project string) string { + return fmt.Sprintf(` +resource "google_cloud_run_service" "default" { + provider = google-beta + name = "%s" + location = "us-central1" + + metadata { + namespace = "%s" + } + + template { + metadata { + annotations = { + "autoscaling.knative.dev/maxScale": "1" + "run.googleapis.com/cpu-throttling": "false" + } + } + spec { + containers { + image = "gcr.io/cloudrun/hello" + resources { + limits = { + "cpu" = "4" + "memory" = "16Gi" + } + } + } + } + } +} +`, name, project) +} + +func testAccCloudRunV2Service_cloudrunServiceWithGpu(name, project string) string { + return fmt.Sprintf(` +resource "google_cloud_run_service" "default" { + provider = google-beta + name = "%s" + location = "us-central1" + + metadata { + namespace = "%s" + annotations = { + "run.googleapis.com/launch-stage" = "BETA" + } + } + + template { + metadata { + annotations = { + "autoscaling.knative.dev/maxScale": "1" + "run.googleapis.com/cpu-throttling": "false" + } + } + spec { + containers { + image = "gcr.io/cloudrun/hello" + resources { + limits = { + "cpu" = "4" + "memory" = "16Gi" + "nvidia.com/gpu" = "1" + } + } + } + node_selector = { + "run.googleapis.com/accelerator" = "nvidia-l4" + } + } + } +} +`, name, project) +} +<% end -%> diff --git a/mmv1/third_party/terraform/services/cloudrunv2/resource_cloud_run_v2_service_test.go.erb b/mmv1/third_party/terraform/services/cloudrunv2/resource_cloud_run_v2_service_test.go.erb index 3e5cce0ddfe6..df1791526e4c 100644 --- a/mmv1/third_party/terraform/services/cloudrunv2/resource_cloud_run_v2_service_test.go.erb +++ b/mmv1/third_party/terraform/services/cloudrunv2/resource_cloud_run_v2_service_test.go.erb @@ -1195,3 +1195,122 @@ resource "google_network_services_mesh" "new_mesh" { `, context) } <% end -%> + +<% unless version == 'ga' -%> +func TestAccCloudRunV2Service_cloudrunv2ServiceWithResourcesRequirements(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: testAccCheckCloudRunV2ServiceDestroyProducer(t), + Steps: []resource.TestStep{ + { + Config: testAccCloudRunV2Service_cloudrunv2ServiceWithoutGpu(context), + }, + { + ResourceName: "google_cloud_run_v2_service.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "launch_stage", "deletion_protection"}, + }, + { + Config: testAccCloudRunV2Service_cloudrunv2ServiceWithGpu(context), + }, + { + ResourceName: "google_cloud_run_v2_service.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "launch_stage", "deletion_protection"}, + }, + { + Config: testAccCloudRunV2Service_cloudrunv2ServiceWithoutGpu(context), + }, + { + ResourceName: "google_cloud_run_v2_service.default", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"name", "location", "annotations", "labels", "terraform_labels", "launch_stage", "deletion_protection"}, + }, + }, + }) +} + +func testAccCloudRunV2Service_cloudrunv2ServiceWithoutGpu(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_cloud_run_v2_service" "default" { + name = "tf-test-cloudrun-service%{random_suffix}" + description = "description creating" + location = "us-central1" + deletion_protection = false + launch_stage = "GA" + annotations = { + generated-by = "magic-modules" + } + ingress = "INGRESS_TRAFFIC_ALL" + labels = { + label-1 = "value-1" + } + client = "client-1" + client_version = "client-version-1" + template { + containers { + image = "us-docker.pkg.dev/cloudrun/container/hello" + resources { + limits = { + "cpu" = "4" + "memory" = "16Gi" + } + startup_cpu_boost = true + } + } + scaling { + max_instance_count = 1 + } + } +} +`, context) +} + +func testAccCloudRunV2Service_cloudrunv2ServiceWithGpu(context map[string]interface{}) string { + return acctest.Nprintf(` +resource "google_cloud_run_v2_service" "default" { + name = "tf-test-cloudrun-service%{random_suffix}" + description = "description creating" + location = "us-central1" + deletion_protection = false + launch_stage = "BETA" + annotations = { + generated-by = "magic-modules" + } + ingress = "INGRESS_TRAFFIC_ALL" + labels = { + label-1 = "value-1" + } + client = "client-1" + client_version = "client-version-1" + template { + containers { + image = "us-docker.pkg.dev/cloudrun/container/hello" + resources { + limits = { + "cpu" = "4" + "memory" = "16Gi" + "nvidia.com/gpu" = "1" + } + startup_cpu_boost = true + } + } + node_selector { + accelerator = "nvidia-l4" + } + scaling { + max_instance_count = 1 + } + } +} +`, context) +} +<% end -%>