6 "github.com/hashicorp/terraform/addrs"
7 "github.com/hashicorp/terraform/configs"
8 "github.com/hashicorp/terraform/dag"
9 "github.com/hashicorp/terraform/lang"
12 // NodeApplyableOutput represents an output that is "applyable":
13 // it is ready to be applied.
14 type NodeApplyableOutput struct {
15 Addr addrs.AbsOutputValue
16 Config *configs.Output // Config is the output in the config
20 _ GraphNodeSubPath = (*NodeApplyableOutput)(nil)
21 _ RemovableIfNotTargeted = (*NodeApplyableOutput)(nil)
22 _ GraphNodeTargetDownstream = (*NodeApplyableOutput)(nil)
23 _ GraphNodeReferenceable = (*NodeApplyableOutput)(nil)
24 _ GraphNodeReferencer = (*NodeApplyableOutput)(nil)
25 _ GraphNodeReferenceOutside = (*NodeApplyableOutput)(nil)
26 _ GraphNodeEvalable = (*NodeApplyableOutput)(nil)
27 _ dag.GraphNodeDotter = (*NodeApplyableOutput)(nil)
30 func (n *NodeApplyableOutput) Name() string {
31 return n.Addr.String()
35 func (n *NodeApplyableOutput) Path() addrs.ModuleInstance {
39 // RemovableIfNotTargeted
40 func (n *NodeApplyableOutput) RemoveIfNotTargeted() bool {
41 // We need to add this so that this node will be removed if
42 // it isn't targeted or a dependency of a target.
46 // GraphNodeTargetDownstream
47 func (n *NodeApplyableOutput) TargetDownstream(targetedDeps, untargetedDeps *dag.Set) bool {
48 // If any of the direct dependencies of an output are targeted then
49 // the output must always be targeted as well, so its value will always
50 // be up-to-date at the completion of an apply walk.
54 func referenceOutsideForOutput(addr addrs.AbsOutputValue) (selfPath, referencePath addrs.ModuleInstance) {
56 // Output values have their expressions resolved in the context of the
57 // module where they are defined.
58 referencePath = addr.Module
60 // ...but they are referenced in the context of their calling module.
61 selfPath = addr.Module.Parent()
63 return // uses named return values
67 // GraphNodeReferenceOutside implementation
68 func (n *NodeApplyableOutput) ReferenceOutside() (selfPath, referencePath addrs.ModuleInstance) {
69 return referenceOutsideForOutput(n.Addr)
72 func referenceableAddrsForOutput(addr addrs.AbsOutputValue) []addrs.Referenceable {
73 // An output in the root module can't be referenced at all.
74 if addr.Module.IsRoot() {
78 // Otherwise, we can be referenced via a reference to our output name
79 // on the parent module's call, or via a reference to the entire call.
80 // e.g. module.foo.bar or just module.foo .
81 // Note that our ReferenceOutside method causes these addresses to be
82 // relative to the calling module, not the module where the output
84 _, outp := addr.ModuleCallOutput()
85 _, call := addr.Module.CallInstance()
86 return []addrs.Referenceable{outp, call}
90 // GraphNodeReferenceable
91 func (n *NodeApplyableOutput) ReferenceableAddrs() []addrs.Referenceable {
92 return referenceableAddrsForOutput(n.Addr)
95 func referencesForOutput(c *configs.Output) []*addrs.Reference {
96 impRefs, _ := lang.ReferencesInExpr(c.Expr)
97 expRefs, _ := lang.References(c.DependsOn)
98 l := len(impRefs) + len(expRefs)
102 refs := make([]*addrs.Reference, 0, l)
103 refs = append(refs, impRefs...)
104 refs = append(refs, expRefs...)
109 // GraphNodeReferencer
110 func (n *NodeApplyableOutput) References() []*addrs.Reference {
111 return appendResourceDestroyReferences(referencesForOutput(n.Config))
115 func (n *NodeApplyableOutput) EvalTree() EvalNode {
116 return &EvalSequence{
119 Ops: []walkOperation{walkRefresh, walkPlan, walkApply, walkValidate, walkDestroy, walkPlanDestroy},
120 Node: &EvalWriteOutput{
121 Addr: n.Addr.OutputValue,
122 Sensitive: n.Config.Sensitive,
130 // dag.GraphNodeDotter impl.
131 func (n *NodeApplyableOutput) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
134 Attrs: map[string]string{
141 // NodeDestroyableOutput represents an output that is "destroybale":
142 // its application will remove the output from the state.
143 type NodeDestroyableOutput struct {
144 Addr addrs.AbsOutputValue
145 Config *configs.Output // Config is the output in the config
149 _ GraphNodeSubPath = (*NodeDestroyableOutput)(nil)
150 _ RemovableIfNotTargeted = (*NodeDestroyableOutput)(nil)
151 _ GraphNodeTargetDownstream = (*NodeDestroyableOutput)(nil)
152 _ GraphNodeReferencer = (*NodeDestroyableOutput)(nil)
153 _ GraphNodeEvalable = (*NodeDestroyableOutput)(nil)
154 _ dag.GraphNodeDotter = (*NodeDestroyableOutput)(nil)
157 func (n *NodeDestroyableOutput) Name() string {
158 return fmt.Sprintf("%s (destroy)", n.Addr.String())
162 func (n *NodeDestroyableOutput) Path() addrs.ModuleInstance {
166 // RemovableIfNotTargeted
167 func (n *NodeDestroyableOutput) RemoveIfNotTargeted() bool {
168 // We need to add this so that this node will be removed if
169 // it isn't targeted or a dependency of a target.
173 // This will keep the destroy node in the graph if its corresponding output
174 // node is also in the destroy graph.
175 func (n *NodeDestroyableOutput) TargetDownstream(targetedDeps, untargetedDeps *dag.Set) bool {
179 // GraphNodeReferencer
180 func (n *NodeDestroyableOutput) References() []*addrs.Reference {
181 return referencesForOutput(n.Config)
185 func (n *NodeDestroyableOutput) EvalTree() EvalNode {
186 return &EvalDeleteOutput{
187 Addr: n.Addr.OutputValue,
191 // dag.GraphNodeDotter impl.
192 func (n *NodeDestroyableOutput) DotNode(name string, opts *dag.DotOpts) *dag.DotNode {
195 Attrs: map[string]string{