From c66651efb6bf279902365b8e23d949f61155a0ae Mon Sep 17 00:00:00 2001 From: Manuel Pedrozo Date: Fri, 31 Oct 2025 10:22:38 +0100 Subject: [PATCH] Add support for typed maps in autogen --- internal/common/autogen/customtypes/list.go | 8 + internal/common/autogen/customtypes/map.go | 172 ++++++++++++++++++ .../common/autogen/customtypes/nested_list.go | 8 + .../common/autogen/customtypes/nested_map.go | 8 + .../common/autogen/customtypes/nested_set.go | 8 + internal/common/autogen/customtypes/object.go | 8 + internal/common/autogen/customtypes/set.go | 8 + internal/common/autogen/marshal.go | 2 + internal/common/autogen/marshal_test.go | 13 ++ internal/common/autogen/unknown.go | 6 + internal/common/autogen/unknown_test.go | 3 + internal/common/autogen/unmarshal.go | 51 ++++-- internal/common/autogen/unmarshal_test.go | 74 ++++++++ .../serviceapi/clusterapi/resource_schema.go | 166 ++++++++++------- .../streaminstanceapi/resource_schema.go | 56 +++--- .../api_to_provider_spec_mapper_test.go | 2 + tools/codegen/codespec/attribute.go | 3 + tools/codegen/codespec/model.go | 9 + tools/codegen/config.yml | 2 - .../gofilegen/schema/schema_file_test.go | 8 + .../custom-types-attributes.golden.go | 7 + tools/codegen/models/cluster_api.yaml | 100 ++++++++++ tools/codegen/models/stream_instance_api.yaml | 52 ++++++ 23 files changed, 666 insertions(+), 108 deletions(-) create mode 100644 internal/common/autogen/customtypes/map.go diff --git a/internal/common/autogen/customtypes/list.go b/internal/common/autogen/customtypes/list.go index 3cf475269f..a65549e310 100644 --- a/internal/common/autogen/customtypes/list.go +++ b/internal/common/autogen/customtypes/list.go @@ -113,6 +113,14 @@ type ListValueInterface interface { Elements() []attr.Value } +func (v ListValue[T]) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + if v.ListValue.ElementType(ctx) == nil { + // ListValue created as a zero value (not explicitly initialized), initialize now so conversion does not panic. + v.ListValue = NewListValueNull[T](ctx).ListValue + } + return v.ListValue.ToTerraformValue(ctx) +} + func (v ListValue[T]) NewListValue(ctx context.Context, value []attr.Value) ListValueInterface { return NewListValue[T](ctx, value) } diff --git a/internal/common/autogen/customtypes/map.go b/internal/common/autogen/customtypes/map.go new file mode 100644 index 0000000000..c59139bd3f --- /dev/null +++ b/internal/common/autogen/customtypes/map.go @@ -0,0 +1,172 @@ +package customtypes + +import ( + "context" + "fmt" + + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types/basetypes" + "github.com/hashicorp/terraform-plugin-go/tftypes" +) + +/* + Custom Map type used in auto-generated code to enable the generic marshal/unmarshal operations to access the elements' type during conversion. + Custom types docs: https://developer.hashicorp.com/terraform/plugin/framework/handling-data/types/custom + + Usage: + - Schema definition: + "sample_string_map": schema.MapAttribute{ + ... + CustomType: customtypes.NewMapType[basetypes.StringValue](ctx), + ElementType: types.StringType, + } + + - TF Models: + type TFModel struct { + SampleStringMap customtypes.MapValue[basetypes.StringValue] `tfsdk:"sample_string_map"` + ... + } +*/ + +var ( + _ basetypes.MapTypable = MapType[basetypes.StringValue]{} + _ basetypes.MapValuable = MapValue[basetypes.StringValue]{} + _ MapValueInterface = MapValue[basetypes.StringValue]{} +) + +type MapType[T attr.Value] struct { + basetypes.MapType +} + +func NewMapType[T attr.Value](ctx context.Context) MapType[T] { + elemType := getElemType[T](ctx) + return MapType[T]{ + MapType: basetypes.MapType{ElemType: elemType}, + } +} + +func (t MapType[T]) Equal(o attr.Type) bool { + other, ok := o.(MapType[T]) + if !ok { + return false + } + + return t.MapType.Equal(other.MapType) +} + +func (MapType[T]) String() string { + var t T + return fmt.Sprintf("MapType[%T]", t) +} + +func (t MapType[T]) ValueFromMap(ctx context.Context, in basetypes.MapValue) (basetypes.MapValuable, diag.Diagnostics) { + if in.IsNull() { + return NewMapValueNull[T](ctx), nil + } + + if in.IsUnknown() { + return NewMapValueUnknown[T](ctx), nil + } + + elemType := getElemType[T](ctx) + baseMapValue, diags := basetypes.NewMapValue(elemType, in.Elements()) + if diags.HasError() { + return nil, diags + } + + return MapValue[T]{MapValue: baseMapValue}, nil +} + +func (t MapType[T]) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { + attrValue, err := t.MapType.ValueFromTerraform(ctx, in) + + if err != nil { + return nil, err + } + + mapValue, ok := attrValue.(basetypes.MapValue) + if !ok { + return nil, fmt.Errorf("unexpected value type of %T", attrValue) + } + + mapValuable, diags := t.ValueFromMap(ctx, mapValue) + if diags.HasError() { + return nil, fmt.Errorf("unexpected error converting MapValue to MapValuable: %v", diags) + } + + return mapValuable, nil +} + +func (t MapType[T]) ValueType(_ context.Context) attr.Value { + return MapValue[T]{} +} + +type MapValue[T attr.Value] struct { + basetypes.MapValue +} + +type MapValueInterface interface { + basetypes.MapValuable + NewMapValue(ctx context.Context, value map[string]attr.Value) MapValueInterface + NewMapValueNull(ctx context.Context) MapValueInterface + ElementType(ctx context.Context) attr.Type + Elements() map[string]attr.Value +} + +func (v MapValue[T]) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + if v.MapValue.ElementType(ctx) == nil { + // MapValue created as a zero value (not explicitly initialized), initialize now so conversion does not panic. + v.MapValue = NewMapValueNull[T](ctx).MapValue + } + return v.MapValue.ToTerraformValue(ctx) +} + +func (v MapValue[T]) NewMapValue(ctx context.Context, value map[string]attr.Value) MapValueInterface { + return NewMapValue[T](ctx, value) +} + +func NewMapValue[T attr.Value](ctx context.Context, value map[string]attr.Value) MapValue[T] { + elemType := getElemType[T](ctx) + + mapValue, diags := basetypes.NewMapValue(elemType, value) + if diags.HasError() { + return NewMapValueUnknown[T](ctx) + } + + return MapValue[T]{MapValue: mapValue} +} + +func (v MapValue[T]) NewMapValueNull(ctx context.Context) MapValueInterface { + return NewMapValueNull[T](ctx) +} + +func NewMapValueNull[T attr.Value](ctx context.Context) MapValue[T] { + elemType := getElemType[T](ctx) + return MapValue[T]{MapValue: basetypes.NewMapNull(elemType)} +} + +func NewMapValueUnknown[T attr.Value](ctx context.Context) MapValue[T] { + elemType := getElemType[T](ctx) + return MapValue[T]{MapValue: basetypes.NewMapUnknown(elemType)} +} + +func (v MapValue[T]) Equal(o attr.Value) bool { + other, ok := o.(MapValue[T]) + if !ok { + return false + } + return v.MapValue.Equal(other.MapValue) +} + +func (v MapValue[T]) Type(ctx context.Context) attr.Type { + return NewMapType[T](ctx) +} + +func (v MapValue[T]) ElementType(ctx context.Context) attr.Type { + return getElemType[T](ctx) +} + +func (v MapValue[T]) Elements() map[string]attr.Value { + return v.MapValue.Elements() +} diff --git a/internal/common/autogen/customtypes/nested_list.go b/internal/common/autogen/customtypes/nested_list.go index 0f40dcfe26..defe91e19a 100644 --- a/internal/common/autogen/customtypes/nested_list.go +++ b/internal/common/autogen/customtypes/nested_list.go @@ -133,6 +133,14 @@ type NestedListValueInterface interface { Len() int } +func (v NestedListValue[T]) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + if v.ElementType(ctx) == nil { + // NestedListValue created as a zero value (not explicitly initialized), initialize now so conversion does not panic. + v.ListValue = NewNestedListValueNull[T](ctx).ListValue + } + return v.ListValue.ToTerraformValue(ctx) +} + func (v NestedListValue[T]) NewNestedListValue(ctx context.Context, value any) NestedListValueInterface { return NewNestedListValue[T](ctx, value) } diff --git a/internal/common/autogen/customtypes/nested_map.go b/internal/common/autogen/customtypes/nested_map.go index a717d0a23b..87d1f588ac 100644 --- a/internal/common/autogen/customtypes/nested_map.go +++ b/internal/common/autogen/customtypes/nested_map.go @@ -131,6 +131,14 @@ type NestedMapValueInterface interface { NewEmptyMapPtr() any } +func (v NestedMapValue[T]) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + if v.ElementType(ctx) == nil { + // NestedMapValue created as a zero value (not explicitly initialized), initialize now so conversion does not panic. + v.MapValue = NewNestedMapValueNull[T](ctx).MapValue + } + return v.MapValue.ToTerraformValue(ctx) +} + func (v NestedMapValue[T]) NewNestedMapValue(ctx context.Context, value any) NestedMapValueInterface { return NewNestedMapValue[T](ctx, value) } diff --git a/internal/common/autogen/customtypes/nested_set.go b/internal/common/autogen/customtypes/nested_set.go index b99397f4bb..887b29bcb2 100644 --- a/internal/common/autogen/customtypes/nested_set.go +++ b/internal/common/autogen/customtypes/nested_set.go @@ -132,6 +132,14 @@ type NestedSetValueInterface interface { Len() int } +func (v NestedSetValue[T]) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + if v.ElementType(ctx) == nil { + // NestedSetValue created as a zero value (not explicitly initialized), initialize now so conversion does not panic. + v.SetValue = NewNestedSetValueNull[T](ctx).SetValue + } + return v.SetValue.ToTerraformValue(ctx) +} + func (v NestedSetValue[T]) NewNestedSetValue(ctx context.Context, value any) NestedSetValueInterface { return NewNestedSetValue[T](ctx, value) } diff --git a/internal/common/autogen/customtypes/object.go b/internal/common/autogen/customtypes/object.go index 1ef5fcaa56..ecc6a7b080 100644 --- a/internal/common/autogen/customtypes/object.go +++ b/internal/common/autogen/customtypes/object.go @@ -129,6 +129,14 @@ type ObjectValueInterface interface { ValuePtrAsAny(ctx context.Context) (any, diag.Diagnostics) } +func (v ObjectValue[T]) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + if v.ObjectValue.Equal(basetypes.ObjectValue{}) { + // ObjectValue created as a zero value (not explicitly initialized), initialize now so conversion does not panic. + v.ObjectValue = NewObjectValueNull[T](ctx).ObjectValue + } + return v.ObjectValue.ToTerraformValue(ctx) +} + func (v ObjectValue[T]) NewObjectValue(ctx context.Context, value any) ObjectValueInterface { return NewObjectValue[T](ctx, value) } diff --git a/internal/common/autogen/customtypes/set.go b/internal/common/autogen/customtypes/set.go index 78fd88293f..0d75938880 100644 --- a/internal/common/autogen/customtypes/set.go +++ b/internal/common/autogen/customtypes/set.go @@ -113,6 +113,14 @@ type SetValueInterface interface { Elements() []attr.Value } +func (v SetValue[T]) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { + if v.SetValue.ElementType(ctx) == nil { + // SetValue created as a zero value (not explicitly initialized), initialize now so conversion does not panic. + v.SetValue = NewSetValueNull[T](ctx).SetValue + } + return v.SetValue.ToTerraformValue(ctx) +} + func (v SetValue[T]) NewSetValue(ctx context.Context, value []attr.Value) SetValueInterface { return NewSetValue[T](ctx, value) } diff --git a/internal/common/autogen/marshal.go b/internal/common/autogen/marshal.go index ca6366765c..b0626703e6 100644 --- a/internal/common/autogen/marshal.go +++ b/internal/common/autogen/marshal.go @@ -106,6 +106,8 @@ func getModelAttr(val attr.Value, isUpdate bool) (any, error) { return getMapAttr(v.Attributes(), false, isUpdate) case types.Map: return getMapAttr(v.Elements(), true, isUpdate) + case customtypes.MapValueInterface: + return getMapAttr(v.Elements(), true, isUpdate) case types.List: return getListAttr(v.Elements(), isUpdate) case customtypes.ListValueInterface: diff --git a/internal/common/autogen/marshal_test.go b/internal/common/autogen/marshal_test.go index 7bd0c8032e..1edff39dd5 100644 --- a/internal/common/autogen/marshal_test.go +++ b/internal/common/autogen/marshal_test.go @@ -130,6 +130,7 @@ func TestMarshalNestedAllTypes(t *testing.T) { AttrCustomSet customtypes.SetValue[types.String] `tfsdk:"attr_custom_set"` AttrSetObj types.Set `tfsdk:"attr_set_obj"` AttrMapSimple types.Map `tfsdk:"attr_map_simple"` + AttrCustomMap customtypes.MapValue[types.String] `tfsdk:"attr_custom_map"` AttrMapObj types.Map `tfsdk:"attr_map_obj"` }{ AttrString: types.StringValue("val"), @@ -143,6 +144,10 @@ func TestMarshalNestedAllTypes(t *testing.T) { "keyOne": types.StringValue("val1"), "KeyTwo": types.StringValue("val2"), // don't change the key case when it's a map }), + AttrCustomMap: customtypes.NewMapValue[types.String](t.Context(), map[string]attr.Value{ + "keyOne": types.StringValue("val1"), + "KeyTwo": types.StringValue("val2"), + }), AttrMapObj: attrMapObj, } const expectedJSON = ` @@ -164,6 +169,10 @@ func TestMarshalNestedAllTypes(t *testing.T) { "keyOne": "val1", "KeyTwo": "val2" }, + "attrCustomMap": { + "keyOne": "val1", + "KeyTwo": "val2" + }, "attrMapObj": { "keyOne": { "attrString": "str1", "attrInt": 1 }, "KeyTwo": { "attrString": "str2", "attrInt": 2 } @@ -268,6 +277,8 @@ func TestMarshalUpdateNull(t *testing.T) { AttrCustomList customtypes.ListValue[types.String] `tfsdk:"attr_custom_list"` AttrSet types.Set `tfsdk:"attr_set"` AttrCustomSet customtypes.SetValue[types.String] `tfsdk:"attr_custom_set"` + AttrMap types.Map `tfsdk:"attr_map"` + AttrCustomMap customtypes.MapValue[types.String] `tfsdk:"attr_custom_map"` AttrString types.String `tfsdk:"attr_string"` AttrObj types.Object `tfsdk:"attr_obj"` AttrIncludeString types.String `tfsdk:"attr_include_update" autogen:"includenullonupdate"` @@ -277,6 +288,8 @@ func TestMarshalUpdateNull(t *testing.T) { AttrCustomList: customtypes.NewListValueNull[types.String](t.Context()), AttrSet: types.SetNull(types.StringType), AttrCustomSet: customtypes.NewSetValueNull[types.String](t.Context()), + AttrMap: types.MapNull(types.StringType), + AttrCustomMap: customtypes.NewMapValueNull[types.String](t.Context()), AttrString: types.StringNull(), AttrObj: types.ObjectNull(objTypeTest.AttrTypes), AttrIncludeString: types.StringNull(), diff --git a/internal/common/autogen/unknown.go b/internal/common/autogen/unknown.go index b0d10e8e41..a35ce2a615 100644 --- a/internal/common/autogen/unknown.go +++ b/internal/common/autogen/unknown.go @@ -98,6 +98,12 @@ func prepareAttr(value attr.Value) (attr.Value, error) { } // If known, no need to process each set item since unmarshal does not generate unknown attributes. return v, nil + case customtypes.MapValueInterface: + if v.IsUnknown() { + return v.NewMapValueNull(ctx), nil + } + // If known, no need to process each map entry since unmarshal does not generate unknown attributes. + return v, nil case customtypes.NestedMapValueInterface: if v.IsUnknown() { return v.NewNestedMapValueNull(ctx), nil diff --git a/internal/common/autogen/unknown_test.go b/internal/common/autogen/unknown_test.go index 65dfa8cdde..138c384cd9 100644 --- a/internal/common/autogen/unknown_test.go +++ b/internal/common/autogen/unknown_test.go @@ -36,6 +36,7 @@ func TestResolveUnknowns(t *testing.T) { AttrCustomObject customtypes.ObjectValue[modelCustomTypeTest] `tfsdk:"attr_custom_object"` AttrCustomListUnknown customtypes.ListValue[types.String] `tfsdk:"attr_custom_list_string"` AttrCustomSetUnknown customtypes.SetValue[types.String] `tfsdk:"attr_custom_set_string"` + AttrCustomMapUnknown customtypes.MapValue[types.String] `tfsdk:"attr_custom_map_string"` AttrCustomNestedListUnknown customtypes.NestedListValue[modelEmptyTest] `tfsdk:"attr_custom_nested_list_unknown"` AttrCustomNestedSetUnknown customtypes.NestedSetValue[modelEmptyTest] `tfsdk:"attr_custom_nested_set_unknown"` AttrCustomNestedMapUnknown customtypes.NestedMapValue[modelEmptyTest] `tfsdk:"attr_custom_nested_map_unknown"` @@ -99,6 +100,7 @@ func TestResolveUnknowns(t *testing.T) { AttrCustomNestedMapUnknown: customtypes.NewNestedMapValueUnknown[modelEmptyTest](ctx), AttrCustomListUnknown: customtypes.NewListValueUnknown[types.String](ctx), AttrCustomSetUnknown: customtypes.NewSetValueUnknown[types.String](ctx), + AttrCustomMapUnknown: customtypes.NewMapValueUnknown[types.String](ctx), AttrCustomNestedList: customtypes.NewNestedListValue[modelCustomTypeTest](ctx, []modelCustomTypeTest{ { AttrKnownString: types.StringValue("val1"), @@ -176,6 +178,7 @@ func TestResolveUnknowns(t *testing.T) { }), AttrCustomListUnknown: customtypes.NewListValueNull[types.String](ctx), AttrCustomSetUnknown: customtypes.NewSetValueNull[types.String](ctx), + AttrCustomMapUnknown: customtypes.NewMapValueNull[types.String](ctx), AttrCustomNestedListUnknown: customtypes.NewNestedListValueNull[modelEmptyTest](ctx), AttrCustomNestedSetUnknown: customtypes.NewNestedSetValueNull[modelEmptyTest](ctx), AttrCustomNestedMapUnknown: customtypes.NewNestedMapValueNull[modelEmptyTest](ctx), diff --git a/internal/common/autogen/unmarshal.go b/internal/common/autogen/unmarshal.go index 319f88fe1c..b175e3533e 100644 --- a/internal/common/autogen/unmarshal.go +++ b/internal/common/autogen/unmarshal.go @@ -136,19 +136,9 @@ func getTfAttr(value any, valueType attr.Type, oldVal attr.Value, name string) ( } return mapNew, nil case customtypes.ObjectValueInterface: - ctx := context.Background() - valuePtr, diags := oldVal.ValuePtrAsAny(ctx) - if diags.HasError() { - return nil, fmt.Errorf("unmarshal failed to convert object: %v", diags) - } - - err := unmarshalAttrs(v, valuePtr) - if err != nil { - return nil, err - } - - objNew := oldVal.NewObjectValue(ctx, valuePtr) - return objNew, nil + return getObjectValueTFAttr(context.Background(), v, oldVal) + case customtypes.MapValueInterface: + return getMapValueTFAttr(context.Background(), v, oldVal) case customtypes.NestedMapValueInterface: return getNestedMapValueTFAttr(context.Background(), v, oldVal) } @@ -309,6 +299,37 @@ func getObjAttrsAndTypes(obj types.Object) (mapAttrs map[string]attr.Value, mapT return mapAttrs, mapTypes, nil } +func getObjectValueTFAttr(ctx context.Context, objJSON map[string]any, obj customtypes.ObjectValueInterface) (attr.Value, error) { + valuePtr, diags := obj.ValuePtrAsAny(ctx) + if diags.HasError() { + return nil, fmt.Errorf("unmarshal failed to convert object: %v", diags) + } + + err := unmarshalAttrs(objJSON, valuePtr) + if err != nil { + return nil, err + } + + return obj.NewObjectValue(ctx, valuePtr), nil +} + +func getMapValueTFAttr(ctx context.Context, mapJSON map[string]any, m customtypes.MapValueInterface) (attr.Value, error) { + mapAttrs := make(map[string]attr.Value, len(mapJSON)) + elemType := m.ElementType(ctx) + + for key, item := range mapJSON { + value, err := getTfAttr(item, elemType, nil, key) + if err != nil { + return nil, err + } + if value != nil { + mapAttrs[key] = value + } + } + + return m.NewMapValue(ctx, mapAttrs), nil +} + func getNestedMapValueTFAttr(ctx context.Context, mapJSON map[string]any, m customtypes.NestedMapValueInterface) (attr.Value, error) { oldMapPtr, diags := m.MapPtrAsAny(ctx) if diags.HasError() { @@ -382,11 +403,11 @@ func getArrayTFAttr(arrayJSON []any, elemType attr.Type, nameErr string) ([]attr slice := make([]attr.Value, len(arrayJSON)) for i, item := range arrayJSON { - newValue, err := getTfAttr(item, elemType, nil, nameErr) + value, err := getTfAttr(item, elemType, nil, nameErr) if err != nil { return nil, err } - slice[i] = newValue + slice[i] = value } return slice, nil diff --git a/internal/common/autogen/unmarshal_test.go b/internal/common/autogen/unmarshal_test.go index adef022279..29e70c7cc8 100644 --- a/internal/common/autogen/unmarshal_test.go +++ b/internal/common/autogen/unmarshal_test.go @@ -420,6 +420,7 @@ func TestUnmarshalCustomObject(t *testing.T) { AttrCustomObjUnknownNotSent customtypes.ObjectValue[unmarshalModelCustomType] `tfsdk:"attr_custom_obj_unknown_not_sent"` AttrCustomObjUnknownSent customtypes.ObjectValue[unmarshalModelCustomType] `tfsdk:"attr_custom_obj_unknown_sent"` AttrCustomObjParent customtypes.ObjectValue[unmarshalModelCustomType] `tfsdk:"attr_custom_obj_parent"` + AttrCustomObjZeroInit customtypes.ObjectValue[unmarshalModelCustomType] `tfsdk:"attr_custom_obj_zero"` } model := modelst{ @@ -460,6 +461,10 @@ func TestUnmarshalCustomObject(t *testing.T) { "attrCustomObjParent": { "attrString": "parent string", "attrNested": {} + }, + "attrCustomObjZeroInit": { + "attrString": "zero init string", + "attrNested": {} } } ` @@ -500,6 +505,14 @@ func TestUnmarshalCustomObject(t *testing.T) { AttrNested: customtypes.NewObjectValue[unmarshalModelEmpty](ctx, unmarshalModelEmpty{}), AttrMANYUpper: types.Int64Null(), }), + AttrCustomObjZeroInit: customtypes.NewObjectValue[unmarshalModelCustomType](ctx, unmarshalModelCustomType{ + AttrString: types.StringValue("zero init string"), + AttrInt: types.Int64Null(), + AttrFloat: types.Float64Null(), + AttrBool: types.BoolNull(), + AttrNested: customtypes.NewObjectValue[unmarshalModelEmpty](ctx, unmarshalModelEmpty{}), + AttrMANYUpper: types.Int64Null(), + }), } require.NoError(t, autogen.Unmarshal([]byte(jsonResp), &model)) @@ -516,6 +529,7 @@ func TestUnmarshalCustomList(t *testing.T) { AttrCustomNestedListNullSent customtypes.NestedListValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_list_null_sent"` AttrCustomNestedListUnknownNotSent customtypes.NestedListValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_list_unknown_not_sent"` AttrCustomNestedListUnknownSent customtypes.NestedListValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_list_unknown_sent"` + AttrCustomNestedListZeroInit customtypes.NestedListValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_list_zero"` } model := modelst{ @@ -572,6 +586,12 @@ func TestUnmarshalCustomList(t *testing.T) { { "attrString": "unknownSent" } + ], + "attrCustomNestedListZeroInit": [ + { + "attrString": "zero init string", + "attrNested": {} + } ] } ` @@ -613,6 +633,16 @@ func TestUnmarshalCustomList(t *testing.T) { AttrMANYUpper: types.Int64Null(), }, }), + AttrCustomNestedListZeroInit: customtypes.NewNestedListValue[unmarshalModelCustomType](ctx, []unmarshalModelCustomType{ + { + AttrString: types.StringValue("zero init string"), + AttrInt: types.Int64Null(), + AttrFloat: types.Float64Null(), + AttrBool: types.BoolNull(), + AttrNested: customtypes.NewObjectValue[unmarshalModelEmpty](ctx, unmarshalModelEmpty{}), + AttrMANYUpper: types.Int64Null(), + }, + }), } require.NoError(t, autogen.Unmarshal([]byte(jsonResp), &model)) @@ -629,6 +659,7 @@ func TestUnmarshalCustomSet(t *testing.T) { AttrCustomNestedSetNullSent customtypes.NestedSetValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_set_null_sent"` AttrCustomNestedSetUnknownNotSent customtypes.NestedSetValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_set_unknown_not_sent"` AttrCustomNestedSetUnknownSent customtypes.NestedSetValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_set_unknown_sent"` + AttrCustomNestedSetZeroInit customtypes.NestedSetValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_set_zero"` } model := modelst{ @@ -677,6 +708,12 @@ func TestUnmarshalCustomSet(t *testing.T) { { "attrString": "unknownSetSent" } + ], + "attrCustomNestedSetZeroInit": [ + { + "attrString": "zero init set string", + "attrNested": {} + } ] } ` @@ -718,6 +755,16 @@ func TestUnmarshalCustomSet(t *testing.T) { AttrMANYUpper: types.Int64Null(), }, }), + AttrCustomNestedSetZeroInit: customtypes.NewNestedSetValue[unmarshalModelCustomType](ctx, []unmarshalModelCustomType{ + { + AttrString: types.StringValue("zero init set string"), + AttrInt: types.Int64Null(), + AttrFloat: types.Float64Null(), + AttrBool: types.BoolNull(), + AttrNested: customtypes.NewObjectValue[unmarshalModelEmpty](ctx, unmarshalModelEmpty{}), + AttrMANYUpper: types.Int64Null(), + }, + }), } require.NoError(t, autogen.Unmarshal([]byte(jsonResp), &model)) @@ -728,14 +775,17 @@ func TestUnmarshalCustomMap(t *testing.T) { ctx := context.Background() type modelst struct { + AttrCustomMapString customtypes.MapValue[types.String] `tfsdk:"attr_custom_map_string"` AttrCustomNestedMap customtypes.NestedMapValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_map"` AttrCustomNestedMapNullNotSent customtypes.NestedMapValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_map_null_not_sent"` AttrCustomNestedMapNullSent customtypes.NestedMapValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_map_null_sent"` AttrCustomNestedMapUnknownNotSent customtypes.NestedMapValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_map_unknown_not_sent"` AttrCustomNestedMapUnknownSent customtypes.NestedMapValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_map_unknown_sent"` + AttrCustomNestedMapZeroInit customtypes.NestedMapValue[unmarshalModelCustomType] `tfsdk:"attr_custom_nested_map_zero"` } model := modelst{ + AttrCustomMapString: customtypes.NewMapValueUnknown[types.String](ctx), AttrCustomNestedMap: customtypes.NewNestedMapValue[unmarshalModelCustomType](ctx, map[string]unmarshalModelCustomType{ "keyOne": { AttrString: types.StringValue("different_string"), @@ -763,6 +813,10 @@ func TestUnmarshalCustomMap(t *testing.T) { const ( jsonResp = ` { + "attrCustomMapString": { + "keyOne": "map1", + "KeyTwo": "map2" + }, "attrCustomNestedMap": { "keyOne": { "attrString": "nestedMap1", @@ -784,12 +838,22 @@ func TestUnmarshalCustomMap(t *testing.T) { "keyOne": { "attrString": "unknownMapSent" } + }, + "attrCustomNestedMapZeroInit": { + "keyOne": { + "attrString": "zero init map string", + "attrNested": {} + } } } ` ) modelExpected := modelst{ + AttrCustomMapString: customtypes.NewMapValue[types.String](ctx, map[string]attr.Value{ + "keyOne": types.StringValue("map1"), + "KeyTwo": types.StringValue("map2"), + }), AttrCustomNestedMap: customtypes.NewNestedMapValue[unmarshalModelCustomType](ctx, map[string]unmarshalModelCustomType{ "keyOne": { AttrString: types.StringValue("nestedMap1"), @@ -821,6 +885,16 @@ func TestUnmarshalCustomMap(t *testing.T) { AttrMANYUpper: types.Int64Null(), }, }), + AttrCustomNestedMapZeroInit: customtypes.NewNestedMapValue[unmarshalModelCustomType](ctx, map[string]unmarshalModelCustomType{ + "keyOne": { + AttrString: types.StringValue("zero init map string"), + AttrInt: types.Int64Null(), + AttrFloat: types.Float64Null(), + AttrBool: types.BoolNull(), + AttrNested: customtypes.NewObjectValue[unmarshalModelEmpty](ctx, unmarshalModelEmpty{}), + AttrMANYUpper: types.Int64Null(), + }, + }), } require.NoError(t, autogen.Unmarshal([]byte(jsonResp), &model)) diff --git a/internal/serviceapi/clusterapi/resource_schema.go b/internal/serviceapi/clusterapi/resource_schema.go index 6433cc8b04..6e704a4044 100755 --- a/internal/serviceapi/clusterapi/resource_schema.go +++ b/internal/serviceapi/clusterapi/resource_schema.go @@ -9,6 +9,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/autogen/customtypes" "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/customplanmodifier" ) @@ -23,11 +24,13 @@ func ResourceSchema(ctx context.Context) schema.Schema { Computed: true, Optional: true, MarkdownDescription: "Group of settings that configures a subset of the advanced configuration details.", + CustomType: customtypes.NewObjectType[TFAdvancedConfigurationModel](ctx), Attributes: map[string]schema.Attribute{ "custom_openssl_cipher_config_tls12": schema.ListAttribute{ Computed: true, Optional: true, MarkdownDescription: "The custom OpenSSL cipher suite list for TLS 1.2. This field is only valid when `tlsCipherConfigMode` is set to `CUSTOM`.", + CustomType: customtypes.NewListType[types.String](ctx), ElementType: types.StringType, }, "minimum_enabled_tls_protocol": schema.StringAttribute{ @@ -51,6 +54,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Computed: true, Optional: true, MarkdownDescription: "Settings needed to configure the MongoDB Connector for Business Intelligence for this cluster.", + CustomType: customtypes.NewObjectType[TFBiConnectorModel](ctx), Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ Computed: true, @@ -80,15 +84,18 @@ func ResourceSchema(ctx context.Context) schema.Schema { "connection_strings": schema.SingleNestedAttribute{ Computed: true, MarkdownDescription: "Collection of Uniform Resource Locators that point to the MongoDB database.", + CustomType: customtypes.NewObjectType[TFConnectionStringsModel](ctx), Attributes: map[string]schema.Attribute{ "aws_private_link": schema.MapAttribute{ Computed: true, MarkdownDescription: "Private endpoint-aware connection strings that use AWS-hosted clusters with Amazon Web Services (AWS) PrivateLink. Each key identifies an Amazon Web Services (AWS) interface endpoint. Each value identifies the related `mongodb://` connection string that you use to connect to MongoDB Cloud through the interface endpoint that the key names.", + CustomType: customtypes.NewMapType[types.String](ctx), ElementType: types.StringType, }, "aws_private_link_srv": schema.MapAttribute{ Computed: true, MarkdownDescription: "Private endpoint-aware connection strings that use AWS-hosted clusters with Amazon Web Services (AWS) PrivateLink. Each key identifies an Amazon Web Services (AWS) interface endpoint. Each value identifies the related `mongodb://` connection string that you use to connect to Atlas through the interface endpoint that the key names. If the cluster uses an optimized connection string, `awsPrivateLinkSrv` contains the optimized connection string. If the cluster has the non-optimized (legacy) connection string, `awsPrivateLinkSrv` contains the non-optimized connection string even if an optimized connection string is also present.", + CustomType: customtypes.NewMapType[types.String](ctx), ElementType: types.StringType, }, "private": schema.StringAttribute{ @@ -98,6 +105,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "private_endpoint": schema.ListNestedAttribute{ Computed: true, MarkdownDescription: "List of private endpoint-aware connection strings that you can use to connect to this cluster through a private endpoint. This parameter returns only if you deployed a private endpoint to all regions to which you deployed this clusters' nodes.", + CustomType: customtypes.NewNestedListType[TFConnectionStringsPrivateEndpointModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "connection_string": schema.StringAttribute{ @@ -107,6 +115,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "endpoints": schema.ListNestedAttribute{ Computed: true, MarkdownDescription: "List that contains the private endpoints through which you connect to MongoDB Cloud when you use **connectionStrings.privateEndpoint[n].connectionString** or **connectionStrings.privateEndpoint[n].srvConnectionString**.", + CustomType: customtypes.NewNestedListType[TFConnectionStringsPrivateEndpointEndpointsModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "endpoint_id": schema.StringAttribute{ @@ -196,6 +205,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "labels": schema.ListNestedAttribute{ Optional: true, MarkdownDescription: "Collection of key-value pairs between 1 to 255 characters in length that tag and categorize the cluster. The MongoDB Cloud console doesn't display your labels.\n\nCluster labels are deprecated and will be removed in a future release. We strongly recommend that you use Resource Tags instead.", + CustomType: customtypes.NewNestedListType[TFLabelsModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "key": schema.StringAttribute{ @@ -212,6 +222,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "mongo_dbemployee_access_grant": schema.SingleNestedAttribute{ Optional: true, MarkdownDescription: "MongoDB employee granted access level and expiration for a cluster.", + CustomType: customtypes.NewObjectType[TFMongoDBEmployeeAccessGrantModel](ctx), Attributes: map[string]schema.Attribute{ "expiration_time": schema.StringAttribute{ Required: true, @@ -259,6 +270,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "replication_specs": schema.ListNestedAttribute{ Optional: true, MarkdownDescription: "List of settings that configure your cluster regions. This array has one object per shard representing node configurations in each shard. For replica sets there is only one object representing node configurations.", + CustomType: customtypes.NewNestedListType[TFReplicationSpecsModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "id": schema.StringAttribute{ @@ -268,15 +280,18 @@ func ResourceSchema(ctx context.Context) schema.Schema { "region_configs": schema.ListNestedAttribute{ Optional: true, MarkdownDescription: "Hardware specifications for nodes set for a given region. Each **regionConfigs** object must be unique by region and cloud provider within the **replicationSpec**. Each **regionConfigs** object describes the region's priority in elections and the number and type of MongoDB nodes that MongoDB Cloud deploys to the region. Each **regionConfigs** object must have either an **analyticsSpecs** object, **electableSpecs** object, or **readOnlySpecs** object. Tenant clusters only require **electableSpecs. Dedicated** clusters can specify any of these specifications, but must have at least one **electableSpecs** object within a **replicationSpec**.\n\n**Example:**\n\nIf you set `\"replicationSpecs[n].regionConfigs[m].analyticsSpecs.instanceSize\" : \"M30\"`, set `\"replicationSpecs[n].regionConfigs[m].electableSpecs.instanceSize\" : `\"M30\"` if you have electable nodes and `\"replicationSpecs[n].regionConfigs[m].readOnlySpecs.instanceSize\" : `\"M30\"` if you have read-only nodes.", + CustomType: customtypes.NewNestedListType[TFReplicationSpecsRegionConfigsModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "analytics_auto_scaling": schema.SingleNestedAttribute{ Optional: true, MarkdownDescription: "Options that determine how this cluster handles resource scaling.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingModel](ctx), Attributes: map[string]schema.Attribute{ "compute": schema.SingleNestedAttribute{ Optional: true, MarkdownDescription: "Options that determine how this cluster handles CPU scaling.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingComputeModel](ctx), Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ Optional: true, @@ -303,6 +318,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "disk_gb": schema.SingleNestedAttribute{ Optional: true, MarkdownDescription: "Setting that enables disk auto-scaling.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingDiskGBModel](ctx), Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ Optional: true, @@ -316,6 +332,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Computed: true, Optional: true, MarkdownDescription: "The current hardware specifications for read only nodes in the region.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAnalyticsSpecsModel](ctx), Attributes: map[string]schema.Attribute{ "disk_iops": schema.Int64Attribute{ Computed: true, @@ -347,11 +364,13 @@ func ResourceSchema(ctx context.Context) schema.Schema { Computed: true, Optional: true, MarkdownDescription: "Options that determine how this cluster handles resource scaling.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAutoScalingModel](ctx), Attributes: map[string]schema.Attribute{ "compute": schema.SingleNestedAttribute{ Computed: true, Optional: true, MarkdownDescription: "Options that determine how this cluster handles CPU scaling.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAutoScalingComputeModel](ctx), Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ Computed: true, @@ -384,6 +403,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Computed: true, Optional: true, MarkdownDescription: "Setting that enables disk auto-scaling.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAutoScalingDiskGBModel](ctx), Attributes: map[string]schema.Attribute{ "enabled": schema.BoolAttribute{ Computed: true, @@ -401,6 +421,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "effective_analytics_specs": schema.SingleNestedAttribute{ Computed: true, MarkdownDescription: "The current hardware specifications for read only nodes in the region.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsEffectiveAnalyticsSpecsModel](ctx), Attributes: map[string]schema.Attribute{ "disk_iops": schema.Int64Attribute{ Computed: true, @@ -427,6 +448,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "effective_electable_specs": schema.SingleNestedAttribute{ Computed: true, MarkdownDescription: "The current hardware specifications for read only nodes in the region.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsEffectiveElectableSpecsModel](ctx), Attributes: map[string]schema.Attribute{ "disk_iops": schema.Int64Attribute{ Computed: true, @@ -453,6 +475,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "effective_read_only_specs": schema.SingleNestedAttribute{ Computed: true, MarkdownDescription: "The current hardware specifications for read only nodes in the region.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsEffectiveReadOnlySpecsModel](ctx), Attributes: map[string]schema.Attribute{ "disk_iops": schema.Int64Attribute{ Computed: true, @@ -479,6 +502,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "electable_specs": schema.SingleNestedAttribute{ Optional: true, MarkdownDescription: "Hardware specifications for all electable nodes deployed in the region. Electable nodes can become the primary and can enable local reads. If you don't specify this option, MongoDB Cloud deploys no electable nodes to the region.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsElectableSpecsModel](ctx), Attributes: map[string]schema.Attribute{ "disk_iops": schema.Int64Attribute{ Computed: true, @@ -521,6 +545,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { Computed: true, Optional: true, MarkdownDescription: "The current hardware specifications for read only nodes in the region.", + CustomType: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsReadOnlySpecsModel](ctx), Attributes: map[string]schema.Attribute{ "disk_iops": schema.Int64Attribute{ Computed: true, @@ -579,6 +604,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "tags": schema.ListNestedAttribute{ Optional: true, MarkdownDescription: "List that contains key-value pairs between 1 to 255 characters in length for tagging and categorizing the cluster.", + CustomType: customtypes.NewNestedListType[TFTagsModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "key": schema.StringAttribute{ @@ -623,66 +649,66 @@ func ResourceSchema(ctx context.Context) schema.Schema { } type TFModel struct { - Labels types.List `tfsdk:"labels"` - Tags types.List `tfsdk:"tags"` - ReplicationSpecs types.List `tfsdk:"replication_specs"` - InternalClusterRole types.String `tfsdk:"internal_cluster_role" autogen:"omitjson"` - MongoDBVersion types.String `tfsdk:"mongo_dbversion" autogen:"omitjson"` - ConfigServerManagementMode types.String `tfsdk:"config_server_management_mode"` - ConfigServerType types.String `tfsdk:"config_server_type" autogen:"omitjson"` - ConnectionStrings types.Object `tfsdk:"connection_strings" autogen:"omitjson"` - CreateDate types.String `tfsdk:"create_date" autogen:"omitjson"` - DiskWarmingMode types.String `tfsdk:"disk_warming_mode"` - EncryptionAtRestProvider types.String `tfsdk:"encryption_at_rest_provider"` - MongoDBMajorVersion types.String `tfsdk:"mongo_dbmajor_version"` - FeatureCompatibilityVersionExpirationDate types.String `tfsdk:"feature_compatibility_version_expiration_date" autogen:"omitjson"` - Timeouts timeouts.Value `tfsdk:"timeouts" autogen:"omitjson"` - GroupId types.String `tfsdk:"group_id" autogen:"omitjson"` - Id types.String `tfsdk:"id" autogen:"omitjson"` - AcceptDataRisksAndForceReplicaSetReconfig types.String `tfsdk:"accept_data_risks_and_force_replica_set_reconfig"` - ClusterType types.String `tfsdk:"cluster_type"` - BiConnector types.Object `tfsdk:"bi_connector"` - FeatureCompatibilityVersion types.String `tfsdk:"feature_compatibility_version" autogen:"omitjson"` - MongoDBEmployeeAccessGrant types.Object `tfsdk:"mongo_dbemployee_access_grant"` - Name types.String `tfsdk:"name"` - VersionReleaseSystem types.String `tfsdk:"version_release_system"` - AdvancedConfiguration types.Object `tfsdk:"advanced_configuration"` - StateName types.String `tfsdk:"state_name" autogen:"omitjson"` - ReplicaSetScalingStrategy types.String `tfsdk:"replica_set_scaling_strategy"` - RootCertType types.String `tfsdk:"root_cert_type"` - BackupEnabled types.Bool `tfsdk:"backup_enabled"` - RedactClientLogData types.Bool `tfsdk:"redact_client_log_data"` - PitEnabled types.Bool `tfsdk:"pit_enabled"` - TerminationProtectionEnabled types.Bool `tfsdk:"termination_protection_enabled"` - UseAwsTimeBasedSnapshotCopyForFastInitialSync types.Bool `tfsdk:"use_aws_time_based_snapshot_copy_for_fast_initial_sync"` - Paused types.Bool `tfsdk:"paused"` - DeleteOnCreateTimeout types.Bool `tfsdk:"delete_on_create_timeout" autogen:"omitjson"` - GlobalClusterSelfManagedSharding types.Bool `tfsdk:"global_cluster_self_managed_sharding"` + Labels customtypes.NestedListValue[TFLabelsModel] `tfsdk:"labels"` + Tags customtypes.NestedListValue[TFTagsModel] `tfsdk:"tags"` + ReplicationSpecs customtypes.NestedListValue[TFReplicationSpecsModel] `tfsdk:"replication_specs"` + InternalClusterRole types.String `tfsdk:"internal_cluster_role" autogen:"omitjson"` + MongoDBVersion types.String `tfsdk:"mongo_dbversion" autogen:"omitjson"` + ConfigServerManagementMode types.String `tfsdk:"config_server_management_mode"` + ConfigServerType types.String `tfsdk:"config_server_type" autogen:"omitjson"` + ConnectionStrings customtypes.ObjectValue[TFConnectionStringsModel] `tfsdk:"connection_strings" autogen:"omitjson"` + CreateDate types.String `tfsdk:"create_date" autogen:"omitjson"` + DiskWarmingMode types.String `tfsdk:"disk_warming_mode"` + EncryptionAtRestProvider types.String `tfsdk:"encryption_at_rest_provider"` + MongoDBMajorVersion types.String `tfsdk:"mongo_dbmajor_version"` + FeatureCompatibilityVersionExpirationDate types.String `tfsdk:"feature_compatibility_version_expiration_date" autogen:"omitjson"` + Timeouts timeouts.Value `tfsdk:"timeouts" autogen:"omitjson"` + GroupId types.String `tfsdk:"group_id" autogen:"omitjson"` + Id types.String `tfsdk:"id" autogen:"omitjson"` + AcceptDataRisksAndForceReplicaSetReconfig types.String `tfsdk:"accept_data_risks_and_force_replica_set_reconfig"` + ClusterType types.String `tfsdk:"cluster_type"` + BiConnector customtypes.ObjectValue[TFBiConnectorModel] `tfsdk:"bi_connector"` + FeatureCompatibilityVersion types.String `tfsdk:"feature_compatibility_version" autogen:"omitjson"` + MongoDBEmployeeAccessGrant customtypes.ObjectValue[TFMongoDBEmployeeAccessGrantModel] `tfsdk:"mongo_dbemployee_access_grant"` + Name types.String `tfsdk:"name"` + VersionReleaseSystem types.String `tfsdk:"version_release_system"` + AdvancedConfiguration customtypes.ObjectValue[TFAdvancedConfigurationModel] `tfsdk:"advanced_configuration"` + StateName types.String `tfsdk:"state_name" autogen:"omitjson"` + ReplicaSetScalingStrategy types.String `tfsdk:"replica_set_scaling_strategy"` + RootCertType types.String `tfsdk:"root_cert_type"` + BackupEnabled types.Bool `tfsdk:"backup_enabled"` + RedactClientLogData types.Bool `tfsdk:"redact_client_log_data"` + PitEnabled types.Bool `tfsdk:"pit_enabled"` + TerminationProtectionEnabled types.Bool `tfsdk:"termination_protection_enabled"` + UseAwsTimeBasedSnapshotCopyForFastInitialSync types.Bool `tfsdk:"use_aws_time_based_snapshot_copy_for_fast_initial_sync"` + Paused types.Bool `tfsdk:"paused"` + DeleteOnCreateTimeout types.Bool `tfsdk:"delete_on_create_timeout" autogen:"omitjson"` + GlobalClusterSelfManagedSharding types.Bool `tfsdk:"global_cluster_self_managed_sharding"` } type TFAdvancedConfigurationModel struct { - CustomOpensslCipherConfigTls12 types.List `tfsdk:"custom_openssl_cipher_config_tls12"` - MinimumEnabledTlsProtocol types.String `tfsdk:"minimum_enabled_tls_protocol"` - TlsCipherConfigMode types.String `tfsdk:"tls_cipher_config_mode"` + CustomOpensslCipherConfigTls12 customtypes.ListValue[types.String] `tfsdk:"custom_openssl_cipher_config_tls12"` + MinimumEnabledTlsProtocol types.String `tfsdk:"minimum_enabled_tls_protocol"` + TlsCipherConfigMode types.String `tfsdk:"tls_cipher_config_mode"` } type TFBiConnectorModel struct { ReadPreference types.String `tfsdk:"read_preference"` Enabled types.Bool `tfsdk:"enabled"` } type TFConnectionStringsModel struct { - AwsPrivateLink types.Map `tfsdk:"aws_private_link" autogen:"omitjson"` - AwsPrivateLinkSrv types.Map `tfsdk:"aws_private_link_srv" autogen:"omitjson"` - Private types.String `tfsdk:"private" autogen:"omitjson"` - PrivateEndpoint types.List `tfsdk:"private_endpoint" autogen:"omitjson"` - PrivateSrv types.String `tfsdk:"private_srv" autogen:"omitjson"` - Standard types.String `tfsdk:"standard" autogen:"omitjson"` - StandardSrv types.String `tfsdk:"standard_srv" autogen:"omitjson"` + AwsPrivateLink customtypes.MapValue[types.String] `tfsdk:"aws_private_link" autogen:"omitjson"` + AwsPrivateLinkSrv customtypes.MapValue[types.String] `tfsdk:"aws_private_link_srv" autogen:"omitjson"` + Private types.String `tfsdk:"private" autogen:"omitjson"` + PrivateEndpoint customtypes.NestedListValue[TFConnectionStringsPrivateEndpointModel] `tfsdk:"private_endpoint" autogen:"omitjson"` + PrivateSrv types.String `tfsdk:"private_srv" autogen:"omitjson"` + Standard types.String `tfsdk:"standard" autogen:"omitjson"` + StandardSrv types.String `tfsdk:"standard_srv" autogen:"omitjson"` } type TFConnectionStringsPrivateEndpointModel struct { - ConnectionString types.String `tfsdk:"connection_string" autogen:"omitjson"` - Endpoints types.List `tfsdk:"endpoints" autogen:"omitjson"` - SrvConnectionString types.String `tfsdk:"srv_connection_string" autogen:"omitjson"` - SrvShardOptimizedConnectionString types.String `tfsdk:"srv_shard_optimized_connection_string" autogen:"omitjson"` - Type types.String `tfsdk:"type" autogen:"omitjson"` + ConnectionString types.String `tfsdk:"connection_string" autogen:"omitjson"` + Endpoints customtypes.NestedListValue[TFConnectionStringsPrivateEndpointEndpointsModel] `tfsdk:"endpoints" autogen:"omitjson"` + SrvConnectionString types.String `tfsdk:"srv_connection_string" autogen:"omitjson"` + SrvShardOptimizedConnectionString types.String `tfsdk:"srv_shard_optimized_connection_string" autogen:"omitjson"` + Type types.String `tfsdk:"type" autogen:"omitjson"` } type TFConnectionStringsPrivateEndpointEndpointsModel struct { EndpointId types.String `tfsdk:"endpoint_id" autogen:"omitjson"` @@ -698,28 +724,28 @@ type TFMongoDBEmployeeAccessGrantModel struct { GrantType types.String `tfsdk:"grant_type"` } type TFReplicationSpecsModel struct { - Id types.String `tfsdk:"id" autogen:"omitjson"` - RegionConfigs types.List `tfsdk:"region_configs"` - ZoneId types.String `tfsdk:"zone_id" autogen:"omitjson"` - ZoneName types.String `tfsdk:"zone_name"` + Id types.String `tfsdk:"id" autogen:"omitjson"` + RegionConfigs customtypes.NestedListValue[TFReplicationSpecsRegionConfigsModel] `tfsdk:"region_configs"` + ZoneId types.String `tfsdk:"zone_id" autogen:"omitjson"` + ZoneName types.String `tfsdk:"zone_name"` } type TFReplicationSpecsRegionConfigsModel struct { - AnalyticsAutoScaling types.Object `tfsdk:"analytics_auto_scaling"` - AnalyticsSpecs types.Object `tfsdk:"analytics_specs" autogen:"omitjson"` - AutoScaling types.Object `tfsdk:"auto_scaling"` - BackingProviderName types.String `tfsdk:"backing_provider_name"` - EffectiveAnalyticsSpecs types.Object `tfsdk:"effective_analytics_specs" autogen:"omitjson"` - EffectiveElectableSpecs types.Object `tfsdk:"effective_electable_specs" autogen:"omitjson"` - EffectiveReadOnlySpecs types.Object `tfsdk:"effective_read_only_specs" autogen:"omitjson"` - ElectableSpecs types.Object `tfsdk:"electable_specs"` - ProviderName types.String `tfsdk:"provider_name"` - ReadOnlySpecs types.Object `tfsdk:"read_only_specs" autogen:"omitjson"` - RegionName types.String `tfsdk:"region_name"` - Priority types.Int64 `tfsdk:"priority"` + AnalyticsAutoScaling customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingModel] `tfsdk:"analytics_auto_scaling"` + AnalyticsSpecs customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAnalyticsSpecsModel] `tfsdk:"analytics_specs" autogen:"omitjson"` + AutoScaling customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAutoScalingModel] `tfsdk:"auto_scaling"` + BackingProviderName types.String `tfsdk:"backing_provider_name"` + EffectiveAnalyticsSpecs customtypes.ObjectValue[TFReplicationSpecsRegionConfigsEffectiveAnalyticsSpecsModel] `tfsdk:"effective_analytics_specs" autogen:"omitjson"` + EffectiveElectableSpecs customtypes.ObjectValue[TFReplicationSpecsRegionConfigsEffectiveElectableSpecsModel] `tfsdk:"effective_electable_specs" autogen:"omitjson"` + EffectiveReadOnlySpecs customtypes.ObjectValue[TFReplicationSpecsRegionConfigsEffectiveReadOnlySpecsModel] `tfsdk:"effective_read_only_specs" autogen:"omitjson"` + ElectableSpecs customtypes.ObjectValue[TFReplicationSpecsRegionConfigsElectableSpecsModel] `tfsdk:"electable_specs"` + ProviderName types.String `tfsdk:"provider_name"` + ReadOnlySpecs customtypes.ObjectValue[TFReplicationSpecsRegionConfigsReadOnlySpecsModel] `tfsdk:"read_only_specs" autogen:"omitjson"` + RegionName types.String `tfsdk:"region_name"` + Priority types.Int64 `tfsdk:"priority"` } type TFReplicationSpecsRegionConfigsAnalyticsAutoScalingModel struct { - Compute types.Object `tfsdk:"compute"` - DiskGB types.Object `tfsdk:"disk_gb"` + Compute customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingComputeModel] `tfsdk:"compute"` + DiskGB customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingDiskGBModel] `tfsdk:"disk_gb"` } type TFReplicationSpecsRegionConfigsAnalyticsAutoScalingComputeModel struct { MaxInstanceSize types.String `tfsdk:"max_instance_size" autogen:"omitjson"` @@ -739,8 +765,8 @@ type TFReplicationSpecsRegionConfigsAnalyticsSpecsModel struct { NodeCount types.Int64 `tfsdk:"node_count" autogen:"omitjson"` } type TFReplicationSpecsRegionConfigsAutoScalingModel struct { - Compute types.Object `tfsdk:"compute"` - DiskGB types.Object `tfsdk:"disk_gb"` + Compute customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAutoScalingComputeModel] `tfsdk:"compute"` + DiskGB customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAutoScalingDiskGBModel] `tfsdk:"disk_gb"` } type TFReplicationSpecsRegionConfigsAutoScalingComputeModel struct { MaxInstanceSize types.String `tfsdk:"max_instance_size" autogen:"omitjson"` diff --git a/internal/serviceapi/streaminstanceapi/resource_schema.go b/internal/serviceapi/streaminstanceapi/resource_schema.go index e921bc6ead..42e12a8651 100755 --- a/internal/serviceapi/streaminstanceapi/resource_schema.go +++ b/internal/serviceapi/streaminstanceapi/resource_schema.go @@ -8,6 +8,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/autogen/customtypes" "github.com/mongodb/terraform-provider-mongodbatlas/internal/common/customplanmodifier" ) @@ -17,11 +18,13 @@ func ResourceSchema(ctx context.Context) schema.Schema { "connections": schema.ListNestedAttribute{ Computed: true, MarkdownDescription: "List of connections configured in the stream instance.", + CustomType: customtypes.NewNestedListType[TFConnectionsModel](ctx), NestedObject: schema.NestedAttributeObject{ Attributes: map[string]schema.Attribute{ "authentication": schema.SingleNestedAttribute{ Computed: true, MarkdownDescription: "User credentials required to connect to a Kafka Cluster. Includes the authentication type, as well as the parameters for that authentication mode.", + CustomType: customtypes.NewObjectType[TFConnectionsAuthenticationModel](ctx), Attributes: map[string]schema.Attribute{ "client_id": schema.StringAttribute{ Computed: true, @@ -78,6 +81,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "aws": schema.SingleNestedAttribute{ Computed: true, MarkdownDescription: "AWS configurations for AWS-based connection types.", + CustomType: customtypes.NewObjectType[TFConnectionsAwsModel](ctx), Attributes: map[string]schema.Attribute{ "role_arn": schema.StringAttribute{ Computed: true, @@ -104,11 +108,13 @@ func ResourceSchema(ctx context.Context) schema.Schema { "config": schema.MapAttribute{ Computed: true, MarkdownDescription: "A map of Kafka key-value pairs for optional configuration. This is a flat object, and keys can have '.' characters.", + CustomType: customtypes.NewMapType[types.String](ctx), ElementType: types.StringType, }, "db_role_to_execute": schema.SingleNestedAttribute{ Computed: true, MarkdownDescription: "The name of a Built in or Custom DB Role to connect to an Atlas Cluster.", + CustomType: customtypes.NewObjectType[TFConnectionsDbRoleToExecuteModel](ctx), Attributes: map[string]schema.Attribute{ "role": schema.StringAttribute{ Computed: true, @@ -123,6 +129,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "headers": schema.MapAttribute{ Computed: true, MarkdownDescription: "A map of key-value pairs that will be passed as headers for the request.", + CustomType: customtypes.NewMapType[types.String](ctx), ElementType: types.StringType, }, "name": schema.StringAttribute{ @@ -132,10 +139,12 @@ func ResourceSchema(ctx context.Context) schema.Schema { "networking": schema.SingleNestedAttribute{ Computed: true, MarkdownDescription: "Networking configuration for Streams connections.", + CustomType: customtypes.NewObjectType[TFConnectionsNetworkingModel](ctx), Attributes: map[string]schema.Attribute{ "access": schema.SingleNestedAttribute{ Computed: true, MarkdownDescription: "Information about networking access.", + CustomType: customtypes.NewObjectType[TFConnectionsNetworkingAccessModel](ctx), Attributes: map[string]schema.Attribute{ "connection_id": schema.StringAttribute{ Computed: true, @@ -160,6 +169,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "security": schema.SingleNestedAttribute{ Computed: true, MarkdownDescription: "Properties for the secure transport connection to Kafka. For SSL, this can include the trusted certificate to use.", + CustomType: customtypes.NewObjectType[TFConnectionsSecurityModel](ctx), Attributes: map[string]schema.Attribute{ "broker_public_certificate": schema.StringAttribute{ Computed: true, @@ -185,6 +195,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "data_process_region": schema.SingleNestedAttribute{ Optional: true, MarkdownDescription: "Information about the cloud provider region in which MongoDB Cloud processes the stream.", + CustomType: customtypes.NewObjectType[TFDataProcessRegionModel](ctx), PlanModifiers: []planmodifier.Object{customplanmodifier.CreateOnly()}, Attributes: map[string]schema.Attribute{ "cloud_provider": schema.StringAttribute{ @@ -205,6 +216,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "hostnames": schema.ListAttribute{ Computed: true, MarkdownDescription: "List that contains the hostnames assigned to the stream instance.", + CustomType: customtypes.NewListType[types.String](ctx), ElementType: types.StringType, }, "name": schema.StringAttribute{ @@ -215,6 +227,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "sample_connections": schema.SingleNestedAttribute{ Optional: true, MarkdownDescription: "Sample connections to add to SPI.", + CustomType: customtypes.NewObjectType[TFSampleConnectionsModel](ctx), PlanModifiers: []planmodifier.Object{customplanmodifier.CreateOnly()}, Attributes: map[string]schema.Attribute{ "solar": schema.BoolAttribute{ @@ -227,6 +240,7 @@ func ResourceSchema(ctx context.Context) schema.Schema { "stream_config": schema.SingleNestedAttribute{ Optional: true, MarkdownDescription: "Configuration options for an Atlas Stream Processing Instance.", + CustomType: customtypes.NewObjectType[TFStreamConfigModel](ctx), PlanModifiers: []planmodifier.Object{customplanmodifier.CreateOnly()}, Attributes: map[string]schema.Attribute{ "max_tier_size": schema.StringAttribute{ @@ -244,28 +258,28 @@ func ResourceSchema(ctx context.Context) schema.Schema { } type TFModel struct { - Connections types.List `tfsdk:"connections" autogen:"omitjson"` - DataProcessRegion types.Object `tfsdk:"data_process_region" autogen:"omitjsonupdate"` - GroupId types.String `tfsdk:"group_id" autogen:"omitjson"` - Hostnames types.List `tfsdk:"hostnames" autogen:"omitjson"` - Name types.String `tfsdk:"name" autogen:"omitjsonupdate"` - SampleConnections types.Object `tfsdk:"sample_connections" autogen:"omitjsonupdate"` - StreamConfig types.Object `tfsdk:"stream_config" autogen:"omitjsonupdate"` + Connections customtypes.NestedListValue[TFConnectionsModel] `tfsdk:"connections" autogen:"omitjson"` + DataProcessRegion customtypes.ObjectValue[TFDataProcessRegionModel] `tfsdk:"data_process_region" autogen:"omitjsonupdate"` + GroupId types.String `tfsdk:"group_id" autogen:"omitjson"` + Hostnames customtypes.ListValue[types.String] `tfsdk:"hostnames" autogen:"omitjson"` + Name types.String `tfsdk:"name" autogen:"omitjsonupdate"` + SampleConnections customtypes.ObjectValue[TFSampleConnectionsModel] `tfsdk:"sample_connections" autogen:"omitjsonupdate"` + StreamConfig customtypes.ObjectValue[TFStreamConfigModel] `tfsdk:"stream_config" autogen:"omitjsonupdate"` } type TFConnectionsModel struct { - Authentication types.Object `tfsdk:"authentication" autogen:"omitjson"` - Aws types.Object `tfsdk:"aws" autogen:"omitjson"` - BootstrapServers types.String `tfsdk:"bootstrap_servers" autogen:"omitjson"` - ClusterGroupId types.String `tfsdk:"cluster_group_id" autogen:"omitjson"` - ClusterName types.String `tfsdk:"cluster_name" autogen:"omitjson"` - Config types.Map `tfsdk:"config" autogen:"omitjson"` - DbRoleToExecute types.Object `tfsdk:"db_role_to_execute" autogen:"omitjson"` - Headers types.Map `tfsdk:"headers" autogen:"omitjson"` - Name types.String `tfsdk:"name" autogen:"omitjson"` - Networking types.Object `tfsdk:"networking" autogen:"omitjson"` - Security types.Object `tfsdk:"security" autogen:"omitjson"` - Type types.String `tfsdk:"type" autogen:"omitjson"` - Url types.String `tfsdk:"url" autogen:"omitjson"` + Authentication customtypes.ObjectValue[TFConnectionsAuthenticationModel] `tfsdk:"authentication" autogen:"omitjson"` + Aws customtypes.ObjectValue[TFConnectionsAwsModel] `tfsdk:"aws" autogen:"omitjson"` + BootstrapServers types.String `tfsdk:"bootstrap_servers" autogen:"omitjson"` + ClusterGroupId types.String `tfsdk:"cluster_group_id" autogen:"omitjson"` + ClusterName types.String `tfsdk:"cluster_name" autogen:"omitjson"` + Config customtypes.MapValue[types.String] `tfsdk:"config" autogen:"omitjson"` + DbRoleToExecute customtypes.ObjectValue[TFConnectionsDbRoleToExecuteModel] `tfsdk:"db_role_to_execute" autogen:"omitjson"` + Headers customtypes.MapValue[types.String] `tfsdk:"headers" autogen:"omitjson"` + Name types.String `tfsdk:"name" autogen:"omitjson"` + Networking customtypes.ObjectValue[TFConnectionsNetworkingModel] `tfsdk:"networking" autogen:"omitjson"` + Security customtypes.ObjectValue[TFConnectionsSecurityModel] `tfsdk:"security" autogen:"omitjson"` + Type types.String `tfsdk:"type" autogen:"omitjson"` + Url types.String `tfsdk:"url" autogen:"omitjson"` } type TFConnectionsAuthenticationModel struct { ClientId types.String `tfsdk:"client_id" autogen:"omitjson"` @@ -290,7 +304,7 @@ type TFConnectionsDbRoleToExecuteModel struct { Type types.String `tfsdk:"type" autogen:"omitjson"` } type TFConnectionsNetworkingModel struct { - Access types.Object `tfsdk:"access" autogen:"omitjson"` + Access customtypes.ObjectValue[TFConnectionsNetworkingAccessModel] `tfsdk:"access" autogen:"omitjson"` } type TFConnectionsNetworkingAccessModel struct { ConnectionId types.String `tfsdk:"connection_id" autogen:"omitjson"` diff --git a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go index 8c15c01908..fbcc38d33d 100644 --- a/tools/codegen/codespec/api_to_provider_spec_mapper_test.go +++ b/tools/codegen/codespec/api_to_provider_spec_mapper_test.go @@ -341,6 +341,7 @@ func TestConvertToProviderSpec_nested(t *testing.T) { TFSchemaName: "map_attr1", TFModelName: "MapAttr1", ComputedOptionalRequired: codespec.Computed, + CustomType: codespec.NewCustomMapType(codespec.String), Map: &codespec.MapAttribute{ ElementType: codespec.String, }, @@ -350,6 +351,7 @@ func TestConvertToProviderSpec_nested(t *testing.T) { TFSchemaName: "map_attr2", TFModelName: "MapAttr2", ComputedOptionalRequired: codespec.Computed, + CustomType: codespec.NewCustomMapType(codespec.String), Map: &codespec.MapAttribute{ ElementType: codespec.String, }, diff --git a/tools/codegen/codespec/attribute.go b/tools/codegen/codespec/attribute.go index 4ecd44a2db..c90b1a63dc 100644 --- a/tools/codegen/codespec/attribute.go +++ b/tools/codegen/codespec/attribute.go @@ -283,6 +283,9 @@ func (s *APISpecSchema) buildMapAttr(name, ancestorsName string, computability C return nil, err } + if useCustomNestedTypes { + result.CustomType = NewCustomMapType(elemType) + } result.Map = &MapAttribute{ ElementType: elemType, } diff --git a/tools/codegen/codespec/model.go b/tools/codegen/codespec/model.go index c1d32863cd..074e0bf997 100644 --- a/tools/codegen/codespec/model.go +++ b/tools/codegen/codespec/model.go @@ -250,6 +250,15 @@ func NewCustomNestedSetType(name string) *CustomType { } } +func NewCustomMapType(elemType ElemType) *CustomType { + elemTypeStr := ElementTypeToModelString[elemType] + return &CustomType{ + Package: CustomTypesPkg, + Model: fmt.Sprintf("customtypes.MapValue[%s]", elemTypeStr), + Schema: fmt.Sprintf("customtypes.NewMapType[%s](ctx)", elemTypeStr), + } +} + func NewCustomNestedMapType(name string) *CustomType { return &CustomType{ Package: CustomTypesPkg, diff --git a/tools/codegen/config.yml b/tools/codegen/config.yml index e97b70d501..dd612fc727 100644 --- a/tools/codegen/config.yml +++ b/tools/codegen/config.yml @@ -61,7 +61,6 @@ resources: target_states: ["DELETED"] # DELETED is a special state value when API returns 404 or empty object version_header: application/vnd.atlas.2024-08-05+json schema: - use_custom_nested_types: false ignores: ["links", "mongo_dbemployee_access_grant.links"] aliases: cluster_name: name # path param name does not match the API request property @@ -443,7 +442,6 @@ resources: method: DELETE version_header: application/vnd.atlas.2023-02-01+json schema: - use_custom_nested_types: false # region and cloud_provider are incorrectly declared in PATCH as root attributes, _id can't be used in Terraform schema ignores: [ diff --git a/tools/codegen/gofilegen/schema/schema_file_test.go b/tools/codegen/gofilegen/schema/schema_file_test.go index 5e85a766d2..226ed5503d 100644 --- a/tools/codegen/gofilegen/schema/schema_file_test.go +++ b/tools/codegen/gofilegen/schema/schema_file_test.go @@ -300,6 +300,14 @@ func TestSchemaGenerationFromCodeSpec(t *testing.T) { }, }, }, + { + TFSchemaName: "string_map_attr", + TFModelName: "StringMapAttr", + Description: admin.PtrString("string map attribute"), + ComputedOptionalRequired: codespec.Optional, + CustomType: codespec.NewCustomMapType(codespec.String), + Map: &codespec.MapAttribute{ElementType: codespec.String}, + }, { TFSchemaName: "map_nested_attribute", TFModelName: "MapNestedAttribute", diff --git a/tools/codegen/gofilegen/schema/testdata/custom-types-attributes.golden.go b/tools/codegen/gofilegen/schema/testdata/custom-types-attributes.golden.go index b330dc89c6..ad5d74df2b 100644 --- a/tools/codegen/gofilegen/schema/testdata/custom-types-attributes.golden.go +++ b/tools/codegen/gofilegen/schema/testdata/custom-types-attributes.golden.go @@ -89,6 +89,12 @@ func ResourceSchema(ctx context.Context) schema.Schema { }, }, }, + "string_map_attr": schema.MapAttribute{ + Optional: true, + MarkdownDescription: "string map attribute", + CustomType: customtypes.NewMapType[types.String](ctx), + ElementType: types.StringType, + }, "map_nested_attribute": schema.MapNestedAttribute{ Optional: true, MarkdownDescription: "nested map attribute", @@ -112,6 +118,7 @@ type TFModel struct { NestedListAttr customtypes.NestedListValue[TFNestedListAttrModel] `tfsdk:"nested_list_attr"` StringSetAttr customtypes.SetValue[types.String] `tfsdk:"string_set_attr"` NestedSetAttr customtypes.NestedSetValue[TFNestedSetAttrModel] `tfsdk:"nested_set_attr"` + StringMapAttr customtypes.MapValue[types.String] `tfsdk:"string_map_attr"` MapNestedAttribute customtypes.NestedMapValue[TFMapNestedAttributeModel] `tfsdk:"map_nested_attribute"` } type TFNestedObjectAttrModel struct { diff --git a/tools/codegen/models/cluster_api.yaml b/tools/codegen/models/cluster_api.yaml index e7dec5387f..735e5e3915 100755 --- a/tools/codegen/models/cluster_api.yaml +++ b/tools/codegen/models/cluster_api.yaml @@ -18,6 +18,10 @@ schema: - list: element_type: 4 description: The custom OpenSSL cipher suite list for TLS 1.2. This field is only valid when `tlsCipherConfigMode` is set to `CUSTOM`. + custom_type: + package: customtypes + model: customtypes.ListValue[types.String] + schema: customtypes.NewListType[types.String](ctx) computed_optional_required: computed_optional tf_schema_name: custom_openssl_cipher_config_tls12 tf_model_name: CustomOpensslCipherConfigTls12 @@ -41,6 +45,10 @@ schema: sensitive: false create_only: false description: Group of settings that configures a subset of the advanced configuration details. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFAdvancedConfigurationModel] + schema: customtypes.NewObjectType[TFAdvancedConfigurationModel](ctx) computed_optional_required: computed_optional tf_schema_name: advanced_configuration tf_model_name: AdvancedConfiguration @@ -76,6 +84,10 @@ schema: sensitive: false create_only: false description: Settings needed to configure the MongoDB Connector for Business Intelligence for this cluster. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFBiConnectorModel] + schema: customtypes.NewObjectType[TFBiConnectorModel](ctx) computed_optional_required: computed_optional tf_schema_name: bi_connector tf_model_name: BiConnector @@ -118,6 +130,10 @@ schema: - map: element_type: 4 description: Private endpoint-aware connection strings that use AWS-hosted clusters with Amazon Web Services (AWS) PrivateLink. Each key identifies an Amazon Web Services (AWS) interface endpoint. Each value identifies the related `mongodb://` connection string that you use to connect to MongoDB Cloud through the interface endpoint that the key names. + custom_type: + package: customtypes + model: customtypes.MapValue[types.String] + schema: customtypes.NewMapType[types.String](ctx) computed_optional_required: computed tf_schema_name: aws_private_link tf_model_name: AwsPrivateLink @@ -127,6 +143,10 @@ schema: - map: element_type: 4 description: Private endpoint-aware connection strings that use AWS-hosted clusters with Amazon Web Services (AWS) PrivateLink. Each key identifies an Amazon Web Services (AWS) interface endpoint. Each value identifies the related `mongodb://` connection string that you use to connect to Atlas through the interface endpoint that the key names. If the cluster uses an optimized connection string, `awsPrivateLinkSrv` contains the optimized connection string. If the cluster has the non-optimized (legacy) connection string, `awsPrivateLinkSrv` contains the non-optimized connection string even if an optimized connection string is also present. + custom_type: + package: customtypes + model: customtypes.MapValue[types.String] + schema: customtypes.NewMapType[types.String](ctx) computed_optional_required: computed tf_schema_name: aws_private_link_srv tf_model_name: AwsPrivateLinkSrv @@ -180,6 +200,10 @@ schema: sensitive: false create_only: false description: List that contains the private endpoints through which you connect to MongoDB Cloud when you use **connectionStrings.privateEndpoint[n].connectionString** or **connectionStrings.privateEndpoint[n].srvConnectionString**. + custom_type: + package: customtypes + model: customtypes.NestedListValue[TFConnectionStringsPrivateEndpointEndpointsModel] + schema: customtypes.NewNestedListType[TFConnectionStringsPrivateEndpointEndpointsModel](ctx) computed_optional_required: computed tf_schema_name: endpoints tf_model_name: Endpoints @@ -211,6 +235,10 @@ schema: sensitive: false create_only: false description: List of private endpoint-aware connection strings that you can use to connect to this cluster through a private endpoint. This parameter returns only if you deployed a private endpoint to all regions to which you deployed this clusters' nodes. + custom_type: + package: customtypes + model: customtypes.NestedListValue[TFConnectionStringsPrivateEndpointModel] + schema: customtypes.NewNestedListType[TFConnectionStringsPrivateEndpointModel](ctx) computed_optional_required: computed tf_schema_name: private_endpoint tf_model_name: PrivateEndpoint @@ -242,6 +270,10 @@ schema: sensitive: false create_only: false description: Collection of Uniform Resource Locators that point to the MongoDB database. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFConnectionStringsModel] + schema: customtypes.NewObjectType[TFConnectionStringsModel](ctx) computed_optional_required: computed tf_schema_name: connection_strings tf_model_name: ConnectionStrings @@ -355,6 +387,10 @@ schema: Cluster labels are deprecated and will be removed in a future release. We strongly recommend that you use Resource Tags instead. deprecation_message: This attribute has been deprecated + custom_type: + package: customtypes + model: customtypes.NestedListValue[TFLabelsModel] + schema: customtypes.NewNestedListType[TFLabelsModel](ctx) computed_optional_required: optional tf_schema_name: labels tf_model_name: Labels @@ -381,6 +417,10 @@ schema: sensitive: false create_only: false description: MongoDB employee granted access level and expiration for a cluster. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFMongoDBEmployeeAccessGrantModel] + schema: customtypes.NewObjectType[TFMongoDBEmployeeAccessGrantModel](ctx) computed_optional_required: optional tf_schema_name: mongo_dbemployee_access_grant tf_model_name: MongoDBEmployeeAccessGrant @@ -527,6 +567,10 @@ schema: sensitive: false create_only: false description: Options that determine how this cluster handles CPU scaling. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingComputeModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingComputeModel](ctx) computed_optional_required: optional tf_schema_name: compute tf_model_name: Compute @@ -545,6 +589,10 @@ schema: sensitive: false create_only: false description: Setting that enables disk auto-scaling. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingDiskGBModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingDiskGBModel](ctx) computed_optional_required: optional tf_schema_name: disk_gb tf_model_name: DiskGB @@ -552,6 +600,10 @@ schema: sensitive: false create_only: false description: Options that determine how this cluster handles resource scaling. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAnalyticsAutoScalingModel](ctx) computed_optional_required: optional tf_schema_name: analytics_auto_scaling tf_model_name: AnalyticsAutoScaling @@ -611,6 +663,10 @@ schema: sensitive: false create_only: false description: The current hardware specifications for read only nodes in the region. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAnalyticsSpecsModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAnalyticsSpecsModel](ctx) computed_optional_required: computed_optional tf_schema_name: analytics_specs tf_model_name: AnalyticsSpecs @@ -672,6 +728,10 @@ schema: sensitive: false create_only: false description: Options that determine how this cluster handles CPU scaling. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAutoScalingComputeModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAutoScalingComputeModel](ctx) computed_optional_required: computed_optional tf_schema_name: compute tf_model_name: Compute @@ -690,6 +750,10 @@ schema: sensitive: false create_only: false description: Setting that enables disk auto-scaling. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAutoScalingDiskGBModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAutoScalingDiskGBModel](ctx) computed_optional_required: computed_optional tf_schema_name: disk_gb tf_model_name: DiskGB @@ -697,6 +761,10 @@ schema: sensitive: false create_only: false description: Options that determine how this cluster handles resource scaling. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsAutoScalingModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsAutoScalingModel](ctx) computed_optional_required: computed_optional tf_schema_name: auto_scaling tf_model_name: AutoScaling @@ -764,6 +832,10 @@ schema: sensitive: false create_only: false description: The current hardware specifications for read only nodes in the region. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsEffectiveAnalyticsSpecsModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsEffectiveAnalyticsSpecsModel](ctx) computed_optional_required: computed tf_schema_name: effective_analytics_specs tf_model_name: EffectiveAnalyticsSpecs @@ -823,6 +895,10 @@ schema: sensitive: false create_only: false description: The current hardware specifications for read only nodes in the region. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsEffectiveElectableSpecsModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsEffectiveElectableSpecsModel](ctx) computed_optional_required: computed tf_schema_name: effective_electable_specs tf_model_name: EffectiveElectableSpecs @@ -882,6 +958,10 @@ schema: sensitive: false create_only: false description: The current hardware specifications for read only nodes in the region. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsEffectiveReadOnlySpecsModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsEffectiveReadOnlySpecsModel](ctx) computed_optional_required: computed tf_schema_name: effective_read_only_specs tf_model_name: EffectiveReadOnlySpecs @@ -949,6 +1029,10 @@ schema: sensitive: false create_only: false description: Hardware specifications for all electable nodes deployed in the region. Electable nodes can become the primary and can enable local reads. If you don't specify this option, MongoDB Cloud deploys no electable nodes to the region. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsElectableSpecsModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsElectableSpecsModel](ctx) computed_optional_required: optional tf_schema_name: electable_specs tf_model_name: ElectableSpecs @@ -1027,6 +1111,10 @@ schema: sensitive: false create_only: false description: The current hardware specifications for read only nodes in the region. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFReplicationSpecsRegionConfigsReadOnlySpecsModel] + schema: customtypes.NewObjectType[TFReplicationSpecsRegionConfigsReadOnlySpecsModel](ctx) computed_optional_required: computed_optional tf_schema_name: read_only_specs tf_model_name: ReadOnlySpecs @@ -1047,6 +1135,10 @@ schema: **Example:** If you set `"replicationSpecs[n].regionConfigs[m].analyticsSpecs.instanceSize" : "M30"`, set `"replicationSpecs[n].regionConfigs[m].electableSpecs.instanceSize" : `"M30"` if you have electable nodes and `"replicationSpecs[n].regionConfigs[m].readOnlySpecs.instanceSize" : `"M30"` if you have read-only nodes. + custom_type: + package: customtypes + model: customtypes.NestedListValue[TFReplicationSpecsRegionConfigsModel] + schema: customtypes.NewNestedListType[TFReplicationSpecsRegionConfigsModel](ctx) computed_optional_required: optional tf_schema_name: region_configs tf_model_name: RegionConfigs @@ -1070,6 +1162,10 @@ schema: sensitive: false create_only: false description: List of settings that configure your cluster regions. This array has one object per shard representing node configurations in each shard. For replica sets there is only one object representing node configurations. + custom_type: + package: customtypes + model: customtypes.NestedListValue[TFReplicationSpecsModel] + schema: customtypes.NewNestedListType[TFReplicationSpecsModel](ctx) computed_optional_required: optional tf_schema_name: replication_specs tf_model_name: ReplicationSpecs @@ -1120,6 +1216,10 @@ schema: sensitive: false create_only: false description: List that contains key-value pairs between 1 to 255 characters in length for tagging and categorizing the cluster. + custom_type: + package: customtypes + model: customtypes.NestedListValue[TFTagsModel] + schema: customtypes.NewNestedListType[TFTagsModel](ctx) computed_optional_required: optional tf_schema_name: tags tf_model_name: Tags diff --git a/tools/codegen/models/stream_instance_api.yaml b/tools/codegen/models/stream_instance_api.yaml index a85f01230c..aa413b4d2d 100755 --- a/tools/codegen/models/stream_instance_api.yaml +++ b/tools/codegen/models/stream_instance_api.yaml @@ -104,6 +104,10 @@ schema: sensitive: false create_only: false description: User credentials required to connect to a Kafka Cluster. Includes the authentication type, as well as the parameters for that authentication mode. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFConnectionsAuthenticationModel] + schema: customtypes.NewObjectType[TFConnectionsAuthenticationModel](ctx) computed_optional_required: computed tf_schema_name: authentication tf_model_name: Authentication @@ -130,6 +134,10 @@ schema: sensitive: false create_only: false description: AWS configurations for AWS-based connection types. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFConnectionsAwsModel] + schema: customtypes.NewObjectType[TFConnectionsAwsModel](ctx) computed_optional_required: computed tf_schema_name: aws tf_model_name: Aws @@ -163,6 +171,10 @@ schema: - map: element_type: 4 description: A map of Kafka key-value pairs for optional configuration. This is a flat object, and keys can have '.' characters. + custom_type: + package: customtypes + model: customtypes.MapValue[types.String] + schema: customtypes.NewMapType[types.String](ctx) computed_optional_required: computed tf_schema_name: config tf_model_name: Config @@ -189,6 +201,10 @@ schema: sensitive: false create_only: false description: The name of a Built in or Custom DB Role to connect to an Atlas Cluster. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFConnectionsDbRoleToExecuteModel] + schema: customtypes.NewObjectType[TFConnectionsDbRoleToExecuteModel](ctx) computed_optional_required: computed tf_schema_name: db_role_to_execute tf_model_name: DbRoleToExecute @@ -198,6 +214,10 @@ schema: - map: element_type: 4 description: A map of key-value pairs that will be passed as headers for the request. + custom_type: + package: customtypes + model: customtypes.MapValue[types.String] + schema: customtypes.NewMapType[types.String](ctx) computed_optional_required: computed tf_schema_name: headers tf_model_name: Headers @@ -251,6 +271,10 @@ schema: sensitive: false create_only: false description: Information about networking access. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFConnectionsNetworkingAccessModel] + schema: customtypes.NewObjectType[TFConnectionsNetworkingAccessModel](ctx) computed_optional_required: computed tf_schema_name: access tf_model_name: Access @@ -258,6 +282,10 @@ schema: sensitive: false create_only: false description: Networking configuration for Streams connections. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFConnectionsNetworkingModel] + schema: customtypes.NewObjectType[TFConnectionsNetworkingModel](ctx) computed_optional_required: computed tf_schema_name: networking tf_model_name: Networking @@ -284,6 +312,10 @@ schema: sensitive: false create_only: false description: Properties for the secure transport connection to Kafka. For SSL, this can include the trusted certificate to use. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFConnectionsSecurityModel] + schema: customtypes.NewObjectType[TFConnectionsSecurityModel](ctx) computed_optional_required: computed tf_schema_name: security tf_model_name: Security @@ -307,6 +339,10 @@ schema: sensitive: false create_only: false description: List of connections configured in the stream instance. + custom_type: + package: customtypes + model: customtypes.NestedListValue[TFConnectionsModel] + schema: customtypes.NewNestedListType[TFConnectionsModel](ctx) computed_optional_required: computed tf_schema_name: connections tf_model_name: Connections @@ -333,6 +369,10 @@ schema: sensitive: false create_only: false description: Information about the cloud provider region in which MongoDB Cloud processes the stream. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFDataProcessRegionModel] + schema: customtypes.NewObjectType[TFDataProcessRegionModel](ctx) computed_optional_required: optional tf_schema_name: data_process_region tf_model_name: DataProcessRegion @@ -353,6 +393,10 @@ schema: - list: element_type: 4 description: List that contains the hostnames assigned to the stream instance. + custom_type: + package: customtypes + model: customtypes.ListValue[types.String] + schema: customtypes.NewListType[types.String](ctx) computed_optional_required: computed tf_schema_name: hostnames tf_model_name: Hostnames @@ -380,6 +424,10 @@ schema: sensitive: false create_only: false description: Sample connections to add to SPI. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFSampleConnectionsModel] + schema: customtypes.NewObjectType[TFSampleConnectionsModel](ctx) computed_optional_required: optional tf_schema_name: sample_connections tf_model_name: SampleConnections @@ -406,6 +454,10 @@ schema: sensitive: false create_only: false description: Configuration options for an Atlas Stream Processing Instance. + custom_type: + package: customtypes + model: customtypes.ObjectValue[TFStreamConfigModel] + schema: customtypes.NewObjectType[TFStreamConfigModel](ctx) computed_optional_required: optional tf_schema_name: stream_config tf_model_name: StreamConfig