Skip to content

Commit

Permalink
terraform apply: restore marks after unknown validation (#35048)
Browse files Browse the repository at this point in the history
  • Loading branch information
liamcervante authored Apr 23, 2024
1 parent 5294d1f commit 073e070
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 9 deletions.
62 changes: 62 additions & 0 deletions internal/terraform/context_apply2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2917,3 +2917,65 @@ resource "test_object" "obj" {
_, diags = ctx.Apply(plan, m, nil)
assertNoErrors(t, diags)
}

func TestContext2Apply_35039(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
resource "test_object" "obj" {
list = ["a", "b", "c"]
}
`,
})

p := testing_provider.MockProvider{}
p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
ResourceTypes: map[string]providers.Schema{
"test_object": {
Block: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"output": {
Type: cty.String,
Computed: true,
},
"list": {
Type: cty.List(cty.String),
Required: true,
Sensitive: true,
},
},
},
},
},
}
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) providers.PlanResourceChangeResponse {
return providers.PlanResourceChangeResponse{
PlannedState: cty.ObjectVal(map[string]cty.Value{
"output": cty.UnknownVal(cty.String),
"list": req.ProposedNewState.GetAttr("list"),
}),
}
}
p.ApplyResourceChangeFn = func(req providers.ApplyResourceChangeRequest) providers.ApplyResourceChangeResponse {
return providers.ApplyResourceChangeResponse{
// This is a bug, the provider shouldn't return unknown values from
// ApplyResourceChange. But, Terraform shouldn't crash in response
// to this. It should return a nice error message.
NewState: req.PlannedState,
}
}

ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(&p),
},
})

plan, diags := ctx.Plan(m, states.NewState(), SimplePlanOpts(plans.NormalMode, testInputValuesUnset(m.Module.Variables)))
assertNoErrors(t, diags)

// Just don't crash, should report an error about the provider.
_, diags = ctx.Apply(plan, m, nil)
if len(diags) != 1 {
t.Fatalf("expected exactly one diagnostic, but got %d: %s", len(diags), diags)
}
}
18 changes: 9 additions & 9 deletions internal/terraform/node_resource_abstract_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -2438,15 +2438,6 @@ func (n *NodeAbstractResourceInstance) apply(
// incomplete.
newVal := resp.NewState

// If we have paths to mark, mark those on this new value we need to
// re-check the value against the schema, because nested computed values
// won't be included in afterPaths, which are only what was read from the
// After plan value.
newVal = newVal.MarkWithPaths(afterPaths)
if sensitivePaths := schema.SensitivePaths(newVal, nil); len(sensitivePaths) != 0 {
newVal = marks.MarkPaths(newVal, marks.Sensitive, sensitivePaths)
}

if newVal == cty.NilVal {
// Providers are supposed to return a partial new value even when errors
// occur, but sometimes they don't and so in that case we'll patch that up
Expand Down Expand Up @@ -2532,6 +2523,15 @@ func (n *NodeAbstractResourceInstance) apply(
newVal = cty.UnknownAsNull(newVal)
}

// If we have paths to mark, mark those on this new value we need to
// re-check the value against the schema, because nested computed values
// won't be included in afterPaths, which are only what was read from the
// After plan value.
newVal = newVal.MarkWithPaths(afterPaths)
if sensitivePaths := schema.SensitivePaths(newVal, nil); len(sensitivePaths) != 0 {
newVal = marks.MarkPaths(newVal, marks.Sensitive, sensitivePaths)
}

if change.Action != plans.Delete && !diags.HasErrors() {
// Only values that were marked as unknown in the planned value are allowed
// to change during the apply operation. (We do this after the unknown-ness
Expand Down

0 comments on commit 073e070

Please sign in to comment.