mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
NestingSingle blocks can be null
NestingSingle blocks removed from from the config were causing a plan to error out with "... planned for existence but config wants absence". Terraform core was proposing an incorrect value in this case, taking the prior instead as a fallback because a null value was not expected. Unlike other collection nesting modes, a NestingSingle block not present in the configuration is a null value, and should be allowed when planning a new value rather than building an empty object or falling back to the prior value.
This commit is contained in:
parent
6e2a7496c4
commit
d5d6d61c4c
@ -69,10 +69,15 @@ func PlannedDataResourceObject(schema *configschema.Block, config cty.Value) cty
|
||||
|
||||
func proposedNew(schema *configschema.Block, prior, config cty.Value) cty.Value {
|
||||
if config.IsNull() || !config.IsKnown() {
|
||||
// This is a weird situation, but we'll allow it anyway to free
|
||||
// callers from needing to specifically check for these cases.
|
||||
// A block config should never be null at this point. The only nullable
|
||||
// block type is NestingSingle, which will return early before coming
|
||||
// back here. We'll allow the null here anyway to free callers from
|
||||
// needing to specifically check for these cases, and any mismatch will
|
||||
// be caught in validation, so just take the prior value rather than
|
||||
// the invalid null.
|
||||
return prior
|
||||
}
|
||||
|
||||
if (!prior.Type().IsObjectType()) || (!config.Type().IsObjectType()) {
|
||||
panic("ProposedNew only supports object-typed values")
|
||||
}
|
||||
@ -106,7 +111,17 @@ func proposedNewNestedBlock(schema *configschema.NestedBlock, prior, config cty.
|
||||
|
||||
switch schema.Nesting {
|
||||
|
||||
case configschema.NestingSingle, configschema.NestingGroup:
|
||||
case configschema.NestingSingle:
|
||||
// A NestingSingle configuration block value can be null, and since it
|
||||
// cannot be computed we can always take the configuration value.
|
||||
if config.IsNull() {
|
||||
newV = config
|
||||
break
|
||||
}
|
||||
|
||||
// Otherwise use the same assignment rules as NestingGroup
|
||||
fallthrough
|
||||
case configschema.NestingGroup:
|
||||
newV = ProposedNew(&schema.Block, prior, config)
|
||||
|
||||
case configschema.NestingList:
|
||||
|
@ -353,6 +353,77 @@ func TestProposedNew(t *testing.T) {
|
||||
}),
|
||||
}),
|
||||
},
|
||||
"prior nested single to null": {
|
||||
&configschema.Block{
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
"foo": {
|
||||
Nesting: configschema.NestingSingle,
|
||||
Block: configschema.Block{
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"bar": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
"baz": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
Computed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"bloop": {
|
||||
NestedType: &configschema.Object{
|
||||
Nesting: configschema.NestingSingle,
|
||||
Attributes: map[string]*configschema.Attribute{
|
||||
"blop": {
|
||||
Type: cty.String,
|
||||
Required: true,
|
||||
},
|
||||
"bleep": {
|
||||
Type: cty.String,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.ObjectVal(map[string]cty.Value{
|
||||
"bar": cty.StringVal("beep"),
|
||||
"baz": cty.StringVal("boop"),
|
||||
}),
|
||||
"bloop": cty.ObjectVal(map[string]cty.Value{
|
||||
"blop": cty.StringVal("glub"),
|
||||
"bleep": cty.NullVal(cty.String),
|
||||
}),
|
||||
}),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.NullVal(cty.Object(map[string]cty.Type{
|
||||
"bar": cty.String,
|
||||
"baz": cty.String,
|
||||
})),
|
||||
"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
|
||||
"blop": cty.String,
|
||||
"bleep": cty.String,
|
||||
})),
|
||||
}),
|
||||
cty.ObjectVal(map[string]cty.Value{
|
||||
"foo": cty.NullVal(cty.Object(map[string]cty.Type{
|
||||
"bar": cty.String,
|
||||
"baz": cty.String,
|
||||
})),
|
||||
"bloop": cty.NullVal(cty.Object(map[string]cty.Type{
|
||||
"blop": cty.String,
|
||||
"bleep": cty.String,
|
||||
})),
|
||||
}),
|
||||
},
|
||||
"prior nested list": {
|
||||
&configschema.Block{
|
||||
BlockTypes: map[string]*configschema.NestedBlock{
|
||||
|
Loading…
Reference in New Issue
Block a user