terraform/internal/terraform/transform_output.go

110 lines
2.8 KiB
Go

package terraform
import (
"log"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/dag"
"github.com/hashicorp/terraform/internal/plans"
)
// OutputTransformer is a GraphTransformer that adds all the outputs
// in the configuration to the graph.
//
// This is done for the apply graph builder even if dependent nodes
// aren't changing since there is no downside: the state will be available
// even if the dependent items aren't changing.
type OutputTransformer struct {
Config *configs.Config
Changes *plans.Changes
// If this is a planned destroy, root outputs are still in the configuration
// so we need to record that we wish to remove them
Destroy bool
// Refresh-only mode means that any failing output preconditions are
// reported as warnings rather than errors
RefreshOnly bool
}
func (t *OutputTransformer) Transform(g *Graph) error {
return t.transform(g, t.Config)
}
func (t *OutputTransformer) transform(g *Graph, c *configs.Config) error {
// If we have no config then there can be no outputs.
if c == nil {
return nil
}
// Transform all the children. We must do this first because
// we can reference module outputs and they must show up in the
// reference map.
for _, cc := range c.Children {
if err := t.transform(g, cc); err != nil {
return err
}
}
// Add outputs to the graph, which will be dynamically expanded
// into NodeApplyableOutputs to reflect possible expansion
// through the presence of "count" or "for_each" on the modules.
var changes []*plans.OutputChangeSrc
if t.Changes != nil {
changes = t.Changes.Outputs
}
for _, o := range c.Module.Outputs {
addr := addrs.OutputValue{Name: o.Name}
var rootChange *plans.OutputChangeSrc
for _, c := range changes {
if c.Addr.Module.IsRoot() && c.Addr.OutputValue.Name == o.Name {
rootChange = c
}
}
destroy := t.Destroy
if rootChange != nil {
destroy = rootChange.Action == plans.Delete
}
// If this is a root output, we add the apply or destroy node directly,
// as the root modules does not expand.
var node dag.Vertex
switch {
case c.Path.IsRoot() && destroy:
node = &NodeDestroyableOutput{
Addr: addr.Absolute(addrs.RootModuleInstance),
Config: o,
}
case c.Path.IsRoot():
node = &NodeApplyableOutput{
Addr: addr.Absolute(addrs.RootModuleInstance),
Config: o,
Change: rootChange,
RefreshOnly: t.RefreshOnly,
}
default:
node = &nodeExpandOutput{
Addr: addr,
Module: c.Path,
Config: o,
Changes: changes,
Destroy: t.Destroy,
RefreshOnly: t.RefreshOnly,
}
}
log.Printf("[TRACE] OutputTransformer: adding %s as %T", o.Name, node)
g.Add(node)
}
return nil
}