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

add app engine flex version #3110

Merged
2 changes: 2 additions & 0 deletions products/appengine/ansible.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ overrides: !ruby/object:Overrides::ResourceOverrides
exclude: true
StandardAppVersion: !ruby/object:Overrides::Ansible::ResourceOverride
exclude: true
FlexibleAppVersion: !ruby/object:Overrides::Ansible::ResourceOverride
exclude: true
DomainMapping: !ruby/object:Overrides::Ansible::ResourceOverride
exclude: true
files: !ruby/object:Provider::Config::Files
Expand Down
651 changes: 645 additions & 6 deletions products/appengine/api.yaml

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions products/appengine/inspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ overrides: !ruby/object:Overrides::ResourceOverrides
exclude: true
service: !ruby/object:Overrides::Inspec::PropertyOverride
exclude: true
FlexibleAppVersion: !ruby/object:Overrides::Inspec::ResourceOverride
exclude: true
Service: !ruby/object:Overrides::Inspec::ResourceOverride
exclude: true
ServiceSplitTraffic: !ruby/object:Overrides::Inspec::ResourceOverride
Expand Down
57 changes: 57 additions & 0 deletions products/appengine/terraform.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,63 @@ overrides: !ruby/object:Overrides::ResourceOverrides
service_name: "ae-service"
test_env_vars:
org_id: :ORG_ID
FlexibleAppVersion: !ruby/object:Overrides::Terraform::ResourceOverride
import_format: ["apps/{{project}}/services/{{service}}/versions/{{version_id}}"]
mutex: "apps/{{project}}"
error_retry_predicates: ["isAppEngineRetryableError"]
parameters:
service: !ruby/object:Overrides::Terraform::PropertyOverride
default_from_api: true
required: false
virtual_fields:
- !ruby/object:Provider::Terraform::VirtualFields
name: 'noop_on_destroy'
description: |
If set to `true`, the application version will not be deleted.
- !ruby/object:Provider::Terraform::VirtualFields
name: 'delete_service_on_destroy'
description: |
If set to `true`, the service will be deleted if it is the last version.
custom_code: !ruby/object:Provider::Terraform::CustomCode
custom_delete: templates/terraform/custom_delete/appversion_delete.go.erb
test_check_destroy: templates/terraform/custom_check_destroy/appengine.go.erb
encoder: templates/terraform/encoders/flex_app_version.go.erb
properties:
id: !ruby/object:Overrides::Terraform::PropertyOverride
name: 'version_id'
deployment: !ruby/object:Overrides::Terraform::PropertyOverride
ignore_read: true
entrypoint: !ruby/object:Overrides::Terraform::PropertyOverride
ignore_read: true
envVariables: !ruby/object:Overrides::Terraform::PropertyOverride
description:
Environment variables available to the application. As these are not returned
in the API request, Terraform will not detect any changes made outside of the Terraform config.
ignore_read: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these are things that can be updated by other tools after create you should override the description here indicating that Terraform won't detect drift.

network.subnetworkName: !ruby/object:Overrides::Terraform::PropertyOverride
name: 'subnetwork'
betaSettings: !ruby/object:Overrides::Terraform::PropertyOverride
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are there default betaSettings that come from the api?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, there are, use_deployment_manager, no_appserver_affinity, and has_docker_image that I've seen.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is confusing - those values are returned in the response, but if I do an update (which is just a POST for a new version), it says those values (no_appserver_affinity and use_deployment_manager) aren't allowed to be set in the flexible environment. Which makes me think we should ignore_read these, however, if there aren't conflicts with other fields, we probably want to write them to state.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can it be set by the user at all? If they can't be sent in a Create or Update then I would just remove the field completely. We can always add them back in as fully computed if a user needs this as an output. Growing a resource is much easier than shrinking it.

# https://issuetracker.google.com/issues/150157861
ignore_read: true
# default_from_api: true
# maxConcurrentRequests defaults to a runtime-specific value
automaticScaling.maxConcurrentRequests: !ruby/object:Overrides::Terraform::PropertyOverride
default_from_api: true
# runtimeApiVersion defaults to a runtime-specific value
runtimeApiVersion: !ruby/object:Overrides::Terraform::PropertyOverride
default_from_api: true
examples:
- !ruby/object:Provider::Terraform::Examples
name: "app_engine_flexible_app_version"
primary_resource_id: "myapp_v1"
ignore_read_extra:
- "delete_service_on_destroy"
vars:
project_id: "tf-test-project"
bucket_name: "appengine-static-content"
service_name: "service-"
test_env_vars:
org_id: :ORG_ID
Service: !ruby/object:Overrides::Terraform::ResourceOverride
exclude: true
DomainMapping: !ruby/object:Overrides::Terraform::ResourceOverride
Expand Down
10 changes: 5 additions & 5 deletions templates/terraform/custom_delete/appversion_delete.go.erb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

