Skip to content

Commit f92a71e

Browse files
committed
Remove rawNames from makeObjectTerraformInputs
It never makes sense to pass `rawNames=true` to `makeObjectTerraformInputs` since that implies we have an object type with properties, but that we should not do property name translations. This is never the case. This PR introduces a subtle change in behavior when walking values of unknown type: Before this PR, we assumed that an untyped `resource.PropertyMap` was an object (name translation is performed) but all nested `resource.PropertyMap` values were then assumed to be a map (name translation is not performed). After this PR, we treat all untyped `resource.PropertyMap` values as maps. IMO this makes more sense: the rule is we don't apply name translation unless we know a value is an object (and can thus generate naming tables for it). I don't expect that this change will break users since user's should never hit untyped values. If they do, neither before or after will work consistently. Addressing the test change: "object_property_value" was used to test object names but never given a type. In light of the above change, we needed to make it typed to get the expected name translation.
1 parent 7aa41da commit f92a71e

File tree

2 files changed

+34
-52
lines changed

2 files changed

+34
-52
lines changed

pkg/tfbridge/schema.go

Lines changed: 33 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -479,51 +479,40 @@ func (ctx *conversionContext) makeTerraformInput(
479479
oldObject = old.ObjectValue()
480480
}
481481

482-
var input map[string]interface{}
483-
if shimutil.IsOfTypeMap(tfs) {
484-
var tfsElem shim.Schema
485-
if tfs != nil {
486-
if s, ok := tfs.Elem().(shim.Schema); ok {
487-
tfsElem = s
488-
}
489-
}
490-
var psElem *SchemaInfo
491-
if ps != nil {
492-
psElem = ps.Elem
493-
}
494-
var err error
495-
input, err = ctx.makeMapTerraformInputs(oldObject, v.ObjectValue(),
496-
tfsElem, psElem)
497-
if err != nil {
498-
return nil, err
499-
}
500-
} else {
501-
var tfflds shim.SchemaMap
502-
if tfs != nil {
503-
if res, isres := tfs.Elem().(shim.Resource); isres {
504-
tfflds = res.Schema()
505-
}
482+
var tfflds shim.SchemaMap
483+
484+
// We cannot use [shimutil.CastToTypeObject] because we have machinery that constructs invalid
485+
// resource objects, such as [elemSchemas].
486+
if tfs != nil {
487+
if r, ok := tfs.Elem().(shim.Resource); ok {
488+
tfflds = r.Schema()
506489
}
490+
}
491+
492+
if tfflds != nil {
507493
var psflds map[string]*SchemaInfo
508494
if ps != nil {
509495
psflds = ps.Fields
510496
}
511-
var err error
512-
input, err = ctx.makeObjectTerraformInputs(oldObject, v.ObjectValue(),
513-
tfflds, psflds, rawNames)
497+
obj, err := ctx.makeObjectTerraformInputs(oldObject, v.ObjectValue(), tfflds, psflds)
514498
if err != nil {
515499
return nil, err
516500
}
517-
}
518501

519-
// If we have schema information that indicates that this value is being presented to a map-typed field whose
520-
// Elem is a shim.Resource, wrap the value in an array in order to work around a bug in Terraform.
521-
if tfs != nil && tfs.Type() == shim.TypeMap {
522-
if _, hasResourceElem := tfs.Elem().(shim.Resource); hasResourceElem {
523-
return []interface{}{input}, nil
502+
if tfs.Type() == shim.TypeMap {
503+
// If we have schema information that indicates that this value is being
504+
// presented to a map-typed field whose Elem is a shim.Resource, wrap the
505+
// value in an array in order to work around a bug in Terraform.
506+
//
507+
// TODO[pulumi/pulumi-terraform-bridge#1828]: This almost certainly stems from
508+
// a bug in the bridge's implementation and not terraform's implementation.
509+
return []interface{}{obj}, nil
524510
}
511+
return obj, nil
525512
}
526-
return input, nil
513+
514+
etfs, eps := elemSchemas(tfs, ps)
515+
return ctx.makeMapTerraformInputs(oldObject, v.ObjectValue(), etfs, eps)
527516
case v.IsComputed() || v.IsOutput():
528517
// If any variables are unknown, we need to mark them in the inputs so the config map treats it right. This
529518
// requires the use of the special UnknownVariableValue sentinel in Terraform, which is how it internally stores
@@ -533,7 +522,6 @@ func (ctx *conversionContext) makeTerraformInput(
533522
contract.Failf("Unexpected value marshaled: %v", v)
534523
return nil, nil
535524
}
536-
537525
}
538526

539527
// makeTerraformInputs takes a property map plus custom schema info and does whatever is necessary
@@ -545,7 +533,7 @@ func (ctx *conversionContext) makeTerraformInputs(
545533
tfs shim.SchemaMap,
546534
ps map[string]*SchemaInfo,
547535
) (map[string]interface{}, error) {
548-
return ctx.makeObjectTerraformInputs(olds, news, tfs, ps, false /*rawNames*/)
536+
return ctx.makeObjectTerraformInputs(olds, news, tfs, ps)
549537
}
550538

551539
// Should only be called from inside makeTerraformInputs. Variation for makeTerraformInputs used
@@ -591,14 +579,14 @@ func (ctx *conversionContext) makeMapTerraformInputs(
591579
return result, nil
592580
}
593581

594-
// Should only be called from inside makeTerraformInputs. This variation should only be handling the
595-
// case when an object type is expected, or else the schema is lost and the translation is not sure
596-
// of the expected type. The case when map types are expected is handled by makeMapTerraformInputs.
582+
// Should only be called from inside makeTerraformInputs. This variation should only be
583+
// handling the case when an object type is expected. The case when map types are expected
584+
// or the schema is lost and the translation is not sure of the expected type is handled
585+
// by makeMapTerraformInputs.
597586
func (ctx *conversionContext) makeObjectTerraformInputs(
598587
olds, news resource.PropertyMap,
599588
tfs shim.SchemaMap,
600589
ps map[string]*SchemaInfo,
601-
rawNames bool,
602590
) (map[string]interface{}, error) {
603591
result := make(map[string]interface{})
604592
tfAttributesToPulumiProperties := make(map[string]string)
@@ -612,14 +600,8 @@ func (ctx *conversionContext) makeObjectTerraformInputs(
612600
}
613601

614602
// First translate the Pulumi property name to a Terraform name.
615-
name, tfi, psi := getInfoFromPulumiName(key, tfs, ps, rawNames)
616-
617-
// rawNames=true indicate that we are processing a map[string,X], not an object type, and therefore
618-
// should not be renaming terraform_style names to pulumiStyle names or assuming that the map keys are
619-
// non-empty.
620-
if !rawNames {
621-
contract.Assertf(name != "", `name != ""`)
622-
}
603+
name, tfi, psi := getInfoFromPulumiName(key, tfs, ps, false)
604+
contract.Assertf(name != "", `Object properties cannot be empty`)
623605

624606
if _, duplicate := result[name]; duplicate {
625607
// If multiple Pulumi `key`s map to the same Terraform attribute `name`, then
@@ -644,7 +626,7 @@ func (ctx *conversionContext) makeObjectTerraformInputs(
644626
}
645627

646628
// And then translate the property value.
647-
v, err := ctx.makeTerraformInput(name, old, value, tfi, psi, rawNames)
629+
v, err := ctx.makeTerraformInput(name, old, value, tfi, psi, false)
648630
if err != nil {
649631
return nil, err
650632
}
@@ -653,15 +635,15 @@ func (ctx *conversionContext) makeObjectTerraformInputs(
653635
}
654636

655637
// Now enumerate and propagate defaults if the corresponding values are still missing.
656-
if err := ctx.applyDefaults(result, olds, news, tfs, ps, rawNames); err != nil {
638+
if err := ctx.applyDefaults(result, olds, news, tfs, ps, false); err != nil {
657639
return nil, err
658640
}
659641

660642
if tfs != nil && ctx.ApplyMaxItemsOneDefaults {
661643
// Iterate over the TF schema and add an empty array for each nil MaxItemsOne property.
662644
tfs.Range(func(key string, value shim.Schema) bool {
663645
// First do a lookup of the name/info.
664-
_, tfi, psi := getInfoFromTerraformName(key, tfs, ps, rawNames)
646+
_, tfi, psi := getInfoFromTerraformName(key, tfs, ps, false)
665647
if IsMaxItemsOne(tfi, psi) && result[key] == nil {
666648
result[key] = []interface{}{}
667649
}

pkg/tfbridge/schema_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3082,7 +3082,7 @@ func Test_makeTerraformInputsNoDefaults(t *testing.T) {
30823082
},
30833083
}),
30843084
//nolint:lll
3085-
expect: autogold.Expect(map[string]interface{}{"property_a": "a", "property_b": true, "property_c": map[string]interface{}{"nested_property_a": true}}),
3085+
expect: autogold.Expect(map[string]interface{}{"property_a": "a", "property_b": true, "property_c": map[string]interface{}{"nestedPropertyA": true}}),
30863086
},
30873087
{
30883088
testCaseName: "list_nested_block",

0 commit comments

Comments
 (0)