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

Introduce Generic Settings Resource #2997

Merged
merged 8 commits into from
Jan 29, 2024
Merged

Conversation

mgyucht
Copy link
Contributor

@mgyucht mgyucht commented Dec 6, 2023

Changes

This is an experimental PR for a generic settings resource in the TF provider. Because all Settings API settings have a consistent schema & mechanism for interaction, the definition of a setting resource in Terraform can also be made generic with several simple assumptions about each setting:

  1. Each setting needs a name (in this case, the name would be "default_namespace", so the resource name would be "databricks_default_namespace_setting") and a field mask used to update the value for that setting.
  2. Each setting needs a structure T containing an Etag field.
  3. Each setting has an API to read the setting by Etag.
  4. Each setting has an API to delete the setting by Etag.
  5. Each setting has a single API to update the setting. The update request must have an AllowMissing boolean field, a Setting field of type *T, and a field mask.

These above requirements are encapsulated in the genericSettingDefinition interface. Because API calls require a specific client depending on whether the setting is an account-level or workspace-level setting, we define two interfaces, one for workspace-level settings where the workspace client is provided, and one for account-level settings where the account client is provided.

After this change, to add a new setting:

  1. Create a new instance of either the workspaceSetting or accountSetting for your setting. The type parameter should be your setting resource.
var defaultNamespaceSetting = workspaceSetting[settings.DefaultNamespaceSetting]{
	settingStruct: settings.DefaultNamespaceSetting{},
	readFunc: func(ctx context.Context, w *databricks.WorkspaceClient, etag string) (*settings.DefaultNamespaceSetting, error) {
		return w.Settings.ReadDefaultWorkspaceNamespace(ctx, settings.ReadDefaultWorkspaceNamespaceRequest{
			Etag: etag,
		})
	},
	updateFunc: func(ctx context.Context, w *databricks.WorkspaceClient, t settings.DefaultNamespaceSetting) (string, error) {
		t.SettingName = "default"
		res, err := w.Settings.UpdateDefaultWorkspaceNamespace(ctx, settings.UpdateDefaultWorkspaceNamespaceRequest{
			AllowMissing: true,
			Setting:      &t,
			FieldMask:    "namespace.value",
		})
		if err != nil {
			return "", err
		}
		return res.Etag, err
	},
	deleteFunc: func(ctx context.Context, w *databricks.WorkspaceClient, etag string) (string, error) {
		res, err := w.Settings.DeleteDefaultWorkspaceNamespace(ctx, settings.DeleteDefaultWorkspaceNamespaceRequest{
			Etag: etag,
		})
		if err != nil {
			return "", err
		}
		return res.Etag, err
	},
}
  1. Add a new constant for the name of the setting and to the AllSettingsResources() function:
func AllSettingsResources() map[string]*schema.Resource {
  return {
    ...
    "my_new_setting": makeSettingResource[settings.MyNewSetting, *databricks.WorkspaceClient](myNewSetting),
  }
}

Additionally, I migrated the tests for this resource to use the Go SDK.

Tests

  • Unit tests verify that the generic setting
  • Process for change is documented in this PR description as well as in all_settings.go.
  • covered with integration tests in internal/acceptance
  • relevant acceptance tests are passing
  • using Go SDK

@mgyucht mgyucht requested review from a team as code owners December 6, 2023 11:02
@mgyucht mgyucht requested review from hectorcast-db and removed request for a team December 6, 2023 11:02
@codecov-commenter
Copy link

codecov-commenter commented Dec 6, 2023

Codecov Report

Attention: 53 lines in your changes are missing coverage. Please review.

Comparison is base (fbb6552) 83.82% compared to head (798736f) 83.64%.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #2997      +/-   ##
==========================================
- Coverage   83.82%   83.64%   -0.19%     
==========================================
  Files         165      167       +2     
  Lines       14590    14636      +46     
