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

chore: PoC - Support configuration of timeout in schema #2717

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions tools/codegen/codespec/api_to_provider_spec_mapper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,12 @@ func TestConvertToProviderSpec_nested_schemaOverrides(t *testing.T) {
},
},
},
{
maastha marked this conversation as resolved.
Show resolved Hide resolved
Name: "timeouts",
Timeouts: &codespec.TimeoutsAttribute{
ConfigurableTimeouts: []codespec.Operation{codespec.Create, codespec.Read, codespec.Update, codespec.Delete},
},
},
},
},
Name: "test_resource_with_nested_attr_overrides",
Expand Down
30 changes: 30 additions & 0 deletions tools/codegen/codespec/config.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package codespec

import (
"log"
"strings"

"github.com/mongodb/terraform-provider-mongodbatlas/tools/codegen/config"
Expand Down Expand Up @@ -33,6 +34,10 @@ func applySchemaOptions(schemaOptions config.SchemaOptions, attributes *Attribut
finalAttributes = append(finalAttributes, *attr)
}

if timeoutAttr := applyTimeoutConfig(schemaOptions); parentName == "" && timeoutAttr != nil { // will not run for nested attributes
finalAttributes = append(finalAttributes, *timeoutAttr)
}

*attributes = finalAttributes
}

Expand Down Expand Up @@ -91,3 +96,28 @@ func processNestedAttributes(attr *Attribute, schemaOptions config.SchemaOptions
applySchemaOptions(schemaOptions, &attr.MapNested.NestedObject.Attributes, attrPathName)
}
}

