Skip to content

Commit 041d9d3

Browse files
committed
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.
1 parent c1e0b04 commit 041d9d3

File tree

3 files changed

+94
-1
lines changed

3 files changed

+94
-1
lines changed

internal/terraform/context_import_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -915,6 +915,76 @@ resource "test_resource" "unused" {
915915
}
916916
}
917917

918+
// New resources in the config during import won't exist for evaluation
919+
// purposes (until import is upgraded to using a complete plan). This means
920+
// that references to them are unknown, but in the case of single instances, we
921+
// can at least know the type of unknown value.
922+
func TestContextImport_newResourceUnknown(t *testing.T) {
923+
p := testProvider("aws")
924+
m := testModuleInline(t, map[string]string{
925+
"main.tf": `
926+
resource "test_resource" "one" {
927+
}
928+
929+
resource "test_resource" "two" {
930+
count = length(flatten([test_resource.one.id]))
931+
}
932+
933+
resource "test_resource" "test" {
934+
}
935+
`})
936+
937+
p.GetProviderSchemaResponse = getProviderSchemaResponseFromProviderSchema(&ProviderSchema{
938+
ResourceTypes: map[string]*configschema.Block{
939+
"test_resource": {
940+
Attributes: map[string]*configschema.Attribute{
941+
"id": {Type: cty.String, Computed: true},
942+
},
943+
},
944+
},
945+
})
946+
947+
p.ImportResourceStateResponse = &providers.ImportResourceStateResponse{
948+
ImportedResources: []providers.ImportedResource{
949+
{
950+
TypeName: "test_resource",
951+
State: cty.ObjectVal(map[string]cty.Value{
952+
"id": cty.StringVal("test"),
953+
}),
954+
},
955+
},
956+
}
957+
958+
ctx := testContext2(t, &ContextOpts{
959+
Providers: map[addrs.Provider]providers.Factory{
960+
addrs.NewDefaultProvider("test"): testProviderFuncFixed(p),
961+
},
962+
})
963+
964+
state, diags := ctx.Import(m, states.NewState(), &ImportOpts{
965+
Targets: []*ImportTarget{
966+
{
967+
Addr: addrs.RootModuleInstance.ResourceInstance(
968+
addrs.ManagedResourceMode, "test_resource", "test", addrs.NoKey,
969+
),
970+
ID: "test",
971+
},
972+
},
973+
})
974+
if diags.HasErrors() {
975+
t.Fatal(diags.ErrWithWarnings())
976+
}
977+
978+
ri := state.ResourceInstance(mustResourceInstanceAddr("test_resource.test"))
979+
expected := `{"id":"test"}`
980+
if ri == nil || ri.Current == nil {
981+
t.Fatal("no state is recorded for resource instance test_resource.test")
982+
}
983+
if string(ri.Current.AttrsJSON) != expected {
984+
t.Fatalf("expected %q, got %q\n", expected, ri.Current.AttrsJSON)
985+
}
986+
}
987+
918988
const testImportStr = `
919989
aws_instance.foo:
920990
ID = foo

internal/terraform/evaluate.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,29 @@ func (d *evaluationStateData) GetResource(addr addrs.Resource, rng tfdiags.Sourc
695695
return cty.DynamicVal, diags
696696
}
697697

698+
case walkImport:
699+
// Import does not yet plan resource changes, so new resources from
700+
// config are not going to be found here. Once walkImport fully
701+
// plans resources, this case should not longer be needed.
702+
// In the single instance case, we can return a typed unknown value
703+
// for the instance to better satisfy other expressions using the
704+
// value. This of course will not help if statically known
705+
// attributes are expected to be known elsewhere, but reduces the
706+
// number of problematic configs for now.
707+
// Unlike in plan and apply above we can't be sure the count or
708+
// for_each instances are empty, so we return a DynamicVal. We
709+
// don't really have a good value to return otherwise -- empty
710+
// values will fail for direct index expressions, and unknown
711+
// Lists and Maps could fail in some type unifications.
712+
switch {
713+
case config.Count != nil:
714+
return cty.DynamicVal, diags
715+
case config.ForEach != nil:
716+
return cty.DynamicVal, diags
717+
default:
718+
return cty.UnknownVal(ty), diags
719+
}
720+
698721
default:
699722
// We should only end up here during the validate walk,
700723
// since later walks should have at least partial states populated

internal/terraform/testdata/import-provider-resources/main.tf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
provider "aws" {
2-
value = "${test_instance.bar.value}"
2+
value = "${test_instance.bar.id}"
33
}
44

55
resource "aws_instance" "foo" {

0 commit comments

Comments
 (0)