Skip to content

Commit

Permalink
Merge pull request #31914 from hashicorp/jbardin/ignore-all-legacy
Browse files Browse the repository at this point in the history
special handling for legacy `ignore_changes = all`
  • Loading branch information
jbardin committed Oct 4, 2022
2 parents 65b531c + 92f3a83 commit 162b727
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 1 deletion.
64 changes: 64 additions & 0 deletions internal/terraform/context_plan_test.go
Expand Up @@ -6689,6 +6689,70 @@ resource "test_instance" "a" {
}
}

func TestContext2Plan_legacyProviderIgnoreAll(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
resource "test_instance" "a" {
lifecycle {
ignore_changes = all
}
data = "foo"
}
`,
})

p := testProvider("test")
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"test_instance": {
Attributes: map[string]*configschema.Attribute{
"id": {Type: cty.String, Computed: true},
"data": {Type: cty.String, Optional: true},
},
},
},
})
p.PlanResourceChangeFn = func(req providers.PlanResourceChangeRequest) (resp providers.PlanResourceChangeResponse) {
plan := req.ProposedNewState.AsValueMap()
// Update both the computed id and the configured data.
// Legacy providers expect terraform to be able to ignore these.

plan["id"] = cty.StringVal("updated")
plan["data"] = cty.StringVal("updated")
resp.PlannedState = cty.ObjectVal(plan)
resp.LegacyTypeSystem = true
return resp
}

state := states.NewState()
root := state.EnsureModule(addrs.RootModuleInstance)
root.SetResourceInstanceCurrent(
mustResourceInstanceAddr("test_instance.a").Resource,
&states.ResourceInstanceObjectSrc{
Status: states.ObjectReady,
AttrsJSON: []byte(`{"id":"orig","data":"orig"}`),
Dependencies: []addrs.ConfigResource{},
},
mustProviderConfig(`provider["registry.terraform.io/hashicorp/test"]`),
)

ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
})
plan, diags := ctx.Plan(m, state, DefaultPlanOpts)
if diags.HasErrors() {
t.Fatal(diags.Err())
}

for _, c := range plan.Changes.Resources {
if c.Action != plans.NoOp {
t.Fatalf("expected NoOp plan, got %s\n", c.Action)
}
}
}

func TestContext2Plan_dataRemovalNoProvider(t *testing.T) {
m := testModuleInline(t, map[string]string{
"main.tf": `
Expand Down
13 changes: 12 additions & 1 deletion internal/terraform/node_resource_abstract_instance.go
Expand Up @@ -881,7 +881,10 @@ func (n *NodeAbstractResourceInstance) plan(
// providers that we must accommodate the behavior for now, so for
// ignore_changes to work at all on these values, we will revert the
// ignored values once more.
plannedNewVal, ignoreChangeDiags = n.processIgnoreChanges(unmarkedPriorVal, plannedNewVal, schema)
// A nil schema is passed to processIgnoreChanges to indicate that we
// don't want to fixup a config value according to the schema when
// ignoring "all", rather we are reverting provider imposed changes.
plannedNewVal, ignoreChangeDiags = n.processIgnoreChanges(unmarkedPriorVal, plannedNewVal, nil)
diags = diags.Append(ignoreChangeDiags)
if ignoreChangeDiags.HasErrors() {
return plan, state, keyData, diags
Expand Down Expand Up @@ -1160,6 +1163,14 @@ func (n *NodeAbstractResource) processIgnoreChanges(prior, config cty.Value, sch
}

if ignoreAll {
// Legacy providers need up to clean up their invalid plans and ensure
// no changes are passed though, but that also means making an invalid
// config with computed values. In that case we just don't supply a
// schema and return the prior val directly.
if schema == nil {
return prior, nil
}

// If we are trying to ignore all attribute changes, we must filter
// computed attributes out from the prior state to avoid sending them
// to the provider as if they were included in the configuration.
Expand Down

0 comments on commit 162b727

Please sign in to comment.