Make all terraform package tests pass under -race
This isn't a pretty refactor, but fixes the race issues in this package for now. Fix race on RawConfig.Config() fix command package races
This commit is contained in:
parent
9dec28bccf
commit
5802f76eaa
|
@ -47,7 +47,7 @@ func (h *CountHook) PreApply(
|
||||||
}
|
}
|
||||||
|
|
||||||
action := countHookActionChange
|
action := countHookActionChange
|
||||||
if d.Destroy {
|
if d.GetDestroy() {
|
||||||
action = countHookActionRemove
|
action = countHookActionRemove
|
||||||
} else if s.ID == "" {
|
} else if s.ID == "" {
|
||||||
action = countHookActionAdd
|
action = countHookActionAdd
|
||||||
|
|
|
@ -84,8 +84,10 @@ func (h *UiHook) PreApply(
|
||||||
// Get all the attributes that are changing, and sort them. Also
|
// Get all the attributes that are changing, and sort them. Also
|
||||||
// determine the longest key so that we can align them all.
|
// determine the longest key so that we can align them all.
|
||||||
keyLen := 0
|
keyLen := 0
|
||||||
keys := make([]string, 0, len(d.Attributes))
|
|
||||||
for key, _ := range d.Attributes {
|
dAttrs := d.CopyAttributes()
|
||||||
|
keys := make([]string, 0, len(dAttrs))
|
||||||
|
for key, _ := range dAttrs {
|
||||||
// Skip the ID since we do that specially
|
// Skip the ID since we do that specially
|
||||||
if key == "id" {
|
if key == "id" {
|
||||||
continue
|
continue
|
||||||
|
@ -100,7 +102,7 @@ func (h *UiHook) PreApply(
|
||||||
|
|
||||||
// Go through and output each attribute
|
// Go through and output each attribute
|
||||||
for _, attrK := range keys {
|
for _, attrK := range keys {
|
||||||
attrDiff := d.Attributes[attrK]
|
attrDiff, _ := d.GetAttribute(attrK)
|
||||||
|
|
||||||
v := attrDiff.New
|
v := attrDiff.New
|
||||||
u := attrDiff.Old
|
u := attrDiff.Old
|
||||||
|
|
|
@ -93,6 +93,8 @@ func (r *RawConfig) Value() interface{} {
|
||||||
// structure will always successfully decode into its ultimate
|
// structure will always successfully decode into its ultimate
|
||||||
// structure using something like mapstructure.
|
// structure using something like mapstructure.
|
||||||
func (r *RawConfig) Config() map[string]interface{} {
|
func (r *RawConfig) Config() map[string]interface{} {
|
||||||
|
r.lock.Lock()
|
||||||
|
defer r.lock.Unlock()
|
||||||
return r.config
|
return r.config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import (
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
// DiffChangeType is an enum with the kind of changes a diff has planned.
|
// DiffChangeType is an enum with the kind of changes a diff has planned.
|
||||||
|
@ -216,9 +217,9 @@ func (d *ModuleDiff) String() string {
|
||||||
|
|
||||||
crud := "UPDATE"
|
crud := "UPDATE"
|
||||||
switch {
|
switch {
|
||||||
case rdiff.RequiresNew() && (rdiff.Destroy || rdiff.DestroyTainted):
|
case rdiff.RequiresNew() && (rdiff.GetDestroy() || rdiff.GetDestroyTainted()):
|
||||||
crud = "DESTROY/CREATE"
|
crud = "DESTROY/CREATE"
|
||||||
case rdiff.Destroy:
|
case rdiff.GetDestroy():
|
||||||
crud = "DESTROY"
|
crud = "DESTROY"
|
||||||
case rdiff.RequiresNew():
|
case rdiff.RequiresNew():
|
||||||
crud = "CREATE"
|
crud = "CREATE"
|
||||||
|
@ -230,8 +231,9 @@ func (d *ModuleDiff) String() string {
|
||||||
name))
|
name))
|
||||||
|
|
||||||
keyLen := 0
|
keyLen := 0
|
||||||
keys := make([]string, 0, len(rdiff.Attributes))
|
rdiffAttrs := rdiff.CopyAttributes()
|
||||||
for key, _ := range rdiff.Attributes {
|
keys := make([]string, 0, len(rdiffAttrs))
|
||||||
|
for key, _ := range rdiffAttrs {
|
||||||
if key == "id" {
|
if key == "id" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -244,7 +246,7 @@ func (d *ModuleDiff) String() string {
|
||||||
sort.Strings(keys)
|
sort.Strings(keys)
|
||||||
|
|
||||||
for _, attrK := range keys {
|
for _, attrK := range keys {
|
||||||
attrDiff := rdiff.Attributes[attrK]
|
attrDiff, _ := rdiff.GetAttribute(attrK)
|
||||||
|
|
||||||
v := attrDiff.New
|
v := attrDiff.New
|
||||||
u := attrDiff.Old
|
u := attrDiff.Old
|
||||||
|
@ -279,6 +281,7 @@ func (d *ModuleDiff) String() string {
|
||||||
|
|
||||||
// InstanceDiff is the diff of a resource from some state to another.
|
// InstanceDiff is the diff of a resource from some state to another.
|
||||||
type InstanceDiff struct {
|
type InstanceDiff struct {
|
||||||
|
mu sync.Mutex
|
||||||
Attributes map[string]*ResourceAttrDiff
|
Attributes map[string]*ResourceAttrDiff
|
||||||
Destroy bool
|
Destroy bool
|
||||||
DestroyTainted bool
|
DestroyTainted bool
|
||||||
|
@ -324,6 +327,10 @@ func (d *InstanceDiff) init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewInstanceDiff() *InstanceDiff {
|
||||||
|
return &InstanceDiff{Attributes: make(map[string]*ResourceAttrDiff)}
|
||||||
|
}
|
||||||
|
|
||||||
// ChangeType returns the DiffChangeType represented by the diff
|
// ChangeType returns the DiffChangeType represented by the diff
|
||||||
// for this single instance.
|
// for this single instance.
|
||||||
func (d *InstanceDiff) ChangeType() DiffChangeType {
|
func (d *InstanceDiff) ChangeType() DiffChangeType {
|
||||||
|
@ -331,11 +338,11 @@ func (d *InstanceDiff) ChangeType() DiffChangeType {
|
||||||
return DiffNone
|
return DiffNone
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.RequiresNew() && (d.Destroy || d.DestroyTainted) {
|
if d.RequiresNew() && (d.GetDestroy() || d.GetDestroyTainted()) {
|
||||||
return DiffDestroyCreate
|
return DiffDestroyCreate
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.Destroy {
|
if d.GetDestroy() {
|
||||||
return DiffDestroy
|
return DiffDestroy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,6 +359,8 @@ func (d *InstanceDiff) Empty() bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
return !d.Destroy && len(d.Attributes) == 0
|
return !d.Destroy && len(d.Attributes) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -366,6 +375,17 @@ func (d *InstanceDiff) RequiresNew() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
return d.requiresNew()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *InstanceDiff) requiresNew() bool {
|
||||||
|
if d == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
if d.DestroyTainted {
|
if d.DestroyTainted {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -379,24 +399,103 @@ func (d *InstanceDiff) RequiresNew() bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These methods are properly locked, for use outside other InstanceDiff
|
||||||
|
// methods but everywhere else within in the terraform package.
|
||||||
|
// TODO refactor the locking scheme
|
||||||
|
func (d *InstanceDiff) SetTainted(b bool) {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
d.DestroyTainted = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *InstanceDiff) GetDestroyTainted() bool {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
return d.DestroyTainted
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *InstanceDiff) SetDestroy(b bool) {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
d.Destroy = b
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *InstanceDiff) GetDestroy() bool {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
return d.Destroy
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *InstanceDiff) SetAttribute(key string, attr *ResourceAttrDiff) {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
d.Attributes[key] = attr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *InstanceDiff) DelAttribute(key string) {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
delete(d.Attributes, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *InstanceDiff) GetAttribute(key string) (*ResourceAttrDiff, bool) {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
attr, ok := d.Attributes[key]
|
||||||
|
return attr, ok
|
||||||
|
}
|
||||||
|
func (d *InstanceDiff) GetAttributesLen() int {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
return len(d.Attributes)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Safely copies the Attributes map
|
||||||
|
func (d *InstanceDiff) CopyAttributes() map[string]*ResourceAttrDiff {
|
||||||
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
attrs := make(map[string]*ResourceAttrDiff)
|
||||||
|
for k, v := range d.Attributes {
|
||||||
|
attrs[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
}
|
||||||
|
|
||||||
// Same checks whether or not two InstanceDiff's are the "same". When
|
// Same checks whether or not two InstanceDiff's are the "same". When
|
||||||
// we say "same", it is not necessarily exactly equal. Instead, it is
|
// we say "same", it is not necessarily exactly equal. Instead, it is
|
||||||
// just checking that the same attributes are changing, a destroy
|
// just checking that the same attributes are changing, a destroy
|
||||||
// isn't suddenly happening, etc.
|
// isn't suddenly happening, etc.
|
||||||
func (d *InstanceDiff) Same(d2 *InstanceDiff) (bool, string) {
|
func (d *InstanceDiff) Same(d2 *InstanceDiff) (bool, string) {
|
||||||
if d == nil && d2 == nil {
|
// we can safely compare the pointers without a lock
|
||||||
|
switch {
|
||||||
|
case d == nil && d2 == nil:
|
||||||
|
return true, ""
|
||||||
|
case d == nil || d2 == nil:
|
||||||
|
return false, "one nil"
|
||||||
|
case d == d2:
|
||||||
return true, ""
|
return true, ""
|
||||||
} else if d == nil || d2 == nil {
|
|
||||||
return false, "both nil"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.Destroy != d2.Destroy {
|
d.mu.Lock()
|
||||||
|
defer d.mu.Unlock()
|
||||||
|
|
||||||
|
if d.Destroy != d2.GetDestroy() {
|
||||||
return false, fmt.Sprintf(
|
return false, fmt.Sprintf(
|
||||||
"diff: Destroy; old: %t, new: %t", d.Destroy, d2.Destroy)
|
"diff: Destroy; old: %t, new: %t", d.Destroy, d2.GetDestroy())
|
||||||
}
|
}
|
||||||
if d.RequiresNew() != d2.RequiresNew() {
|
if d.requiresNew() != d2.RequiresNew() {
|
||||||
return false, fmt.Sprintf(
|
return false, fmt.Sprintf(
|
||||||
"diff RequiresNew; old: %t, new: %t", d.RequiresNew(), d2.RequiresNew())
|
"diff RequiresNew; old: %t, new: %t", d.requiresNew(), d2.RequiresNew())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Go through the old diff and make sure the new diff has all the
|
// Go through the old diff and make sure the new diff has all the
|
||||||
|
@ -406,7 +505,7 @@ func (d *InstanceDiff) Same(d2 *InstanceDiff) (bool, string) {
|
||||||
for k, _ := range d.Attributes {
|
for k, _ := range d.Attributes {
|
||||||
checkOld[k] = struct{}{}
|
checkOld[k] = struct{}{}
|
||||||
}
|
}
|
||||||
for k, _ := range d2.Attributes {
|
for k, _ := range d2.CopyAttributes() {
|
||||||
checkNew[k] = struct{}{}
|
checkNew[k] = struct{}{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -431,7 +530,7 @@ func (d *InstanceDiff) Same(d2 *InstanceDiff) (bool, string) {
|
||||||
delete(checkOld, k)
|
delete(checkOld, k)
|
||||||
delete(checkNew, k)
|
delete(checkNew, k)
|
||||||
|
|
||||||
_, ok := d2.Attributes[k]
|
_, ok := d2.GetAttribute(k)
|
||||||
if !ok {
|
if !ok {
|
||||||
// If there's no new attribute, and the old diff expected the attribute
|
// If there's no new attribute, and the old diff expected the attribute
|
||||||
// to be removed, that's just fine.
|
// to be removed, that's just fine.
|
||||||
|
@ -483,7 +582,7 @@ func (d *InstanceDiff) Same(d2 *InstanceDiff) (bool, string) {
|
||||||
// Similarly, in a RequiresNew scenario, a list that shows up in the plan
|
// Similarly, in a RequiresNew scenario, a list that shows up in the plan
|
||||||
// diff can disappear from the apply diff, which is calculated from an
|
// diff can disappear from the apply diff, which is calculated from an
|
||||||
// empty state.
|
// empty state.
|
||||||
if d.RequiresNew() && (strings.HasSuffix(k, ".#") || strings.HasSuffix(k, ".%")) {
|
if d.requiresNew() && (strings.HasSuffix(k, ".#") || strings.HasSuffix(k, ".%")) {
|
||||||
ok = true
|
ok = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,9 +35,9 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove any output values from the diff
|
// Remove any output values from the diff
|
||||||
for k, ad := range diff.Attributes {
|
for k, ad := range diff.CopyAttributes() {
|
||||||
if ad.Type == DiffAttrOutput {
|
if ad.Type == DiffAttrOutput {
|
||||||
delete(diff.Attributes, k)
|
diff.DelAttribute(k)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,7 +49,7 @@ func (n *EvalApply) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
|
|
||||||
// Flag if we're creating a new instance
|
// Flag if we're creating a new instance
|
||||||
if n.CreateNew != nil {
|
if n.CreateNew != nil {
|
||||||
*n.CreateNew = state.ID == "" && !diff.Destroy || diff.RequiresNew()
|
*n.CreateNew = state.ID == "" && !diff.GetDestroy() || diff.RequiresNew()
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -22,7 +22,7 @@ func (n *EvalCheckPreventDestroy) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
diff := *n.Diff
|
diff := *n.Diff
|
||||||
preventDestroy := n.Resource.Lifecycle.PreventDestroy
|
preventDestroy := n.Resource.Lifecycle.PreventDestroy
|
||||||
|
|
||||||
if diff.Destroy && preventDestroy {
|
if diff.GetDestroy() && preventDestroy {
|
||||||
return nil, fmt.Errorf(preventDestroyErrStr, n.Resource.Id())
|
return nil, fmt.Errorf(preventDestroyErrStr, n.Resource.Id())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,16 +28,16 @@ func (n *EvalCompareDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
two = new(InstanceDiff)
|
two = new(InstanceDiff)
|
||||||
two.init()
|
two.init()
|
||||||
}
|
}
|
||||||
oneId := one.Attributes["id"]
|
oneId, _ := one.GetAttribute("id")
|
||||||
twoId := two.Attributes["id"]
|
twoId, _ := two.GetAttribute("id")
|
||||||
delete(one.Attributes, "id")
|
one.DelAttribute("id")
|
||||||
delete(two.Attributes, "id")
|
two.DelAttribute("id")
|
||||||
defer func() {
|
defer func() {
|
||||||
if oneId != nil {
|
if oneId != nil {
|
||||||
one.Attributes["id"] = oneId
|
one.SetAttribute("id", oneId)
|
||||||
}
|
}
|
||||||
if twoId != nil {
|
if twoId != nil {
|
||||||
two.Attributes["id"] = twoId
|
two.SetAttribute("id", twoId)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
@ -114,12 +114,12 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
|
|
||||||
// Preserve the DestroyTainted flag
|
// Preserve the DestroyTainted flag
|
||||||
if n.Diff != nil {
|
if n.Diff != nil {
|
||||||
diff.DestroyTainted = (*n.Diff).DestroyTainted
|
diff.SetTainted((*n.Diff).GetDestroyTainted())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Require a destroy if there is an ID and it requires new.
|
// Require a destroy if there is an ID and it requires new.
|
||||||
if diff.RequiresNew() && state != nil && state.ID != "" {
|
if diff.RequiresNew() && state != nil && state.ID != "" {
|
||||||
diff.Destroy = true
|
diff.SetDestroy(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we're creating a new resource, compute its ID
|
// If we're creating a new resource, compute its ID
|
||||||
|
@ -131,12 +131,12 @@ func (n *EvalDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
|
|
||||||
// Add diff to compute new ID
|
// Add diff to compute new ID
|
||||||
diff.init()
|
diff.init()
|
||||||
diff.Attributes["id"] = &ResourceAttrDiff{
|
diff.SetAttribute("id", &ResourceAttrDiff{
|
||||||
Old: oldID,
|
Old: oldID,
|
||||||
NewComputed: true,
|
NewComputed: true,
|
||||||
RequiresNew: true,
|
RequiresNew: true,
|
||||||
Type: DiffAttrOutput,
|
Type: DiffAttrOutput,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := n.processIgnoreChanges(diff); err != nil {
|
if err := n.processIgnoreChanges(diff); err != nil {
|
||||||
|
@ -187,7 +187,7 @@ func (n *EvalDiff) processIgnoreChanges(diff *InstanceDiff) error {
|
||||||
|
|
||||||
ignorableAttrKeys := make(map[string]bool)
|
ignorableAttrKeys := make(map[string]bool)
|
||||||
for _, ignoredKey := range ignoreChanges {
|
for _, ignoredKey := range ignoreChanges {
|
||||||
for k := range diff.Attributes {
|
for k := range diff.CopyAttributes() {
|
||||||
if strings.HasPrefix(k, ignoredKey) {
|
if strings.HasPrefix(k, ignoredKey) {
|
||||||
ignorableAttrKeys[k] = true
|
ignorableAttrKeys[k] = true
|
||||||
}
|
}
|
||||||
|
@ -200,7 +200,7 @@ func (n *EvalDiff) processIgnoreChanges(diff *InstanceDiff) error {
|
||||||
// "<computed>". Filtering these out allows us to see if we might be able to
|
// "<computed>". Filtering these out allows us to see if we might be able to
|
||||||
// skip this diff altogether.
|
// skip this diff altogether.
|
||||||
if changeType == DiffDestroyCreate {
|
if changeType == DiffDestroyCreate {
|
||||||
for k, v := range diff.Attributes {
|
for k, v := range diff.CopyAttributes() {
|
||||||
if v.Empty() || v.NewComputed {
|
if v.Empty() || v.NewComputed {
|
||||||
ignorableAttrKeys[k] = true
|
ignorableAttrKeys[k] = true
|
||||||
}
|
}
|
||||||
|
@ -210,7 +210,7 @@ func (n *EvalDiff) processIgnoreChanges(diff *InstanceDiff) error {
|
||||||
// tweak, we ignore the "id" attribute diff that gets added by EvalDiff,
|
// tweak, we ignore the "id" attribute diff that gets added by EvalDiff,
|
||||||
// since that was added in reaction to RequiresNew being true.
|
// since that was added in reaction to RequiresNew being true.
|
||||||
requiresNewAfterIgnores := false
|
requiresNewAfterIgnores := false
|
||||||
for k, v := range diff.Attributes {
|
for k, v := range diff.CopyAttributes() {
|
||||||
if k == "id" {
|
if k == "id" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -233,15 +233,15 @@ func (n *EvalDiff) processIgnoreChanges(diff *InstanceDiff) error {
|
||||||
// attribute diff and the Destroy boolean field
|
// attribute diff and the Destroy boolean field
|
||||||
log.Printf("[DEBUG] Removing 'id' diff and setting Destroy to false " +
|
log.Printf("[DEBUG] Removing 'id' diff and setting Destroy to false " +
|
||||||
"because after ignore_changes, this diff no longer requires replacement")
|
"because after ignore_changes, this diff no longer requires replacement")
|
||||||
delete(diff.Attributes, "id")
|
diff.DelAttribute("id")
|
||||||
diff.Destroy = false
|
diff.SetDestroy(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we didn't hit any of our early exit conditions, we can filter the diff.
|
// If we didn't hit any of our early exit conditions, we can filter the diff.
|
||||||
for k := range ignorableAttrKeys {
|
for k := range ignorableAttrKeys {
|
||||||
log.Printf("[DEBUG] [EvalIgnoreChanges] %s - Ignoring diff attribute: %s",
|
log.Printf("[DEBUG] [EvalIgnoreChanges] %s - Ignoring diff attribute: %s",
|
||||||
n.Resource.Id(), k)
|
n.Resource.Id(), k)
|
||||||
delete(diff.Attributes, k)
|
diff.DelAttribute(k)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -333,8 +333,8 @@ func (n *EvalFilterDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
result := new(InstanceDiff)
|
result := new(InstanceDiff)
|
||||||
|
|
||||||
if n.Destroy {
|
if n.Destroy {
|
||||||
if input.Destroy || input.RequiresNew() {
|
if input.GetDestroy() || input.RequiresNew() {
|
||||||
result.Destroy = true
|
result.SetDestroy(true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ func (n *EvalReadDataDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
|
|
||||||
var diff *InstanceDiff
|
var diff *InstanceDiff
|
||||||
|
|
||||||
if n.Previous != nil && *n.Previous != nil && (*n.Previous).Destroy {
|
if n.Previous != nil && *n.Previous != nil && (*n.Previous).GetDestroy() {
|
||||||
// If we're re-diffing for a diff that was already planning to
|
// If we're re-diffing for a diff that was already planning to
|
||||||
// destroy, then we'll just continue with that plan.
|
// destroy, then we'll just continue with that plan.
|
||||||
diff = &InstanceDiff{Destroy: true}
|
diff = &InstanceDiff{Destroy: true}
|
||||||
|
@ -49,12 +49,12 @@ func (n *EvalReadDataDiff) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
|
|
||||||
// id is always computed, because we're always "creating a new resource"
|
// id is always computed, because we're always "creating a new resource"
|
||||||
diff.init()
|
diff.init()
|
||||||
diff.Attributes["id"] = &ResourceAttrDiff{
|
diff.SetAttribute("id", &ResourceAttrDiff{
|
||||||
Old: "",
|
Old: "",
|
||||||
NewComputed: true,
|
NewComputed: true,
|
||||||
RequiresNew: true,
|
RequiresNew: true,
|
||||||
Type: DiffAttrOutput,
|
Type: DiffAttrOutput,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ctx.Hook(func(h Hook) (HookAction, error) {
|
err = ctx.Hook(func(h Hook) (HookAction, error) {
|
||||||
|
@ -97,7 +97,7 @@ func (n *EvalReadDataApply) Eval(ctx EvalContext) (interface{}, error) {
|
||||||
// If the diff is for *destroying* this resource then we'll
|
// If the diff is for *destroying* this resource then we'll
|
||||||
// just drop its state and move on, since data resources don't
|
// just drop its state and move on, since data resources don't
|
||||||
// support an actual "destroy" action.
|
// support an actual "destroy" action.
|
||||||
if diff != nil && diff.Destroy {
|
if diff != nil && diff.GetDestroy() {
|
||||||
if n.Output != nil {
|
if n.Output != nil {
|
||||||
*n.Output = nil
|
*n.Output = nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -485,7 +485,7 @@ func (n *graphNodeResourceDestroy) destroyInclude(
|
||||||
if d != nil {
|
if d != nil {
|
||||||
for k, v := range d.Resources {
|
for k, v := range d.Resources {
|
||||||
match := k == prefix || strings.HasPrefix(k, prefix+".")
|
match := k == prefix || strings.HasPrefix(k, prefix+".")
|
||||||
if match && v.Destroy {
|
if match && v.GetDestroy() {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
// MockHook is an implementation of Hook that can be used for tests.
|
// MockHook is an implementation of Hook that can be used for tests.
|
||||||
// It records all of its function calls.
|
// It records all of its function calls.
|
||||||
type MockHook struct {
|
type MockHook struct {
|
||||||
|
sync.Mutex
|
||||||
|
|
||||||
PreApplyCalled bool
|
PreApplyCalled bool
|
||||||
PreApplyInfo *InstanceInfo
|
PreApplyInfo *InstanceInfo
|
||||||
PreApplyDiff *InstanceDiff
|
PreApplyDiff *InstanceDiff
|
||||||
|
@ -89,6 +93,9 @@ type MockHook struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PreApply(n *InstanceInfo, s *InstanceState, d *InstanceDiff) (HookAction, error) {
|
func (h *MockHook) PreApply(n *InstanceInfo, s *InstanceState, d *InstanceDiff) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PreApplyCalled = true
|
h.PreApplyCalled = true
|
||||||
h.PreApplyInfo = n
|
h.PreApplyInfo = n
|
||||||
h.PreApplyDiff = d
|
h.PreApplyDiff = d
|
||||||
|
@ -97,6 +104,9 @@ func (h *MockHook) PreApply(n *InstanceInfo, s *InstanceState, d *InstanceDiff)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PostApply(n *InstanceInfo, s *InstanceState, e error) (HookAction, error) {
|
func (h *MockHook) PostApply(n *InstanceInfo, s *InstanceState, e error) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PostApplyCalled = true
|
h.PostApplyCalled = true
|
||||||
h.PostApplyInfo = n
|
h.PostApplyInfo = n
|
||||||
h.PostApplyState = s
|
h.PostApplyState = s
|
||||||
|
@ -105,6 +115,9 @@ func (h *MockHook) PostApply(n *InstanceInfo, s *InstanceState, e error) (HookAc
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PreDiff(n *InstanceInfo, s *InstanceState) (HookAction, error) {
|
func (h *MockHook) PreDiff(n *InstanceInfo, s *InstanceState) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PreDiffCalled = true
|
h.PreDiffCalled = true
|
||||||
h.PreDiffInfo = n
|
h.PreDiffInfo = n
|
||||||
h.PreDiffState = s
|
h.PreDiffState = s
|
||||||
|
@ -112,6 +125,9 @@ func (h *MockHook) PreDiff(n *InstanceInfo, s *InstanceState) (HookAction, error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PostDiff(n *InstanceInfo, d *InstanceDiff) (HookAction, error) {
|
func (h *MockHook) PostDiff(n *InstanceInfo, d *InstanceDiff) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PostDiffCalled = true
|
h.PostDiffCalled = true
|
||||||
h.PostDiffInfo = n
|
h.PostDiffInfo = n
|
||||||
h.PostDiffDiff = d
|
h.PostDiffDiff = d
|
||||||
|
@ -119,6 +135,9 @@ func (h *MockHook) PostDiff(n *InstanceInfo, d *InstanceDiff) (HookAction, error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PreProvisionResource(n *InstanceInfo, s *InstanceState) (HookAction, error) {
|
func (h *MockHook) PreProvisionResource(n *InstanceInfo, s *InstanceState) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PreProvisionResourceCalled = true
|
h.PreProvisionResourceCalled = true
|
||||||
h.PreProvisionResourceInfo = n
|
h.PreProvisionResourceInfo = n
|
||||||
h.PreProvisionInstanceState = s
|
h.PreProvisionInstanceState = s
|
||||||
|
@ -126,6 +145,9 @@ func (h *MockHook) PreProvisionResource(n *InstanceInfo, s *InstanceState) (Hook
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PostProvisionResource(n *InstanceInfo, s *InstanceState) (HookAction, error) {
|
func (h *MockHook) PostProvisionResource(n *InstanceInfo, s *InstanceState) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PostProvisionResourceCalled = true
|
h.PostProvisionResourceCalled = true
|
||||||
h.PostProvisionResourceInfo = n
|
h.PostProvisionResourceInfo = n
|
||||||
h.PostProvisionInstanceState = s
|
h.PostProvisionInstanceState = s
|
||||||
|
@ -133,6 +155,9 @@ func (h *MockHook) PostProvisionResource(n *InstanceInfo, s *InstanceState) (Hoo
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PreProvision(n *InstanceInfo, provId string) (HookAction, error) {
|
func (h *MockHook) PreProvision(n *InstanceInfo, provId string) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PreProvisionCalled = true
|
h.PreProvisionCalled = true
|
||||||
h.PreProvisionInfo = n
|
h.PreProvisionInfo = n
|
||||||
h.PreProvisionProvisionerId = provId
|
h.PreProvisionProvisionerId = provId
|
||||||
|
@ -140,6 +165,9 @@ func (h *MockHook) PreProvision(n *InstanceInfo, provId string) (HookAction, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PostProvision(n *InstanceInfo, provId string) (HookAction, error) {
|
func (h *MockHook) PostProvision(n *InstanceInfo, provId string) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PostProvisionCalled = true
|
h.PostProvisionCalled = true
|
||||||
h.PostProvisionInfo = n
|
h.PostProvisionInfo = n
|
||||||
h.PostProvisionProvisionerId = provId
|
h.PostProvisionProvisionerId = provId
|
||||||
|
@ -150,6 +178,9 @@ func (h *MockHook) ProvisionOutput(
|
||||||
n *InstanceInfo,
|
n *InstanceInfo,
|
||||||
provId string,
|
provId string,
|
||||||
msg string) {
|
msg string) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.ProvisionOutputCalled = true
|
h.ProvisionOutputCalled = true
|
||||||
h.ProvisionOutputInfo = n
|
h.ProvisionOutputInfo = n
|
||||||
h.ProvisionOutputProvisionerId = provId
|
h.ProvisionOutputProvisionerId = provId
|
||||||
|
@ -157,6 +188,9 @@ func (h *MockHook) ProvisionOutput(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PreRefresh(n *InstanceInfo, s *InstanceState) (HookAction, error) {
|
func (h *MockHook) PreRefresh(n *InstanceInfo, s *InstanceState) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PreRefreshCalled = true
|
h.PreRefreshCalled = true
|
||||||
h.PreRefreshInfo = n
|
h.PreRefreshInfo = n
|
||||||
h.PreRefreshState = s
|
h.PreRefreshState = s
|
||||||
|
@ -164,6 +198,9 @@ func (h *MockHook) PreRefresh(n *InstanceInfo, s *InstanceState) (HookAction, er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PostRefresh(n *InstanceInfo, s *InstanceState) (HookAction, error) {
|
func (h *MockHook) PostRefresh(n *InstanceInfo, s *InstanceState) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PostRefreshCalled = true
|
h.PostRefreshCalled = true
|
||||||
h.PostRefreshInfo = n
|
h.PostRefreshInfo = n
|
||||||
h.PostRefreshState = s
|
h.PostRefreshState = s
|
||||||
|
@ -171,6 +208,9 @@ func (h *MockHook) PostRefresh(n *InstanceInfo, s *InstanceState) (HookAction, e
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PreImportState(info *InstanceInfo, id string) (HookAction, error) {
|
func (h *MockHook) PreImportState(info *InstanceInfo, id string) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PreImportStateCalled = true
|
h.PreImportStateCalled = true
|
||||||
h.PreImportStateInfo = info
|
h.PreImportStateInfo = info
|
||||||
h.PreImportStateId = id
|
h.PreImportStateId = id
|
||||||
|
@ -178,6 +218,9 @@ func (h *MockHook) PreImportState(info *InstanceInfo, id string) (HookAction, er
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PostImportState(info *InstanceInfo, s []*InstanceState) (HookAction, error) {
|
func (h *MockHook) PostImportState(info *InstanceInfo, s []*InstanceState) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PostImportStateCalled = true
|
h.PostImportStateCalled = true
|
||||||
h.PostImportStateInfo = info
|
h.PostImportStateInfo = info
|
||||||
h.PostImportStateState = s
|
h.PostImportStateState = s
|
||||||
|
@ -185,6 +228,9 @@ func (h *MockHook) PostImportState(info *InstanceInfo, s []*InstanceState) (Hook
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *MockHook) PostStateUpdate(s *State) (HookAction, error) {
|
func (h *MockHook) PostStateUpdate(s *State) (HookAction, error) {
|
||||||
|
h.Lock()
|
||||||
|
defer h.Unlock()
|
||||||
|
|
||||||
h.PostStateUpdateCalled = true
|
h.PostStateUpdateCalled = true
|
||||||
h.PostStateUpdateState = s
|
h.PostStateUpdateState = s
|
||||||
return h.PostStateUpdateReturn, h.PostStateUpdateError
|
return h.PostStateUpdateReturn, h.PostStateUpdateError
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
package terraform
|
package terraform
|
||||||
|
|
||||||
|
import "sync"
|
||||||
|
|
||||||
// MockResourceProvisioner implements ResourceProvisioner but mocks out all the
|
// MockResourceProvisioner implements ResourceProvisioner but mocks out all the
|
||||||
// calls for testing purposes.
|
// calls for testing purposes.
|
||||||
type MockResourceProvisioner struct {
|
type MockResourceProvisioner struct {
|
||||||
|
sync.Mutex
|
||||||
// Anything you want, in case you need to store extra data with the mock.
|
// Anything you want, in case you need to store extra data with the mock.
|
||||||
Meta interface{}
|
Meta interface{}
|
||||||
|
|
||||||
|
@ -21,6 +24,9 @@ type MockResourceProvisioner struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *MockResourceProvisioner) Validate(c *ResourceConfig) ([]string, []error) {
|
func (p *MockResourceProvisioner) Validate(c *ResourceConfig) ([]string, []error) {
|
||||||
|
p.Lock()
|
||||||
|
defer p.Unlock()
|
||||||
|
|
||||||
p.ValidateCalled = true
|
p.ValidateCalled = true
|
||||||
p.ValidateConfig = c
|
p.ValidateConfig = c
|
||||||
if p.ValidateFn != nil {
|
if p.ValidateFn != nil {
|
||||||
|
@ -33,6 +39,9 @@ func (p *MockResourceProvisioner) Apply(
|
||||||
output UIOutput,
|
output UIOutput,
|
||||||
state *InstanceState,
|
state *InstanceState,
|
||||||
c *ResourceConfig) error {
|
c *ResourceConfig) error {
|
||||||
|
p.Lock()
|
||||||
|
defer p.Unlock()
|
||||||
|
|
||||||
p.ApplyCalled = true
|
p.ApplyCalled = true
|
||||||
p.ApplyOutput = output
|
p.ApplyOutput = output
|
||||||
p.ApplyState = state
|
p.ApplyState = state
|
||||||
|
|
|
@ -1331,7 +1331,7 @@ func (s *InstanceState) MergeDiff(d *InstanceDiff) *InstanceState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if d != nil {
|
if d != nil {
|
||||||
for k, diff := range d.Attributes {
|
for k, diff := range d.CopyAttributes() {
|
||||||
if diff.NewRemoved {
|
if diff.NewRemoved {
|
||||||
delete(result.Attributes, k)
|
delete(result.Attributes, k)
|
||||||
continue
|
continue
|
||||||
|
|
|
@ -418,11 +418,11 @@ func (n *graphNodeExpandedResource) managedResourceEvalNodes(resource *Resource,
|
||||||
return true, EvalEarlyExitError{}
|
return true, EvalEarlyExitError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if diffApply.Destroy && len(diffApply.Attributes) == 0 {
|
if diffApply.GetDestroy() && diffApply.GetAttributesLen() == 0 {
|
||||||
return true, EvalEarlyExitError{}
|
return true, EvalEarlyExitError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
diffApply.Destroy = false
|
diffApply.SetDestroy(false)
|
||||||
return true, nil
|
return true, nil
|
||||||
},
|
},
|
||||||
Then: EvalNoop{},
|
Then: EvalNoop{},
|
||||||
|
@ -432,7 +432,7 @@ func (n *graphNodeExpandedResource) managedResourceEvalNodes(resource *Resource,
|
||||||
If: func(ctx EvalContext) (bool, error) {
|
If: func(ctx EvalContext) (bool, error) {
|
||||||
destroy := false
|
destroy := false
|
||||||
if diffApply != nil {
|
if diffApply != nil {
|
||||||
destroy = diffApply.Destroy || diffApply.RequiresNew()
|
destroy = diffApply.GetDestroy() || diffApply.RequiresNew()
|
||||||
}
|
}
|
||||||
|
|
||||||
createBeforeDestroyEnabled =
|
createBeforeDestroyEnabled =
|
||||||
|
@ -762,7 +762,7 @@ func (n *graphNodeExpandedResource) dataResourceEvalNodes(resource *Resource, in
|
||||||
return true, EvalEarlyExitError{}
|
return true, EvalEarlyExitError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(diff.Attributes) == 0 {
|
if diff.GetAttributesLen() == 0 {
|
||||||
return true, EvalEarlyExitError{}
|
return true, EvalEarlyExitError{}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -887,7 +887,7 @@ func (n *graphNodeExpandedResourceDestroy) EvalTree() EvalNode {
|
||||||
// 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) {
|
||||||
if diffApply != nil && diffApply.Destroy {
|
if diffApply != nil && diffApply.GetDestroy() {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue