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

[Internal] Generate Effective Fields #4057

Merged
merged 3 commits into from
Oct 15, 2024

Conversation

rauchy
Copy link
Contributor

@rauchy rauchy commented Sep 30, 2024

This PR introduces changes to the TFSDK generator to support “effective fields” for server-provided values. When fields are marked with the new proto annotation ServerProposedIfEmpty (name pending final decision, until then the computed annotation is used to indicate these fields, while specific fields are excluded), the generator will create an additional computed field (e.g., Effective<FieldName>) and add two sync functions to ensure proper handling of user-provided and server-determined values.

Generated Struct:

type ResourceModel struct {
    OriginalField    types.String `tfsdk:"original_field" tf:"optional"`
    EffectiveField   types.String `tfsdk:"effective_field" tf:"computed"`
}

Sync Functions:

func (newState *ResourceModel) SyncEffectiveFieldsDuringCreateOrUpdate(plan ResourceModel) {
    newState.EffectiveField = newState.OriginalField
    newState.OriginalField = plan.OriginalField
}

func (newState *ResourceModel) SyncEffectiveFieldsDuringRead(existingState ResourceModel) {
    if existingState.EffectiveField.ValueString() == newState.OriginalField.ValueString() {
        newState.OriginalField = existingState.OriginalField
    }
}

Changes

Tests

  • make test run locally
  • relevant change in docs/ folder
  • covered with integration tests in internal/acceptance
  • relevant acceptance tests are passing
  • using Go SDK

@rauchy rauchy marked this pull request as ready for review September 30, 2024 11:23
@rauchy rauchy requested review from a team as code owners September 30, 2024 11:23
@rauchy rauchy force-pushed the rauchy/generate-original-fields-for-computed-fields branch from 0c85215 to 4379a58 Compare September 30, 2024 11:32
@rauchy rauchy force-pushed the rauchy/generate-original-fields-for-computed-fields branch 3 times, most recently from be33436 to 3d7cd32 Compare October 4, 2024 12:45
@rauchy rauchy force-pushed the rauchy/generate-original-fields-for-computed-fields branch 2 times, most recently from 8d223c2 to 7879ccb Compare October 14, 2024 11:37
@rauchy rauchy changed the title [Internal] Add another field starting with _Original for each computed field [Internal] Generate Effective Fields Oct 14, 2024
@rauchy rauchy force-pushed the rauchy/generate-original-fields-for-computed-fields branch from 7879ccb to ae55d9a Compare October 14, 2024 12:59
@rauchy rauchy force-pushed the rauchy/generate-original-fields-for-computed-fields branch from ae55d9a to 84b9be0 Compare October 14, 2024 14:02
Copy link
Contributor

@tanmay-db tanmay-db left a comment

Choose a reason for hiding this comment

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

codewise LGTM, had some questions.

cf9c61453990df0f9453670f2fe68e1b128647a2
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this need the new sha? If not we can generate over existing sha (genkit generate-sdk terraform --openapi-spec 0c86ea6dbd9a730c24ff0d4e509603e476955ac5 ` and decouple bumping sha with changes in the PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We don't really need them as part of this PR, it was more to give an example of the changes. I'll remove that commit.

@@ -18,20 +18,74 @@ import (
"github.com/databricks/databricks-sdk-go/marshal"
"github.com/hashicorp/terraform-plugin-framework/types"
)
{{- $excluded := dict "ShareInfo" (list "CreatedAt" "CreatedBy" "UpdatedAt" "UpdatedBy")
Copy link
Contributor

Choose a reason for hiding this comment

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

I think this will need to be done for rest of the resources as well? If yes then this dictionary might become long and something we have to maintain.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We will soon implement a new annotation (ServerProposedIfEmpty) for these effective fields. This annotation will not be applied to the excluded fields, allowing us to eliminate the exclusion list. As a result, the list will not expand to include other resources.

{{- $type := "" -}}
{{- if .Entity.IsString}}{{$type = "String"}}{{end}}
{{- if .Entity.IsBool}}{{$type = "Bool"}}{{end}}
{{- if .Entity.IsInt64}}{{$type = "Int64"}}{{end}}
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be good to also add Int32? (types.Int32)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Possibly, but I was only transferring what was already in place, so I wasn't aware of the consequences of making changes that fall outside the scope of this PR.

{{- if .Entity.IsFloat64}}{{$type = "Float64"}}{{end}}
{{- if .Entity.IsInt}}{{$type = "Int64"}}{{end}}
{{- if .Entity.Enum}}{{$type = "String"}}{{end}}
if existingState.Effective_{{.PascalName}}.Value{{$type}}() == newState.{{.PascalName}}.Value{{$type}}() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Note: .Value returns zero value (eg: "" string if string is null or unknown), is there a case where we would want to differentiate between these? Right now if one is null / one is unknown, then we will compare them to be the same.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Since this occurs solely during Read operations, it can only be null and never unknown, I believe.

{{end}}
}

func (newState *{{.PascalName}}) SyncEffectiveFieldsDuringRead(existingState {{.PascalName}}) {
Copy link
Contributor

Choose a reason for hiding this comment

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

For my understanding, where would we be calling these in the read? Asking because in case there is an error in the read, we shouldn't sync.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

SyncEffectiveFieldsDuringRead is a function that should be invoked before saving to the state during a Read operation, while SyncEffectiveFieldsDuringCreateOrUpdate should be called before saving to the state during a Create or Update operation. We might consider introducing an interface here to allow this syncing to be done automatically by the Resource. However, I would prefer to postpone this refactoring for the time being.

{{- if .Entity.IsString}}{{$type = "String"}}{{end}}
{{- if .Entity.IsBool}}{{$type = "Bool"}}{{end}}
{{- if .Entity.IsInt64}}{{$type = "Int64"}}{{end}}
{{- if .Entity.IsFloat64}}{{$type = "Float64"}}{{end}}
Copy link
Contributor

Choose a reason for hiding this comment

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

same for float32

{{- if and .Entity.IsComputed (or .Entity.IsString .Entity.IsBool .Entity.IsInt64 .Entity.IsFloat64 .Entity.IsInt .Entity.Enum) -}}
{{- if not (in $excluded .PascalName) -}}
{{- $type := "" -}}
{{- if .Entity.IsString}}{{$type = "String"}}{{end}}
Copy link
Contributor

Choose a reason for hiding this comment

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

I am guessing -- we don't support other types like Object, list, map for now and this is to unblock share migration right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Correct. For the moment, I chose primitives because I didn't see a use case for other options. We should revisit this decision in the future if we encounter any relevant cases.

// The canonical identifier for this job.
JobId types.Int64 `tfsdk:"job_id" tf:"optional"`
// Settings for this job and all of its runs. These settings can be updated
// using the `resetJob` method.
Settings []JobSettings `tfsdk:"settings" tf:"optional,object"`
}

func (newState *BaseJob) SyncEffectiveFieldsDuringCreateOrUpdate(plan BaseJob) {

Copy link
Contributor

Choose a reason for hiding this comment

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

nit: The space here and below can be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Addressed in ddc10d2

{{- range .Fields -}}
{{- if and .Entity.IsComputed (or .Entity.IsString .Entity.IsBool .Entity.IsInt64 .Entity.IsFloat64 .Entity.IsInt .Entity.Enum) -}}
{{- if not (in $excluded .PascalName) -}}
newState.Effective_{{.PascalName}} = newState.{{.PascalName}}
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we want the _ in the variable names? Also it seems like some places have 2 Effective, highlighted in another comment.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I believe that using an underscore helps differentiate the actual field name, especially in rare edge cases where the field name includes "Effective." Personally, it helps my understanding. However, if using underscores is considered a significant style violation in Golang, we can reconsider our approach.

// Name of the share.
Name types.String `tfsdk:"name" tf:"optional"`
// A list of shared data objects within the share.
Objects []SharedDataObject `tfsdk:"objects" tf:"optional"`
Objects []SharedDataObject `tfsdk:"object" tf:"optional"`
Copy link
Contributor

Choose a reason for hiding this comment

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

was this (objects -> object) done upstream?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yupp

// based on accessible budget policies of the run_as identity on job
// creation or modification.
EffectiveBudgetPolicyId types.String `tfsdk:"effective_budget_policy_id" tf:"optional"`
Effective_EffectiveBudgetPolicyId types.String `tfsdk:"effective_effective_budget_policy_id" tf:"computed,optional"`
Copy link
Contributor

@tanmay-db tanmay-db Oct 14, 2024

Choose a reason for hiding this comment

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

Rare case when the field name upstream itself starts with Effective?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wonderful :)

Copy link
Contributor Author

@rauchy rauchy Oct 15, 2024

Choose a reason for hiding this comment

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

Anyway, dropped underscores in ec8415a.

@rauchy rauchy force-pushed the rauchy/generate-original-fields-for-computed-fields branch from 84b9be0 to 11d6f16 Compare October 15, 2024 09:02
@rauchy rauchy force-pushed the rauchy/generate-original-fields-for-computed-fields branch from 11d6f16 to cabc683 Compare October 15, 2024 09:29
@rauchy rauchy added this pull request to the merge queue Oct 15, 2024
Merged via the queue into main with commit 1f59bfd Oct 15, 2024
7 checks passed
@rauchy rauchy deleted the rauchy/generate-original-fields-for-computed-fields branch October 15, 2024 10:24
hectorcast-db added a commit that referenced this pull request Oct 17, 2024
### New Features and Improvements

 * Add `databricks_registered_model` data source ([#4033](#4033)).
 * Add data source `databricks_notification_destinations` ([#4087](#4087)).

### Bug Fixes

 * Fix databricks_cluster_pluginframework data source ([#4097](#4097)).
 * Mark unity_catalog_provisioning_state as ReadOnly ([#4116](#4116)).
 * Tolerate invalid keys in `databricks_workspace_conf` ([#4102](#4102)).
 * force send `read_only` in `databricks_external_location` when it's changed ([#4067](#4067)).
 * force send `read_only` in `databricks_storage_credential` when it's changed ([#4083](#4083)).

### Documentation

 * Document `budget_policy_id` in `databricks_pipeline` and `databricks_job` ([#4110](#4110)).
 * Reformat code examples in documentation ([#4081](#4081)).
 * Update documentation for `databricks_model_serving` ([#4115](#4115)).
 * Updates to resource examples ([#4093](#4093)).

### Internal Changes

 * Add maxItem=1 validator for object types in plugin framework schema ([#4094](#4094)).
 * Fix acceptance test for `databricks_registered_model` data source ([#4105](#4105)).
 * Generate Effective Fields ([#4057](#4057)).
 * Generate Effective Fields ([#4112](#4112)).
 * Set SDK used in the useragent in context ([#4092](#4092)).
 * Support adding context in resources and data sources ([#4085](#4085)).
 * Update plugin framework schema to use ListNestedBlocks ([#4040](#4040)).
github-merge-queue bot pushed a commit that referenced this pull request Oct 18, 2024
### New Features and Improvements

* Add `databricks_registered_model` data source
([#4033](#4033)).
* Add data source `databricks_notification_destinations`
([#4087](#4087)).


### Bug Fixes

* Fix databricks_cluster_pluginframework data source
([#4097](#4097)).
* Mark unity_catalog_provisioning_state as ReadOnly
([#4116](#4116)).
* Tolerate invalid keys in `databricks_workspace_conf`
([#4102](#4102)).
* force send `read_only` in `databricks_external_location` when it's
changed
([#4067](#4067)).
* force send `read_only` in `databricks_storage_credential` when it's
changed
([#4083](#4083)).


### Documentation

* Document `budget_policy_id` in `databricks_pipeline` and
`databricks_job`
([#4110](#4110)).
* Reformat code examples in documentation
([#4081](#4081)).
* Update documentation for `databricks_model_serving`
([#4115](#4115)).
* Updates to resource examples
([#4093](#4093)).


### Internal Changes

* Add maxItem=1 validator for object types in plugin framework schema
([#4094](#4094)).
* Fix acceptance test for `databricks_registered_model` data source
([#4105](#4105)).
* Generate Effective Fields
([#4057](#4057)).
* Generate Effective Fields
([#4112](#4112)).
* Set SDK used in the useragent in context
([#4092](#4092)).
* Support adding context in resources and data sources
([#4085](#4085)).
* Update plugin framework schema to use ListNestedBlocks
([#4040](#4040)).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants