-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
add app engine flex version #3110
Conversation
a823e69
to
e47f880
Compare
Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are. Diff report:Terraform GA: Diff ( 7 files changed, 4795 insertions(+), 7 deletions(-)) |
|
||
func init() { | ||
resource.AddTestSweepers("AppEngineFlexibleAppVersion", &resource.Sweeper{ | ||
Name: "AppEngineFlexibleAppVersion", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This sweeper should sweep Standard/Flexible indiscriminately right? Might be worth renaming to reflect that. Mostly so I don't forget and add a sweeper for standard in the future...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just looked at the sweeper for now
// Setup variables to replace in list template | ||
d := &ResourceDataMock{ | ||
FieldsInSchema: map[string]interface{}{ | ||
"project": config.Project, | ||
"region": region, | ||
"location": region, | ||
"zone": "-", | ||
}, | ||
} | ||
|
||
listTemplate := strings.Split("https://appengine.googleapis.com/v1/apps/{{project}}/services", "?")[0] | ||
listUrl, err := replaceVars(d, config, listTemplate) | ||
if err != nil { | ||
log.Printf("[INFO][SWEEPER_LOG] error preparing sweeper list url: %s", err) | ||
return nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These lines are in the sweeper template because the we won't know what the URL will look like until generation. Fortunately we with a handwritten sweeper we can just replace these lines with:
listUrl := "https://appengine.googleapis.com/v1/apps/" + config.Project + "/services"
for _, ri := range rl { | ||
obj := ri.(map[string]interface{}) | ||
if obj["id"] == nil { | ||
log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is on my TODO list to handle id's in the sweeper generation, so resources like these would be covered. For now, I think it is important to keep the distinction between id & name, especially since both are present in the api.yaml
log.Printf("[INFO][SWEEPER_LOG] %s resource name was nil", resourceName) | |
log.Printf("[INFO][SWEEPER_LOG] %s resource id was nil", resourceName) |
return nil | ||
} | ||
|
||
name := GetResourceNameFromSelfLink(obj["id"].(string)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
id is all we need
name := GetResourceNameFromSelfLink(obj["id"].(string)) | |
id := obj["id"].(string) |
|
||
name := GetResourceNameFromSelfLink(obj["id"].(string)) | ||
// Only sweep resources with the test prefix | ||
if !strings.HasPrefix(name, "tf-test") { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if !strings.HasPrefix(name, "tf-test") { | |
if !strings.HasPrefix(id, "tf-test") { |
deleteTemplate := "https://appengine.googleapis.com/v1/apps/{{project}}/services/{{service}}" | ||
deleteUrl, err := replaceVars(d, config, deleteTemplate) | ||
if err != nil { | ||
log.Printf("[INFO][SWEEPER_LOG] error preparing delete url: %s", err) | ||
return nil | ||
} | ||
deleteUrl = deleteUrl + name |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See: my explanation on the list URL code.
We can replace these lines with:
deleteUrl := "https://appengine.googleapis.com/v1/apps/" + config.Project + "/services/" + id
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, d.Get("service")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, d.Get("service")) | |
log.Printf("[INFO][SWEEPER_LOG] Sent delete request for %s resource: %s", resourceName, id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a Big resource (capital B) so I can't promise much more than spot checking some of the fields to see if they make sense. But I have some overall thoughts as well:
It appears to be a true superset of the StandardAppVersion
resource and they share the same endpoints. It is probably good to add a comment in the api.yaml indicating the relationship as I imagine that any bug fix on one resource will need to be added to the other. This is effectively "cross linking" the resources for developers, but should also be done in the public docs as well.
The surface area of this resource is huge, but you only have a single test. I would add a couple more testable examples, as this will improve test coverage and also help our users figure out how it should be used. For example handlers
appears to be the most important field of the resource and there's no go example of how to use it. Also there should be some hand written update tests otherwise the update method is completely untested. Extra tests will be extra important with large resources like this as reviewers are unlikely to catch the small stuff like fields that should be required or defaulted.
products/appengine/api.yaml
Outdated
- !ruby/object:Api::Resource | ||
name: 'FlexibleAppVersion' | ||
description: | | ||
Flexible App Version resource to create a new version of flexible GAE Application. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's worth explaining how this resource is different from the standard app engine resource and cross linking the other resource in the doc will go a long way to helping users find the right one. Linking to https://cloud.google.com/appengine/docs/the-appengine-environments would be a good call.
products/appengine/api.yaml
Outdated
collection_url_key: 'versions' | ||
base_url: 'apps/{{project}}/services/{{service}}/versions' | ||
delete_url: 'apps/{{project}}/services/{{service}}/versions/{{version_id}}' | ||
delete_verb: :DELETE |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't this the default already?
products/appengine/api.yaml
Outdated
references: !ruby/object:Api::Resource::ReferenceLinks | ||
guides: | ||
'Official Documentation': | ||
'https://cloud.google.com/appengine/docs/admin-api/deploying-overview' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if this is the most helpful "overview" link. This appears to be more about the admin api and less about the resource at large. Would https://cloud.google.com/appengine/docs/flexible be more appropriate?
products/appengine/terraform.yaml
Outdated
default_from_api: true | ||
betaSettings: !ruby/object:Overrides::Terraform::PropertyOverride | ||
default_from_api: true | ||
livenessCheck: !ruby/object:Overrides::Terraform::PropertyOverride |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious if both livenessCheck
and readinessCheck
need to be defaulted from the API. Since they are set to at_least_one_of
1 will always be defined in the config, are you seeing default values coming back from the non-defined field? Is this something where we could just ignore what was coming back from the API for the non-intended block instead of marking them both computed?
Optional/Computed doesn't always work the same way for all fields so I personally try to avoid it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, there are default values coming back. I will just set the defaults in api.yaml
, which might be a better option.
default_from_api: true | ||
automaticScaling.maxConcurrentRequests: !ruby/object:Overrides::Terraform::PropertyOverride | ||
default_from_api: true | ||
betaSettings: !ruby/object:Overrides::Terraform::PropertyOverride |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
products/appengine/api.yaml
Outdated
description: | | ||
Security (HTTPS) enforcement for this URL. | ||
values: | ||
- :SECURE_UNSPECIFIED |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A lot of these enums have a 0 value (default value) of SOMETHING_UNSPECIFIED
. But the API almost always rejects a request that contains one of these values. AFAIK it's primarily used for internal error handling of uninitialized objects. 99% of the time we should not expose these values to Terraform users.
products/appengine/api.yaml
Outdated
- :REDIRECT_HTTP_RESPONSE_CODE_307 | ||
- !ruby/object:Api::Type::NestedObject | ||
name: 'script' | ||
# TODO (mbang): Exactly one of script, staticFiles, or apiEndpoint must be set |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently ExactlyOneOf
won't' work for arrays (or fields whose parent's are arrays). We're hoping to eventually make that possible, so I added this in places where I want to update when we have that ability.
products/appengine/api.yaml
Outdated
- !ruby/object:Api::Type::Enum | ||
name: 'redirectHttpResponseCode' | ||
description: | | ||
Redirect codes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a user supplied value? If yes is there a better description of how it should be used?
products/appengine/api.yaml
Outdated
- !ruby/object:Api::Type::NestedObject | ||
name: 'vpcAccessConnector' | ||
description: | | ||
The entrypoint for the application. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copy/pasted from entrypoint?
products/appengine/terraform.yaml
Outdated
threadsafe: !ruby/object:Overrides::Terraform::PropertyOverride | ||
ignore_read: true | ||
instanceClass: !ruby/object:Overrides::Terraform::PropertyOverride | ||
ignore_read: true |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels like a lot of ignore read values. Some like deployment
make more sense to not care about, but instanceClass
seems like something Terraform would want to correct. Adding something to the description to indicate that upstream changes are ignored might be helpful for some of them if there is a reason that's not super intuitive. For Terraform specific behavior like this you can override description
here in the terraform.yaml
.
059c0b4
to
27e7aa7
Compare
Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are. Diff report:Terraform GA: Diff ( 10 files changed, 4016 insertions(+), 14 deletions(-)) |
I ended up removing a few fields - I'm super confused, and hope that's fine, just going to note them here:
I also wrote an update test, but it failed due to 27e7aa7#r382746058 so I took it out and we can decide maybe decide how to handle that? |
@megan07 Thank you very much for picking this up, I was going to start working on it. I will keep watch on this. If you need help let me know. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you elaborate on why the update test was failing? I can't tell from the linked commit.
default_from_api: true | ||
automaticScaling.maxConcurrentRequests: !ruby/object:Overrides::Terraform::PropertyOverride | ||
default_from_api: true | ||
betaSettings: !ruby/object:Overrides::Terraform::PropertyOverride |
There was a problem hiding this comment.
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.
resource "google_storage_bucket_object" "object" { | ||
name = "hello-world-django.zip" | ||
bucket = google_storage_bucket.bucket.name | ||
source = "./test-fixtures/appengine/hello-world-django.zip" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this have to be a zip file? I would prefer adding this as a file or folder so that git can do file by file diffs, especially if this ever needs updating.
27e7aa7
to
a3e18ed
Compare
Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are. Diff report:Terraform GA: Diff ( 10 files changed, 4016 insertions(+), 14 deletions(-)) |
Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are. Diff report:Terraform GA: Diff ( 13 files changed, 4086 insertions(+), 14 deletions(-)) |
Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are. Diff report:Terraform GA: Diff ( 13 files changed, 4099 insertions(+), 14 deletions(-)) |
Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are. Diff report:Terraform GA: Diff ( 12 files changed, 4099 insertions(+), 14 deletions(-)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All my comments are test related at this point, nothing critical.
entrypoint: !ruby/object:Overrides::Terraform::PropertyOverride | ||
ignore_read: true | ||
envVariables: !ruby/object:Overrides::Terraform::PropertyOverride | ||
ignore_read: true |
There was a problem hiding this comment.
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.
} | ||
|
||
liveness_check { | ||
path = "" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be nice to have more of these fields being updated if possible. Especially anything where the empty case makes sense. ie: if it makes sense to set a liveness_check.path and then remove it later by passing an empty string it should be set in the initial create and then empty string in a second update.
delete_service_on_destroy = true | ||
} | ||
|
||
resource "google_app_engine_flexible_app_version" "myflexapp_v2" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I have a slight preference for these to be 2 different example blocks instead of 2 app_versions in a single example. If possible I like to have each example be a single use case so that the example can have a title block like "NodeJs Example with scaling" and a user doesn't have to parse both whole resource blocks to understand the difference between the two. As pointed out by a user aws s3 bucket does a better job of this than many of our resources.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm totally fine with that, I copied this from the standard app (again), and it appears both versions are the same. I'm guessing the example of it was just having 2 versions to the same service? But if that doesn't seem like a great thing to show in an example, I'm happy to remove v2.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only difference I saw was noop_on_destroy = true
vs delete_service_on_destroy = true
which doesn't seem like it's worth all of the wasted real estate on the docs page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sweeper looks good to me
Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are. Diff report:Terraform GA: Diff ( 12 files changed, 4117 insertions(+), 14 deletions(-)) |
* added flexible app version * add sweeper file for flexible_app_version * sweeper changes, add website link, etc * add exclude to inspec.yaml * add exclude to ansible.yaml * missed * sweeper review comments * add test, other changes * update test to flask, ignore read on beta_settings for now * add copyright to app.yaml * rm django zip * update after review comments
Added flexible app version resource.
Fixes hashicorp/terraform-provider-google#5025
This uses the same API as
google_app_engine_standard_app_version
, but they have different schemas (some fields are flex-only, etc) so we have decided to split them into two different resources.Release Note Template for Downstream PRs (will be copied)