terraform: destroy node should not create
This commit is contained in:
parent
53a75f63ba
commit
6affc57b2d
|
@ -238,6 +238,38 @@ func (n *EvalDiffTainted) Eval(ctx EvalContext) (interface{}, error) {
|
|||
return nil, nil
|
||||
}
|
||||
|
||||
// EvalFilterDiff is an EvalNode implementation that filters the diff
|
||||
// according to some filter.
|
||||
type EvalFilterDiff struct {
|
||||
// Input and output
|
||||
Diff **InstanceDiff
|
||||
Output **InstanceDiff
|
||||
|
||||
// Destroy, if true, will only include a destroy diff if it is set.
|
||||
Destroy bool
|
||||
}
|
||||
|
||||
func (n *EvalFilterDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||
if *n.Diff == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
input := *n.Diff
|
||||
result := new(InstanceDiff)
|
||||
|
||||
if n.Destroy {
|
||||
if input.Destroy || input.RequiresNew() {
|
||||
result.Destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
if n.Output != nil {
|
||||
*n.Output = result
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// EvalReadDiff is an EvalNode implementation that writes the diff to
|
||||
// the full diff.
|
||||
type EvalReadDiff struct {
|
||||
|
@ -275,7 +307,10 @@ func (n *EvalWriteDiff) Eval(ctx EvalContext) (interface{}, error) {
|
|||
diff, lock := ctx.Diff()
|
||||
|
||||
// The diff to write, if its empty it should write nil
|
||||
diffVal := *n.Diff
|
||||
var diffVal *InstanceDiff
|
||||
if n.Diff != nil {
|
||||
diffVal = *n.Diff
|
||||
}
|
||||
if diffVal.Empty() {
|
||||
diffVal = nil
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestEvalFilterDiff(t *testing.T) {
|
||||
ctx := new(MockEvalContext)
|
||||
|
||||
cases := []struct {
|
||||
Node *EvalFilterDiff
|
||||
Input *InstanceDiff
|
||||
Output *InstanceDiff
|
||||
}{
|
||||
// With no settings, it returns an empty diff
|
||||
{
|
||||
&EvalFilterDiff{},
|
||||
&InstanceDiff{Destroy: true},
|
||||
&InstanceDiff{},
|
||||
},
|
||||
|
||||
// Destroy
|
||||
{
|
||||
&EvalFilterDiff{Destroy: true},
|
||||
&InstanceDiff{Destroy: false},
|
||||
&InstanceDiff{Destroy: false},
|
||||
},
|
||||
{
|
||||
&EvalFilterDiff{Destroy: true},
|
||||
&InstanceDiff{Destroy: true},
|
||||
&InstanceDiff{Destroy: true},
|
||||
},
|
||||
{
|
||||
&EvalFilterDiff{Destroy: true},
|
||||
&InstanceDiff{
|
||||
Destroy: true,
|
||||
Attributes: map[string]*ResourceAttrDiff{
|
||||
"foo": &ResourceAttrDiff{},
|
||||
},
|
||||
},
|
||||
&InstanceDiff{Destroy: true},
|
||||
},
|
||||
{
|
||||
&EvalFilterDiff{Destroy: true},
|
||||
&InstanceDiff{
|
||||
Attributes: map[string]*ResourceAttrDiff{
|
||||
"foo": &ResourceAttrDiff{
|
||||
RequiresNew: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
&InstanceDiff{Destroy: true},
|
||||
},
|
||||
{
|
||||
&EvalFilterDiff{Destroy: true},
|
||||
&InstanceDiff{
|
||||
Attributes: map[string]*ResourceAttrDiff{
|
||||
"foo": &ResourceAttrDiff{},
|
||||
},
|
||||
},
|
||||
&InstanceDiff{Destroy: false},
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
var output *InstanceDiff
|
||||
tc.Node.Diff = &tc.Input
|
||||
tc.Node.Output = &output
|
||||
if _, err := tc.Node.Eval(ctx); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(output, tc.Output) {
|
||||
t.Fatalf("bad: %d\n\n%#v", i, output)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,10 +43,9 @@ func (n *EvalReadState) Eval(ctx EvalContext) (interface{}, error) {
|
|||
if idx < 0 {
|
||||
idx = len(rs.Tainted) - 1
|
||||
}
|
||||
|
||||
if idx < len(rs.Tainted) {
|
||||
if idx >= 0 && idx < len(rs.Tainted) {
|
||||
// Return the proper tainted resource
|
||||
result = rs.Tainted[n.TaintedIndex]
|
||||
result = rs.Tainted[idx]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,6 +57,25 @@ func (n *EvalReadState) Eval(ctx EvalContext) (interface{}, error) {
|
|||
return result, nil
|
||||
}
|
||||
|
||||
// EvalRequireState is an EvalNode implementation that early exits
|
||||
// if the state doesn't have an ID.
|
||||
type EvalRequireState struct {
|
||||
State **InstanceState
|
||||
}
|
||||
|
||||
func (n *EvalRequireState) Eval(ctx EvalContext) (interface{}, error) {
|
||||
if n.State == nil {
|
||||
return nil, EvalEarlyExitError{}
|
||||
}
|
||||
|
||||
state := *n.State
|
||||
if state == nil || state.ID == "" {
|
||||
return nil, EvalEarlyExitError{}
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// EvalUpdateStateHook is an EvalNode implementation that calls the
|
||||
// PostStateUpdate hook with the current state.
|
||||
type EvalUpdateStateHook struct{}
|
||||
|
|
|
@ -5,6 +5,47 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func TestEvalRequireState(t *testing.T) {
|
||||
ctx := new(MockEvalContext)
|
||||
|
||||
cases := []struct {
|
||||
State *InstanceState
|
||||
Exit bool
|
||||
}{
|
||||
{
|
||||
nil,
|
||||
true,
|
||||
},
|
||||
{
|
||||
&InstanceState{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
&InstanceState{ID: "foo"},
|
||||
false,
|
||||
},
|
||||
}
|
||||
|
||||
var exitVal EvalEarlyExitError
|
||||
for _, tc := range cases {
|
||||
node := &EvalRequireState{State: &tc.State}
|
||||
_, err := node.Eval(ctx)
|
||||
if tc.Exit {
|
||||
if err != exitVal {
|
||||
t.Fatalf("should've exited: %#v", tc.State)
|
||||
}
|
||||
|
||||
continue
|
||||
}
|
||||
if !tc.Exit && err != nil {
|
||||
t.Fatalf("shouldn't exit: %#v", tc.State)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestEvalUpdateStateHook(t *testing.T) {
|
||||
mockHook := new(MockHook)
|
||||
|
||||
|
|
|
@ -386,6 +386,15 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
|||
Name: n.stateId(),
|
||||
},
|
||||
},
|
||||
|
||||
// We clear the diff out here so that future nodes
|
||||
// don't see a diff that is already complete. There
|
||||
// is no longer a diff!
|
||||
&EvalWriteDiff{
|
||||
Name: n.stateId(),
|
||||
Diff: nil,
|
||||
},
|
||||
|
||||
&EvalWriteState{
|
||||
Name: n.stateId(),
|
||||
ResourceType: n.Resource.Type,
|
||||
|
@ -455,6 +464,13 @@ func (n *graphNodeExpandedResourceDestroy) EvalTree() EvalNode {
|
|||
Diff: &diffApply,
|
||||
},
|
||||
|
||||
// Filter the diff so we only get the destroy
|
||||
&EvalFilterDiff{
|
||||
Diff: &diffApply,
|
||||
Output: &diffApply,
|
||||
Destroy: true,
|
||||
},
|
||||
|
||||
// If we're not destroying, then compare diffs
|
||||
&EvalIf{
|
||||
If: func(ctx EvalContext) (bool, error) {
|
||||
|
@ -477,6 +493,9 @@ func (n *graphNodeExpandedResourceDestroy) EvalTree() EvalNode {
|
|||
Tainted: n.Resource.Lifecycle.CreateBeforeDestroy,
|
||||
TaintedIndex: -1,
|
||||
},
|
||||
&EvalRequireState{
|
||||
State: &state,
|
||||
},
|
||||
&EvalApply{
|
||||
Info: info,
|
||||
State: &state,
|
||||
|
|
Loading…
Reference in New Issue