From fd9235dd9a9148dc2b5e476afd98368f133002e1 Mon Sep 17 00:00:00 2001 From: Dan Vogel Date: Wed, 19 Aug 2020 10:54:54 -0700 Subject: [PATCH] Add vpcAccessConnector property on google_app_engine_standard_app_version terraform resource (#3789) * add vpc access connector property in standard app version resource * add Gemfile.lock and .ruby-version * modify .ruby-version * Update Gemfile.lock * Update Gemfile.lock * Update Gemfile.lock * add test for vpcAccessConnector field * change casing of test field * add comma * format app engine connector test * make vpc_access_connector an object * add vpc access connector resource to test * pass connector id output property to app engine resource instead of hardcoding connector id --- products/appengine/api.yaml | 18 ++- ...ce_app_engine_standard_app_version_test.go | 117 ++++++++++++++++++ 2 files changed, 131 insertions(+), 4 deletions(-) diff --git a/products/appengine/api.yaml b/products/appengine/api.yaml index 5bb077aaae9a..95ab6e3eecc3 100644 --- a/products/appengine/api.yaml +++ b/products/appengine/api.yaml @@ -186,7 +186,7 @@ objects: name: 'Service' description: | A Service resource is a logical component of an application that can share state and communicate in a secure fashion with other services. - For example, an application that handles customer requests might include separate services to handle tasks such as backend data analysis or API requests from mobile devices. + For example, an application that handles customer requests might include separate services to handle tasks such as backend data analysis or API requests from mobile devices. Each service has a collection of versions that define a specific set of code used to implement the functionality of that service. base_url: 'apps/{{project}}/services' self_link: 'apps/{{project}}/services/{{id}}' @@ -269,7 +269,7 @@ objects: name: 'id' input: true description: | - Relative name of the version within the service. For example, `v1`. Version names can contain only lowercase letters, numbers, or hyphens. Reserved names,"default", "latest", and any name with the prefix "ah-". + Relative name of the version within the service. For example, `v1`. Version names can contain only lowercase letters, numbers, or hyphens. Reserved names,"default", "latest", and any name with the prefix "ah-". - !ruby/object:Api::Type::String name: 'runtime' description: | @@ -458,6 +458,16 @@ objects: required: true description: | The format should be a shell command that can be fed to bash -c. + - !ruby/object:Api::Type::NestedObject + name: 'vpcAccessConnector' + description: | + Enables VPC connectivity for standard apps. + properties: + - !ruby/object:Api::Type::String + name: 'name' + required: true + description: | + Full Serverless VPC Access Connector name e.g. /projects/my-project/locations/us-central1/connectors/c1. - !ruby/object:Api::Type::Array name: 'inboundServices' description: | @@ -568,7 +578,7 @@ objects: description: | Number of instances to assign to the service at the start. - **Note:** When managing the number of instances at runtime through the App Engine Admin API or the (now deprecated) Python 2 + **Note:** When managing the number of instances at runtime through the App Engine Admin API or the (now deprecated) Python 2 Modules API set_num_instances() you must use `lifecycle.ignore_changes = ["manual_scaling"[0].instances]` to prevent drift detection. # StandardAppVersion and FlexibleAppVersion use the same API endpoint (apps.services.versions) @@ -1451,4 +1461,4 @@ objects: name: 'allocations' required: true description: | - Mapping from version IDs within the service to fractional (0.000, 1] allocations of traffic for that version. Each version can be specified only once, but some versions in the service may not have any traffic allocation. Services that have traffic allocated cannot be deleted until either the service is deleted or their traffic allocation is removed. Allocations must sum to 1. Up to two decimal place precision is supported for IP-based splits and up to three decimal places is supported for cookie-based splits. + Mapping from version IDs within the service to fractional (0.000, 1] allocations of traffic for that version. Each version can be specified only once, but some versions in the service may not have any traffic allocation. Services that have traffic allocated cannot be deleted until either the service is deleted or their traffic allocation is removed. Allocations must sum to 1. Up to two decimal place precision is supported for IP-based splits and up to three decimal places is supported for cookie-based splits. diff --git a/third_party/terraform/tests/resource_app_engine_standard_app_version_test.go b/third_party/terraform/tests/resource_app_engine_standard_app_version_test.go index 5f6c099830a2..01e8312cb49a 100644 --- a/third_party/terraform/tests/resource_app_engine_standard_app_version_test.go +++ b/third_party/terraform/tests/resource_app_engine_standard_app_version_test.go @@ -37,6 +37,15 @@ func TestAccAppEngineStandardAppVersion_update(t *testing.T) { ImportStateVerify: true, ImportStateVerifyIgnore: []string{"env_variables", "deployment", "entrypoint", "service", "noop_on_destroy"}, }, + { + Config: testAccAppEngineStandardAppVersion_vpcAccessConnector(context), + }, + { + ResourceName: "google_app_engine_standard_app_version.foo", + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"env_variables", "deployment", "entrypoint", "service", "noop_on_destroy"}, + }, }, }) } @@ -127,6 +136,114 @@ resource "google_storage_bucket_object" "main" { }`, context) } +func testAccAppEngineStandardAppVersion_vpcAccessConnector(context map[string]interface{}) string { + return Nprintf(` +resource "google_project" "my_project" { + name = "tf-test-appeng-std%{random_suffix}" + project_id = "tf-test-appeng-std%{random_suffix}" + org_id = "%{org_id}" + billing_account = "%{billing_account}" +} + +resource "google_app_engine_application" "app" { + project = google_project.my_project.project_id + location_id = "us-central" +} + +resource "google_project_service" "project" { + project = google_project.my_project.project_id + service = "appengine.googleapis.com" + + disable_dependent_services = false +} + +resource "google_project_service" "vpcaccess_api" { + project = google_project.my_project.project_id + service = "vpcaccess.googleapis.com" + + disable_dependent_services = false +} + +resource "google_vpc_access_connector" "bar" { + depends_on = [ + google_project_service.vpcaccess_api + ] + project = google_project.my_project.project_id + name = "bar" + region = "us-central1" + ip_cidr_range = "10.8.0.0/28" + network = "default" +} + +resource "google_app_engine_standard_app_version" "foo" { + project = google_project_service.project.project + version_id = "v1" + service = "default" + runtime = "python38" + + vpc_access_connector { + name = "${google_vpc_access_connector.bar.id}" + } + + entrypoint { + shell = "gunicorn -b :$PORT main:app" + } + + deployment { + files { + name = "main.py" + source_url = "https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.main.name}" + } + + files { + name = "requirements.txt" + source_url = "https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.requirements.name}" + } + } + + inbound_services = ["INBOUND_SERVICE_WARMUP", "INBOUND_SERVICE_MAIL"] + + env_variables = { + port = "8000" + } + + instance_class = "F2" + + automatic_scaling { + max_concurrent_requests = 10 + min_idle_instances = 1 + max_idle_instances = 3 + min_pending_latency = "1s" + max_pending_latency = "5s" + standard_scheduler_settings { + target_cpu_utilization = 0.5 + target_throughput_utilization = 0.75 + min_instances = 2 + max_instances = 10 + } + } + + noop_on_destroy = true +} + +resource "google_storage_bucket" "bucket" { + project = google_project.my_project.project_id + name = "tf-test-%{random_suffix}-standard-ae-bucket" +} + +resource "google_storage_bucket_object" "requirements" { + name = "requirements.txt" + bucket = google_storage_bucket.bucket.name + source = "./test-fixtures/appengine/hello-world-flask/requirements.txt" +} + +resource "google_storage_bucket_object" "main" { + name = "main.py" + bucket = google_storage_bucket.bucket.name + source = "./test-fixtures/appengine/hello-world-flask/main.py" +}`, context) +} + func testAccAppEngineStandardAppVersion_pythonUpdate(context map[string]interface{}) string { return Nprintf(` resource "google_project" "my_project" {