Merge pull request #20308 from hashicorp/jbardin/requires-replace
Requires replace should not error on missing index steps
This commit is contained in:
commit
b758628e51
|
@ -25,6 +25,11 @@ func testResourceList() *schema.Resource {
|
||||||
Type: schema.TypeInt,
|
Type: schema.TypeInt,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
},
|
},
|
||||||
|
"force_new": {
|
||||||
|
Type: schema.TypeString,
|
||||||
|
Optional: true,
|
||||||
|
ForceNew: true,
|
||||||
|
},
|
||||||
"sublist_block": {
|
"sublist_block": {
|
||||||
Type: schema.TypeList,
|
Type: schema.TypeList,
|
||||||
Optional: true,
|
Optional: true,
|
||||||
|
|
|
@ -188,3 +188,33 @@ resource "test_resource_list" "bar" {
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestResourceList_removedForcesNew(t *testing.T) {
|
||||||
|
resource.UnitTest(t, resource.TestCase{
|
||||||
|
Providers: testAccProviders,
|
||||||
|
CheckDestroy: testAccCheckResourceDestroy,
|
||||||
|
Steps: []resource.TestStep{
|
||||||
|
resource.TestStep{
|
||||||
|
Config: strings.TrimSpace(`
|
||||||
|
resource "test_resource_list" "foo" {
|
||||||
|
list_block {
|
||||||
|
force_new = "ok"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`),
|
||||||
|
Check: resource.ComposeTestCheckFunc(
|
||||||
|
resource.TestCheckResourceAttr(
|
||||||
|
"test_resource_list.foo", "list_block.0.force_new", "ok",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
resource.TestStep{
|
||||||
|
Config: strings.TrimSpace(`
|
||||||
|
resource "test_resource_list" "foo" {
|
||||||
|
}
|
||||||
|
`),
|
||||||
|
Check: resource.ComposeTestCheckFunc(),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
@ -264,16 +264,15 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
for _, path := range resp.RequiresReplace {
|
for _, path := range resp.RequiresReplace {
|
||||||
if priorVal.IsNull() {
|
if priorVal.IsNull() {
|
||||||
// If prior is null then we don't expect any RequiresReplace at all,
|
// If prior is null then we don't expect any RequiresReplace at all,
|
||||||
// because this is a Create action. (This is just to avoid errors
|
// because this is a Create action.
|
||||||
// when we use this value below, if the provider misbehaves.)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
plannedChangedVal, pathDiags := hcl.ApplyPath(plannedNewVal, path, nil)
|
|
||||||
if pathDiags.HasErrors() {
|
priorChangedVal, priorPathDiags := hcl.ApplyPath(priorVal, path, nil)
|
||||||
// This always indicates a provider bug, since RequiresReplace
|
plannedChangedVal, plannedPathDiags := hcl.ApplyPath(plannedNewVal, path, nil)
|
||||||
// should always refer only to whole attributes (and not into
|
if plannedPathDiags.HasErrors() && priorPathDiags.HasErrors() {
|
||||||
// attribute values themselves) and these should always be
|
// This means the path was invalid in both the prior and new
|
||||||
// present, even though they might be null or unknown.
|
// values, which is an error with the provider itself.
|
||||||
diags = diags.Append(tfdiags.Sourceless(
|
diags = diags.Append(tfdiags.Sourceless(
|
||||||
tfdiags.Error,
|
tfdiags.Error,
|
||||||
"Provider produced invalid plan",
|
"Provider produced invalid plan",
|
||||||
|
@ -284,17 +283,26 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
))
|
))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
priorChangedVal, err := path.Apply(priorVal)
|
|
||||||
if err != nil {
|
// Make sure we have valid Values for both values.
|
||||||
// Should never happen since prior and changed should be of
|
// Note: if the opposing value was of the type
|
||||||
// the same type, but we'll allow it for robustness.
|
// cty.DynamicPseudoType, the type assigned here may not exactly
|
||||||
reqRep.Add(path)
|
// match the schema. This is fine here, since we're only going to
|
||||||
|
// check for equality, but if the NullVal is to be used, we need to
|
||||||
|
// check the schema for th true type.
|
||||||
|
switch {
|
||||||
|
case priorChangedVal == cty.NilVal && plannedChangedVal == cty.NilVal:
|
||||||
|
// this should never happen without ApplyPath errors above
|
||||||
|
panic("requires replace path returned 2 nil values")
|
||||||
|
case priorChangedVal == cty.NilVal:
|
||||||
|
priorChangedVal = cty.NullVal(plannedChangedVal.Type())
|
||||||
|
case plannedChangedVal == cty.NilVal:
|
||||||
|
plannedChangedVal = cty.NullVal(priorChangedVal.Type())
|
||||||
}
|
}
|
||||||
if priorChangedVal != cty.NilVal {
|
|
||||||
eqV := plannedChangedVal.Equals(priorChangedVal)
|
eqV := plannedChangedVal.Equals(priorChangedVal)
|
||||||
if !eqV.IsKnown() || eqV.False() {
|
if !eqV.IsKnown() || eqV.False() {
|
||||||
reqRep.Add(path)
|
reqRep.Add(path)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if diags.HasErrors() {
|
if diags.HasErrors() {
|
||||||
|
|
Loading…
Reference in New Issue