github.com/federicobaldo/terraform@v0.6.15-0.20160323222747-b20f680cbf05/terraform/eval_ignore_changes.go (about)

     1  package terraform
     2  
     3  import (
     4  	"log"
     5  	"strings"
     6  
     7  	"github.com/hashicorp/terraform/config"
     8  )
     9  
    10  // EvalIgnoreChanges is an EvalNode implementation that removes diff
    11  // attributes if their name matches names provided by the resource's
    12  // IgnoreChanges lifecycle.
    13  type EvalIgnoreChanges struct {
    14  	Resource      *config.Resource
    15  	Diff          **InstanceDiff
    16  	WasChangeType *DiffChangeType
    17  }
    18  
    19  func (n *EvalIgnoreChanges) Eval(ctx EvalContext) (interface{}, error) {
    20  	if n.Diff == nil || *n.Diff == nil || n.Resource == nil || n.Resource.Id() == "" {
    21  		return nil, nil
    22  	}
    23  
    24  	diff := *n.Diff
    25  	ignoreChanges := n.Resource.Lifecycle.IgnoreChanges
    26  
    27  	if len(ignoreChanges) == 0 {
    28  		return nil, nil
    29  	}
    30  
    31  	changeType := diff.ChangeType()
    32  	// Let the passed in change type pointer override what the diff currently has.
    33  	if n.WasChangeType != nil && *n.WasChangeType != DiffInvalid {
    34  		changeType = *n.WasChangeType
    35  	}
    36  
    37  	// If we're just creating the resource, we shouldn't alter the
    38  	// Diff at all
    39  	if changeType == DiffCreate {
    40  		return nil, nil
    41  	}
    42  
    43  	for _, ignoredName := range ignoreChanges {
    44  		for name := range diff.Attributes {
    45  			if strings.HasPrefix(name, ignoredName) {
    46  				delete(diff.Attributes, name)
    47  			}
    48  		}
    49  	}
    50  
    51  	// If we are replacing the resource, then we expect there to be a bunch of
    52  	// extraneous attribute diffs we need to filter out for the other
    53  	// non-requires-new attributes going from "" -> "configval" or "" ->
    54  	// "<computed>". Filtering these out allows us to see if we might be able to
    55  	// skip this diff altogether.
    56  	if changeType == DiffDestroyCreate {
    57  		for k, v := range diff.Attributes {
    58  			if v.Empty() || v.NewComputed {
    59  				delete(diff.Attributes, k)
    60  			}
    61  		}
    62  
    63  		// Here we emulate the implementation of diff.RequiresNew() with one small
    64  		// tweak, we ignore the "id" attribute diff that gets added by EvalDiff,
    65  		// since that was added in reaction to RequiresNew being true.
    66  		requiresNewAfterIgnores := false
    67  		for k, v := range diff.Attributes {
    68  			if k == "id" {
    69  				continue
    70  			}
    71  			if v.RequiresNew == true {
    72  				requiresNewAfterIgnores = true
    73  			}
    74  		}
    75  
    76  		// Here we undo the two reactions to RequireNew in EvalDiff - the "id"
    77  		// attribute diff and the Destroy boolean field
    78  		if !requiresNewAfterIgnores {
    79  			log.Printf("[DEBUG] Removing 'id' diff and setting Destroy to false " +
    80  				"because after ignore_changes, this diff no longer requires replacement")
    81  			delete(diff.Attributes, "id")
    82  			diff.Destroy = false
    83  		}
    84  	}
    85  
    86  	return nil, nil
    87  }