Skip to content

Commit

Permalink
Propagate generated config filename into the Terraform graph (#33255)
Browse files Browse the repository at this point in the history
  • Loading branch information
liamcervante authored May 24, 2023
1 parent 2106b4c commit 07aa7ee
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 41 deletions.
12 changes: 6 additions & 6 deletions internal/backend/local/backend_local.go
Original file line number Diff line number Diff line change
Expand Up @@ -190,12 +190,12 @@ func (b *Local) localRunDirect(op *backend.Operation, run *backend.LocalRun, cor
}

planOpts := &terraform.PlanOpts{
Mode: op.PlanMode,
Targets: op.Targets,
ForceReplace: op.ForceReplace,
SetVariables: variables,
SkipRefresh: op.Type != backend.OperationTypeRefresh && !op.PlanRefresh,
GenerateConfig: len(op.GenerateConfigOut) > 0,
Mode: op.PlanMode,
Targets: op.Targets,
ForceReplace: op.ForceReplace,
SetVariables: variables,
SkipRefresh: op.Type != backend.OperationTypeRefresh && !op.PlanRefresh,
GenerateConfigPath: op.GenerateConfigOut,
}
run.PlanOpts = planOpts

Expand Down
10 changes: 6 additions & 4 deletions internal/terraform/context_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,9 +78,11 @@ type PlanOpts struct {
// will be added to the plan graph.
ImportTargets []*ImportTarget

// GenerateConfig tells Terraform to generate configuration for any
// ImportTargets that do not have configuration already.
GenerateConfig bool
// GenerateConfig tells Terraform where to write any generated configuration
// for any ImportTargets that do not have configuration already.
//
// If empty, then no config will be generated.
GenerateConfigPath string
}

// Plan generates an execution plan by comparing the given configuration
Expand Down Expand Up @@ -669,7 +671,7 @@ func (c *Context) planGraph(config *configs.Config, prevRunState *states.State,
preDestroyRefresh: opts.PreDestroyRefresh,
Operation: walkPlan,
ImportTargets: opts.ImportTargets,
GenerateConfig: opts.GenerateConfig,
GenerateConfigPath: opts.GenerateConfigPath,
}).Build(addrs.RootModuleInstance)
return graph, walkPlan, diags
case plans.RefreshOnlyMode:
Expand Down
16 changes: 8 additions & 8 deletions internal/terraform/context_plan2_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4598,8 +4598,8 @@ resource "test_object" "a" {
}

plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
Mode: plans.NormalMode,
GenerateConfig: true,
Mode: plans.NormalMode,
GenerateConfigPath: "generated.tf", // Actual value here doesn't matter, as long as it is not empty.
})
if diags.HasErrors() {
t.Fatalf("unexpected errors\n%s", diags.Err().Error())
Expand Down Expand Up @@ -4658,8 +4658,8 @@ import {
}

plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
Mode: plans.NormalMode,
GenerateConfig: true,
Mode: plans.NormalMode,
GenerateConfigPath: "generated.tf", // Actual value here doesn't matter, as long as it is not empty.
})
if diags.HasErrors() {
t.Fatalf("unexpected errors\n%s", diags.Err().Error())
Expand Down Expand Up @@ -4740,8 +4740,8 @@ import {
}

plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
Mode: plans.NormalMode,
GenerateConfig: true,
Mode: plans.NormalMode,
GenerateConfigPath: "generated.tf", // Actual value here doesn't matter, as long as it is not empty.
})
if diags.HasErrors() {
t.Fatalf("unexpected errors\n%s", diags.Err().Error())
Expand Down Expand Up @@ -4823,8 +4823,8 @@ import {
}

plan, diags := ctx.Plan(m, states.NewState(), &PlanOpts{
Mode: plans.NormalMode,
GenerateConfig: true,
Mode: plans.NormalMode,
GenerateConfigPath: "generated.tf", // Actual value here doesn't matter, as long as it is not empty.
})
if !diags.HasErrors() {
t.Fatal("expected error")
Expand Down
10 changes: 6 additions & 4 deletions internal/terraform/graph_builder_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,11 @@ type PlanGraphBuilder struct {
// ImportTargets are the list of resources to import.
ImportTargets []*ImportTarget

// GenerateConfig tells Terraform to generate config for any import targets
// that do not already have configuration.
GenerateConfig bool
// GenerateConfig tells Terraform where to write and generated config for
// any import targets that do not already have configuration.
//
// If empty, then config will not be generated.
GenerateConfigPath string
}

// See GraphBuilder
Expand Down Expand Up @@ -117,7 +119,7 @@ func (b *PlanGraphBuilder) Steps() []GraphTransformer {
importTargets: b.ImportTargets,

// We only want to generate config during a plan operation.
generateConfigForImportTargets: b.GenerateConfig,
generateConfigPathForImportTargets: b.GenerateConfigPath,
},

// Add dynamic values
Expand Down
5 changes: 3 additions & 2 deletions internal/terraform/node_resource_abstract.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,9 @@ type NodeAbstractResource struct {
// This resource may expand into instances which need to be imported.
importTargets []*ImportTarget

// generateConfig tells this node that it's okay for it to generate config.
generateConfig bool
// generateConfigPath tells this node which file to write generated config
// into. If empty, then config should not be generated.
generateConfigPath string
}

var (
Expand Down
2 changes: 1 addition & 1 deletion internal/terraform/node_resource_plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,7 @@ func (n *nodeExpandPlannableResource) resourceInstanceSubgraph(ctx EvalContext,
a.dependsOn = n.dependsOn
a.Dependencies = n.dependencies
a.preDestroyRefresh = n.preDestroyRefresh
a.generateConfig = n.generateConfig
a.generateConfigPath = n.generateConfigPath

m = &NodePlannableResourceInstance{
NodeAbstractResourceInstance: a,
Expand Down
9 changes: 5 additions & 4 deletions internal/terraform/node_resource_plan_instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package terraform
import (
"fmt"
"log"
"path/filepath"
"sort"

"github.com/hashicorp/hcl/v2"
Expand Down Expand Up @@ -160,7 +161,7 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)

importing := n.importTarget.ID != ""

if importing && n.Config == nil && !n.generateConfig {
if importing && n.Config == nil && len(n.generateConfigPath) == 0 {
// Then the user wrote an import target to a target that didn't exist.
if n.Addr.Module.IsRoot() {
diags = diags.Append(&hcl.Diagnostic{
Expand Down Expand Up @@ -275,7 +276,7 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext)
// If we are importing and generating a configuration, we need to
// ensure the change is written out so the configuration can be
// captured.
if n.generateConfig {
if len(n.generateConfigPath) > 0 {
// Update our return plan
change := &plans.ResourceInstanceChange{
Addr: n.Addr,
Expand Down Expand Up @@ -543,7 +544,7 @@ func (n *NodePlannableResourceInstance) importState(ctx EvalContext, addr addrs.
}

// If we're importing and generating config, generate it now.
if n.generateConfig {
if len(n.generateConfigPath) > 0 {
if n.Config != nil {
return instanceRefreshState, diags.Append(fmt.Errorf("tried to generate config for %s, but it already exists", n.Addr))
}
Expand All @@ -565,7 +566,7 @@ func (n *NodePlannableResourceInstance) importState(ctx EvalContext, addr addrs.
n.generatedConfigHCL = genconfig.WrapResourceContents(n.Addr, generatedHCLAttributes)

// parse the "file" as HCL to get the hcl.Body
synthHCLFile, hclDiags := hclsyntax.ParseConfig([]byte(generatedHCLAttributes), "generated_resources.tf", hcl.Pos{Byte: 0, Line: 1, Column: 1})
synthHCLFile, hclDiags := hclsyntax.ParseConfig([]byte(generatedHCLAttributes), filepath.Base(n.generateConfigPath), hcl.Pos{Byte: 0, Line: 1, Column: 1})
diags = diags.Append(hclDiags)
if hclDiags.HasErrors() {
return instanceRefreshState, diags
Expand Down
24 changes: 12 additions & 12 deletions internal/terraform/transform_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ type ConfigTransformer struct {
// imported for them.
importTargets []*ImportTarget

// generateConfigForImportTargets tells the graph to generate config for any
// import targets that are not contained within config.
// generateConfigPathForImportTargets tells the graph where to write any
// generated config for import targets that are not contained within config.
//
// If this is false and an import target has no config, the graph will
// If this is empty and an import target has no config, the graph will
// simply import the state for the target and any follow-up operations will
// try to delete the imported resource unless the config is updated
// manually.
generateConfigForImportTargets bool
generateConfigPathForImportTargets string
}

func (t *ConfigTransformer) Transform(g *Graph) error {
Expand All @@ -60,31 +60,31 @@ func (t *ConfigTransformer) Transform(g *Graph) error {
}

// Start the transformation process
return t.transform(g, t.Config, t.generateConfigForImportTargets)
return t.transform(g, t.Config, t.generateConfigPathForImportTargets)
}

func (t *ConfigTransformer) transform(g *Graph, config *configs.Config, generateConfig bool) error {
func (t *ConfigTransformer) transform(g *Graph, config *configs.Config, generateConfigPath string) error {
// If no config, do nothing
if config == nil {
return nil
}

// Add our resources
if err := t.transformSingle(g, config, generateConfig); err != nil {
if err := t.transformSingle(g, config, generateConfigPath); err != nil {
return err
}

// Transform all the children without generating config.
for _, c := range config.Children {
if err := t.transform(g, c, false); err != nil {
if err := t.transform(g, c, ""); err != nil {
return err
}
}

return nil
}

func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config, generateConfig bool) error {
func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config, generateConfigPath string) error {
path := config.Path
module := config.Module
log.Printf("[TRACE] ConfigTransformer: Starting for path: %v", path)
Expand Down Expand Up @@ -171,9 +171,9 @@ func (t *ConfigTransformer) transformSingle(g *Graph, config *configs.Config, ge
// this is something that could be done during the Validate process.
for _, i := range importTargets {
abstract := &NodeAbstractResource{
Addr: i.Addr.ConfigResource(),
importTargets: []*ImportTarget{i},
generateConfig: generateConfig,
Addr: i.Addr.ConfigResource(),
importTargets: []*ImportTarget{i},
generateConfigPath: generateConfigPath,
}

var node dag.Vertex = abstract
Expand Down

0 comments on commit 07aa7ee

Please sign in to comment.