Skip to content

Commit

Permalink
Add config.maxItemsSync schema traverser for syncing the MaxItems
Browse files Browse the repository at this point in the history
constraints between the JSON & Go schemas.

- We've observed that some MaxItems constraints in the JSON schemas are not set
  where the corresponding MaxItems constraints in the Go schemas are set to 1.
- This inconsistency results in some singleton lists not being properly converted
  in the MR API.
- This traverser can mitigate such inconsistencies and can also embed
  the singleton lists.

Signed-off-by: Alper Rifat Ulucinar <[email protected]>
  • Loading branch information
ulucinar committed May 30, 2024
1 parent 5318cd9 commit ad820b3
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 1 deletion.
44 changes: 44 additions & 0 deletions pkg/config/schema_conversions.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,47 @@ func (l *SingletonListEmbedder) VisitResource(r *traverser.ResourceNode) error {
l.r.AddSingletonListConversion(traverser.FieldPathWithWildcard(r.TFPath), traverser.FieldPathWithWildcard(r.CRDPath))
return nil
}

// maxItemsSync is a visitor to sync the MaxItems constraints from the
// Go schema to the JSON schema. We've observed that some MaxItems constraints
// in the JSON schemas are not set where the corresponding MaxItems constraints
// in the Go schemas are set to 1. This inconsistency results in some singleton
// lists not being properly converted in the MR API whereas at runtime we may
// try to invoke the corresponding Terraform conversion functions. This
// traverser can mitigate such inconsistencies and can also embed the
// singleton lists.
type maxItemsSync struct {
traverser.NoopTraverser

embedder SingletonListEmbedder
jsonSchema map[string]*Resource
}

// NewListEmbedderWithMaxItemsSync returns a new schema traverser capable of
// syncing the MaxItems constraints from the Go schema to the specified JSON
// schema and can embed singleton lists as objects after the sync. This will
// ensure the generation time and the runtime schema MaxItems constraints will
// match while embedding singleton lists. If both the generation time and
// runtime use the same schema, then SingletonListEmbedder should be used
// instead.
func NewListEmbedderWithMaxItemsSync(s map[string]*Resource) traverser.SchemaTraverser {
return &maxItemsSync{
jsonSchema: s,
}
}

func (m *maxItemsSync) VisitResource(r *traverser.ResourceNode) error {
// this visitor only works on singleton lists
if (r.Schema.Type != schema.TypeList && r.Schema.Type != schema.TypeSet) || r.Schema.MaxItems != 1 {
return nil
}

if err := traverser.AccessSchema(m.jsonSchema[r.TFName].TerraformResource, r.TFPath, func(s *schema.Schema) error {
s.MaxItems = 1
return nil
}); err != nil {
return errors.Wrapf(err, "failed to access the schema element at path %v for resource %q", r.TFPath, r.TFName)
}
m.embedder.SetResource(m.jsonSchema[r.TFName])
return errors.Wrapf(m.embedder.VisitResource(r), "failed to embed the singleton list at path %v for resource %q", r.TFPath, r.TFName)
}
2 changes: 1 addition & 1 deletion pkg/schema/traverser/access.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type SchemaAccessor func(*schema.Schema) error
// the accessors. The terminal node at the end of the specified path must be
// a *schema.Resource or an error will be reported. The specified path must
// have at least one component.
func AccessSchema(sch any, path []string, accessors ...SchemaAccessor) error {
func AccessSchema(sch any, path []string, accessors ...SchemaAccessor) error { //nolint:gocyclo // easier to follow the flow
if len(path) == 0 {
return errors.New("empty path specified while accessing the Terraform resource schema")
}
Expand Down

0 comments on commit ad820b3

Please sign in to comment.