Merge pull request #16213 from hashicorp/jbardin/local-destroy
Don't evaluate locals during destroy
This commit is contained in:
commit
feb3883568
|
@ -8809,3 +8809,110 @@ module.child:
|
|||
t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Apply_destroyWithLocals(t *testing.T) {
|
||||
m := testModule(t, "apply-destroy-with-locals")
|
||||
p := testProvider("aws")
|
||||
p.ApplyFn = testApplyFn
|
||||
p.DiffFn = func(info *InstanceInfo, s *InstanceState, c *ResourceConfig) (*InstanceDiff, error) {
|
||||
d, err := testDiffFn(info, s, c)
|
||||
fmt.Println("DIFF:", d)
|
||||
return d, err
|
||||
}
|
||||
|
||||
s := &State{
|
||||
Modules: []*ModuleState{
|
||||
&ModuleState{
|
||||
Path: rootModulePath,
|
||||
Outputs: map[string]*OutputState{
|
||||
"name": &OutputState{
|
||||
Type: "string",
|
||||
Value: "test-bar",
|
||||
},
|
||||
},
|
||||
Resources: map[string]*ResourceState{
|
||||
"aws_instance.foo": &ResourceState{
|
||||
Type: "aws_instance",
|
||||
Primary: &InstanceState{
|
||||
ID: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Module: m,
|
||||
ProviderResolver: ResourceProviderResolverFixed(
|
||||
map[string]ResourceProviderFactory{
|
||||
"aws": testProviderFuncFixed(p),
|
||||
},
|
||||
),
|
||||
State: s,
|
||||
Destroy: true,
|
||||
})
|
||||
|
||||
if _, err := ctx.Plan(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
state, err := ctx.Apply()
|
||||
if err != nil {
|
||||
t.Fatalf("error during apply: %s", err)
|
||||
}
|
||||
|
||||
got := strings.TrimSpace(state.String())
|
||||
want := strings.TrimSpace(`<no state>`)
|
||||
if got != want {
|
||||
t.Fatalf("wrong final state\ngot:\n%s\nwant:\n%s", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestContext2Apply_providerWithLocals(t *testing.T) {
|
||||
m := testModule(t, "provider-with-locals")
|
||||
p := testProvider("aws")
|
||||
p.DiffFn = testDiffFn
|
||||
p.ApplyFn = testApplyFn
|
||||
ctx := testContext2(t, &ContextOpts{
|
||||
Module: m,
|
||||
ProviderResolver: ResourceProviderResolverFixed(
|
||||
map[string]ResourceProviderFactory{
|
||||
"aws": testProviderFuncFixed(p),
|
||||
},
|
||||
),
|
||||
})
|
||||
|
||||
if _, err := ctx.Plan(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
state, err := ctx.Apply()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
ctx = testContext2(t, &ContextOpts{
|
||||
Module: m,
|
||||
ProviderResolver: ResourceProviderResolverFixed(
|
||||
map[string]ResourceProviderFactory{
|
||||
"aws": testProviderFuncFixed(p),
|
||||
},
|
||||
),
|
||||
State: state,
|
||||
Destroy: true,
|
||||
})
|
||||
|
||||
if _, err = ctx.Plan(); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
state, err = ctx.Apply()
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if state.HasResources() {
|
||||
t.Fatal("expected no state, got:", state)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,3 +56,31 @@ func (n *EvalLocal) Eval(ctx EvalContext) (interface{}, error) {
|
|||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// EvalDeleteLocal is an EvalNode implementation that deletes a Local value
|
||||
// from the state. Locals aren't persisted, but we don't need to evaluate them
|
||||
// during destroy.
|
||||
type EvalDeleteLocal struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (n *EvalDeleteLocal) Eval(ctx EvalContext) (interface{}, error) {
|
||||
state, lock := ctx.State()
|
||||
if state == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Get a write lock so we can access this instance
|
||||
lock.Lock()
|
||||
defer lock.Unlock()
|
||||
|
||||
// Look for the module state. If we don't have one, create it.
|
||||
mod := state.ModuleByPath(ctx.Path())
|
||||
if mod == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
delete(mod.Locals, n.Name)
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
|
|
@ -59,20 +59,36 @@ func (n *NodeLocal) References() []string {
|
|||
|
||||
// GraphNodeEvalable
|
||||
func (n *NodeLocal) EvalTree() EvalNode {
|
||||
return &EvalOpFilter{
|
||||
Ops: []walkOperation{
|
||||
walkInput,
|
||||
walkValidate,
|
||||
walkRefresh,
|
||||
walkPlan,
|
||||
walkApply,
|
||||
walkDestroy,
|
||||
},
|
||||
Node: &EvalSequence{
|
||||
Nodes: []EvalNode{
|
||||
&EvalLocal{
|
||||
Name: n.Config.Name,
|
||||
Value: n.Config.RawConfig,
|
||||
return &EvalSequence{
|
||||
Nodes: []EvalNode{
|
||||
&EvalOpFilter{
|
||||
Ops: []walkOperation{
|
||||
walkInput,
|
||||
walkValidate,
|
||||
walkRefresh,
|
||||
walkPlan,
|
||||
walkApply,
|
||||
},
|
||||
Node: &EvalSequence{
|
||||
Nodes: []EvalNode{
|
||||
&EvalLocal{
|
||||
Name: n.Config.Name,
|
||||
Value: n.Config.RawConfig,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
&EvalOpFilter{
|
||||
Ops: []walkOperation{
|
||||
walkPlanDestroy,
|
||||
walkDestroy,
|
||||
},
|
||||
Node: &EvalSequence{
|
||||
Nodes: []EvalNode{
|
||||
&EvalDeleteLocal{
|
||||
Name: n.Config.Name,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
locals {
|
||||
name = "test-${aws_instance.foo.id}"
|
||||
}
|
||||
resource "aws_instance" "foo" {}
|
||||
|
||||
output "name" {
|
||||
value = "${local.name}"
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
provider "aws" {
|
||||
alias = "${local.foo}"
|
||||
}
|
||||
|
||||
locals {
|
||||
foo = "bar"
|
||||
}
|
||||
|
||||
resource "aws_instance" "foo" {
|
||||
value = "${local.foo}"
|
||||
}
|
Loading…
Reference in New Issue