==========================================
+ Hits        12230    12242      +12     
- Misses       1649     1682      +33     
- Partials      711      712       +1     
Files Coverage Δ
provider/provider.go 94.44% <100.00%> (ø)
settings/all_settings.go 100.00% <100.00%> (ø)
settings/resource_default_namespace_setting.go 100.00% <100.00%> (+19.58%) ⬆️
settings/generic_setting.go 55.83% <55.83%> (ø)

Copy link
Contributor

@alexott alexott left a comment

Choose a reason for hiding this comment

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

If the schema is consistent, I'm wondering if we need to have individual resources, because we may have dozens of settings and this may lead to the proliferation of resources and resource instances that may significantly slow down Terraform in the big installations.

Why not define two resources - one for workspace settings, and another - for account? Both will support patch method, not put, so it will be possible to define multiple instances if necessary.

@alexott alexott requested a review from nfx December 6, 2023 15:44
Copy link

@deryasusm-db deryasusm-db left a comment

Choose a reason for hiding this comment

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

This should be tested by running the TF integration test for Default Namespace against a test shard

return nil
}

return common.Resource{

Choose a reason for hiding this comment

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

The common resource definition and the common methods should move out of this file

// Instructions for adding a new setting:
//
// 1. Add a new setting name constant. The resulting Terraform resource name will be "databricks_<your settings_name>_setting".
// 2. Create a struct corresponding to your setting, and implement either the workspaceSettingDefinition or accountSettingDefinition interface.

Choose a reason for hiding this comment

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

Create a struct corresponding to your setting,

Are you referring to settings.DefaultNamespaceSetting as this struct to be created or type defaultNamespaceSetting struct{}?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The latter, I can clarify that.

@mgyucht
Copy link
Contributor Author

mgyucht commented Dec 8, 2023

@alexott We could also do that, however, 1) it probably has less to do with Terraform than it does with the API itself, as there are still many API calls that need to be made to retrieve all values of all settings. There definitely will be TF overhead, but I suspect it would be comparable or maybe even smaller than the cost of making requests to the backend. 2) This keeps TF as close as possible to the REST API, which is generally a design goal. I think for consistency & as a general principle we should keep these as close as possible to one another.

@alexott alexott marked this pull request as draft December 10, 2023 13:13
@mgyucht mgyucht marked this pull request as ready for review January 22, 2024 09:42
@mgyucht mgyucht changed the title WIP: Generic Settings Resource Generic Settings Resource Jan 22, 2024
@mgyucht mgyucht changed the title Generic Settings Resource Introduce Generic Settings Resource Jan 22, 2024
@deryasusm-db
Copy link

@hectorcast-db Can you review this one as you did the TF integration for Default Namespace setting? Thanks.

if err != nil {
return err
}
res, err = retryOnEtagError(func(etag string) (*T, error) { return defn.Read(ctx, w, etag) }, d.Id(), func(req *string, newEtag string) { *req = newEtag })
Copy link
Contributor

Choose a reason for hiding this comment

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

Can read fail on a EtagError?
From the docs:

The server will accept any etag and respond with a response which is at least as recent as the etag.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point, removed need to retry in reads.

if err != nil {
return err
}
etag, err = retryOnEtagError(func(etag string) (string, error) { return defn.Delete(ctx, w, etag) }, d.Id(), func(req *string, newEtag string) { *req = newEtag })
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 really need to retry on the NotFound error? If it's not found then this typically it means that it was removed by external agent, so we just need to record deletion...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. Removed retry on Not Found, so we only retry on conflict.