if d.Get("noop_on_destroy") == true {
log.Printf("[DEBUG] Keeping the StandardAppVersion %q", d.Id())
log.Printf("[DEBUG] Keeping the AppVersion %q", d.Id())
return nil
}
config := meta.(*Config)
Expand Down Expand Up @@ -43,19 +43,19 @@ if d.Get("delete_service_on_destroy") == true {
return err
}
var obj map[string]interface{}
log.Printf("[DEBUG] Deleting StandardAppVersion %q", d.Id())
log.Printf("[DEBUG] Deleting AppVersion %q", d.Id())
res, err := sendRequestWithTimeout(config, "DELETE", project, url, obj, d.Timeout(schema.TimeoutDelete)<%= object.error_retry_predicates ? ", " + object.error_retry_predicates.join(',') : "" -%>)
if err != nil {
return handleNotFoundError(err, d, "StandardAppVersion")
return handleNotFoundError(err, d, "AppVersion")
}
err = appEngineOperationWaitTime(
config, res, project, "Deleting StandardAppVersion",
config, res, project, "Deleting AppVersion",
int(d.Timeout(schema.TimeoutDelete).Minutes()))

if err != nil {
return err
}
log.Printf("[DEBUG] Finished deleting StandardAppVersion %q: %#v", d.Id(), res)
log.Printf("[DEBUG] Finished deleting AppVersion %q: %#v", d.Id(), res)
return nil


Expand Down
2 changes: 2 additions & 0 deletions templates/terraform/encoders/flex_app_version.go.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
obj["env"] = "flex"
return obj, nil
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
resource "google_app_engine_flexible_app_version" "<%= ctx[:primary_resource_id] %>" {
version_id = "v1"
service = "<%= ctx[:vars]['service_name'] %>"
runtime = "nodejs"

entrypoint {
shell = "node ./app.js"
}

deployment {
zip {
source_url = "https://storage.googleapis.com/${google_storage_bucket.bucket.name}/${google_storage_bucket_object.object.name}"
}
}

liveness_check {
path = "/"
}

readiness_check {
path = "/"
}

env_variables = {
port = "8080"
}

automatic_scaling {
cool_down_period = "120s"
cpu_utilization {
target_utilization = 0.5
}
}

delete_service_on_destroy = true
}

resource "google_storage_bucket" "bucket" {
name = "<%= ctx[:vars]['bucket_name'] %>"
}

resource "google_storage_bucket_object" "object" {
name = "hello-world.zip"
bucket = google_storage_bucket.bucket.name
source = "./test-fixtures/appengine/hello-world.zip"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package google

import (
"context"
"log"
"strings"

"github.com/hashicorp/terraform-plugin-sdk/helper/resource"
)

// This will sweep both Standard and Flexible App Engine App Versions
func init() {
resource.AddTestSweepers("AppEngineAppVersion", &resource.Sweeper{
Name: "AppEngineAppVersion",
F: testSweepAppEngineAppVersion,
})
}

// At the time of writing, the CI only passes us-central1 as the region
func testSweepAppEngineAppVersion(region string) error {
resourceName := "AppEngineAppVersion"
log.Printf("[INFO][SWEEPER_LOG] Starting sweeper for %s", resourceName)

config, err := sharedConfigForRegion(region)
if err != nil {
log.Printf("[INFO][SWEEPER_LOG] error getting shared config for region: %s", err)
return err
}

err = config.LoadAndValidate(context.Background())
if err != nil {
log.Printf("[INFO][SWEEPER_LOG] error loading: %s", err)
return err
}

servicesUrl := "https://appengine.googleapis.com/v1/apps/" + config.Project + "/services"
res, err := sendRequest(config, "GET", config.Project, servicesUrl, nil)
if err != nil {
log.Printf("[INFO][SWEEPER_LOG] Error in response from request %s: %s", servicesUrl, err)
return nil
}

resourceList, ok := res["services"]
if !ok {
log.Printf("[INFO][SWEEPER_LOG] Nothing found in response.")
return nil
}

rl := resourceList.([]interface{})

log.Printf("[INFO][SWEEPER_LOG] Found %d items in %s list response.", len(rl), resourceName)
// items who don't match the tf-test prefix
nonPrefixCount := 0
for _, ri := range rl {
obj := ri.(map[string]interface{})
if obj["id"] == nil {
log.Printf("[INFO][SWEEPER_LOG] %s resource id was nil", resourceName)
return nil
}

id := obj["id"].(string)
// Only sweep resources with the test prefix
if !strings.HasPrefix(id, "tf-test") {
nonPrefixCount++
continue
}

deleteUrl := servicesUrl + "/" + id
// Don't wait on operations as we may have a lot to delete
_, err = sendRequest(config, "DELETE", config.Project, deleteUrl, nil)
if err != nil {
log.Printf("[INFO][SWEEPER_LOG] Error deleting for url %s : %s", deleteUrl, err)
} else {
log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, id)
}
}

if nonPrefixCount > 0 {
log.Printf("[INFO][SWEEPER_LOG] %d items without tf_test prefix remain.", nonPrefixCount)
}

return nil
}
Loading