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

Migrate SQL Warehouse to Go SDK #3044

Merged
merged 39 commits into from
Jan 10, 2024
Merged

Conversation

mgyucht
Copy link
Contributor

@mgyucht mgyucht commented Dec 19, 2023

Changes

This PR migrates the SQL Warehouse resource to the Go SDK. It also modifies all tests that used the original API client, which means appending ? to resource URIs in fixtures.

To do this, some changes to supporting code are also made:

  1. Introduced several helper methods in common to simplify customizing schemas computed by StructToSchema for several common cases:
  • SetSuppressDiff: sets a diff suppressor on the field so that fields not populated by the user in their configuration are not treated as a diff, even if the API returned some value for that field.
  • SetDefault: marks a schema as optional and sets a default value for it.
  • SetReadOnly: marks a schema as not configurable by users but that can be referenced in Terraform.
  1. Improved suppress diff logic to work with lists/sets. If two lists have a different number of elements, the size of the list is compared, rather than individual list items. The corresponding check should be that new is "0" (not in config) and old is not "0" (state captured something).
  2. Improved all reflection-based methods to work with embedded structs. It is now possible to use StructToSchema on structs like
type S struct {
  sdk.SdkType
  AnotherField string `json:"another_field,omitempty"`
}

The fields of the embedded field are expanded into the schema. This way, maintainers can reuse the Go type as-is without having to copy all of its fields into a new structure.

  1. Bugfix in collectionToMaps that assumed that a data structure is a list iff MaxItems is 1. MaxItems can't be set on read-only fields. This now checks the underlying type is a slice or array.
  2. Introduced WorkspaceDataWithCustomAttrs and AccountDataWithCustomAttrs. These functions are similar to WorkspaceData and AccountData except that they permit two type parameters. The first corresponds to the type used for the resource, ensuring that the schema of the data source and that of the resource are identical. The second corresponds to any additional data that a user might specify in the data source.

Side note: we should probably look into changing suppress diff from being a schema-level configuration to actually adjusting the returned value from the Read method. Otherwise, if the only change made by a user is e.g. to remove all tags, that won't show up as a diff.

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

@mgyucht mgyucht requested review from a team as code owners December 19, 2023 14:34
@mgyucht mgyucht requested review from tanmay-db and removed request for a team December 19, 2023 14:34
@codecov-commenter
Copy link

codecov-commenter commented Dec 21, 2023

Codecov Report

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

Comparison is base (44eefaa) 84.55% compared to head (a3f415d) 84.21%.
Report is 3 commits behind head on master.

Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #3044      +/-   ##
==========================================
- Coverage   84.55%   84.21%   -0.35%     
==========================================
  Files         161      161              
  Lines       14187    14260      +73     
==========================================
+ Hits        11996    12009      +13     
- Misses       1508     1559      +51     
- Partials      683      692       +9     
Files Coverage Δ
exporter/util.go 78.76% <100.00%> (-0.05%) ⬇️
qa/testing.go 80.06% <100.00%> (ø)
sql/data_sql_warehouses.go 100.00% <100.00%> (ø)
exporter/importables.go 79.77% <33.33%> (-0.12%) ⬇️
sql/data_sql_warehouse.go 70.37% <66.66%> (-13.31%) ⬇️
sql/resource_sql_endpoint.go 86.51% <85.71%> (-11.08%) ⬇️
common/reflect_resource.go 80.87% <52.08%> (-3.25%) ⬇️
common/resource.go 65.24% <0.00%> (-8.70%) ⬇️

... and 1 file with indirect coverage changes

@mgyucht mgyucht requested a review from alexott December 21, 2023 12:19
@@ -175,26 +191,52 @@ func diffSuppressor(zero string) func(k, old, new string, d *schema.ResourceData
log.Printf("[DEBUG] Suppressing diff for %v: platform=%#v config=%#v", k, old, new)
return true
}
if strings.HasSuffix(".#", k) && new == "0" && old != "0" {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Lists and sets are compared first for size, which end with .# and the values provided are the sizes of the list/set as a string. If the API returned a non-nil value like {}, the resulting state will have an entry (e.g. for SQL Warehouses, it will be a [{"custom_tags": []}]. The "new" config will be completely empty because it is not defined in the resource itself.

if err != nil {
return err
}
name_contains := (*data).WarehouseNameContains
for _, e := range list.Endpoints {
for _, e := range list {
match_name := strings.Contains(strings.ToLower(e.Name), name_contains)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, I was just preserving the existing behavior. Can we make any changes as a follow-up?

}, false)
}

