github.com/rhenning/terraform@v0.8.0-beta2/terraform/node_resource_plan_instance.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/terraform/config"
     7  )
     8  
     9  // NodePlannableResourceInstance represents a _single_ resource
    10  // instance that is plannable. This means this represents a single
    11  // count index, for example.
    12  type NodePlannableResourceInstance struct {
    13  	*NodeAbstractResource
    14  }
    15  
    16  // GraphNodeEvalable
    17  func (n *NodePlannableResourceInstance) EvalTree() EvalNode {
    18  	addr := n.NodeAbstractResource.Addr
    19  
    20  	// stateId is the ID to put into the state
    21  	stateId := addr.stateId()
    22  	if addr.Index > -1 {
    23  		stateId = fmt.Sprintf("%s.%d", stateId, addr.Index)
    24  	}
    25  
    26  	// Build the instance info. More of this will be populated during eval
    27  	info := &InstanceInfo{
    28  		Id:         stateId,
    29  		Type:       addr.Type,
    30  		ModulePath: normalizeModulePath(addr.Path),
    31  	}
    32  
    33  	// Build the resource for eval
    34  	resource := &Resource{
    35  		Name:       addr.Name,
    36  		Type:       addr.Type,
    37  		CountIndex: addr.Index,
    38  	}
    39  	if resource.CountIndex < 0 {
    40  		resource.CountIndex = 0
    41  	}
    42  
    43  	// Determine the dependencies for the state. We use some older
    44  	// code for this that we've used for a long time.
    45  	var stateDeps []string
    46  	{
    47  		oldN := &graphNodeExpandedResource{Resource: n.Config}
    48  		stateDeps = oldN.StateDependencies()
    49  	}
    50  
    51  	// Eval info is different depending on what kind of resource this is
    52  	switch n.Config.Mode {
    53  	case config.ManagedResourceMode:
    54  		return n.evalTreeManagedResource(
    55  			stateId, info, resource, stateDeps,
    56  		)
    57  	case config.DataResourceMode:
    58  		return n.evalTreeDataResource(
    59  			stateId, info, resource, stateDeps)
    60  	default:
    61  		panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
    62  	}
    63  }
    64  
    65  func (n *NodePlannableResourceInstance) evalTreeDataResource(
    66  	stateId string, info *InstanceInfo,
    67  	resource *Resource, stateDeps []string) EvalNode {
    68  	var provider ResourceProvider
    69  	var config *ResourceConfig
    70  	var diff *InstanceDiff
    71  	var state *InstanceState
    72  
    73  	return &EvalSequence{
    74  		Nodes: []EvalNode{
    75  			&EvalReadState{
    76  				Name:   stateId,
    77  				Output: &state,
    78  			},
    79  
    80  			// We need to re-interpolate the config here because some
    81  			// of the attributes may have become computed during
    82  			// earlier planning, due to other resources having
    83  			// "requires new resource" diffs.
    84  			&EvalInterpolate{
    85  				Config:   n.Config.RawConfig.Copy(),
    86  				Resource: resource,
    87  				Output:   &config,
    88  			},
    89  
    90  			&EvalIf{
    91  				If: func(ctx EvalContext) (bool, error) {
    92  					computed := config.ComputedKeys != nil && len(config.ComputedKeys) > 0
    93  
    94  					// If the configuration is complete and we
    95  					// already have a state then we don't need to
    96  					// do any further work during apply, because we
    97  					// already populated the state during refresh.
    98  					if !computed && state != nil {
    99  						return true, EvalEarlyExitError{}
   100  					}
   101  
   102  					return true, nil
   103  				},
   104  				Then: EvalNoop{},
   105  			},
   106  
   107  			&EvalGetProvider{
   108  				Name:   n.ProvidedBy()[0],
   109  				Output: &provider,
   110  			},
   111  
   112  			&EvalReadDataDiff{
   113  				Info:        info,
   114  				Config:      &config,
   115  				Provider:    &provider,
   116  				Output:      &diff,
   117  				OutputState: &state,
   118  			},
   119  
   120  			&EvalWriteState{
   121  				Name:         stateId,
   122  				ResourceType: n.Config.Type,
   123  				Provider:     n.Config.Provider,
   124  				Dependencies: stateDeps,
   125  				State:        &state,
   126  			},
   127  
   128  			&EvalWriteDiff{
   129  				Name: stateId,
   130  				Diff: &diff,
   131  			},
   132  		},
   133  	}
   134  }
   135  
   136  func (n *NodePlannableResourceInstance) evalTreeManagedResource(
   137  	stateId string, info *InstanceInfo,
   138  	resource *Resource, stateDeps []string) EvalNode {
   139  	// Declare a bunch of variables that are used for state during
   140  	// evaluation. Most of this are written to by-address below.
   141  	var provider ResourceProvider
   142  	var diff *InstanceDiff
   143  	var state *InstanceState
   144  	var resourceConfig *ResourceConfig
   145  
   146  	return &EvalSequence{
   147  		Nodes: []EvalNode{
   148  			&EvalInterpolate{
   149  				Config:   n.Config.RawConfig.Copy(),
   150  				Resource: resource,
   151  				Output:   &resourceConfig,
   152  			},
   153  			&EvalGetProvider{
   154  				Name:   n.ProvidedBy()[0],
   155  				Output: &provider,
   156  			},
   157  			// Re-run validation to catch any errors we missed, e.g. type
   158  			// mismatches on computed values.
   159  			&EvalValidateResource{
   160  				Provider:       &provider,
   161  				Config:         &resourceConfig,
   162  				ResourceName:   n.Config.Name,
   163  				ResourceType:   n.Config.Type,
   164  				ResourceMode:   n.Config.Mode,
   165  				IgnoreWarnings: true,
   166  			},
   167  			&EvalReadState{
   168  				Name:   stateId,
   169  				Output: &state,
   170  			},
   171  			&EvalDiff{
   172  				Info:        info,
   173  				Config:      &resourceConfig,
   174  				Resource:    n.Config,
   175  				Provider:    &provider,
   176  				State:       &state,
   177  				OutputDiff:  &diff,
   178  				OutputState: &state,
   179  			},
   180  			&EvalCheckPreventDestroy{
   181  				Resource: n.Config,
   182  				Diff:     &diff,
   183  			},
   184  			&EvalWriteState{
   185  				Name:         stateId,
   186  				ResourceType: n.Config.Type,
   187  				Provider:     n.Config.Provider,
   188  				Dependencies: stateDeps,
   189  				State:        &state,
   190  			},
   191  			&EvalWriteDiff{
   192  				Name: stateId,
   193  				Diff: &diff,
   194  			},
   195  		},
   196  	}
   197  }