func applyTimeoutConfig(options config.SchemaOptions) *Attribute {
var result []Operation
for _, op := range options.Timeouts {
switch op {
case "create":
result = append(result, Create)
case "read":
result = append(result, Read)
case "delete":
result = append(result, Delete)
case "update":
result = append(result, Update)
default:
log.Printf("[WARN] Unknown operation type defined in timeout configuration: %s", op)
}
}
if result != nil {
return &Attribute{
Name: "timeouts",
Timeouts: &TimeoutsAttribute{ConfigurableTimeouts: result},
}
}
return nil
}
14 changes: 14 additions & 0 deletions tools/codegen/codespec/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ type Attribute struct {
Set *SetAttribute
Int64 *Int64Attribute
SingleNested *SingleNestedAttribute
Timeouts *TimeoutsAttribute
Copy link
Collaborator

Choose a reason for hiding this comment

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

Should be on a resource level (in Schema might be more intuitive). Any reason we want to keep it at an attribute level? Is it only because it simplifies code generation?

Copy link
Member Author

@AgustinBettati AgustinBettati Oct 21, 2024

Choose a reason for hiding this comment

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

Was thinking at the attribute level given how it is configured in terraform plugin framework schema. You will see it is configure as an attribute, not as a property at the schema level. Defining at the resource is definitely possible, but think an attribute type is more aligned with how it is defined.


Description *string
Name SnakeCaseString
Expand Down Expand Up @@ -99,6 +100,19 @@ type NestedAttributeObject struct {
Attributes Attributes
}

type TimeoutsAttribute struct {
ConfigurableTimeouts []Operation
}

type Operation int

const (
Create Operation = iota
Update
Read
Delete
)

type CustomDefault struct {
Definition string
Imports []string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,5 @@ resources:
nested_list_array_attr.inner_num_attr_alias:
description: "Overridden inner_num_attr_alias description"
outer_object.nested_level1.level_field1_alias:
description: "Overridden level_field1_alias description"
description: "Overridden level_field1_alias description"
timeouts: ["create", "read", "update", "delete"]
2 changes: 1 addition & 1 deletion tools/codegen/codespec/testdata/config-no-schema-opts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ resources:
method: PATCH
delete:
path: /api/atlas/v2/groups/{groupId}/testResource
method: DELETE
method: DELETE
2 changes: 1 addition & 1 deletion tools/codegen/codespec/testdata/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ resources:
optional: true
computed: true

timeouts: ["create", "read", "delete"]
timeouts: ["create", "read", "delete"]
41 changes: 19 additions & 22 deletions tools/codegen/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,27 @@ resources:
schema:
aliases:
group_id: project_id

ignores: ["links"]
timeouts: ["create", "update", "delete"]

overrides:
project_id:
description: "Unique 24-hexadecimal digit string that identifies your project."
plan_modifiers: [{
imports: [ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" ],
definition: "stringplanmodifier.RequiresReplace()"
}]
validators: [{
imports: [
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator",
"github.com/hashicorp/terraform-plugin-framework/path"
],
definition: "stringvalidator.ConflictsWith(path.MatchRoot(\"name\"))"
}]

prefix_path:
computability:
optional: true
computed: true
# overrides:
Copy link
Member Author

Choose a reason for hiding this comment

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

commenting out config features that are not yet supported

# project_id:
# plan_modifiers: [{
# imports: [ "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" ],
# definition: "stringplanmodifier.RequiresReplace()"
# }]
# validators: [{
# imports: [
# "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator",
# "github.com/hashicorp/terraform-plugin-framework/path"
# ],
# definition: "stringvalidator.ConflictsWith(path.MatchRoot(\"name\"))"
# }]

timeouts: ["create", "read", "delete"]
# prefix_path:
# computability:
# optional: true
# computed: true

search_deployment:
read:
Expand All @@ -45,4 +42,4 @@ resources:
aliases:
group_id: project_id
ignores: ["links"]
timeouts: ["create", "read", "delete"]
timeouts: ["create", "update", "delete"]
143 changes: 88 additions & 55 deletions tools/codegen/schema/schema_attribute.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ func GenerateSchemaAttributes(attrs codespec.Attributes) CodeStatement {
attrsCode := []string{}
imports := []string{}
for i := range attrs {
result := generateAttribute(&attrs[i])
result := generator(&attrs[i]).AttributeCode()
attrsCode = append(attrsCode, result.Code)
imports = append(imports, result.Imports...)
}
Expand All @@ -22,24 +22,102 @@ func GenerateSchemaAttributes(attrs codespec.Attributes) CodeStatement {
}
}

func generateAttribute(attr *codespec.Attribute) CodeStatement {
generator := typeGenerator(attr)
type attributeGenerator interface {
AttributeCode() CodeStatement
}

typeDefinition := generator.TypeDefinition()
additionalPropertyStatements := generator.TypeSpecificProperties()
func generator(attr *codespec.Attribute) attributeGenerator {
if attr.Int64 != nil {
return &Int64AttrGenerator{intModel: *attr.Int64, attr: *attr}
}
if attr.Float64 != nil {
return &Float64AttrGenerator{
floatModel: *attr.Float64,
attr: *attr,
}
}
if attr.String != nil {
return &StringAttrGenerator{
stringModel: *attr.String,
attr: *attr,
}
}
if attr.Bool != nil {
return &BoolAttrGenerator{
boolModel: *attr.Bool,
attr: *attr,
}
}
if attr.List != nil {
return &ListAttrGenerator{
listModel: *attr.List,
attr: *attr,
}
}
if attr.ListNested != nil {
return &ListNestedAttrGenerator{
listNestedModel: *attr.ListNested,
attr: *attr,
}
}
if attr.Map != nil {
return &MapAttrGenerator{
mapModel: *attr.Map,
attr: *attr,
}
}
if attr.MapNested != nil {
return &MapNestedAttrGenerator{
mapNestedModel: *attr.MapNested,
attr: *attr,
}
}
if attr.Number != nil {
return &NumberAttrGenerator{
numberModel: *attr.Number,
attr: *attr,
}
}
if attr.Set != nil {
return &SetAttrGenerator{
setModel: *attr.Set,
attr: *attr,
}
}
if attr.SetNested != nil {
return &SetNestedGenerator{
setNestedModel: *attr.SetNested,
attr: *attr,
}
}
if attr.SingleNested != nil {
return &SingleNestedAttrGenerator{
singleNestedModel: *attr.SingleNested,
attr: *attr,
}
}
if attr.Timeouts != nil {
return &timeoutAttributeGenerator{
timeouts: *attr.Timeouts,
}
}
panic("Attribute with unknown type defined when generating schema attribute")
}

// generation of conventional attribute types which have common properties like MarkdownDescription, Computed/Optional/Required, Sensitive
func commonAttrStructure(attr *codespec.Attribute, typeDef string, specificProperties []CodeStatement) CodeStatement {
properties := commonProperties(attr)
imports := []string{"github.com/hashicorp/terraform-plugin-framework/resource/schema"}
for i := range additionalPropertyStatements {
properties = append(properties, additionalPropertyStatements[i].Code)
imports = append(imports, additionalPropertyStatements[i].Imports...)
imports := []string{}
for i := range specificProperties {
properties = append(properties, specificProperties[i].Code)
imports = append(imports, specificProperties[i].Imports...)
}

name := attr.Name
propsResultString := strings.Join(properties, ",\n") + ","
code := fmt.Sprintf(`"%s": %s{
%s
}`, name, typeDefinition, propsResultString)
}`, name, typeDef, propsResultString)
return CodeStatement{
Code: code,
Imports: imports,
Expand All @@ -65,48 +143,3 @@ func commonProperties(attr *codespec.Attribute) []string {
}
return result
}

type schemaAttributeGenerator interface {
TypeDefinition() string
TypeSpecificProperties() []CodeStatement
}

func typeGenerator(attr *codespec.Attribute) schemaAttributeGenerator {
if attr.Int64 != nil {
return &Int64AttrGenerator{model: *attr.Int64}
}
if attr.Float64 != nil {
return &Float64AttrGenerator{model: *attr.Float64}
}
if attr.String != nil {
return &StringAttrGenerator{model: *attr.String}
}
if attr.Bool != nil {
return &BoolAttrGenerator{model: *attr.Bool}
}
if attr.List != nil {
return &ListAttrGenerator{model: *attr.List}
}
if attr.ListNested != nil {
return &ListNestedAttrGenerator{model: *attr.ListNested}
}
if attr.Map != nil {
return &MapAttrGenerator{model: *attr.Map}
}
if attr.MapNested != nil {
return &MapNestedAttrGenerator{model: *attr.MapNested}
}
if attr.Number != nil {
return &NumberAttrGenerator{model: *attr.Number}
}
if attr.Set != nil {
return &SetAttrGenerator{model: *attr.Set}
}
if attr.SetNested != nil {
return &SetNestedGenerator{model: *attr.SetNested}
}
if attr.SingleNested != nil {
return &SingleNestedAttrGenerator{model: *attr.SingleNested}
}
panic("Attribute with unknown type defined")
}
Loading