summaryrefslogtreecommitdiff
path: root/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply.go
diff options
context:
space:
mode:
authorFlavio Castelli <fcastelli@suse.com>2017-05-03 11:37:08 +0200
committerAlvaro <alvaro.saurin@gmail.com>2017-05-03 11:40:31 +0200
commitee12004ab93e54f326896e9909ba9e6a2bd11e89 (patch)
tree1ea30d204b04425ebd1dadaf8cc991d572c7f0fb /vendor/github.com/hashicorp/terraform/terraform/node_resource_apply.go
parenta286dc5494691c2b04c48ef6695ed0c902912c0f (diff)
downloadterraform-provider-libvirt-ee12004ab93e54f326896e9909ba9e6a2bd11e89.tar
terraform-provider-libvirt-ee12004ab93e54f326896e9909ba9e6a2bd11e89.tar.gz
Vendor dependencies with vndr
This fixes issue #123
Diffstat (limited to 'vendor/github.com/hashicorp/terraform/terraform/node_resource_apply.go')
-rw-r--r--vendor/github.com/hashicorp/terraform/terraform/node_resource_apply.go357
1 files changed, 357 insertions, 0 deletions
diff --git a/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply.go b/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply.go
new file mode 100644
index 00000000..3599782b
--- /dev/null
+++ b/vendor/github.com/hashicorp/terraform/terraform/node_resource_apply.go
@@ -0,0 +1,357 @@
+package terraform
+
+import (
+ "fmt"
+
+ "github.com/hashicorp/terraform/config"
+)
+
+// NodeApplyableResource represents a resource that is "applyable":
+// it is ready to be applied and is represented by a diff.
+type NodeApplyableResource struct {
+ *NodeAbstractResource
+}
+
+// GraphNodeCreator
+func (n *NodeApplyableResource) CreateAddr() *ResourceAddress {
+ return n.NodeAbstractResource.Addr
+}
+
+// GraphNodeReferencer, overriding NodeAbstractResource
+func (n *NodeApplyableResource) References() []string {
+ result := n.NodeAbstractResource.References()
+
+ // The "apply" side of a resource generally also depends on the
+ // destruction of its dependencies as well. For example, if a LB
+ // references a set of VMs with ${vm.foo.*.id}, then we must wait for
+ // the destruction so we get the newly updated list of VMs.
+ //
+ // The exception here is CBD. When CBD is set, we don't do this since
+ // it would create a cycle. By not creating a cycle, we require two
+ // applies since the first apply the creation step will use the OLD
+ // values (pre-destroy) and the second step will update.
+ //
+ // This is how Terraform behaved with "legacy" graphs (TF <= 0.7.x).
+ // We mimic that behavior here now and can improve upon it in the future.
+ //
+ // This behavior is tested in graph_build_apply_test.go to test ordering.
+ cbd := n.Config != nil && n.Config.Lifecycle.CreateBeforeDestroy
+ if !cbd {
+ // The "apply" side of a resource always depends on the destruction
+ // of all its dependencies in addition to the creation.
+ for _, v := range result {
+ result = append(result, v+".destroy")
+ }
+ }
+
+ return result
+}
+
+// GraphNodeEvalable
+func (n *NodeApplyableResource) EvalTree() EvalNode {
+ addr := n.NodeAbstractResource.Addr
+
+ // stateId is the ID to put into the state
+ stateId := addr.stateId()
+
+ // Build the instance info. More of this will be populated during eval
+ info := &InstanceInfo{
+ Id: stateId,
+ Type: addr.Type,
+ }
+
+ // Build the resource for eval
+ resource := &Resource{
+ Name: addr.Name,
+ Type: addr.Type,
+ CountIndex: addr.Index,
+ }
+ if resource.CountIndex < 0 {
+ resource.CountIndex = 0
+ }
+
+ // Determine the dependencies for the state.
+ stateDeps := n.StateReferences()
+
+ // Eval info is different depending on what kind of resource this is
+ switch n.Config.Mode {
+ case config.ManagedResourceMode:
+ return n.evalTreeManagedResource(
+ stateId, info, resource, stateDeps,
+ )
+ case config.DataResourceMode:
+ return n.evalTreeDataResource(
+ stateId, info, resource, stateDeps)
+ default:
+ panic(fmt.Errorf("unsupported resource mode %s", n.Config.Mode))
+ }
+}
+
+func (n *NodeApplyableResource) evalTreeDataResource(
+ stateId string, info *InstanceInfo,
+ resource *Resource, stateDeps []string) EvalNode {
+ var provider ResourceProvider
+ var config *ResourceConfig
+ var diff *InstanceDiff
+ var state *InstanceState
+
+ return &EvalSequence{
+ Nodes: []EvalNode{
+ // Build the instance info
+ &EvalInstanceInfo{
+ Info: info,
+ },
+
+ // Get the saved diff for apply
+ &EvalReadDiff{
+ Name: stateId,
+ Diff: &diff,
+ },
+
+ // Stop here if we don't actually have a diff
+ &EvalIf{
+ If: func(ctx EvalContext) (bool, error) {
+ if diff == nil {
+ return true, EvalEarlyExitError{}
+ }
+
+ if diff.GetAttributesLen() == 0 {
+ return true, EvalEarlyExitError{}
+ }
+
+ return true, nil
+ },
+ Then: EvalNoop{},
+ },
+
+ // We need to re-interpolate the config here, rather than
+ // just using the diff's values directly, because we've
+ // potentially learned more variable values during the
+ // apply pass that weren't known when the diff was produced.
+ &EvalInterpolate{
+ Config: n.Config.RawConfig.Copy(),
+ Resource: resource,
+ Output: &config,
+ },
+
+ &EvalGetProvider{
+ Name: n.ProvidedBy()[0],
+ Output: &provider,
+ },
+
+ // Make a new diff with our newly-interpolated config.
+ &EvalReadDataDiff{
+ Info: info,
+ Config: &config,
+ Previous: &diff,
+ Provider: &provider,
+ Output: &diff,
+ },
+
+ &EvalReadDataApply{
+ Info: info,
+ Diff: &diff,
+ Provider: &provider,
+ Output: &state,
+ },
+
+ &EvalWriteState{
+ Name: stateId,
+ ResourceType: n.Config.Type,
+ Provider: n.Config.Provider,
+ Dependencies: stateDeps,
+ State: &state,
+ },
+
+ // Clear the diff now that we've applied it, so
+ // later nodes won't see a diff that's now a no-op.
+ &EvalWriteDiff{
+ Name: stateId,
+ Diff: nil,
+ },
+
+ &EvalUpdateStateHook{},
+ },
+ }
+}
+
+func (n *NodeApplyableResource) evalTreeManagedResource(
+ stateId string, info *InstanceInfo,
+ resource *Resource, stateDeps []string) EvalNode {
+ // Declare a bunch of variables that are used for state during
+ // evaluation. Most of this are written to by-address below.
+ var provider ResourceProvider
+ var diff, diffApply *InstanceDiff
+ var state *InstanceState
+ var resourceConfig *ResourceConfig
+ var err error
+ var createNew bool
+ var createBeforeDestroyEnabled bool
+
+ return &EvalSequence{
+ Nodes: []EvalNode{
+ // Build the instance info
+ &EvalInstanceInfo{
+ Info: info,
+ },
+
+ // Get the saved diff for apply
+ &EvalReadDiff{
+ Name: stateId,
+ Diff: &diffApply,
+ },
+
+ // We don't want to do any destroys
+ &EvalIf{
+ If: func(ctx EvalContext) (bool, error) {
+ if diffApply == nil {
+ return true, EvalEarlyExitError{}
+ }
+
+ if diffApply.GetDestroy() && diffApply.GetAttributesLen() == 0 {
+ return true, EvalEarlyExitError{}
+ }
+
+ diffApply.SetDestroy(false)
+ return true, nil
+ },
+ Then: EvalNoop{},
+ },
+
+ &EvalIf{
+ If: func(ctx EvalContext) (bool, error) {
+ destroy := false
+ if diffApply != nil {
+ destroy = diffApply.GetDestroy() || diffApply.RequiresNew()
+ }
+
+ createBeforeDestroyEnabled =
+ n.Config.Lifecycle.CreateBeforeDestroy &&
+ destroy
+
+ return createBeforeDestroyEnabled, nil
+ },
+ Then: &EvalDeposeState{
+ Name: stateId,
+ },
+ },
+
+ &EvalInterpolate{
+ Config: n.Config.RawConfig.Copy(),
+ Resource: resource,
+ Output: &resourceConfig,
+ },
+ &EvalGetProvider{
+ Name: n.ProvidedBy()[0],
+ Output: &provider,
+ },
+ &EvalReadState{
+ Name: stateId,
+ Output: &state,
+ },
+ // Re-run validation to catch any errors we missed, e.g. type
+ // mismatches on computed values.
+ &EvalValidateResource{
+ Provider: &provider,
+ Config: &resourceConfig,
+ ResourceName: n.Config.Name,
+ ResourceType: n.Config.Type,
+ ResourceMode: n.Config.Mode,
+ IgnoreWarnings: true,
+ },
+ &EvalDiff{
+ Info: info,
+ Config: &resourceConfig,
+ Resource: n.Config,
+ Provider: &provider,
+ Diff: &diffApply,
+ State: &state,
+ OutputDiff: &diffApply,
+ },
+
+ // Get the saved diff
+ &EvalReadDiff{
+ Name: stateId,
+ Diff: &diff,
+ },
+
+ // Compare the diffs
+ &EvalCompareDiff{
+ Info: info,
+ One: &diff,
+ Two: &diffApply,
+ },
+
+ &EvalGetProvider{
+ Name: n.ProvidedBy()[0],
+ Output: &provider,
+ },
+ &EvalReadState{
+ Name: stateId,
+ Output: &state,
+ },
+ // Call pre-apply hook
+ &EvalApplyPre{
+ Info: info,
+ State: &state,
+ Diff: &diffApply,
+ },
+ &EvalApply{
+ Info: info,
+ State: &state,
+ Diff: &diffApply,
+ Provider: &provider,
+ Output: &state,
+ Error: &err,
+ CreateNew: &createNew,
+ },
+ &EvalWriteState{
+ Name: stateId,
+ ResourceType: n.Config.Type,
+ Provider: n.Config.Provider,
+ Dependencies: stateDeps,
+ State: &state,
+ },
+ &EvalApplyProvisioners{
+ Info: info,
+ State: &state,
+ Resource: n.Config,
+ InterpResource: resource,
+ CreateNew: &createNew,
+ Error: &err,
+ When: config.ProvisionerWhenCreate,
+ },
+ &EvalIf{
+ If: func(ctx EvalContext) (bool, error) {
+ return createBeforeDestroyEnabled && err != nil, nil
+ },
+ Then: &EvalUndeposeState{
+ Name: stateId,
+ State: &state,
+ },
+ Else: &EvalWriteState{
+ Name: stateId,
+ ResourceType: n.Config.Type,
+ Provider: n.Config.Provider,
+ Dependencies: stateDeps,
+ State: &state,
+ },
+ },
+
+ // We clear the diff out here so that future nodes
+ // don't see a diff that is already complete. There
+ // is no longer a diff!
+ &EvalWriteDiff{
+ Name: stateId,
+ Diff: nil,
+ },
+
+ &EvalApplyPost{
+ Info: info,
+ State: &state,
+ Error: &err,
+ },
+ &EvalUpdateStateHook{},
+ },
+ }
+}