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
|
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
|
// EvalReadDiff is an EvalNode implementation that writes the diff to
|
||||||
// the full diff.
|
// the full diff.
|
||||||
type EvalReadDiff struct {
|
type EvalReadDiff struct {
|
||||||
|
@ -275,7 +307,10 @@ func (n *EvalWriteDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
diff, lock := ctx.Diff()
|
diff, lock := ctx.Diff()
|
||||||
|
|
||||||
// The diff to write, if its empty it should write nil
|
// 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() {
|
if diffVal.Empty() {
|
||||||
diffVal = nil
|
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 {
|
if idx < 0 {
|
||||||
idx = len(rs.Tainted) - 1
|
idx = len(rs.Tainted) - 1
|
||||||
}
|
}
|
||||||
|
if idx >= 0 && idx < len(rs.Tainted) {
|
||||||
if idx < len(rs.Tainted) {
|
|
||||||
// Return the proper tainted resource
|
// 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
|
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
|
// EvalUpdateStateHook is an EvalNode implementation that calls the
|
||||||
// PostStateUpdate hook with the current state.
|
// PostStateUpdate hook with the current state.
|
||||||
type EvalUpdateStateHook struct{}
|
type EvalUpdateStateHook struct{}
|
||||||
|
|
|
@ -5,6 +5,47 @@ import (
|
||||||
"testing"
|
"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) {
|
func TestEvalUpdateStateHook(t *testing.T) {
|
||||||
mockHook := new(MockHook)
|
mockHook := new(MockHook)
|
||||||
|
|
||||||
|
|
|
@ -386,6 +386,15 @@ func (n *graphNodeExpandedResource) EvalTree() EvalNode {
|
||||||
Name: n.stateId(),
|
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{
|
&EvalWriteState{
|
||||||
Name: n.stateId(),
|
Name: n.stateId(),
|
||||||
ResourceType: n.Resource.Type,
|
ResourceType: n.Resource.Type,
|
||||||
|
@ -455,6 +464,13 @@ func (n *graphNodeExpandedResourceDestroy) EvalTree() EvalNode {
|
||||||
Diff: &diffApply,
|
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
|
// If we're not destroying, then compare diffs
|
||||||
&EvalIf{
|
&EvalIf{
|
||||||
If: func(ctx EvalContext) (bool, error) {
|
If: func(ctx EvalContext) (bool, error) {
|
||||||
|
@ -477,6 +493,9 @@ func (n *graphNodeExpandedResourceDestroy) EvalTree() EvalNode {
|
||||||
Tainted: n.Resource.Lifecycle.CreateBeforeDestroy,
|
Tainted: n.Resource.Lifecycle.CreateBeforeDestroy,
|
||||||
TaintedIndex: -1,
|
TaintedIndex: -1,
|
||||||
},
|
},
|
||||||
|
&EvalRequireState{
|
||||||
|
State: &state,
|
||||||
|
},
|
||||||
&EvalApply{
|
&EvalApply{
|
||||||
Info: info,
|
Info: info,
|
||||||
State: &state,
|
State: &state,
|
||||||
|
|
Loading…
Reference in New Issue