Skip to content

Commit

Permalink
allow interpolation in import block id
Browse files Browse the repository at this point in the history
The import block id field can now reference variables, attributes, and module outputs, as long as the result is a known non-empty string at plan time. A null or unknown value will result in an error.

This commit slightly modifies the legacy CLI terraform import code path to construct a synthetic hcl.Expression from the import id passed in from the command line, with no intended change of functionality.
  • Loading branch information
kmoe committed Aug 2, 2023
1 parent 3bea117 commit 207b49b
Show file tree
Hide file tree
Showing 17 changed files with 457 additions and 46 deletions.
6 changes: 5 additions & 1 deletion internal/command/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

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

"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/backend"
Expand Down Expand Up @@ -236,7 +237,10 @@ func (c *ImportCommand) Run(args []string) int {
Targets: []*terraform.ImportTarget{
{
Addr: addr,
ID: args[1],

// 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()),
},
},

Expand Down
7 changes: 2 additions & 5 deletions internal/configs/import.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ package configs

import (
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/terraform/internal/addrs"
)

type Import struct {
ID string
ID hcl.Expression
To addrs.AbsResourceInstance

ProviderConfigRef *ProviderConfigRef
Expand All @@ -30,9 +29,7 @@ func decodeImportBlock(block *hcl.Block) (*Import, hcl.Diagnostics) {
diags = append(diags, moreDiags...)

if attr, exists := content.Attributes["id"]; exists {
attrDiags := gohcl.DecodeExpression(attr.Expr, nil, &imp.ID)
diags = append(diags, attrDiags...)

imp.ID = attr.Expr
}

if attr, exists := content.Attributes["to"]; exists {
Expand Down
15 changes: 10 additions & 5 deletions internal/configs/import_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ import (
"github.com/zclconf/go-cty/cty"
)

var (
typeComparer = cmp.Comparer(cty.Type.Equals)
valueComparer = cmp.Comparer(cty.Value.RawEquals)
)

func TestImportBlock_decode(t *testing.T) {
blockRange := hcl.Range{
Filename: "mock.tf",
Expand Down Expand Up @@ -52,7 +57,7 @@ func TestImportBlock_decode(t *testing.T) {
},
&Import{
To: mustAbsResourceInstanceAddr("test_instance.bar"),
ID: "foo",
ID: foo_str_expr,
DeclRange: blockRange,
},
``,
Expand All @@ -76,7 +81,7 @@ func TestImportBlock_decode(t *testing.T) {
},
&Import{
To: mustAbsResourceInstanceAddr("test_instance.bar[\"one\"]"),
ID: "foo",
ID: foo_str_expr,
DeclRange: blockRange,
},
``,
Expand All @@ -100,7 +105,7 @@ func TestImportBlock_decode(t *testing.T) {
},
&Import{
To: mustAbsResourceInstanceAddr("module.bar.test_instance.bar"),
ID: "foo",
ID: foo_str_expr,
DeclRange: blockRange,
},
``,
Expand Down Expand Up @@ -138,7 +143,7 @@ func TestImportBlock_decode(t *testing.T) {
DefRange: blockRange,
},
&Import{
ID: "foo",
ID: foo_str_expr,
DeclRange: blockRange,
},
"Missing required argument",
Expand All @@ -160,7 +165,7 @@ func TestImportBlock_decode(t *testing.T) {
t.Fatal("expected error")
}

if !cmp.Equal(got, test.want, cmp.AllowUnexported(addrs.MoveEndpoint{})) {
if !cmp.Equal(got, test.want, typeComparer, valueComparer) {
t.Fatalf("wrong result: %s", cmp.Diff(got, test.want))
}
})
Expand Down
6 changes: 4 additions & 2 deletions internal/terraform/context_import.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package terraform
import (
"log"

"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/configs"
"github.com/hashicorp/terraform/internal/states"
Expand All @@ -22,7 +23,8 @@ type ImportOpts struct {
SetVariables InputValues
}

// ImportTarget is a single resource to import.
// ImportTarget is a single resource to import,
// in legacy (CLI) import mode.
type ImportTarget struct {
// Config is the original import block for this import. This might be null
// if the import did not originate in config.
Expand All @@ -33,7 +35,7 @@ type ImportTarget struct {
Addr addrs.AbsResourceInstance

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

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

0 comments on commit 207b49b

Please sign in to comment.