]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blobdiff - vendor/github.com/hashicorp/terraform/terraform/node_resource_abstract.go
Upgrade to 0.12
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / hashicorp / terraform / terraform / node_resource_abstract.go
index 73509c87f126a5f211f5cb5770d396908cecc60e..3a0570c5b62a2383bbd35a0b30f7cf078ae7227c 100644 (file)
@@ -2,10 +2,16 @@ package terraform
 
 import (
        "fmt"
-       "strings"
+       "log"
+       "sort"
 
-       "github.com/hashicorp/terraform/config"
+       "github.com/hashicorp/terraform/addrs"
+       "github.com/hashicorp/terraform/configs"
+       "github.com/hashicorp/terraform/configs/configschema"
        "github.com/hashicorp/terraform/dag"
+       "github.com/hashicorp/terraform/lang"
+       "github.com/hashicorp/terraform/states"
+       "github.com/hashicorp/terraform/tfdiags"
 )
 
 // ConcreteResourceNodeFunc is a callback type used to convert an
@@ -16,225 +22,420 @@ type ConcreteResourceNodeFunc func(*NodeAbstractResource) dag.Vertex
 // The type of operation cannot be assumed, only that this node represents
 // the given resource.
 type GraphNodeResource interface {
-       ResourceAddr() *ResourceAddress
+       ResourceAddr() addrs.AbsResource
+}
+
+// ConcreteResourceInstanceNodeFunc is a callback type used to convert an
+// abstract resource instance to a concrete one of some type.
+type ConcreteResourceInstanceNodeFunc func(*NodeAbstractResourceInstance) dag.Vertex
+
+// GraphNodeResourceInstance is implemented by any nodes that represent
+// a resource instance. A single resource may have multiple instances if,
+// for example, the "count" or "for_each" argument is used for it in
+// configuration.
+type GraphNodeResourceInstance interface {
+       ResourceInstanceAddr() addrs.AbsResourceInstance
 }
 
 // NodeAbstractResource represents a resource that has no associated
 // operations. It registers all the interfaces for a resource that common
 // across multiple operation types.
 type NodeAbstractResource struct {
-       Addr *ResourceAddress // Addr is the address for this resource
+       Addr addrs.AbsResource // Addr is the address for this resource
 
        // The fields below will be automatically set using the Attach
        // interfaces if you're running those transforms, but also be explicitly
        // set if you already have that information.
 
-       Config        *config.Resource // Config is the resource in the config
-       ResourceState *ResourceState   // ResourceState is the ResourceState for this
+       Schema        *configschema.Block // Schema for processing the configuration body
+       SchemaVersion uint64              // Schema version of "Schema", as decided by the provider
+       Config        *configs.Resource   // Config is the resource in the config
 
-       Targets []ResourceAddress // Set from GraphNodeTargetable
+       ProvisionerSchemas map[string]*configschema.Block
+
+       Targets []addrs.Targetable // Set from GraphNodeTargetable
 
        // The address of the provider this resource will use
-       ResolvedProvider string
+       ResolvedProvider addrs.AbsProviderConfig
+}
+
+var (
+       _ GraphNodeSubPath                 = (*NodeAbstractResource)(nil)
+       _ GraphNodeReferenceable           = (*NodeAbstractResource)(nil)
+       _ GraphNodeReferencer              = (*NodeAbstractResource)(nil)
+       _ GraphNodeProviderConsumer        = (*NodeAbstractResource)(nil)
+       _ GraphNodeProvisionerConsumer     = (*NodeAbstractResource)(nil)
+       _ GraphNodeResource                = (*NodeAbstractResource)(nil)
+       _ GraphNodeAttachResourceConfig    = (*NodeAbstractResource)(nil)
+       _ GraphNodeAttachResourceSchema    = (*NodeAbstractResource)(nil)
+       _ GraphNodeAttachProvisionerSchema = (*NodeAbstractResource)(nil)
+       _ GraphNodeTargetable              = (*NodeAbstractResource)(nil)
+       _ dag.GraphNodeDotter              = (*NodeAbstractResource)(nil)
+)
+
+// NewNodeAbstractResource creates an abstract resource graph node for
+// the given absolute resource address.
+func NewNodeAbstractResource(addr addrs.AbsResource) *NodeAbstractResource {
+       return &NodeAbstractResource{
+               Addr: addr,
+       }
+}
+
+// NodeAbstractResourceInstance represents a resource instance with no
+// associated operations. It embeds NodeAbstractResource but additionally
+// contains an instance key, used to identify one of potentially many
+// instances that were created from a resource in configuration, e.g. using
+// the "count" or "for_each" arguments.
+type NodeAbstractResourceInstance struct {
+       NodeAbstractResource
+       InstanceKey addrs.InstanceKey
+
+       // The fields below will be automatically set using the Attach
+       // interfaces if you're running those transforms, but also be explicitly
+       // set if you already have that information.
+
+       ResourceState *states.Resource
+}
+
+var (
+       _ GraphNodeSubPath                 = (*NodeAbstractResourceInstance)(nil)
+       _ GraphNodeReferenceable           = (*NodeAbstractResourceInstance)(nil)
+       _ GraphNodeReferencer              = (*NodeAbstractResourceInstance)(nil)
+       _ GraphNodeProviderConsumer        = (*NodeAbstractResourceInstance)(nil)
+       _ GraphNodeProvisionerConsumer     = (*NodeAbstractResourceInstance)(nil)
+       _ GraphNodeResource                = (*NodeAbstractResourceInstance)(nil)
+       _ GraphNodeResourceInstance        = (*NodeAbstractResourceInstance)(nil)
+       _ GraphNodeAttachResourceState     = (*NodeAbstractResourceInstance)(nil)
+       _ GraphNodeAttachResourceConfig    = (*NodeAbstractResourceInstance)(nil)
+       _ GraphNodeAttachResourceSchema    = (*NodeAbstractResourceInstance)(nil)
+       _ GraphNodeAttachProvisionerSchema = (*NodeAbstractResourceInstance)(nil)
+       _ GraphNodeTargetable              = (*NodeAbstractResourceInstance)(nil)
+       _ dag.GraphNodeDotter              = (*NodeAbstractResourceInstance)(nil)
+)
+
+// NewNodeAbstractResourceInstance creates an abstract resource instance graph
+// node for the given absolute resource instance address.
+func NewNodeAbstractResourceInstance(addr addrs.AbsResourceInstance) *NodeAbstractResourceInstance {
+       // Due to the fact that we embed NodeAbstractResource, the given address
+       // actually ends up split between the resource address in the embedded
+       // object and the InstanceKey field in our own struct. The
+       // ResourceInstanceAddr method will stick these back together again on
+       // request.
+       return &NodeAbstractResourceInstance{
+               NodeAbstractResource: NodeAbstractResource{
+                       Addr: addr.ContainingResource(),
+               },
+               InstanceKey: addr.Resource.Key,
+       }
 }
 
 func (n *NodeAbstractResource) Name() string {
-       return n.Addr.String()
+       return n.ResourceAddr().String()
+}
+
+func (n *NodeAbstractResourceInstance) Name() string {
+       return n.ResourceInstanceAddr().String()
 }
 
 // GraphNodeSubPath