func WorkspaceData2[SdkType, OtherType any](read func(context.Context, OtherType, *SdkType, *databricks.WorkspaceClient) error) *schema.Resource {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah this name is not very good. I was planning on revisiting this & adding the account-level version in this PR as well.

@@ -214,33 +85,58 @@ func ResourceSqlEndpoint() *schema.Resource {
Create: schema.DefaultTimeout(30 * time.Minute),
},
Create: func(ctx context.Context, d *schema.ResourceData, c *common.DatabricksClient) error {
var se SQLEndpoint
common.DataToStructPointer(d, s, &se)
if err := NewSQLEndpointsAPI(ctx, c).Create(&se, d.Timeout(schema.TimeoutCreate)); err != nil {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mgyucht mgyucht requested a review from nkvuong December 22, 2023 09:21
Copy link
Contributor

@edwardfeng-db edwardfeng-db left a comment

Choose a reason for hiding this comment

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

Halfway through reviewing, need a bit more time understanding context on the WorkspaceData and AccountData

@@ -260,7 +317,7 @@ func typeToSchema(v reflect.Value, t reflect.Type, path []string) map[string]*sc
scm[fieldName].Type = schema.TypeList
elem := typeField.Type.Elem()
sv := reflect.New(elem).Elem()
nestedSchema := typeToSchema(sv, elem, append(path, fieldName, "0"))
nestedSchema := typeToSchema(sv, append(path, fieldName, "0"))
if strings.Contains(tfTag, "suppress_diff") {
blockCount := strings.Join(append(path, fieldName, "#"), ".")
scm[fieldName].DiffSuppressFunc = makeEmptyBlockSuppressFunc(blockCount)
Copy link
Contributor

Choose a reason for hiding this comment

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

With the new suffix checking in diffSuppressor, can we replace makeEmptyBlockSuppressFunc calls?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe we can do this as a separate PR?

@mgyucht mgyucht enabled auto-merge January 8, 2024 10:35
m map[string]*schema.Schema) map[string]*schema.Schema {
m["id"].Computed = true
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we use common.SetReadOnly for this one?

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.

in general, looks good for me from the first pass...


func listAllFields(v reflect.Value) []field {
t := v.Type()
fields := make([]field, 0)
Copy link
Contributor

Choose a reason for hiding this comment

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

what about doing

fields := make([]field, 0, v.NumField())

to avoid reallocations?

// }
//
// WorkspaceDataWithParams(
// func(ctx context.Context, data SqlWarehouseDataParams, w *databricks.WorkspaceClient) (*Warehouse, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

*Warehouse should be *SqlWarehouse ?

@@ -313,7 +314,7 @@ var emptyWorkspace = qa.HTTPFixture{

var emptySqlEndpoints = qa.HTTPFixture{
Method: "GET",
Resource: "/api/2.0/sql/warehouses",
Resource: "/api/2.0/sql/warehouses?",
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we fix SDK to not to add ? if there are no parameters?

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 could. Let's talk online about testing for TF, we just added some testing interfaces which should hide the network layer from you (if you want). Take a look at databricks/databricks-sdk-go@b3cdc97 for the change. That would allow you to mock the responses from Databricks more easily.

m["cluster_size"].ValidateDiagFunc = validation.ToDiagFunc(
validation.StringInSlice(ClusterSizes, false))
common.SetDefault(m["enable_photon"], true)
common.SetSuppressDiff(m["enable_serverless_compute"])
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we try to handle force send fields here for serverless & photon?

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 was going to do that in a follow-up PR, in case that change causes issues and we need to revert.

Copy link
Contributor

Choose a reason for hiding this comment

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

@mgyucht I think that we need to add at least two new test cases:

  1. For inherited structure - so we can see that it's flattened correctly into schema
  2. For a structure with a field from Go SDK

@mgyucht mgyucht added this pull request to the merge queue Jan 9, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 9, 2024
@mgyucht mgyucht added this pull request to the merge queue Jan 10, 2024
Merged via the queue into master with commit d3427f5 Jan 10, 2024
5 checks passed
@mgyucht mgyucht deleted the migrate-sql-warehouse-to-go-sdk branch January 10, 2024 09:12
@tanmay-db tanmay-db mentioned this pull request Jan 11, 2024
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.

5 participants