Skip to content

Commit

Permalink
Add config.SchemaElementOption.EmbeddedObject to specify schema elements
Browse files Browse the repository at this point in the history
which will be generated as embedded objects instead of singleton lists in CRDs.

Signed-off-by: Alper Rifat Ulucinar <[email protected]>
  • Loading branch information
ulucinar committed Feb 13, 2024
1 parent c589cdb commit a57975b
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 7 deletions.
18 changes: 18 additions & 0 deletions pkg/config/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -532,10 +532,28 @@ func (m SchemaElementOptions) AddToObservation(el string) bool {
return m[el] != nil && m[el].AddToObservation
}

// SetEmbeddedObject sets the EmbeddedObject for the specified key.
func (m SchemaElementOptions) SetEmbeddedObject(el string) {
if m[el] == nil {
m[el] = &SchemaElementOption{}
}
m[el].EmbeddedObject = true
}

// EmbeddedObject returns true if the schema element at the specified path
// should be generated as an embedded object.
func (m SchemaElementOptions) EmbeddedObject(el string) bool {
return m[el] != nil && m[el].EmbeddedObject
}

// SchemaElementOption represents configuration options on a schema element.
type SchemaElementOption struct {
// AddToObservation is set to true if the field represented by
// a schema element is to be added to the generated CRD type's
// Observation type.
AddToObservation bool
// EmbeddedObject is set to true if the field represented by
// a schema element is to be embedded into its parent instead of being
// generated as a single element list.
EmbeddedObject bool
}
27 changes: 22 additions & 5 deletions pkg/types/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ func (g *Builder) AddToBuilder(typeNames *TypeNames, r *resource) (*types.Named,
return paramType, obsType, initType
}

func (g *Builder) buildSchema(f *Field, cfg *config.Resource, names []string, r *resource) (types.Type, types.Type, error) { //nolint:gocyclo
func (g *Builder) buildSchema(f *Field, cfg *config.Resource, names []string, cpath string, r *resource) (types.Type, types.Type, error) { //nolint:gocyclo
switch f.Schema.Type {
case schema.TypeBool:
return types.NewPointer(types.Universe.Lookup("bool").Type()), nil, nil
Expand Down Expand Up @@ -272,9 +272,16 @@ func (g *Builder) buildSchema(f *Field, cfg *config.Resource, names []string, r
// that can go under spec. This check prevents the elimination of fields in parameter type, by checking
// whether the schema in observation type has nested parameter (spec) fields.
if paramType.Underlying().String() != emptyStruct {
field := types.NewField(token.NoPos, g.Package, f.Name.Camel, types.NewSlice(paramType), false)
r.addParameterField(f, field)
r.addInitField(f, field, g, nil)
var tParam, tInit types.Type
if cfg.SchemaElementOptions.EmbeddedObject(cpath) {
tParam = types.NewPointer(paramType)
tInit = types.NewPointer(initType)
} else {
tParam = types.NewSlice(paramType)
tInit = types.NewSlice(initType)
}
r.addParameterField(f, types.NewField(token.NoPos, g.Package, f.Name.Camel, tParam, false))
r.addInitField(f, types.NewField(token.NoPos, g.Package, f.Name.Camel, tInit, false), g, nil)
}
default:
if paramType == nil {
Expand All @@ -285,7 +292,13 @@ func (g *Builder) buildSchema(f *Field, cfg *config.Resource, names []string, r
// This check prevents the elimination of fields in observation type, by checking whether the schema in
// parameter type has nested observation (status) fields.
if obsType.Underlying().String() != emptyStruct {
field := types.NewField(token.NoPos, g.Package, f.Name.Camel, types.NewSlice(obsType), false)
var t types.Type
if cfg.SchemaElementOptions.EmbeddedObject(cpath) {
t = types.NewPointer(obsType)
} else {
t = types.NewSlice(obsType)
}
field := types.NewField(token.NoPos, g.Package, f.Name.Camel, t, false)
r.addObservationField(f, field)
}
}
Expand All @@ -298,6 +311,10 @@ func (g *Builder) buildSchema(f *Field, cfg *config.Resource, names []string, r
return nil, nil, errors.Errorf("element type of %s should be either schema.Resource or schema.Schema", fieldPath(names))
}

// if the singleton list is to be replaced by an embedded object
if cfg.SchemaElementOptions.EmbeddedObject(cpath) {
return types.NewPointer(elemType), types.NewPointer(initElemType), nil
}
// NOTE(muvaf): Maps and slices are already pointers, so we don't need to
// wrap them even if they are optional.
if f.Schema.Type == schema.TypeMap {
Expand Down
2 changes: 1 addition & 1 deletion pkg/types/conversion/tfjson/tfjson.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func tfJSONBlockTypeToV2Schema(nb *tfjson.SchemaBlockType) *schemav2.Schema { //
v2sch.Computed = true
}

switch nb.NestingMode {
switch nb.NestingMode { //nolint:exhaustive
case tfjson.SchemaNestingModeSet:
v2sch.Type = schemav2.TypeSet
case tfjson.SchemaNestingModeList:
Expand Down
2 changes: 1 addition & 1 deletion pkg/types/field.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func NewField(g *Builder, cfg *config.Resource, r *resource, sch *schema.Schema,
}
}

fieldType, initType, err := g.buildSchema(f, cfg, names, r)
fieldType, initType, err := g.buildSchema(f, cfg, names, fieldPath(append(tfPath, snakeFieldName)), r)
if err != nil {
return nil, errors.Wrapf(err, "cannot infer type from schema of field %s", f.Name.Snake)
}
Expand Down

0 comments on commit a57975b

Please sign in to comment.