opentofu/internal/terraform/context_import_test.go
James Bardin 041d9d3eec unknown evaluation of missing instances in import
Because import does not yet plan new instances as part of the import
process, we can end up evaluating references to resources which have no
state at all. The fallback for this situation could result in slightly
better values during import. The count and for_each values were
technically incorrect, since the length is not known to be zero, and the
single instance does have a concrete type which we can return.
2022-10-04 11:07:16 -04:00

1043 lines
26 KiB
Go

package terraform
import (
"errors"
"strings"
"testing"
"github.com/hashicorp/terraform/internal/addrs"
"github.com/hashicorp/terraform/internal/configs/configschema"
"github.com/hashicorp/terraform/internal/providers"
"github.com/hashicorp/terraform/internal/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{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*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("wrong final state\ngot:\n%s\nwant:\n%s", actual, expected)
}
}
// import 1 of count instances in the configuration
func TestContextImport_countIndex(t *testing.T) {
p := testProvider("aws")
m := testModuleInline(t, map[string]string{
"main.tf": `
provider "aws" {
foo = "bar"
}
resource "aws_instance" "foo" {
count = 2
}
`})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*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{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("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.NewDefaultProvider("aws"),
Module: addrs.RootModule,
},
)
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
state, diags := ctx.Import(m, state, &ImportOpts{
Targets: []*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/hashicorp/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.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*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.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
foo := req.Config.GetAttr("foo").AsString()
if foo != "bar" {
resp.Diagnostics = resp.Diagnostics.Append(errors.New("not bar"))
}
return
}
m := testModule(t, "import-provider")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*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 !p.ConfigureProviderCalled {
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{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
p.ConfigureProviderFn = func(req providers.ConfigureProviderRequest) (resp providers.ConfigureProviderResponse) {
foo := req.Config.GetAttr("foo").AsString()
if foo != "bar" {
resp.Diagnostics = resp.Diagnostics.Append(errors.New("not bar"))
}
return
}
_, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*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 !p.ConfigureProviderCalled {
t.Fatal("didn't configure provider")
}
}
// Test that import will interpolate provider configuration and use
// that configuration for import.
func TestContextImport_providerConfig(t *testing.T) {
testCases := map[string]struct {
module string
value string
}{
"variables": {
module: "import-provider-vars",
value: "bar",
},
"locals": {
module: "import-provider-locals",
value: "baz-bar",
},
}
for name, test := range testCases {
t.Run(name, func(t *testing.T) {
p := testProvider("aws")
m := testModule(t, test.module)
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*ImportTarget{
{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
SetVariables: InputValues{
"foo": &InputValue{
Value: cty.StringVal("bar"),
SourceType: ValueFromCaller,
},
},
})
if diags.HasErrors() {
t.Fatalf("unexpected errors: %s", diags.Err())
}
if !p.ConfigureProviderCalled {
t.Fatal("didn't configure provider")
}
if foo := p.ConfigureProviderRequest.Config.GetAttr("foo").AsString(); foo != test.value {
t.Fatalf("bad value %#v; want %#v", foo, test.value)
}
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_providerConfigResources(t *testing.T) {
p := testProvider("aws")
pTest := testProvider("test")
m := testModule(t, "import-provider-resources")
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
addrs.NewDefaultProvider("test"): testProviderFuncFixed(pTest),
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
_, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*ImportTarget{
{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "aws_instance", "foo", addrs.NoKey,
),
ID: "bar",
},
},
})
if !diags.HasErrors() {
t.Fatal("should error")
}
if got, want := diags.Err().Error(), `The configuration for provider["registry.terraform.io/hashicorp/aws"] depends on values that cannot be determined until apply.`; !strings.Contains(got, want) {
t.Errorf("wrong error\n got: %s\nwant: %s", got, want)
}
}
func TestContextImport_refresh(t *testing.T) {
p := testProvider("aws")
m := testModuleInline(t, map[string]string{
"main.tf": `
provider "aws" {
foo = "bar"
}
resource "aws_instance" "foo" {
}
// we are only importing aws_instance.foo, so these resources will be unknown
resource "aws_instance" "bar" {
}
data "aws_data_source" "bar" {
foo = aws_instance.bar.id
}
`})
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
p.ReadDataSourceResponse = &providers.ReadDataSourceResponse{
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("id"),
"foo": cty.UnknownVal(cty.String),
}),
}
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(m, states.NewState(), &ImportOpts{
Targets: []*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 d := state.ResourceInstance(mustResourceInstanceAddr("data.aws_data_source.bar")); d != nil {
t.Errorf("data.aws_data_source.bar has a status of ObjectPlanned and should not be in the state\ngot:%#v\n", d.Current)
}
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{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
p.ReadResourceFn = func(req providers.ReadResourceRequest) providers.ReadResourceResponse {
return providers.ReadResourceResponse{
NewState: cty.NullVal(cty.DynamicPseudoType),
}
}
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*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{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*ImportTarget{
{
Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).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{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*ImportTarget{
{
Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).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{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
},
}
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*ImportTarget{
{
Addr: addrs.RootModuleInstance.Child("child", addrs.IntKey(0)).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.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&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.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
{
TypeName: "aws_instance_thing",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("bar"),
}),
},
},
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*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.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&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.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "aws_instance",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("foo"),
}),
},
{
TypeName: "aws_instance_thing",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("bar"),
}),
},
{
TypeName: "aws_instance_thing",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("qux"),
}),
},
},
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
},
})
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*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)
}
}
func TestContextImport_nestedModuleImport(t *testing.T) {
p := testProvider("aws")
m := testModuleInline(t, map[string]string{
"main.tf": `
locals {
xs = toset(["foo"])
}
module "a" {
for_each = local.xs
source = "./a"
}
module "b" {
for_each = local.xs
source = "./b"
y = module.a[each.key].y
}
resource "test_resource" "test" {
}
`,
"a/main.tf": `
output "y" {
value = "bar"
}
`,
"b/main.tf": `
variable "y" {
type = string
}
resource "test_resource" "unused" {
value = var.y
// missing required, but should not error
}
`,
})
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
Provider: &configschema.Block{
Attributes: map[string]*configschema.Attribute{
"foo": {Type: cty.String, Optional: true},
},
},
ResourceTypes: map[string]*configschema.Block{
"test_resource": {
Attributes: map[string]*configschema.Attribute{
"id": {Type: cty.String, Computed: true},
"required": {Type: cty.String, Required: true},
},
},
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "test_resource",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("test"),
"required": cty.StringVal("value"),
}),
},
},
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
})
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*ImportTarget{
{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "test_resource", "test", addrs.NoKey,
),
ID: "test",
},
},
})
if diags.HasErrors() {
t.Fatal(diags.ErrWithWarnings())
}
ri := state.ResourceInstance(mustResourceInstanceAddr("test_resource.test"))
expected := `{"id":"test","required":"value"}`
if ri == nil || ri.Current == nil {
t.Fatal("no state is recorded for resource instance test_resource.test")
}
if string(ri.Current.AttrsJSON) != expected {
t.Fatalf("expected %q, got %q\n", expected, ri.Current.AttrsJSON)
}
}
// New resources in the config during import won't exist for evaluation
// purposes (until import is upgraded to using a complete plan). This means
// that references to them are unknown, but in the case of single instances, we
// can at least know the type of unknown value.
func TestContextImport_newResourceUnknown(t *testing.T) {
p := testProvider("aws")
m := testModuleInline(t, map[string]string{
"main.tf": `
resource "test_resource" "one" {
}
resource "test_resource" "two" {
count = length(flatten([test_resource.one.id]))
}
resource "test_resource" "test" {
}
`})
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
ResourceTypes: map[string]*configschema.Block{
"test_resource": {
Attributes: map[string]*configschema.Attribute{
"id": {Type: cty.String, Computed: true},
},
},
},
})
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
ImportedResources: []providers.ImportedResource{
{
TypeName: "test_resource",
State: cty.ObjectVal(map[string]cty.Value{
"id": cty.StringVal("test"),
}),
},
},
}
ctx := testContext2(t, &ContextOpts{
Providers: map[addrs.Provider]providers.Factory{
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
},
})
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
Targets: []*ImportTarget{
{
Addr: addrs.RootModuleInstance.ResourceInstance(
addrs.ManagedResourceMode, "test_resource", "test", addrs.NoKey,
),
ID: "test",
},
},
})
if diags.HasErrors() {
t.Fatal(diags.ErrWithWarnings())
}
ri := state.ResourceInstance(mustResourceInstanceAddr("test_resource.test"))
expected := `{"id":"test"}`
if ri == nil || ri.Current == nil {
t.Fatal("no state is recorded for resource instance test_resource.test")
}
if string(ri.Current.AttrsJSON) != expected {
t.Fatalf("expected %q, got %q\n", expected, ri.Current.AttrsJSON)
}
}
const testImportStr = `
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/hashicorp/aws"]
`
const testImportCountIndexStr = `
aws_instance.foo.0:
ID = foo
provider = provider["registry.terraform.io/hashicorp/aws"]
`
const testImportModuleStr = `
<no state>
module.child[0]:
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/hashicorp/aws"]
`
const testImportModuleDepth2Str = `
<no state>
module.child[0].nested:
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/hashicorp/aws"]
`
const testImportMultiStr = `
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/hashicorp/aws"]
aws_instance_thing.foo:
ID = bar
provider = provider["registry.terraform.io/hashicorp/aws"]
`
const testImportMultiSameStr = `
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/hashicorp/aws"]
aws_instance_thing.foo:
ID = bar
provider = provider["registry.terraform.io/hashicorp/aws"]
aws_instance_thing.foo-1:
ID = qux
provider = provider["registry.terraform.io/hashicorp/aws"]
`
const testImportRefreshStr = `
aws_instance.foo:
ID = foo
provider = provider["registry.terraform.io/hashicorp/aws"]
foo = bar
`