Skip to content

Commit

Permalink
allow interpolation in import block id (#33618)
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 8b764f2 commit 765c25d
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 765c25d

Please sign in to comment.