github.com/trawler/terraform@v0.10.8-0.20171106022149-4b1c7a1d9b48/terraform/eval_count_boundary.go (about)

     1  package terraform
     2  
     3  import (
     4  	"log"
     5  )
     6  
     7  // EvalCountFixZeroOneBoundaryGlobal is an EvalNode that fixes up the state
     8  // when there is a resource count with zero/one boundary, i.e. fixing
     9  // a resource named "aws_instance.foo" to "aws_instance.foo.0" and vice-versa.
    10  //
    11  // This works on the global state.
    12  type EvalCountFixZeroOneBoundaryGlobal struct{}
    13  
    14  // TODO: test
    15  func (n *EvalCountFixZeroOneBoundaryGlobal) Eval(ctx EvalContext) (interface{}, error) {
    16  	// Get the state and lock it since we'll potentially modify it
    17  	state, lock := ctx.State()
    18  	lock.Lock()
    19  	defer lock.Unlock()
    20  
    21  	// Prune the state since we require a clean state to work
    22  	state.prune()
    23  
    24  	// Go through each modules since the boundaries are restricted to a
    25  	// module scope.
    26  	for _, m := range state.Modules {
    27  		if err := n.fixModule(m); err != nil {
    28  			return nil, err
    29  		}
    30  	}
    31  
    32  	return nil, nil
    33  }
    34  
    35  func (n *EvalCountFixZeroOneBoundaryGlobal) fixModule(m *ModuleState) error {
    36  	// Counts keeps track of keys and their counts
    37  	counts := make(map[string]int)
    38  	for k, _ := range m.Resources {
    39  		// Parse the key
    40  		key, err := ParseResourceStateKey(k)
    41  		if err != nil {
    42  			return err
    43  		}
    44  
    45  		// Set the index to -1 so that we can keep count
    46  		key.Index = -1
    47  
    48  		// Increment
    49  		counts[key.String()]++
    50  	}
    51  
    52  	// Go through the counts and do the fixup for each resource
    53  	for raw, count := range counts {
    54  		// Search and replace this resource
    55  		search := raw
    56  		replace := raw + ".0"
    57  		if count < 2 {
    58  			search, replace = replace, search
    59  		}
    60  		log.Printf("[TRACE] EvalCountFixZeroOneBoundaryGlobal: count %d, search %q, replace %q", count, search, replace)
    61  
    62  		// Look for the resource state. If we don't have one, then it is okay.
    63  		rs, ok := m.Resources[search]
    64  		if !ok {
    65  			continue
    66  		}
    67  
    68  		// If the replacement key exists, we just keep both
    69  		if _, ok := m.Resources[replace]; ok {
    70  			continue
    71  		}
    72  
    73  		m.Resources[replace] = rs
    74  		delete(m.Resources, search)
    75  	}
    76  
    77  	return nil
    78  }