@mgyucht mgyucht added this pull request to the merge queue Jan 29, 2024
Merged via the queue into master with commit 4acd04d Jan 29, 2024
5 checks passed
@mgyucht mgyucht deleted the generic-settings-resource branch January 29, 2024 13:50
tanmay-db added a commit that referenced this pull request Feb 5, 2024
### New Features and Improvements
* Exporter: timestamps are now added to log entries ([#3146](#3146)).
* Validate metastore id for databricks_grant and databricks_grants resources ([#3159](#3159)).
* Exporter: Skip emitting of clusters that come from more cluster sources ([#3161](#3161)).
* Fix typo in docs ([#3166](#3166)).
* Migrate cluster schema to use the go-sdk struct ([#3076](#3076)).
* Introduce Generic Settings Resource ([#2997](#2997)).
* Update actions/setup-go to v5 ([#3154](#3154)).
* Change default branch from `master` to `main` ([#3174](#3174)).
* Add .codegen.json configuration ([#3180](#3180)).
* Exporter: performance improvements for big workspaces ([#3167](#3167)).
* update ([#3192](#3192)).
* Exporter: fix generation of cluster policy resources ([#3185](#3185)).
* Fix unit test ([#3201](#3201)).
* Suppress diff should apply to new fields added in the same chained call to CustomizableSchema ([#3200](#3200)).
* Various documentation updates ([#3198](#3198)).
* Use common.Resource consistently throughout the provider ([#3193](#3193)).
* Extending customizable schema with `AtLeastOneOf`, `ExactlyOneOf`, `RequiredWith` ([#3182](#3182)).
* Fix `databricks_connection` regression when creating without owner ([#3186](#3186)).
* add test code for job task order ([#3183](#3183)).
* Allow using empty strings as job parameters ([#3158](#3158)).
* Fix notebook parameters in acceptance test ([#3205](#3205)).
* Exporter: Add retries for `Search`, `ReadContext` and `Import` operations when importing the resource ([#3202](#3202)).
* Fixed updating owners for UC resources ([#3189](#3189)).
* Adds `databricks_volumes` as data source  ([#3150](#3150)).

### Documentation Changes

### Exporter

### Internal Changes
@tanmay-db tanmay-db mentioned this pull request Feb 5, 2024
github-merge-queue bot pushed a commit that referenced this pull request Feb 6, 2024
* Release v1.35.1

### New Features and Improvements
* Exporter: timestamps are now added to log entries ([#3146](#3146)).
* Validate metastore id for databricks_grant and databricks_grants resources ([#3159](#3159)).
* Exporter: Skip emitting of clusters that come from more cluster sources ([#3161](#3161)).
* Fix typo in docs ([#3166](#3166)).
* Migrate cluster schema to use the go-sdk struct ([#3076](#3076)).
* Introduce Generic Settings Resource ([#2997](#2997)).
* Update actions/setup-go to v5 ([#3154](#3154)).
* Change default branch from `master` to `main` ([#3174](#3174)).
* Add .codegen.json configuration ([#3180](#3180)).
* Exporter: performance improvements for big workspaces ([#3167](#3167)).
* update ([#3192](#3192)).
* Exporter: fix generation of cluster policy resources ([#3185](#3185)).
* Fix unit test ([#3201](#3201)).
* Suppress diff should apply to new fields added in the same chained call to CustomizableSchema ([#3200](#3200)).
* Various documentation updates ([#3198](#3198)).
* Use common.Resource consistently throughout the provider ([#3193](#3193)).
* Extending customizable schema with `AtLeastOneOf`, `ExactlyOneOf`, `RequiredWith` ([#3182](#3182)).
* Fix `databricks_connection` regression when creating without owner ([#3186](#3186)).
* add test code for job task order ([#3183](#3183)).
* Allow using empty strings as job parameters ([#3158](#3158)).
* Fix notebook parameters in acceptance test ([#3205](#3205)).
* Exporter: Add retries for `Search`, `ReadContext` and `Import` operations when importing the resource ([#3202](#3202)).
* Fixed updating owners for UC resources ([#3189](#3189)).
* Adds `databricks_volumes` as data source  ([#3150](#3150)).

### Documentation Changes

### Exporter

### Internal Changes

* upd

* readable

* upd

* upd
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.

None yet

5 participants