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 conditional validation, allow sending empty capacity scaler for regional backend service #3033

Merged
merged 5 commits into from
Jan 31, 2020

Conversation

emilymye
Copy link
Contributor

@emilymye emilymye commented Jan 28, 2020

Fixes hashicorp/terraform-provider-google#5449

compute: Added conditional requirement of `google_compute_**region**_backend_service` `backend.capacity_scaler` to no longer accept the API default if not INTERNAL. Non-INTERNAL backend services must now specify `capacity_scaler` explicitly and have a total capacity greater than 0. In addition, API default of 1.0 must now be explicitly set and will be treated as nil or zero if not set in config.
compute: Fixed `google_compute_**region**_backend_service` so it no longer has a permadiff if `backend.capacity_scaler` is unset in config by requiring capacity scaler. 
compute: Fixed `backend.capacity_scaler` to actually set zero (0.0) value.

This PR includes a breaking change/bug fix and weird validation because RegionBackendService has a conditional default, and schema.Set cannot tell the difference between nil and zero values for scalars like float/int.

Changes:

  • Adds ability to send empty/zero capacity scaler --> forces capacity scaler to be required when settable (i.e. non-INTERNAL). (added validation)
  • Adds an encoder to throw out fields that can't be sent to the API for INTERNAL requests and validation to make sure INTERNAL backends don't have these values set explicitly

Context

  1. RegionBackendService has typically only allowed for Internal Load Balancing (load_balancing_scheme defaults to INTERNAL), and the API rejects INTERNAL backend requests with specific fields in backend set like capacity_scaler, max_rate, etc

  2. A new INTERNAL_MANAGED lb_scheme allows users to specify fields that were previously managed (unsettable). If not sent in the request, the API returns 1.0 for the value of capacity_scaler. NOTE: This is technically also true for BackendService, but as BackendService cannot be INTERNAL, it will always return 1.0 in the case of nil capacity_scaler so we slapped a default value on and it works fine.

  3. Then, for INTERNAL_MANAGED region backend services: If capacity_scaler is not set in config, the API returns 1.0 --> schema.Set cannot tell capacity_scaler = 0.0 and not-set-capacity-scaler apart --> a diff is detected because of new hash-value of set object, which we can't suppress. d,

We also need to be able to send an empty value if non-INTERNAL, but we can't send the empty value if the RegionBackendService is INTERNAL (default)

FUTURE WORK

Right now, BackendService/RegionBackendService has unfixable behavior in that there is no way to send zero values for the other fields either BackendService or RegionBackendService backend. On read, schema.Set will zero any unset fields out, and they in turn will get sent to the API on next apply. We can force capacity_scaler to be set just because it's a requirement (hence default 1.0), but the other fields cannot be required because they can't all be set at once on the object (max_rate, max_rate_per_instance, etc have conflicts)

@modular-magician
Copy link
Collaborator

Hi! I'm the modular magician. Your PR hasn't generated any diffs, but I'll let you know if a future commit does.

1 similar comment
@modular-magician
Copy link
Collaborator

Hi! I'm the modular magician. Your PR hasn't generated any diffs, but I'll let you know if a future commit does.

@emilymye emilymye force-pushed the backend_service branch 2 times, most recently from 56886d1 to 2932dde Compare January 30, 2020 02:02
@modular-magician
Copy link
Collaborator

Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are.

Diff report:

Terraform GA: Diff
Terraform Beta: Diff
Ansible: Diff
TF Conversion: Diff
Inspec: Diff

@modular-magician
Copy link
Collaborator

Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are.

Diff report:

Terraform GA: Diff
Terraform Beta: Diff
Ansible: Diff
TF Conversion: Diff
Inspec: Diff

@emilymye emilymye changed the title WIP Add conditional validation, allow sending empty capacity scaler for regional backend service Jan 30, 2020
@modular-magician
Copy link
Collaborator

Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are.

Diff report:

Terraform GA: Diff
Terraform Beta: Diff
Ansible: Diff
TF Conversion: Diff
Inspec: Diff

@modular-magician
Copy link
Collaborator

Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are.

Diff report:

Terraform GA: Diff
Terraform Beta: Diff
Ansible: Diff
TF Conversion: Diff
Inspec: Diff

@emilymye emilymye requested review from slevenick, chrisst, rambleraptor and rileykarson and removed request for chrisst January 30, 2020 23:35
Copy link
Member

@rileykarson rileykarson left a comment

Choose a reason for hiding this comment

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

Won't https://github.com/modular-magician/terraform-provider-google/compare/auto-pr-3033-old..auto-pr-3033#diff-212e80d75682146384aa4a2de927dec7L203-L214 cause a real breaking change / regression for users who haven't defined a value? As I understand their state will have 1.0 recorded but Terraform will now see 0 and cause a diff.

// float and because INTERNAL backends can't have the value set, so there will be a permadiff for a
// situational non-zero default returned from the API. We can't diff suppress or customdiff a
// field inside a set object in ResourceDiff, since the value also determines the hash for that set object.
func validateNonInternalBackendServiceBackends(backends []interface{}, d *schema.ResourceDiff) error {
Copy link
Member

Choose a reason for hiding this comment

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

One thing to watch out for here is unknown values. If I interpolate a variable into one of the fields and that variable isn't known at plan-time it'll appear to be unset/zero. This may fail an otherwise valid config if the value will have a value that works.

You can check values with d.NewValueKnown. I forget the exact interaction with sets- whether a single unknown value makes the parent count as unknown or not.

Handling unknown values properly is hard though, and it's may not be worth handling correctly. It doesn't come up much and it's painful to simulate with a small config 🤷‍♀

@@ -0,0 +1,100 @@
<%# The license inside this block applies to this file.
# Copyright 2019 Google Inc.
Copy link
Member

Choose a reason for hiding this comment

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

nit: license blocks should all be 2020

Copy link
Contributor

@rambleraptor rambleraptor left a comment

Choose a reason for hiding this comment

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

Ansible looks good!

@emilymye
Copy link
Contributor Author

@rileykarson yep, that's the breaking change I mentioned - it also has to create a permadiff right now because if they don't have it defined in config, Terraform calculates the set value as 0.00 which causes a hashcode change. If they just are using the INTERNAL default (which i think most people are) then the API doesn't return a value anyways.

Copy link
Member

@rileykarson rileykarson left a comment

Choose a reason for hiding this comment

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

Can you write in the changelog (in the breaking change or as a note) that Terraform now defaults the field to 0.0 while previously it was 1.0, and that users will need to explicitly specify it to have it set to 1.0? It's implied by your current message, but making it explicit would help.

@modular-magician
Copy link
Collaborator

Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are.

Diff report:

Terraform GA: Diff ( 6 files changed, 59 insertions(+), 499 deletions(-))
Terraform Beta: Diff ( 7 files changed, 69 insertions(+), 511 deletions(-))
Ansible: Diff ( 2 files changed, 33 insertions(+), 48 deletions(-))
TF Conversion: Diff ( 2 files changed, 1 insertion(+), 45 deletions(-))
Inspec: Diff ( 1 file changed, 8 insertions(+), 8 deletions(-))

Copy link
Contributor

@slevenick slevenick left a comment

Choose a reason for hiding this comment

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

InSpec looks fine!

@modular-magician
Copy link
Collaborator

Hi! I'm the modular magician. Your PR generated some diffs in downstreams - here they are.

Diff report:

Terraform GA: Diff ( 6 files changed, 59 insertions(+), 503 deletions(-))
Terraform Beta: Diff ( 8 files changed, 69 insertions(+), 516 deletions(-))
Ansible: Diff ( 2 files changed, 33 insertions(+), 48 deletions(-))
TF Conversion: Diff ( 2 files changed, 1 insertion(+), 45 deletions(-))
Inspec: Diff ( 1 file changed, 8 insertions(+), 8 deletions(-))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Fix Tests using RegionBackendService
6 participants