Skip to content

Commit

Permalink
Import ForEach: Prerequisite - Prepare codebase for dynamic addresses…
Browse files Browse the repository at this point in the history
… for `ImportTarget`s (opentofu#1207)

Signed-off-by: RLRabinowitz <[email protected]>
  • Loading branch information
RLRabinowitz authored Feb 8, 2024
1 parent f92ae16 commit 80f72ce
Show file tree
Hide file tree
Showing 15 changed files with 550 additions and 252 deletions.
11 changes: 4 additions & 7 deletions internal/command/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ import (

"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
"github.com/zclconf/go-cty/cty"

"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/backend"
"github.com/opentofu/opentofu/internal/command/arguments"
Expand Down Expand Up @@ -238,11 +236,10 @@ func (c *ImportCommand) Run(args []string) int {
newState, importDiags := lr.Core.Import(lr.Config, lr.InputState, &tofu.ImportOpts{
Targets: []*tofu.ImportTarget{
{
Addr: addr,

// In the import block, the ID can be an arbitrary hcl.Expression,
// but here it's always interpreted as a literal string.
ID: hcl.StaticExpr(cty.StringVal(args[1]), configs.SynthBody("import", nil).MissingItemRange()),
CommandLineImportTarget: &tofu.CommandLineImportTarget{
Addr: addr,
ID: args[1],
},
},
},

Expand Down
85 changes: 78 additions & 7 deletions internal/tofu/context_import.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"log"

"github.com/hashicorp/hcl/v2"

"github.com/opentofu/opentofu/internal/addrs"
"github.com/opentofu/opentofu/internal/configs"
"github.com/opentofu/opentofu/internal/states"
Expand All @@ -25,19 +26,89 @@ type ImportOpts struct {
SetVariables InputValues
}

// ImportTarget is a single resource to import,
// in legacy (CLI) import mode.
// CommandLineImportTarget is a target that we need to import, that originated from the CLI command
// It represents a single resource that we need to import.
// The resource's ID and Address are fully known when executing the command (unlike when using the `import` block)
type CommandLineImportTarget struct {
// Addr is the address for the resource instance that the new object should
// be imported into.
Addr addrs.AbsResourceInstance

// ID is the string ID of the resource to import. This is resource-specific.
ID string
}

// ImportTarget is a target that we need to import.
// It could either represent a single resource or multiple instances of the same resource, if for_each is used
// ImportTarget can be either a result of the import CLI command, or the import block
type ImportTarget struct {
// Config is the original import block for this import. This might be null
// if the import did not originate in config.
// Config is mutually-exclusive with CommandLineImportTarget
Config *configs.Import

// Addr is the address for the resource instance that the new object should
// be imported into.
Addr addrs.AbsResourceInstance
// CommandLineImportTarget is the ImportTarget information in the case of an import target origination for the
// command line. CommandLineImportTarget is mutually-exclusive with Config
*CommandLineImportTarget
}

// IsFromImportBlock checks whether the import target originates from an `import` block
// Currently, it should yield the opposite result of IsFromImportCommandLine, as those two are mutually-exclusive
func (i *ImportTarget) IsFromImportBlock() bool {
return i.Config != nil
}

// IsFromImportCommandLine checks whether the import target originates from a `tofu import` command
// Currently, it should yield the opposite result of IsFromImportBlock, as those two are mutually-exclusive
func (i *ImportTarget) IsFromImportCommandLine() bool {
return i.CommandLineImportTarget != nil
}

// StaticAddr returns the static address part of an import target
// For an ImportTarget originating from the command line, the address is already known
// However for an ImportTarget originating from an import block, the full address might not be known initially,
// and could only be evaluated down the line. Here, we create a static representation for the address.
// This is useful so that we could have information on the ImportTarget early on, such as the Module and Resource of it
func (i *ImportTarget) StaticAddr() addrs.ConfigResource {
if i.CommandLineImportTarget != nil {
return i.CommandLineImportTarget.Addr.ConfigResource()
}

// TODO change this later, once we change Config.To to not be a static address
return i.Config.To.ConfigResource()
}

// ResolvedAddr returns the resolved address of an import target, if possible. If not possible, returns an HCL diag
// For an ImportTarget originating from the command line, the address is already known
// However for an ImportTarget originating from an import block, the full address might not be known initially,
// and could only be evaluated down the line. Here, we attempt to resolve the address as though it is a static absolute
// traversal, if that's possible
func (i *ImportTarget) ResolvedAddr() (address addrs.AbsResourceInstance, evaluationDiags hcl.Diagnostics) {
if i.CommandLineImportTarget != nil {
address = i.CommandLineImportTarget.Addr
} else {
// TODO change this later, when Config.To is not a static address
address = i.Config.To
}
return
}

// ResolvedConfigImportsKey is a key for a map of ImportTargets originating from the configuration
// It is used as a one-to-one representation of an EvaluatedConfigImportTarget.
// Used in ResolvedImports to maintain a map of all resolved imports when walking the graph
type ResolvedConfigImportsKey struct {
// An address string is one-to-one with addrs.AbsResourceInstance
AddrStr string
ID string
}

// ID is the ID of the resource to import. This is resource-specific.
ID hcl.Expression
// ResolvedImports is a struct that maintains a map of all imports as they are being resolved.
// This is specifically for imports originating from configuration.
// Import targets' addresses are not fully known from the get-go, and could only be resolved later when walking
// the graph. This struct helps keep track of the resolved imports, mostly for validation that all imports
// have been addressed and point to an actual configuration
type ResolvedImports struct {
imports map[ResolvedConfigImportsKey]bool
}

// Import takes already-created external resources and brings them
Expand Down
Loading

0 comments on commit 80f72ce

Please sign in to comment.