-func (n *NodeAbstractResource) Path() []string {
-       return n.Addr.Path
+func (n *NodeAbstractResource) Path() addrs.ModuleInstance {
+       return n.Addr.Module
 }
 
 // GraphNodeReferenceable
-func (n *NodeAbstractResource) ReferenceableName() []string {
-       // We always are referenceable as "type.name" as long as
-       // we have a config or address. Determine what that value is.
-       var id string
-       if n.Config != nil {
-               id = n.Config.Id()
-       } else if n.Addr != nil {
-               addrCopy := n.Addr.Copy()
-               addrCopy.Path = nil // ReferenceTransformer handles paths
-               addrCopy.Index = -1 // We handle indexes below
-               id = addrCopy.String()
-       } else {
-               // No way to determine our type.name, just return
-               return nil
-       }
+func (n *NodeAbstractResource) ReferenceableAddrs() []addrs.Referenceable {
+       return []addrs.Referenceable{n.Addr.Resource}
+}
 
-       var result []string
+// GraphNodeReferenceable
+func (n *NodeAbstractResourceInstance) ReferenceableAddrs() []addrs.Referenceable {
+       addr := n.ResourceInstanceAddr()
+       return []addrs.Referenceable{
+               addr.Resource,
+
+               // A resource instance can also be referenced by the address of its
+               // containing resource, so that e.g. a reference to aws_instance.foo
+               // would match both aws_instance.foo[0] and aws_instance.foo[1].
+               addr.ContainingResource().Resource,
+       }
+}
 
-       // Always include our own ID. This is primarily for backwards
-       // compatibility with states that didn't yet support the more
-       // specific dep string.
-       result = append(result, id)
+// GraphNodeReferencer
+func (n *NodeAbstractResource) References() []*addrs.Reference {
+       // If we have a config then we prefer to use that.
+       if c := n.Config; c != nil {
+               var result []*addrs.Reference
+
+               for _, traversal := range c.DependsOn {
+                       ref, err := addrs.ParseRef(traversal)
+                       if err != nil {
+                               // We ignore this here, because this isn't a suitable place to return
+                               // errors. This situation should be caught and rejected during
+                               // validation.
+                               log.Printf("[ERROR] Can't parse %#v from depends_on as reference: %s", traversal, err)
+                               continue
+                       }
 
-       // We represent all multi-access
-       result = append(result, fmt.Sprintf("%s.*", id))
+                       result = append(result, ref)
+               }
 
-       // We represent either a specific number, or all numbers
-       suffix := "N"
-       if n.Addr != nil {
-               idx := n.Addr.Index
-               if idx == -1 {
-                       idx = 0
+               if n.Schema == nil {
+                       // Should never happens, but we'll log if it does so that we can
+                       // see this easily when debugging.
+                       log.Printf("[WARN] no schema is attached to %s, so config references cannot be detected", n.Name())
                }
 
-               suffix = fmt.Sprintf("%d", idx)
+               refs, _ := lang.ReferencesInExpr(c.Count)
+               result = append(result, refs...)
+               refs, _ = lang.ReferencesInBlock(c.Config, n.Schema)
+               result = append(result, refs...)
+               if c.Managed != nil {
+                       for _, p := range c.Managed.Provisioners {
+                               if p.When != configs.ProvisionerWhenCreate {
+                                       continue
+                               }
+                               if p.Connection != nil {
+                                       refs, _ = lang.ReferencesInBlock(p.Connection.Config, connectionBlockSupersetSchema)
+                                       result = append(result, refs...)
+                               }
+
+                               schema := n.ProvisionerSchemas[p.Type]
+                               if schema == nil {
+                                       log.Printf("[WARN] no schema for provisioner %q is attached to %s, so provisioner block references cannot be detected", p.Type, n.Name())
+                               }
+                               refs, _ = lang.ReferencesInBlock(p.Config, schema)
+                               result = append(result, refs...)
+                       }
+               }
+               return result
        }
-       result = append(result, fmt.Sprintf("%s.%s", id, suffix))
 
-       return result
+       // Otherwise, we have no references.
+       return nil
 }
 
 // GraphNodeReferencer
-func (n *NodeAbstractResource) References() []string {
-       // If we have a config, that is our source of truth
-       if c := n.Config; c != nil {
-               // Grab all the references
-               var result []string
-               result = append(result, c.DependsOn...)
-               result = append(result, ReferencesFromConfig(c.RawCount)...)
-               result = append(result, ReferencesFromConfig(c.RawConfig)...)
-               for _, p := range c.Provisioners {
-                       if p.When == config.ProvisionerWhenCreate {
-                               result = append(result, ReferencesFromConfig(p.ConnInfo)...)
-                               result = append(result, ReferencesFromConfig(p.RawConfig)...)
-                       }
+func (n *NodeAbstractResourceInstance) References() []*addrs.Reference {
+       // If we have a configuration attached then we'll delegate to our
+       // embedded abstract resource, which knows how to extract dependencies
+       // from configuration.
+       if n.Config != nil {
+               if n.Schema == nil {
+                       // We'll produce a log message about this out here so that
+                       // we can include the full instance address, since the equivalent
+                       // message in NodeAbstractResource.References cannot see it.
+                       log.Printf("[WARN] no schema is attached to %s, so config references cannot be detected", n.Name())
+                       return nil
                }
-
-               return uniqueStrings(result)
+               return n.NodeAbstractResource.References()
        }
 
-       // If we have state, that is our next source
-       if s := n.ResourceState; s != nil {
-               return s.Dependencies
+       // Otherwise, if we have state then we'll use the values stored in state
+       // as a fallback.
+       if rs := n.ResourceState; rs != nil {
+               if s := rs.Instance(n.InstanceKey); s != nil {
+                       // State is still storing dependencies as old-style strings, so we'll
+                       // need to do a little work here to massage this to the form we now
+                       // want.
+                       var result []*addrs.Reference
+                       for _, addr := range s.Current.Dependencies {
+                               if addr == nil {
+                                       // Should never happen; indicates a bug in the state loader
+                                       panic(fmt.Sprintf("dependencies for current object on %s contains nil address", n.ResourceInstanceAddr()))
+                               }
+
+                               // This is a little weird: we need to manufacture an addrs.Reference
+                               // with a fake range here because the state isn't something we can
+                               // make source references into.
+                               result = append(result, &addrs.Reference{
+                                       Subject: addr,
+                                       SourceRange: tfdiags.SourceRange{
+                                               Filename: "(state file)",
+                                       },
+                               })
+                       }
+                       return result
+               }
        }
 
+       // If we have neither config nor state then we have no references.
        return nil
 }
 
+// converts an instance address to the legacy dotted notation
+func dottedInstanceAddr(tr addrs.ResourceInstance) string {
+       // The legacy state format uses dot-separated instance keys,
+       // rather than bracketed as in our modern syntax.
+       var suffix string
+       switch tk := tr.Key.(type) {
+       case addrs.IntKey:
+               suffix = fmt.Sprintf(".%d", int(tk))
+       case addrs.StringKey:
+               suffix = fmt.Sprintf(".%s", string(tk))
+       }
+       return tr.Resource.String() + suffix
+}
+
 // StateReferences returns the dependencies to put into the state for
 // this resource.
-func (n *NodeAbstractResource) StateReferences() []string {
-       self := n.ReferenceableName()
-
-       // Determine what our "prefix" is for checking for references to
-       // ourself.
-       addrCopy := n.Addr.Copy()
-       addrCopy.Index = -1
-       selfPrefix := addrCopy.String() + "."
+func (n *NodeAbstractResourceInstance) StateReferences() []addrs.Referenceable {
+       selfAddrs := n.ReferenceableAddrs()
+
+       // Since we don't include the source location references in our
+       // results from this method, we'll also filter out duplicates:
+       // there's no point in listing the same object twice without
+       // that additional context.
+       seen := map[string]struct{}{}
+
+       // Pretend that we've already "seen" all of our own addresses so that we
+       // won't record self-references in the state. This can arise if, for
+       // example, a provisioner for a resource refers to the resource itself,
+       // which is valid (since provisioners always run after apply) but should
+       // not create an explicit dependency edge.
+       for _, selfAddr := range selfAddrs {
+               seen[selfAddr.String()] = struct{}{}
+               if riAddr, ok := selfAddr.(addrs.ResourceInstance); ok {
+                       seen[riAddr.ContainingResource().String()] = struct{}{}
+               }
+       }
 
        depsRaw := n.References()
-       deps := make([]string, 0, len(depsRaw))
+       deps := make([]addrs.Referenceable, 0, len(depsRaw))
        for _, d := range depsRaw {
-               // Ignore any variable dependencies
-               if strings.HasPrefix(d, "var.") {
-                       continue
+               subj := d.Subject
+               if mco, isOutput := subj.(addrs.ModuleCallOutput); isOutput {
+                       // For state dependencies, we simplify outputs to just refer
+                       // to the module as a whole. It's not really clear why we do this,
+                       // but this logic is preserved from before the 0.12 rewrite of
+                       // this function.
+                       subj = mco.Call
                }
 
-               // If this has a backup ref, ignore those for now. The old state
-               // file never contained those and I'd rather store the rich types we
-               // add in the future.
-               if idx := strings.IndexRune(d, '/'); idx != -1 {
-                       d = d[:idx]
-               }
-
-               // If we're referencing ourself, then ignore it
-               found := false
-               for _, s := range self {
-                       if d == s {
-                               found = true
-                       }
-               }
-               if found {
+               k := subj.String()
+               if _, exists := seen[k]; exists {
                        continue
                }
-
-               // If this is a reference to ourself and a specific index, we keep
-               // it. For example, if this resource is "foo.bar" and the reference
-               // is "foo.bar.0" then we keep it exact. Otherwise, we strip it.
-               if strings.HasSuffix(d, ".0") && !strings.HasPrefix(d, selfPrefix) {
-                       d = d[:len(d)-2]
-               }
-
-               // This is sad. The dependencies are currently in the format of
-               // "module.foo.bar" (the full field). This strips the field off.
-               if strings.HasPrefix(d, "module.") {
-                       parts := strings.SplitN(d, ".", 3)
-                       d = strings.Join(parts[0:2], ".")
+               seen[k] = struct{}{}
+               switch tr := subj.(type) {
+               case addrs.ResourceInstance:
+                       deps = append(deps, tr)
+               case addrs.Resource:
+                       deps = append(deps, tr)
+               case addrs.ModuleCallInstance:
+                       deps = append(deps, tr)
+               default:
+                       // No other reference types are recorded in the state.
                }
-
-               deps = append(deps, d)
        }
 
+       // We'll also sort them, since that'll avoid creating changes in the
+       // serialized state that make no semantic difference.
+       sort.Slice(deps, func(i, j int) bool {
+               // Simple string-based sort because we just care about consistency,
+               // not user-friendliness.
+               return deps[i].String() < deps[j].String()
+       })
+
        return deps
 }
 
-func (n *NodeAbstractResource) SetProvider(p string) {
+func (n *NodeAbstractResource) SetProvider(p addrs.AbsProviderConfig) {
        n.ResolvedProvider = p
 }
 
 // GraphNodeProviderConsumer
-func (n *NodeAbstractResource) ProvidedBy() string {
+func (n *NodeAbstractResource) ProvidedBy() (addrs.AbsProviderConfig, bool) {
        // If we have a config we prefer that above all else
        if n.Config != nil {
-               return resourceProvider(n.Config.Type, n.Config.Provider)
+               relAddr := n.Config.ProviderConfigAddr()
+               return relAddr.Absolute(n.Path()), false
+       }
+
+       // Use our type and containing module path to guess a provider configuration address
+       return n.Addr.Resource.DefaultProviderConfig().Absolute(n.Addr.Module), false
+}
+
+// GraphNodeProviderConsumer
+func (n *NodeAbstractResourceInstance) ProvidedBy() (addrs.AbsProviderConfig, bool) {
+       // If we have a config we prefer that above all else
+       if n.Config != nil {
+               relAddr := n.Config.ProviderConfigAddr()
+               return relAddr.Absolute(n.Path()), false
        }
 
        // If we have state, then we will use the provider from there
-       if n.ResourceState != nil && n.ResourceState.Provider != "" {
-               return n.ResourceState.Provider
+       if n.ResourceState != nil {
+               // An address from the state must match exactly, since we must ensure
+               // we refresh/destroy a resource with the same provider configuration
+               // that created it.
+               return n.ResourceState.ProviderConfig, true
        }
 
-       // Use our type
-       return resourceProvider(n.Addr.Type, "")
+       // Use our type and containing module path to guess a provider configuration address
+       return n.Addr.Resource.DefaultProviderConfig().Absolute(n.Path()), false
 }
 
 // GraphNodeProvisionerConsumer
 func (n *NodeAbstractResource) ProvisionedBy() []string {
        // If we have no configuration, then we have no provisioners
-       if n.Config == nil {
+       if n.Config == nil || n.Config.Managed == nil {
                return nil
        }
 
        // Build the list of provisioners we need based on the configuration.
        // It is okay to have duplicates here.
-       result := make([]string, len(n.Config.Provisioners))
-       for i, p := range n.Config.Provisioners {
+       result := make([]string, len(n.Config.Managed.Provisioners))
+       for i, p := range n.Config.Managed.Provisioners {
                result[i] = p.Type
        }
 
        return result
 }
 
-// GraphNodeResource, GraphNodeAttachResourceState
-func (n *NodeAbstractResource) ResourceAddr() *ResourceAddress {
+// GraphNodeProvisionerConsumer
+func (n *NodeAbstractResource) AttachProvisionerSchema(name string, schema *configschema.Block) {
+       if n.ProvisionerSchemas == nil {
+               n.ProvisionerSchemas = make(map[string]*configschema.Block)
+       }
+       n.ProvisionerSchemas[name] = schema
+}
+
+// GraphNodeResource
+func (n *NodeAbstractResource) ResourceAddr() addrs.AbsResource {
        return n.Addr
 }
 
+// GraphNodeResourceInstance
+func (n *NodeAbstractResourceInstance) ResourceInstanceAddr() addrs.AbsResourceInstance {
+       return n.NodeAbstractResource.Addr.Instance(n.InstanceKey)
+}
+
 // GraphNodeAddressable, TODO: remove, used by target, should unify
 func (n *NodeAbstractResource) ResourceAddress() *ResourceAddress {
-       return n.ResourceAddr()
+       return NewLegacyResourceAddress(n.Addr)
 }
 
 // GraphNodeTargetable
-func (n *NodeAbstractResource) SetTargets(targets []ResourceAddress) {
+func (n *NodeAbstractResource) SetTargets(targets []addrs.Targetable) {
        n.Targets = targets
 }
 
 // GraphNodeAttachResourceState
-func (n *NodeAbstractResource) AttachResourceState(s *ResourceState) {
+func (n *NodeAbstractResourceInstance) AttachResourceState(s *states.Resource) {
        n.ResourceState = s
 }
 
 // GraphNodeAttachResourceConfig
-func (n *NodeAbstractResource) AttachResourceConfig(c *config.Resource) {
+func (n *NodeAbstractResource) AttachResourceConfig(c *configs.Resource) {
        n.Config = c
 }
 
+// GraphNodeAttachResourceSchema impl
+func (n *NodeAbstractResource) AttachResourceSchema(schema *configschema.Block, version uint64) {
+       n.Schema = schema
+       n.SchemaVersion = version
+}
+
 // GraphNodeDotter impl.
 func (n *NodeAbstractResource) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
        return &dag.DotNode{