opentofu/terraform/context_import_test.go
Kristin Laemmert c8d64846ad
Mildwonkey/ps import (#24412)
* import: remove Config from ImportOpts

`Config` in ImportOpts was any provider configuration provided by the
user on the command line. This option has already been removed in favor
of only taking the provider from the configuration loaded in the current
context.

* terrafrom: add Config to ImportStateTransformer and refactor Transform
to get the resource provider FQN from the Config
2020-03-20 08:15:29 -04:00

852 lines
20 KiB
Go

package terraform
import (
"fmt"
"strings"
"testing"
"github.com/hashicorp/terraform/addrs"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/providers"
"github.com/hashicorp/terraform/states"
"github.com/zclconf/go-cty/cty"
)
func TestContextImport_basic(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
// Importing a resource which does not exist in the configuration results in an error
func TestContextImport_basic_errpr(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
_, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "test", addrs.NoKey,
),
ID: "bar",
},
},
})
if !diags.HasErrors() {
t.Fatal("should error")
}
}
func TestContextImport_countIndex(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.IntKey(0),
),
ID: "bar",
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportCountIndexStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
func TestContextImport_collision(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
State: states.BuildState(func(s *states.SyncState) {
s.SetResourceInstanceCurrent(
addrs.Resource{
Mode: addrs.ManagedResourceMode,
Type: "aws_instance",
Name: "foo",
}.Instance(addrs.NoKey).Absolute(addrs.RootModuleInstance),
&states.ResourceInstanceObjectSrc{
AttrsFlat: map[string]string{
"id": "bar",
},
Status: states.ObjectReady,
},
addrs.AbsProviderConfig{
Provider: addrs.NewLegacyProvider("aws"),
Module: addrs.RootModule,
},
)
}),
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if !diags.HasErrors() {
t.Fatalf("succeeded; want an error indicating that the resource already exists in state")
}
actual := strings.TrimSpace(state.String())
expected := `aws_instance.foo:
ID = bar
provider = provider["registry.terraform.io/-/aws"]`
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
func TestContextImport_missingType(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
},
}
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if !diags.HasErrors() {
t.Fatal("should error")
}
actual := strings.TrimSpace(state.String())
expected := "<no state>"
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
func TestContextImport_moduleProvider(t *testing.T) {
p := testProvider("aws")
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
configured := false
p.ConfigureFn = func(c *ResourceConfig) error {
configured = true
if v, ok := c.Get("foo"); !ok || v.(string) != "bar" {
return fmt.Errorf("bad")
}
return nil
}
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
if !configured {
t.Fatal("didn't configure provider")
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportStr)
if actual != expected {
t.Fatalf("expected:\n%s\n\ngot:\n%s", expected, actual)
}
}
// Importing into a module requires a provider config in that module.
func TestContextImport_providerModule(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-module")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
configured := false
p.ConfigureFn = func(c *ResourceConfig) error {
configured = true
if v, ok := c.Get("foo"); !ok || v.(string) != "bar" {
return fmt.Errorf("bad")
}
return nil
}
_, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.Child("child", addrs.NoKey).ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
if !configured {
t.Fatal("didn't configure provider")
}
}
// Test that import will interpolate provider configuration and use
// that configuration for import.
func TestContextImport_providerVarConfig(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider-vars")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
Variables: InputValues{
"foo": &InputValue{
Value: cty.StringVal("bar"),
SourceType: ValueFromCaller,
},
},
})
configured := false
p.ConfigureFn = func(c *ResourceConfig) error {
configured = true
if v, ok := c.Get("foo"); !ok || v.(string) != "bar" {
return fmt.Errorf("bad value %#v; want %#v", v, "bar")
}
return nil
}
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
if !configured {
t.Fatal("didn't configure provider")
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
// Test that provider configs can't reference resources.
func TestContextImport_providerNonVarConfig(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider-non-vars")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
_, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if !diags.HasErrors() {
t.Fatal("should error")
}
}
func TestContextImport_refresh(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
p.ReadResourceFn = nil
p.ReadResourceResponse = providers.ReadResourceResponse{
NewState: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
"foo": cty.StringVal("bar"),
}),
}
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportRefreshStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
func TestContextImport_refreshNil(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
return providers.ReadResourceResponse{
NewState: cty.NullVal(cty.DynamicPseudoType),
}
}
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if !diags.HasErrors() {
t.Fatal("should error")
}
actual := strings.TrimSpace(state.String())
expected := "<no state>"
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
func TestContextImport_module(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-module")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.Child("child", addrs.NoKey).ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportModuleStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
func TestContextImport_moduleDepth2(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-module")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.Child("child", addrs.NoKey).Child("nested", addrs.NoKey).ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "baz",
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportModuleDepth2Str)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
func TestContextImport_moduleDiff(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-module")
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
}
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.Child("child", addrs.NoKey).ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "baz",
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportModuleStr)
if actual != expected {
t.Fatalf("\nexpected: %q\ngot: %q\n", expected, actual)
}
}
func TestContextImport_multiState(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
p.GetSchemaReturn = &ProviderSchema{
Provider: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"id": {Type: cty.String, Computed: true},
},
},
"aws_instance_thing": {
Attributes: map[string]*configschema.Attribute{
"id": {Type: cty.String, Computed: true},
},
},
},
}
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
&InstanceState{
ID: "bar",
Ephemeral: EphemeralState{Type: "aws_instance_thing"},
},
}
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportMultiStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
func TestContextImport_multiStateSame(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "import-provider")
p.GetSchemaReturn = &ProviderSchema{
Provider: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
ResourceTypes: map[string]*configschema.Block{
"aws_instance": {
Attributes: map[string]*configschema.Attribute{
"id": {Type: cty.String, Computed: true},
},
},
"aws_instance_thing": {
Attributes: map[string]*configschema.Attribute{
"id": {Type: cty.String, Computed: true},
},
},
},
}
p.ImportStateReturn = []*InstanceState{
&InstanceState{
ID: "foo",
Ephemeral: EphemeralState{Type: "aws_instance"},
},
&InstanceState{
ID: "bar",
Ephemeral: EphemeralState{Type: "aws_instance_thing"},
},
&InstanceState{
ID: "qux",
Ephemeral: EphemeralState{Type: "aws_instance_thing"},
},
}
ctx := testContext2(t, &ContextOpts{
Config: m,
ProviderResolver: providers.ResolverFixed(
map[addrs.Provider]providers.Factory{
addrs.NewLegacyProvider("aws"): testProviderFuncFixed(p),
},
),
})
state, diags := ctx.Import(&ImportOpts{
Targets: []*ImportTarget{
&ImportTarget{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
actual := strings.TrimSpace(state.String())
expected := strings.TrimSpace(testImportMultiSameStr)
if actual != expected {
t.Fatalf("bad: \n%s", actual)
}
}
const testImportStr = `
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/-/aws"]
`
const testImportCountIndexStr = `
aws_instance.foo.0:
ID = foo
provider = provider["registry.terraform.io/-/aws"]
`
const testImportModuleStr = `
<no state>
module.child:
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/-/aws"]
`
const testImportModuleDepth2Str = `
<no state>
module.child.nested:
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/-/aws"]
`
const testImportModuleExistingStr = `
<no state>
module.foo:
aws_instance.bar:
ID = bar
provider = provider["registry.terraform.io/-/aws"]
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/-/aws"]
`
const testImportMultiStr = `
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/-/aws"]
aws_instance_thing.foo:
ID = bar
provider = provider["registry.terraform.io/-/aws"]
`
const testImportMultiSameStr = `
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/-/aws"]
aws_instance_thing.foo:
ID = bar
provider = provider["registry.terraform.io/-/aws"]
aws_instance_thing.foo-1:
ID = qux
provider = provider["registry.terraform.io/-/aws"]
`
const testImportRefreshStr = `
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/-/aws"]
foo = bar
`