github.com/ibm-cloud/terraform@v0.6.4-0.20170726051544-8872b87621df/terraform/node_resource_refresh.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/hashicorp/terraform/config"
     7  	"github.com/hashicorp/terraform/dag"
     8  )
     9  
    10  // NodeRefreshableManagedResource represents a resource that is expanabled into
    11  // NodeRefreshableManagedResourceInstance. Resource count orphans are also added.
    12  type NodeRefreshableManagedResource struct {
    13  	*NodeAbstractCountResource
    14  }
    15  
    16  // GraphNodeDynamicExpandable
    17  func (n *NodeRefreshableManagedResource) DynamicExpand(ctx EvalContext) (*Graph, error) {
    18  	// Grab the state which we read
    19  	state, lock := ctx.State()
    20  	lock.RLock()
    21  	defer lock.RUnlock()
    22  
    23  	// Expand the resource count which must be available by now from EvalTree
    24  	count, err := n.Config.Count()
    25  	if err != nil {
    26  		return nil, err
    27  	}
    28  
    29  	// The concrete resource factory we'll use
    30  	concreteResource := func(a *NodeAbstractResource) dag.Vertex {
    31  		// Add the config and state since we don't do that via transforms
    32  		a.Config = n.Config
    33  
    34  		return &NodeRefreshableManagedResourceInstance{
    35  			NodeAbstractResource: a,
    36  		}
    37  	}
    38  
    39  	// Start creating the steps
    40  	steps := []GraphTransformer{
    41  		// Expand the count.
    42  		&ResourceCountTransformer{
    43  			Concrete: concreteResource,
    44  			Count:    count,
    45  			Addr:     n.ResourceAddr(),
    46  		},
    47  
    48  		// Switch up any node missing state to a plannable resource. This helps
    49  		// catch cases where data sources depend on the counts from this resource
    50  		// during a scale out.
    51  		&ResourceRefreshPlannableTransformer{
    52  			State: state,
    53  		},
    54  
    55  		// Add the count orphans to make sure these resources are accounted for
    56  		// during a scale in.
    57  		&OrphanResourceCountTransformer{
    58  			Concrete: concreteResource,
    59  			Count:    count,
    60  			Addr:     n.ResourceAddr(),
    61  			State:    state,
    62  		},
    63  
    64  		// Attach the state
    65  		&AttachStateTransformer{State: state},
    66  
    67  		// Targeting
    68  		&TargetsTransformer{ParsedTargets: n.Targets},
    69  
    70  		// Connect references so ordering is correct
    71  		&ReferenceTransformer{},
    72  
    73  		// Make sure there is a single root
    74  		&RootTransformer{},
    75  	}
    76  
    77  	// Build the graph
    78  	b := &BasicGraphBuilder{
    79  		Steps:    steps,
    80  		Validate: true,
    81  		Name:     "NodeRefreshableManagedResource",
    82  	}
    83  
    84  	return b.Build(ctx.Path())
    85  }
    86  
    87  // NodeRefreshableManagedResourceInstance represents a resource that is "applyable":
    88  // it is ready to be applied and is represented by a diff.
    89  type NodeRefreshableManagedResourceInstance struct {
    90  	*NodeAbstractResource
    91  }
    92  
    93  // GraphNodeDestroyer
    94  func (n *NodeRefreshableManagedResourceInstance) DestroyAddr() *ResourceAddress {
    95  	return n.Addr
    96  }
    97  
    98  // GraphNodeEvalable
    99  func (n *NodeRefreshableManagedResourceInstance) EvalTree() EvalNode {
   100  	// Eval info is different depending on what kind of resource this is
   101  	switch mode := n.Addr.Mode; mode {
   102  	case config.ManagedResourceMode:
   103  		return n.evalTreeManagedResource()
   104  
   105  	case config.DataResourceMode:
   106  		// Get the data source node. If we don't have a configuration
   107  		// then it is an orphan so we destroy it (remove it from the state).
   108  		var dn GraphNodeEvalable
   109  		if n.Config != nil {
   110  			dn = &NodeRefreshableDataResourceInstance{
   111  				NodeAbstractResource: n.NodeAbstractResource,
   112  			}
   113  		} else {
   114  			dn = &NodeDestroyableDataResource{
   115  				NodeAbstractResource: n.NodeAbstractResource,
   116  			}
   117  		}
   118  
   119  		return dn.EvalTree()
   120  	default:
   121  		panic(fmt.Errorf("unsupported resource mode %s", mode))
   122  	}
   123  }
   124  
   125  func (n *NodeRefreshableManagedResourceInstance) evalTreeManagedResource() EvalNode {
   126  	addr := n.NodeAbstractResource.Addr
   127  
   128  	// stateId is the ID to put into the state
   129  	stateId := addr.stateId()
   130  
   131  	// Build the instance info. More of this will be populated during eval
   132  	info := &InstanceInfo{
   133  		Id:   stateId,
   134  		Type: addr.Type,
   135  	}
   136  
   137  	// Declare a bunch of variables that are used for state during
   138  	// evaluation. Most of this are written to by-address below.
   139  	var provider ResourceProvider
   140  	var state *InstanceState
   141  
   142  	// This happened during initial development. All known cases were
   143  	// fixed and tested but as a sanity check let's assert here.
   144  	if n.ResourceState == nil {
   145  		err := fmt.Errorf(
   146  			"No resource state attached for addr: %s\n\n"+
   147  				"This is a bug. Please report this to Terraform with your configuration\n"+
   148  				"and state attached. Please be careful to scrub any sensitive information.",
   149  			addr)
   150  		return &EvalReturnError{Error: &err}
   151  	}
   152  
   153  	return &EvalSequence{
   154  		Nodes: []EvalNode{
   155  			&EvalGetProvider{
   156  				Name:   n.ProvidedBy()[0],
   157  				Output: &provider,
   158  			},
   159  			&EvalReadState{
   160  				Name:   stateId,
   161  				Output: &state,
   162  			},
   163  			&EvalRefresh{
   164  				Info:     info,
   165  				Provider: &provider,
   166  				State:    &state,
   167  				Output:   &state,
   168  			},
   169  			&EvalWriteState{
   170  				Name:         stateId,
   171  				ResourceType: n.ResourceState.Type,
   172  				Provider:     n.ResourceState.Provider,
   173  				Dependencies: n.ResourceState.Dependencies,
   174  				State:        &state,
   175  			},
   176  		},
   177  	}
   178  }