mirror of
https://github.com/opentofu/opentofu.git
synced 2024-12-30 10:47:14 -06:00
42bb4a644c
Make use of the new Dependencies field in the instance state. The inter-instance dependencies will be determined from the complete reference graph, so that absolute addresses can be stored, rather than just references within a module. The Dependencies are added to the node in the same manner as state, i.e. via an "attacher" interface and transformer. This is because dependencies are calculated from the graph itself, and not from the config.
196 lines
5.6 KiB
Go
196 lines
5.6 KiB
Go
package terraform
|
|
|
|
import (
|
|
"log"
|
|
|
|
"github.com/hashicorp/terraform/states"
|
|
"github.com/hashicorp/terraform/tfdiags"
|
|
|
|
"github.com/hashicorp/terraform/addrs"
|
|
"github.com/hashicorp/terraform/configs"
|
|
"github.com/hashicorp/terraform/dag"
|
|
)
|
|
|
|
// RefreshGraphBuilder implements GraphBuilder and is responsible for building
|
|
// a graph for refreshing (updating the Terraform state).
|
|
//
|
|
// The primary difference between this graph and others:
|
|
//
|
|
// * Based on the state since it represents the only resources that
|
|
// need to be refreshed.
|
|
//
|
|
// * Ignores lifecycle options since no lifecycle events occur here. This
|
|
// simplifies the graph significantly since complex transforms such as
|
|
// create-before-destroy can be completely ignored.
|
|
//
|
|
type RefreshGraphBuilder struct {
|
|
// Config is the configuration tree.
|
|
Config *configs.Config
|
|
|
|
// State is the prior state
|
|
State *states.State
|
|
|
|
// Components is a factory for the plug-in components (providers and
|
|
// provisioners) available for use.
|
|
Components contextComponentFactory
|
|
|
|
// Schemas is the repository of schemas we will draw from to analyse
|
|
// the configuration.
|
|
Schemas *Schemas
|
|
|
|
// Targets are resources to target
|
|
Targets []addrs.Targetable
|
|
|
|
// DisableReduce, if true, will not reduce the graph. Great for testing.
|
|
DisableReduce bool
|
|
|
|
// Validate will do structural validation of the graph.
|
|
Validate bool
|
|
}
|
|
|
|
// See GraphBuilder
|
|
func (b *RefreshGraphBuilder) Build(path addrs.ModuleInstance) (*Graph, tfdiags.Diagnostics) {
|
|
return (&BasicGraphBuilder{
|
|
Steps: b.Steps(),
|
|
Validate: b.Validate,
|
|
Name: "RefreshGraphBuilder",
|
|
}).Build(path)
|
|
}
|
|
|
|
// See GraphBuilder
|
|
func (b *RefreshGraphBuilder) Steps() []GraphTransformer {
|
|
// Custom factory for creating providers.
|
|
concreteProvider := func(a *NodeAbstractProvider) dag.Vertex {
|
|
return &NodeApplyableProvider{
|
|
NodeAbstractProvider: a,
|
|
}
|
|
}
|
|
|
|
concreteManagedResource := func(a *NodeAbstractResource) dag.Vertex {
|
|
return &NodeRefreshableManagedResource{
|
|
NodeAbstractResource: a,
|
|
}
|
|
}
|
|
|
|
concreteManagedResourceInstance := func(a *NodeAbstractResourceInstance) dag.Vertex {
|
|
return &NodeRefreshableManagedResourceInstance{
|
|
NodeAbstractResourceInstance: a,
|
|
}
|
|
}
|
|
|
|
concreteResourceInstanceDeposed := func(a *NodeAbstractResourceInstance, key states.DeposedKey) dag.Vertex {
|
|
// The "Plan" node type also handles refreshing behavior.
|
|
return &NodePlanDeposedResourceInstanceObject{
|
|
NodeAbstractResourceInstance: a,
|
|
DeposedKey: key,
|
|
}
|
|
}
|
|
|
|
concreteDataResource := func(a *NodeAbstractResource) dag.Vertex {
|
|
return &NodeRefreshableDataResource{
|
|
NodeAbstractResource: a,
|
|
}
|
|
}
|
|
|
|
steps := []GraphTransformer{
|
|
// Creates all the managed resources that aren't in the state, but only if
|
|
// we have a state already. No resources in state means there's not
|
|
// anything to refresh.
|
|
func() GraphTransformer {
|
|
if b.State.HasResources() {
|
|
return &ConfigTransformer{
|
|
Concrete: concreteManagedResource,
|
|
Config: b.Config,
|
|
Unique: true,
|
|
ModeFilter: true,
|
|
Mode: addrs.ManagedResourceMode,
|
|
}
|
|
}
|
|
log.Println("[TRACE] No managed resources in state during refresh; skipping managed resource transformer")
|
|
return nil
|
|
}(),
|
|
|
|
// Creates all the data resources that aren't in the state. This will also
|
|
// add any orphans from scaling in as destroy nodes.
|
|
&ConfigTransformer{
|
|
Concrete: concreteDataResource,
|
|
Config: b.Config,
|
|
Unique: true,
|
|
ModeFilter: true,
|
|
Mode: addrs.DataResourceMode,
|
|
},
|
|
|
|
// Add any fully-orphaned resources from config (ones that have been
|
|
// removed completely, not ones that are just orphaned due to a scaled-in
|
|
// count.
|
|
&OrphanResourceInstanceTransformer{
|
|
Concrete: concreteManagedResourceInstance,
|
|
State: b.State,
|
|
Config: b.Config,
|
|
},
|
|
|
|
// We also need nodes for any deposed instance objects present in the
|
|
// state, so we can check if they still exist. (This intentionally
|
|
// skips creating nodes for _current_ objects, since ConfigTransformer
|
|
// created nodes that will do that during DynamicExpand.)
|
|
&StateTransformer{
|
|
ConcreteDeposed: concreteResourceInstanceDeposed,
|
|
State: b.State,
|
|
},
|
|
|
|
// Attach the state
|
|
&AttachStateTransformer{State: b.State},
|
|
|
|
// Attach the configuration to any resources
|
|
&AttachResourceConfigTransformer{Config: b.Config},
|
|
|
|
// Add root variables
|
|
&RootVariableTransformer{Config: b.Config},
|
|
|
|
// Add the local values
|
|
&LocalTransformer{Config: b.Config},
|
|
|
|
// Add the outputs
|
|
&OutputTransformer{Config: b.Config},
|
|
|
|
// Add module variables
|
|
&ModuleVariableTransformer{Config: b.Config},
|
|
|
|
TransformProviders(b.Components.ResourceProviders(), concreteProvider, b.Config),
|
|
|
|
// Must attach schemas before ReferenceTransformer so that we can
|
|
// analyze the configuration to find references.
|
|
&AttachSchemaTransformer{Schemas: b.Schemas},
|
|
|
|
// Connect so that the references are ready for targeting. We'll
|
|
// have to connect again later for providers and so on.
|
|
&ReferenceTransformer{},
|
|
&AttachDependenciesTransformer{},
|
|
|
|
// Target
|
|
&TargetsTransformer{
|
|
Targets: b.Targets,
|
|
|
|
// Resource nodes from config have not yet been expanded for
|
|
// "count", so we must apply targeting without indices. Exact
|
|
// targeting will be dealt with later when these resources
|
|
// DynamicExpand.
|
|
IgnoreIndices: true,
|
|
},
|
|
|
|
// Close opened plugin connections
|
|
&CloseProviderTransformer{},
|
|
|
|
// Single root
|
|
&RootTransformer{},
|
|
}
|
|
|
|
if !b.DisableReduce {
|
|
// Perform the transitive reduction to make our graph a bit
|
|
// more sane if possible (it usually is possible).
|
|
steps = append(steps, &TransitiveReductionTransformer{})
|
|
}
|
|
|
|
return steps
|
|
}
|