diff --git a/tfexec/import.go b/tfexec/import.go index bd204ca2..c1de8ba1 100644 --- a/tfexec/import.go +++ b/tfexec/import.go @@ -31,14 +31,6 @@ type ImportOption interface { configureImport(*importConfig) } -func (opt *AddrOption) configureImport(conf *importConfig) { - conf.addr = opt.addr -} - -func (opt *IdOption) configureImport(conf *importConfig) { - conf.id = opt.id -} - func (opt *BackupOption) configureImport(conf *importConfig) { conf.backup = opt.path } @@ -75,8 +67,8 @@ func (opt *VarFileOption) configureImport(conf *importConfig) { conf.varFile = opt.path } -func (t *Terraform) Import(ctx context.Context, opts ...ImportOption) error { - importCmd := t.ImportCmd(ctx, opts...) +func (t *Terraform) Import(ctx context.Context, address, id string, opts ...ImportOption) error { + importCmd := t.ImportCmd(ctx, address, id, opts...) var errBuf strings.Builder importCmd.Stderr = &errBuf @@ -89,7 +81,7 @@ func (t *Terraform) Import(ctx context.Context, opts ...ImportOption) error { return nil } -func (tf *Terraform) ImportCmd(ctx context.Context, opts ...ImportOption) *exec.Cmd { +func (tf *Terraform) ImportCmd(ctx context.Context, address, id string, opts ...ImportOption) *exec.Cmd { c := defaultImportOptions for _, o := range opts { @@ -133,5 +125,8 @@ func (tf *Terraform) ImportCmd(ctx context.Context, opts ...ImportOption) *exec. } } + // required args, always pass + args = append(args, address, id) + return tf.buildTerraformCmd(ctx, args...) } diff --git a/tfexec/import_test.go b/tfexec/import_test.go index 9cdb81d0..0b55346e 100644 --- a/tfexec/import_test.go +++ b/tfexec/import_test.go @@ -3,32 +3,101 @@ package tfexec import ( "context" "os" + "path/filepath" "strings" "testing" ) +func TestImport(t *testing.T) { + const ( + expectedID = "asdlfjksdlfkjsdlfk" + resourceAddress = "random_string.random_string" + ) + ctx := context.Background() + + for _, tfv := range []string{ + // "0.11.14", doesn't support show JSON output, but does support import + "0.12.28", + "0.13.0-beta3", + } { + t.Run(tfv, func(t *testing.T) { + td := testTempDir(t) + defer os.RemoveAll(td) + + err := copyFiles(filepath.Join(testFixtureDir, "import"), td) + if err != nil { + t.Fatal(err) + } + + tf, err := NewTerraform(td, tfVersion(t, tfv)) + if err != nil { + t.Fatal(err) + } + + err = tf.Init(ctx, Lock(false)) + if err != nil { + t.Fatal(err) + } + + err = tf.Import(ctx, resourceAddress, expectedID, DisableBackup(), Lock(false)) + if err != nil { + t.Fatal(err) + } + + state, err := tf.StateShow(ctx) + if err != nil { + t.Fatal(err) + } + + for _, r := range state.Values.RootModule.Resources { + if r.Address != resourceAddress { + continue + } + + raw, ok := r.AttributeValues["id"] + if !ok { + t.Fatal("value not found for \"id\" attribute") + } + actual, ok := raw.(string) + if !ok { + t.Fatalf("unable to cast %T to string: %#v", raw, raw) + } + + if actual != expectedID { + t.Fatalf("expected %q, got %q", expectedID, actual) + } + + // success + return + } + + t.Fatalf("imported resource %q not found", resourceAddress) + }) + } +} + func TestImportCmd(t *testing.T) { td := testTempDir(t) defer os.RemoveAll(td) - tf, err := NewTerraform(td, tfPath) + tf, err := NewTerraform(td, tfVersion(t, "0.12.28")) if err != nil { t.Fatal(err) } // defaults - importCmd := tf.ImportCmd(context.Background()) + importCmd := tf.ImportCmd(context.Background(), "my-addr", "my-id") actual := strings.TrimPrefix(cmdString(importCmd), importCmd.Path+" ") - expected := "import -no-color -input=false -lock-timeout=0s -lock=true" + expected := "import -no-color -input=false -lock-timeout=0s -lock=true my-addr my-id" if actual != expected { t.Fatalf("expected default arguments of ImportCmd:\n%s\n actual arguments:\n%s\n", expected, actual) } // override all defaults - importCmd = tf.ImportCmd(context.Background(), + importCmd = tf.ImportCmd(context.Background(), "my-addr2", "my-id2", Backup("testbackup"), LockTimeout("200s"), State("teststate"), @@ -37,11 +106,12 @@ func TestImportCmd(t *testing.T) { Lock(false), Var("var1=foo"), Var("var2=bar"), - AllowMissingConfig(true)) + AllowMissingConfig(true), + ) actual = strings.TrimPrefix(cmdString(importCmd), importCmd.Path+" ") - expected = "import -no-color -input=false -backup=testbackup -lock-timeout=200s -state=teststate -state-out=teststateout -var-file=testvarfile -lock=false -allow-missing-config -var 'var1=foo' -var 'var2=bar'" + expected = "import -no-color -input=false -backup=testbackup -lock-timeout=200s -state=teststate -state-out=teststateout -var-file=testvarfile -lock=false -allow-missing-config -var 'var1=foo' -var 'var2=bar' my-addr2 my-id2" if actual != expected { t.Fatalf("expected arguments of ImportCmd:\n%s\n actual arguments:\n%s\n", expected, actual) diff --git a/tfexec/options.go b/tfexec/options.go index 970e92fa..035268ea 100644 --- a/tfexec/options.go +++ b/tfexec/options.go @@ -1,13 +1,5 @@ package tfexec -type AddrOption struct { - addr string -} - -func Addr(addr string) *AddrOption { - return &AddrOption{addr} -} - type AllowMissingConfigOption struct { allowMissingConfig bool } @@ -40,6 +32,11 @@ func Backup(path string) *BackupOption { return &BackupOption{path} } +// DisableBackup is a convenience method for Backup("-"), indicating backup state should be disabled. +func DisableBackup() *BackupOption { + return &BackupOption{"-"} +} + type ConfigOption struct { path string } @@ -97,14 +94,6 @@ func GetPlugins(getPlugins bool) *GetPluginsOption { return &GetPluginsOption{getPlugins} } -type IdOption struct { - id string -} - -func Id(id string) *IdOption { - return &IdOption{id} -} - type LockOption struct { lock bool } diff --git a/tfexec/testdata/import/main.tf b/tfexec/testdata/import/main.tf new file mode 100644 index 00000000..848a0d72 --- /dev/null +++ b/tfexec/testdata/import/main.tf @@ -0,0 +1,5 @@ +provider "random" { +} + +resource "random_string" "random_string" { +} \ No newline at end of file