Skip to content

Commit

Permalink
[Internal] Auto generated customizable schemas (#4356)
Browse files Browse the repository at this point in the history
## Changes
<!-- Summary of your changes that are easy to understand -->

## Tests
<!-- 
How is this tested? Please see the checklist below and also describe any
other relevant tests
-->

- [ ] `make test` run locally
- [ ] relevant change in `docs/` folder
- [ ] covered with integration tests in `internal/acceptance`
- [ ] using Go SDK
- [ ] using TF Plugin Framework

---------

Co-authored-by: Omer Lachish <[email protected]>
  • Loading branch information
rauchy and rauchy authored Jan 3, 2025
1 parent b15e372 commit 1b429c3
Show file tree
Hide file tree
Showing 44 changed files with 16,754 additions and 5,855 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ func (r *LibraryResource) Schema(ctx context.Context, req resource.SchemaRequest
c.AddPlanModifier(listplanmodifier.RequiresReplace(), field)
}
}
c.SetComputed("id")
return c
})
resp.Schema = schema.Schema{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ func (r *QualityMonitorResource) Schema(ctx context.Context, req resource.Schema
c.SetReadOnly("status")
c.SetReadOnly("dashboard_id")
c.SetReadOnly("schedule", "pause_status")
c.SetComputed("id")
return c
})
resp.Schema = schema.Schema{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,6 @@ func (r *ShareResource) Schema(ctx context.Context, req resource.SchemaRequest,
c.SetRequired("object", "partition", "value", "op")
c.SetRequired("object", "partition", "value", "name")

c.SetOptional("owner")
return c
})
resp.Schema = schema.Schema{
Expand Down
56 changes: 38 additions & 18 deletions internal/providers/pluginfw/tfschema/struct_to_schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ import (
"github.com/hashicorp/terraform-plugin-framework/types"
)

type CustomizableSchemaProvider interface {
ApplySchemaCustomizations(cs CustomizableSchema, path ...string) CustomizableSchema
}

type structTag struct {
optional bool
computed bool
Expand All @@ -26,6 +30,7 @@ type structTag struct {
func typeToSchema(ctx context.Context, v reflect.Value) NestedBlockObject {
scmAttr := map[string]AttributeBuilder{}
rk := v.Kind()
typeProvidesSchemaCustomization := v.Type().Implements(reflect.TypeOf((*CustomizableSchemaProvider)(nil)).Elem())
if rk == reflect.Ptr {
v = v.Elem()
rk = v.Kind()
Expand Down Expand Up @@ -139,21 +144,28 @@ func typeToSchema(ctx context.Context, v reflect.Value) NestedBlockObject {
}
panic(fmt.Errorf("unexpected type %T in tfsdk structs, expected a plugin framework value type. %s", value, common.TerraformBugErrorMessage))
}

attr := scmAttr[fieldName]
if structTag.computed {
// Computed attributes are always computed and may be optional.
attr = attr.SetComputed()
if structTag.optional {
attr = attr.SetOptional()
}

if typeProvidesSchemaCustomization {
attr = attr.SetOptional() // default to optional, ToSchema may override this
} else {
// Non-computed attributes must be either optional or required.
if structTag.optional {
attr = attr.SetOptional()
if structTag.computed {
// Computed attributes are always computed and may be optional.
attr = attr.SetComputed()
if structTag.optional {
attr = attr.SetOptional()
}
} else {
attr = attr.SetRequired()
// Non-computed attributes must be either optional or required.
if structTag.optional {
attr = attr.SetOptional()
} else {
attr = attr.SetRequired()
}
}
}

scmAttr[fieldName] = attr
}
return NestedBlockObject{Attributes: scmAttr}
Expand Down Expand Up @@ -183,23 +195,31 @@ func DataSourceStructToSchema(ctx context.Context, v any, customizeSchema func(C
// ResourceStructToSchemaMap returns two maps from string to resource schema attributes and blocks using a tfsdk struct, with custoimzations applied.
func ResourceStructToSchemaMap(ctx context.Context, v any, customizeSchema func(CustomizableSchema) CustomizableSchema) (map[string]schema.Attribute, map[string]schema.Block) {
nestedBlockObj := typeToSchema(ctx, reflect.ValueOf(v))
cs := *ConstructCustomizableSchema(nestedBlockObj)

if schemaProvider, ok := v.(CustomizableSchemaProvider); ok {
cs = schemaProvider.ApplySchemaCustomizations(cs)
}

if customizeSchema != nil {
cs := customizeSchema(*ConstructCustomizableSchema(nestedBlockObj))
return BuildResourceAttributeMap(cs.ToNestedBlockObject().Attributes), BuildResourceBlockMap(cs.ToNestedBlockObject().Blocks)
} else {
return BuildResourceAttributeMap(nestedBlockObj.Attributes), BuildResourceBlockMap(nestedBlockObj.Blocks)
cs = customizeSchema(cs)
}

return BuildResourceAttributeMap(cs.ToNestedBlockObject().Attributes), BuildResourceBlockMap(cs.ToNestedBlockObject().Blocks)
}

// DataSourceStructToSchemaMap returns twp maps from string to data source schema attributes and blocks using a tfsdk struct, with custoimzations applied.
func DataSourceStructToSchemaMap(ctx context.Context, v any, customizeSchema func(CustomizableSchema) CustomizableSchema) (map[string]dataschema.Attribute, map[string]dataschema.Block) {
nestedBlockObj := typeToSchema(ctx, reflect.ValueOf(v))
cs := *ConstructCustomizableSchema(nestedBlockObj)

if schemaProvider, ok := v.(CustomizableSchemaProvider); ok {
cs = schemaProvider.ApplySchemaCustomizations(cs)
}

if customizeSchema != nil {
cs := customizeSchema(*ConstructCustomizableSchema(nestedBlockObj))
return BuildDataSourceAttributeMap(cs.ToNestedBlockObject().Attributes), BuildDataSourceBlockMap(cs.ToNestedBlockObject().Blocks)
} else {
return BuildDataSourceAttributeMap(nestedBlockObj.Attributes), BuildDataSourceBlockMap(nestedBlockObj.Blocks)
cs = customizeSchema(cs)
}

return BuildDataSourceAttributeMap(cs.ToNestedBlockObject().Attributes), BuildDataSourceBlockMap(cs.ToNestedBlockObject().Blocks)
}
Loading

0 comments on commit 1b429c3

Please sign in to comment.