Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

terraform apply: restore marks after unknown validation #35048

Merged
merged 1 commit into from
Apr 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading