github.com/Hashicorp/terraform@v0.11.12-beta1/terraform/node_resource_abstract.go (about)

     1  package terraform
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/hashicorp/terraform/config"
     8  	"github.com/hashicorp/terraform/dag"
     9  )
    10  
    11  // ConcreteResourceNodeFunc is a callback type used to convert an
    12  // abstract resource to a concrete one of some type.
    13  type ConcreteResourceNodeFunc func(*NodeAbstractResource) dag.Vertex
    14  
    15  // GraphNodeResource is implemented by any nodes that represent a resource.
    16  // The type of operation cannot be assumed, only that this node represents
    17  // the given resource.
    18  type GraphNodeResource interface {
    19  	ResourceAddr() *ResourceAddress
    20  }
    21  
    22  // NodeAbstractResource represents a resource that has no associated
    23  // operations. It registers all the interfaces for a resource that common
    24  // across multiple operation types.
    25  type NodeAbstractResource struct {
    26  	Addr *ResourceAddress // Addr is the address for this resource
    27  
    28  	// The fields below will be automatically set using the Attach
    29  	// interfaces if you're running those transforms, but also be explicitly
    30  	// set if you already have that information.
    31  
    32  	Config        *config.Resource // Config is the resource in the config
    33  	ResourceState *ResourceState   // ResourceState is the ResourceState for this
    34  
    35  	Targets []ResourceAddress // Set from GraphNodeTargetable
    36  
    37  	// The address of the provider this resource will use
    38  	ResolvedProvider string
    39  }
    40  
    41  func (n *NodeAbstractResource) Name() string {
    42  	return n.Addr.String()
    43  }
    44  
    45  // GraphNodeSubPath
    46  func (n *NodeAbstractResource) Path() []string {
    47  	return n.Addr.Path
    48  }
    49  
    50  // GraphNodeReferenceable
    51  func (n *NodeAbstractResource) ReferenceableName() []string {
    52  	// We always are referenceable as "type.name" as long as
    53  	// we have a config or address. Determine what that value is.
    54  	var id string
    55  	if n.Config != nil {
    56  		id = n.Config.Id()
    57  	} else if n.Addr != nil {
    58  		addrCopy := n.Addr.Copy()
    59  		addrCopy.Path = nil // ReferenceTransformer handles paths
    60  		addrCopy.Index = -1 // We handle indexes below
    61  		id = addrCopy.String()
    62  	} else {
    63  		// No way to determine our type.name, just return
    64  		return nil
    65  	}
    66  
    67  	var result []string
    68  
    69  	// Always include our own ID. This is primarily for backwards
    70  	// compatibility with states that didn't yet support the more
    71  	// specific dep string.
    72  	result = append(result, id)
    73  
    74  	// We represent all multi-access
    75  	result = append(result, fmt.Sprintf("%s.*", id))
    76  
    77  	// We represent either a specific number, or all numbers
    78  	suffix := "N"
    79  	if n.Addr != nil {
    80  		idx := n.Addr.Index
    81  		if idx == -1 {
    82  			idx = 0
    83  		}
    84  
    85  		suffix = fmt.Sprintf("%d", idx)
    86  	}
    87  	result = append(result, fmt.Sprintf("%s.%s", id, suffix))
    88  
    89  	return result
    90  }
    91  
    92  // GraphNodeReferencer
    93  func (n *NodeAbstractResource) References() []string {
    94  	// If we have a config, that is our source of truth
    95  	if c := n.Config; c != nil {
    96  		// Grab all the references
    97  		var result []string
    98  		result = append(result, c.DependsOn...)
    99  		result = append(result, ReferencesFromConfig(c.RawCount)...)
   100  		result = append(result, ReferencesFromConfig(c.RawConfig)...)
   101  		for _, p := range c.Provisioners {
   102  			if p.When == config.ProvisionerWhenCreate {
   103  				result = append(result, ReferencesFromConfig(p.ConnInfo)...)
   104  				result = append(result, ReferencesFromConfig(p.RawConfig)...)
   105  			}
   106  		}
   107  
   108  		return uniqueStrings(result)
   109  	}
   110  
   111  	// If we have state, that is our next source
   112  	if s := n.ResourceState; s != nil {
   113  		return s.Dependencies
   114  	}
   115  
   116  	return nil
   117  }
   118  
   119  // StateReferences returns the dependencies to put into the state for
   120  // this resource.
   121  func (n *NodeAbstractResource) StateReferences() []string {
   122  	self := n.ReferenceableName()
   123  
   124  	// Determine what our "prefix" is for checking for references to
   125  	// ourself.
   126  	addrCopy := n.Addr.Copy()
   127  	addrCopy.Index = -1
   128  	selfPrefix := addrCopy.String() + "."
   129  
   130  	depsRaw := n.References()
   131  	deps := make([]string, 0, len(depsRaw))
   132  	for _, d := range depsRaw {
   133  		// Ignore any variable dependencies
   134  		if strings.HasPrefix(d, "var.") {
   135  			continue
   136  		}
   137  
   138  		// If this has a backup ref, ignore those for now. The old state
   139  		// file never contained those and I'd rather store the rich types we
   140  		// add in the future.
   141  		if idx := strings.IndexRune(d, '/'); idx != -1 {
   142  			d = d[:idx]
   143  		}
   144  
   145  		// If we're referencing ourself, then ignore it
   146  		found := false
   147  		for _, s := range self {
   148  			if d == s {
   149  				found = true
   150  			}
   151  		}
   152  		if found {
   153  			continue
   154  		}
   155  
   156  		// If this is a reference to ourself and a specific index, we keep
   157  		// it. For example, if this resource is "foo.bar" and the reference
   158  		// is "foo.bar.0" then we keep it exact. Otherwise, we strip it.
   159  		if strings.HasSuffix(d, ".0") && !strings.HasPrefix(d, selfPrefix) {
   160  			d = d[:len(d)-2]
   161  		}
   162  
   163  		// This is sad. The dependencies are currently in the format of
   164  		// "module.foo.bar" (the full field). This strips the field off.
   165  		if strings.HasPrefix(d, "module.") {
   166  			parts := strings.SplitN(d, ".", 3)
   167  			d = strings.Join(parts[0:2], ".")
   168  		}
   169  
   170  		deps = append(deps, d)
   171  	}
   172  
   173  	return deps
   174  }
   175  
   176  func (n *NodeAbstractResource) SetProvider(p string) {
   177  	n.ResolvedProvider = p
   178  }
   179  
   180  // GraphNodeProviderConsumer
   181  func (n *NodeAbstractResource) ProvidedBy() string {
   182  	// If we have a config we prefer that above all else
   183  	if n.Config != nil {
   184  		return resourceProvider(n.Config.Type, n.Config.Provider)
   185  	}
   186  
   187  	// If we have state, then we will use the provider from there
   188  	if n.ResourceState != nil && n.ResourceState.Provider != "" {
   189  		return n.ResourceState.Provider
   190  	}
   191  
   192  	// Use our type
   193  	return resourceProvider(n.Addr.Type, "")
   194  }
   195  
   196  // GraphNodeProvisionerConsumer
   197  func (n *NodeAbstractResource) ProvisionedBy() []string {
   198  	// If we have no configuration, then we have no provisioners
   199  	if n.Config == nil {
   200  		return nil
   201  	}
   202  
   203  	// Build the list of provisioners we need based on the configuration.
   204  	// It is okay to have duplicates here.
   205  	result := make([]string, len(n.Config.Provisioners))
   206  	for i, p := range n.Config.Provisioners {
   207  		result[i] = p.Type
   208  	}
   209  
   210  	return result
   211  }
   212  
   213  // GraphNodeResource, GraphNodeAttachResourceState
   214  func (n *NodeAbstractResource) ResourceAddr() *ResourceAddress {
   215  	return n.Addr
   216  }
   217  
   218  // GraphNodeAddressable, TODO: remove, used by target, should unify
   219  func (n *NodeAbstractResource) ResourceAddress() *ResourceAddress {
   220  	return n.ResourceAddr()
   221  }
   222  
   223  // GraphNodeTargetable
   224  func (n *NodeAbstractResource) SetTargets(targets []ResourceAddress) {
   225  	n.Targets = targets
   226  }
   227  
   228  // GraphNodeAttachResourceState
   229  func (n *NodeAbstractResource) AttachResourceState(s *ResourceState) {
   230  	n.ResourceState = s
   231  }
   232  
   233  // GraphNodeAttachResourceConfig
   234  func (n *NodeAbstractResource) AttachResourceConfig(c *config.Resource) {
   235  	n.Config = c
   236  }
   237  
   238  // GraphNodeDotter impl.
   239  func (n *NodeAbstractResource) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
   240  	return &dag.DotNode{
   241  		Name: name,
   242  		Attrs: map[string]string{
   243  			"label": n.Name(),
   244  			"shape": "box",
   245  		},
   246  	}
   247  }