From 96da5e9f465f23c23626d6fae0255086b1df59b9 Mon Sep 17 00:00:00 2001 From: Liam Cervante Date: Wed, 12 Jun 2024 12:59:28 +0200 Subject: [PATCH] deferred actinos: add support for unknown ids in import blocks (#35300) --- internal/plans/changes.go | 26 ++-- internal/plans/changes_src.go | 27 +++- internal/plans/planfile/tfplan.go | 6 +- internal/plans/planproto/planfile.pb.go | 132 ++++++++++-------- internal/plans/planproto/planfile.proto | 3 + .../terraform/context_apply_deferred_test.go | 40 ++++++ internal/terraform/eval_import.go | 29 ++-- .../terraform/node_resource_partial_plan.go | 12 +- internal/terraform/node_resource_plan.go | 42 +++--- .../terraform/node_resource_plan_instance.go | 22 ++- 10 files changed, 215 insertions(+), 124 deletions(-) diff --git a/internal/plans/changes.go b/internal/plans/changes.go index 3864d7fa80..7c43da9729 100644 --- a/internal/plans/changes.go +++ b/internal/plans/changes.go @@ -510,8 +510,23 @@ func (oc *OutputChange) Encode() (*OutputChangeSrc, error) { // The fields in here are subject to change, so downstream consumers should be // prepared for backwards compatibility in case the contents changes. type Importing struct { - // ID is the original ID of the imported resource. - ID string + ID cty.Value +} + +// Encode converts the Importing object into a form suitable for serialization +// to a plan file. +func (i *Importing) Encode() *ImportingSrc { + if i == nil { + return nil + } + if i.ID.IsKnown() { + return &ImportingSrc{ + ID: i.ID.AsString(), + } + } + return &ImportingSrc{ + Unknown: true, + } } // Change describes a single change with a given action. @@ -593,18 +608,13 @@ func (c *Change) Encode(ty cty.Type) (*ChangeSrc, error) { return nil, err } - var importing *ImportingSrc - if c.Importing != nil { - importing = &ImportingSrc{ID: c.Importing.ID} - } - return &ChangeSrc{ Action: c.Action, Before: beforeDV, After: afterDV, BeforeSensitivePaths: sensitiveAttrsBefore, AfterSensitivePaths: sensitiveAttrsAfter, - Importing: importing, + Importing: c.Importing.Encode(), GeneratedConfig: c.GeneratedConfig, }, nil } diff --git a/internal/plans/changes_src.go b/internal/plans/changes_src.go index 90670d3b39..1c3f697076 100644 --- a/internal/plans/changes_src.go +++ b/internal/plans/changes_src.go @@ -207,6 +207,26 @@ func (ocs *OutputChangeSrc) DeepCopy() *OutputChangeSrc { type ImportingSrc struct { // ID is the original ID of the imported resource. ID string + + // Unknown is true if the ID was unknown when we tried to import it. This + // should only be true if the overall change is embedded within a deferred + // action. + Unknown bool +} + +// Decode unmarshals the raw representation of the importing action. +func (is *ImportingSrc) Decode() *Importing { + if is == nil { + return nil + } + if is.Unknown { + return &Importing{ + ID: cty.UnknownVal(cty.String), + } + } + return &Importing{ + ID: cty.StringVal(is.ID), + } } // ChangeSrc is a not-yet-decoded Change. @@ -266,16 +286,11 @@ func (cs *ChangeSrc) Decode(ty cty.Type) (*Change, error) { } } - var importing *Importing - if cs.Importing != nil { - importing = &Importing{ID: cs.Importing.ID} - } - return &Change{ Action: cs.Action, Before: marks.MarkPaths(before, marks.Sensitive, cs.BeforeSensitivePaths), After: marks.MarkPaths(after, marks.Sensitive, cs.AfterSensitivePaths), - Importing: importing, + Importing: cs.Importing.Decode(), GeneratedConfig: cs.GeneratedConfig, }, nil } diff --git a/internal/plans/planfile/tfplan.go b/internal/plans/planfile/tfplan.go index 01be61b507..ed7a723ba3 100644 --- a/internal/plans/planfile/tfplan.go +++ b/internal/plans/planfile/tfplan.go @@ -417,7 +417,8 @@ func changeFromTfplan(rawChange *planproto.Change) (*plans.ChangeSrc, error) { if rawChange.Importing != nil { ret.Importing = &plans.ImportingSrc{ - ID: rawChange.Importing.Id, + ID: rawChange.Importing.Id, + Unknown: rawChange.Importing.Unknown, } } ret.GeneratedConfig = rawChange.GeneratedConfig @@ -812,7 +813,8 @@ func changeToTfplan(change *plans.ChangeSrc) (*planproto.Change, error) { if change.Importing != nil { ret.Importing = &planproto.Importing{ - Id: change.Importing.ID, + Id: change.Importing.ID, + Unknown: change.Importing.Unknown, } } diff --git a/internal/plans/planproto/planfile.pb.go b/internal/plans/planproto/planfile.pb.go index c7e1dda063..8f9844b691 100644 --- a/internal/plans/planproto/planfile.pb.go +++ b/internal/plans/planproto/planfile.pb.go @@ -1347,6 +1347,8 @@ type Importing struct { // The original ID of the resource. Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + // unknown is true if the original ID of the resource is unknown. + Unknown bool `protobuf:"varint,2,opt,name=unknown,proto3" json:"unknown,omitempty"` } func (x *Importing) Reset() { @@ -1388,6 +1390,13 @@ func (x *Importing) GetId() string { return "" } +func (x *Importing) GetUnknown() bool { + if x != nil { + return x.Unknown + } + return false +} + // Deferred contains all the metadata about a the deferral of a resource // instance change. type Deferred struct { @@ -1829,68 +1838,69 @@ var file_planfile_proto_rawDesc = []byte{ 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44, 0x79, 0x6e, 0x61, 0x6d, 0x69, 0x63, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x48, 0x00, 0x52, 0x0a, 0x65, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x4b, 0x65, 0x79, 0x42, 0x0a, 0x0a, 0x08, 0x73, 0x65, 0x6c, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x1b, 0x0a, 0x09, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x22, 0x35, 0x0a, 0x09, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x69, 0x6e, 0x67, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, - 0x69, 0x64, 0x22, 0x3a, 0x0a, 0x08, 0x44, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x12, 0x2e, - 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, - 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, 0x6e, 0x2e, 0x44, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, - 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0x31, - 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, - 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x01, 0x12, - 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x46, 0x52, 0x45, 0x53, 0x48, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, - 0x02, 0x2a, 0x94, 0x01, 0x0a, 0x06, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, - 0x4e, 0x4f, 0x4f, 0x50, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, - 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x52, 0x45, 0x41, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, - 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, - 0x54, 0x45, 0x10, 0x05, 0x12, 0x16, 0x0a, 0x12, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x54, - 0x48, 0x45, 0x4e, 0x5f, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, - 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x44, 0x45, 0x4c, 0x45, - 0x54, 0x45, 0x10, 0x07, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x4f, 0x52, 0x47, 0x45, 0x54, 0x10, 0x08, - 0x12, 0x16, 0x0a, 0x12, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, - 0x46, 0x4f, 0x52, 0x47, 0x45, 0x54, 0x10, 0x09, 0x2a, 0xc8, 0x03, 0x0a, 0x1c, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, - 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, - 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x54, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x01, - 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, 0x5f, 0x52, - 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45, 0x50, 0x4c, - 0x41, 0x43, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x4e, - 0x4f, 0x54, 0x5f, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x25, 0x0a, 0x21, 0x44, - 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, - 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, - 0x10, 0x04, 0x12, 0x23, 0x0a, 0x1f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, - 0x41, 0x55, 0x53, 0x45, 0x5f, 0x57, 0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x50, 0x45, 0x54, - 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x44, 0x45, 0x4c, 0x45, 0x54, - 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, - 0x49, 0x4e, 0x44, 0x45, 0x58, 0x10, 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x45, 0x4c, 0x45, 0x54, - 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x45, 0x41, 0x43, 0x48, 0x5f, 0x4b, - 0x45, 0x59, 0x10, 0x07, 0x12, 0x1c, 0x0a, 0x18, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, - 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x44, 0x55, 0x4c, 0x45, - 0x10, 0x08, 0x12, 0x17, 0x0a, 0x13, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, - 0x5f, 0x54, 0x52, 0x49, 0x47, 0x47, 0x45, 0x52, 0x53, 0x10, 0x09, 0x12, 0x1f, 0x0a, 0x1b, 0x52, - 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, - 0x49, 0x47, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x0a, 0x12, 0x23, 0x0a, 0x1f, - 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x44, 0x45, 0x50, - 0x45, 0x4e, 0x44, 0x45, 0x4e, 0x43, 0x59, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, - 0x0b, 0x12, 0x1d, 0x0a, 0x19, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, - 0x45, 0x5f, 0x43, 0x48, 0x45, 0x43, 0x4b, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x10, 0x0d, - 0x12, 0x21, 0x0a, 0x1d, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, - 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, - 0x54, 0x10, 0x0c, 0x2a, 0x9b, 0x01, 0x0a, 0x0e, 0x44, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, - 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, - 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, 0x16, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4e, 0x43, 0x45, 0x5f, - 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x01, 0x12, - 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, - 0x49, 0x47, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, - 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, 0x45, 0x52, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, - 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x42, 0x53, - 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x52, 0x45, 0x52, 0x45, 0x51, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, - 0x44, 0x45, 0x46, 0x45, 0x52, 0x52, 0x45, 0x44, 0x5f, 0x50, 0x52, 0x45, 0x52, 0x45, 0x51, 0x10, - 0x05, 0x42, 0x39, 0x5a, 0x37, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, 0x6f, 0x72, 0x70, 0x2f, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, - 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x61, - 0x6e, 0x73, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x69, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x08, 0x52, 0x07, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x22, 0x3a, 0x0a, 0x08, + 0x44, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x12, 0x2e, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x73, + 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x16, 0x2e, 0x74, 0x66, 0x70, 0x6c, 0x61, + 0x6e, 0x2e, 0x44, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x52, 0x06, 0x72, 0x65, 0x61, 0x73, 0x6f, 0x6e, 0x2a, 0x31, 0x0a, 0x04, 0x4d, 0x6f, 0x64, 0x65, + 0x12, 0x0a, 0x0a, 0x06, 0x4e, 0x4f, 0x52, 0x4d, 0x41, 0x4c, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, + 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x01, 0x12, 0x10, 0x0a, 0x0c, 0x52, 0x45, 0x46, + 0x52, 0x45, 0x53, 0x48, 0x5f, 0x4f, 0x4e, 0x4c, 0x59, 0x10, 0x02, 0x2a, 0x94, 0x01, 0x0a, 0x06, + 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4f, 0x50, 0x10, 0x00, + 0x12, 0x0a, 0x0a, 0x06, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, + 0x52, 0x45, 0x41, 0x44, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, + 0x10, 0x03, 0x12, 0x0a, 0x0a, 0x06, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x05, 0x12, 0x16, + 0x0a, 0x12, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x43, 0x52, + 0x45, 0x41, 0x54, 0x45, 0x10, 0x06, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, + 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x10, 0x07, 0x12, 0x0a, + 0x0a, 0x06, 0x46, 0x4f, 0x52, 0x47, 0x45, 0x54, 0x10, 0x08, 0x12, 0x16, 0x0a, 0x12, 0x43, 0x52, + 0x45, 0x41, 0x54, 0x45, 0x5f, 0x54, 0x48, 0x45, 0x4e, 0x5f, 0x46, 0x4f, 0x52, 0x47, 0x45, 0x54, + 0x10, 0x09, 0x2a, 0xc8, 0x03, 0x0a, 0x1c, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x49, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x41, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x61, + 0x73, 0x6f, 0x6e, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x4f, 0x4e, 0x45, 0x10, 0x00, 0x12, 0x1b, 0x0a, + 0x17, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, + 0x5f, 0x54, 0x41, 0x49, 0x4e, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x16, 0x0a, 0x12, 0x52, 0x45, + 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, 0x5f, 0x52, 0x45, 0x51, 0x55, 0x45, 0x53, 0x54, + 0x10, 0x02, 0x12, 0x21, 0x0a, 0x1d, 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x45, + 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x41, 0x4e, 0x4e, 0x4f, 0x54, 0x5f, 0x55, 0x50, 0x44, + 0x41, 0x54, 0x45, 0x10, 0x03, 0x12, 0x25, 0x0a, 0x21, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, + 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, 0x52, 0x45, 0x53, 0x4f, 0x55, + 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x10, 0x04, 0x12, 0x23, 0x0a, 0x1f, + 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x57, + 0x52, 0x4f, 0x4e, 0x47, 0x5f, 0x52, 0x45, 0x50, 0x45, 0x54, 0x49, 0x54, 0x49, 0x4f, 0x4e, 0x10, + 0x05, 0x12, 0x1e, 0x0a, 0x1a, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, + 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, 0x49, 0x4e, 0x44, 0x45, 0x58, 0x10, + 0x06, 0x12, 0x1b, 0x0a, 0x17, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, + 0x55, 0x53, 0x45, 0x5f, 0x45, 0x41, 0x43, 0x48, 0x5f, 0x4b, 0x45, 0x59, 0x10, 0x07, 0x12, 0x1c, + 0x0a, 0x18, 0x44, 0x45, 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, + 0x5f, 0x4e, 0x4f, 0x5f, 0x4d, 0x4f, 0x44, 0x55, 0x4c, 0x45, 0x10, 0x08, 0x12, 0x17, 0x0a, 0x13, + 0x52, 0x45, 0x50, 0x4c, 0x41, 0x43, 0x45, 0x5f, 0x42, 0x59, 0x5f, 0x54, 0x52, 0x49, 0x47, 0x47, + 0x45, 0x52, 0x53, 0x10, 0x09, 0x12, 0x1f, 0x0a, 0x1b, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, + 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x0a, 0x12, 0x23, 0x0a, 0x1f, 0x52, 0x45, 0x41, 0x44, 0x5f, 0x42, + 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x44, 0x45, 0x50, 0x45, 0x4e, 0x44, 0x45, 0x4e, 0x43, + 0x59, 0x5f, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x0b, 0x12, 0x1d, 0x0a, 0x19, 0x52, + 0x45, 0x41, 0x44, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x43, 0x48, 0x45, 0x43, + 0x4b, 0x5f, 0x4e, 0x45, 0x53, 0x54, 0x45, 0x44, 0x10, 0x0d, 0x12, 0x21, 0x0a, 0x1d, 0x44, 0x45, + 0x4c, 0x45, 0x54, 0x45, 0x5f, 0x42, 0x45, 0x43, 0x41, 0x55, 0x53, 0x45, 0x5f, 0x4e, 0x4f, 0x5f, + 0x4d, 0x4f, 0x56, 0x45, 0x5f, 0x54, 0x41, 0x52, 0x47, 0x45, 0x54, 0x10, 0x0c, 0x2a, 0x9b, 0x01, + 0x0a, 0x0e, 0x44, 0x65, 0x66, 0x65, 0x72, 0x72, 0x65, 0x64, 0x52, 0x65, 0x61, 0x73, 0x6f, 0x6e, + 0x12, 0x0b, 0x0a, 0x07, 0x49, 0x4e, 0x56, 0x41, 0x4c, 0x49, 0x44, 0x10, 0x00, 0x12, 0x1a, 0x0a, + 0x16, 0x49, 0x4e, 0x53, 0x54, 0x41, 0x4e, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x55, 0x4e, 0x54, 0x5f, + 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x01, 0x12, 0x1b, 0x0a, 0x17, 0x52, 0x45, 0x53, + 0x4f, 0x55, 0x52, 0x43, 0x45, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x55, 0x4e, 0x4b, + 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x02, 0x12, 0x1b, 0x0a, 0x17, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x44, + 0x45, 0x52, 0x5f, 0x43, 0x4f, 0x4e, 0x46, 0x49, 0x47, 0x5f, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, + 0x4e, 0x10, 0x03, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x42, 0x53, 0x45, 0x4e, 0x54, 0x5f, 0x50, 0x52, + 0x45, 0x52, 0x45, 0x51, 0x10, 0x04, 0x12, 0x13, 0x0a, 0x0f, 0x44, 0x45, 0x46, 0x45, 0x52, 0x52, + 0x45, 0x44, 0x5f, 0x50, 0x52, 0x45, 0x52, 0x45, 0x51, 0x10, 0x05, 0x42, 0x39, 0x5a, 0x37, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x68, 0x61, 0x73, 0x68, 0x69, 0x63, + 0x6f, 0x72, 0x70, 0x2f, 0x74, 0x65, 0x72, 0x72, 0x61, 0x66, 0x6f, 0x72, 0x6d, 0x2f, 0x69, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x2f, 0x70, 0x6c, 0x61, + 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/internal/plans/planproto/planfile.proto b/internal/plans/planproto/planfile.proto index c117bc14de..56084bf952 100644 --- a/internal/plans/planproto/planfile.proto +++ b/internal/plans/planproto/planfile.proto @@ -374,6 +374,9 @@ message Path { message Importing { // The original ID of the resource. string id = 1; + + // unknown is true if the original ID of the resource is unknown. + bool unknown = 2; } // DeferredReason describes the reason why a resource instance change was diff --git a/internal/terraform/context_apply_deferred_test.go b/internal/terraform/context_apply_deferred_test.go index 16cb6c1bb7..1093d8a6b0 100644 --- a/internal/terraform/context_apply_deferred_test.go +++ b/internal/terraform/context_apply_deferred_test.go @@ -2581,6 +2581,45 @@ resource "test" "a" { }, }, } + + unknownImportId = deferredActionsTest{ + configs: map[string]string{ + "main.tf": ` +variable "id" { + type = string +} + +resource "test" "a" { + name = "a" +} + +import { + id = var.id + to = test.a +} +`, + }, + stages: []deferredActionsTestStage{ + { + inputs: map[string]cty.Value{ + "id": cty.UnknownVal(cty.String), + }, + wantPlanned: map[string]cty.Value{ + "a": cty.ObjectVal(map[string]cty.Value{ + "name": cty.StringVal("a"), + "upstream_names": cty.NullVal(cty.Set(cty.String)), + "output": cty.UnknownVal(cty.String), + }), + }, + wantActions: make(map[string]plans.Action), + wantDeferred: map[string]ExpectedDeferred{ + "test.a": {Reason: providers.DeferredReasonResourceConfigUnknown, Action: plans.Create}, + }, + wantApplied: make(map[string]cty.Value), + wantOutputs: make(map[string]cty.Value), + }, + }, + } ) func TestContextApply_deferredActions(t *testing.T) { @@ -2615,6 +2654,7 @@ func TestContextApply_deferredActions(t *testing.T) { "plan_destroy_resource_change_but_forbidden": planDestroyResourceChangeButForbidden, "module_deferred_for_each_value": moduleDeferredForEachValue, "module_inner_resource_instance_deferred": moduleInnerResourceInstanceDeferred, + "unknown_import_id": unknownImportId, } for name, test := range tests { diff --git a/internal/terraform/eval_import.go b/internal/terraform/eval_import.go index 518eaccf06..ff7e9a8112 100644 --- a/internal/terraform/eval_import.go +++ b/internal/terraform/eval_import.go @@ -8,15 +8,15 @@ 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/instances" "github.com/hashicorp/terraform/internal/lang/marks" "github.com/hashicorp/terraform/internal/tfdiags" - "github.com/zclconf/go-cty/cty" - "github.com/zclconf/go-cty/cty/gocty" ) -func evaluateImportIdExpression(expr hcl.Expression, ctx EvalContext, keyData instances.RepetitionData) (string, tfdiags.Diagnostics) { +func evaluateImportIdExpression(expr hcl.Expression, ctx EvalContext, keyData instances.RepetitionData, allowUnknown bool) (cty.Value, tfdiags.Diagnostics) { var diags tfdiags.Diagnostics // import blocks only exist in the root module, and must be evaluated in @@ -24,7 +24,7 @@ func evaluateImportIdExpression(expr hcl.Expression, ctx EvalContext, keyData in ctx = evalContextForModuleInstance(ctx, addrs.RootModuleInstance) if expr == nil { - return "", diags.Append(&hcl.Diagnostic{ + return cty.NilVal, diags.Append(&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Invalid import id argument", Detail: "The import ID cannot be null.", @@ -37,16 +37,15 @@ func evaluateImportIdExpression(expr hcl.Expression, ctx EvalContext, keyData in diags = diags.Append(evalDiags) if importIdVal.IsNull() { - return "", diags.Append(&hcl.Diagnostic{ + return cty.NilVal, diags.Append(&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Invalid import id argument", Detail: "The import ID cannot be null.", Subject: expr.Range().Ptr(), }) } - - if !importIdVal.IsKnown() { - return "", diags.Append(&hcl.Diagnostic{ + if !allowUnknown && !importIdVal.IsKnown() { + return cty.NilVal, diags.Append(&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Invalid import id argument", Detail: `The import block "id" argument depends on resource attributes that cannot be determined until apply, so Terraform cannot plan to import this resource.`, // FIXME and what should I do about that? @@ -61,19 +60,17 @@ func evaluateImportIdExpression(expr hcl.Expression, ctx EvalContext, keyData in // sent to the provider. importIdVal, _ = importIdVal.Unmark() - var importId string - err := gocty.FromCtyValue(importIdVal, &importId) - if err != nil { - return "", diags.Append(&hcl.Diagnostic{ + if importIdVal.Type() != cty.String { + return cty.NilVal, diags.Append(&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Invalid import id argument", - Detail: fmt.Sprintf("The import ID value is unsuitable: %s.", err), + Detail: "The import ID value is unsuitable: not a string.", Subject: expr.Range().Ptr(), }) } - if importId == "" { - return "", diags.Append(&hcl.Diagnostic{ + if importIdVal.IsKnown() && importIdVal.AsString() == "" { + return cty.NilVal, diags.Append(&hcl.Diagnostic{ Severity: hcl.DiagError, Summary: "Invalid import id argument", Detail: "The import ID value evaluates to an empty string, please provide a non-empty value.", @@ -81,7 +78,7 @@ func evaluateImportIdExpression(expr hcl.Expression, ctx EvalContext, keyData in }) } - return importId, diags + return importIdVal, diags } func evalImportToExpression(expr hcl.Expression, keyData instances.RepetitionData) (addrs.AbsResourceInstance, tfdiags.Diagnostics) { diff --git a/internal/terraform/node_resource_partial_plan.go b/internal/terraform/node_resource_partial_plan.go index 235ca112f4..fa24db034b 100644 --- a/internal/terraform/node_resource_partial_plan.go +++ b/internal/terraform/node_resource_partial_plan.go @@ -6,6 +6,8 @@ package terraform import ( "fmt" + "github.com/zclconf/go-cty/cty" + "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/tfdiags" ) @@ -25,7 +27,7 @@ import ( // would be nice to integrate this logic a little better with the main // DynamicExpand logic, but it's separate for now to minimize the risk of // stacks-specific behavior impacting configurations that are not opted into it. -func (n *nodeExpandPlannableResource) dynamicExpandPartial(ctx EvalContext, knownModules []addrs.ModuleInstance, partialModules addrs.Set[addrs.PartialExpandedModule], imports addrs.Map[addrs.AbsResourceInstance, string]) (*Graph, tfdiags.Diagnostics) { +func (n *nodeExpandPlannableResource) dynamicExpandPartial(ctx EvalContext, knownModules []addrs.ModuleInstance, partialModules addrs.Set[addrs.PartialExpandedModule], imports addrs.Map[addrs.AbsResourceInstance, cty.Value]) (*Graph, tfdiags.Diagnostics) { var g Graph var diags tfdiags.Diagnostics @@ -81,7 +83,7 @@ func (n *nodeExpandPlannableResource) dynamicExpandPartial(ctx EvalContext, know // Then each of the instances is a "maybe orphan" // instance, and we need to add a node for that. maybeOrphanResources.Add(res.Addr.Instance(key)) - g.Add(n.concreteResource(addrs.MakeMap[addrs.AbsResourceInstance, string](), true)(NewNodeAbstractResourceInstance(res.Addr.Instance(key)))) + g.Add(n.concreteResource(addrs.MakeMap[addrs.AbsResourceInstance, cty.Value](), true)(NewNodeAbstractResourceInstance(res.Addr.Instance(key)))) } @@ -163,7 +165,7 @@ ImportValidation: return &g, diags } -func (n *nodeExpandPlannableResource) expandKnownModule(globalCtx EvalContext, resAddr addrs.AbsResource, imports addrs.Map[addrs.AbsResourceInstance, string], g *Graph) (addrs.Set[addrs.AbsResourceInstance], addrs.Set[addrs.PartialExpandedResource], addrs.Set[addrs.AbsResourceInstance], tfdiags.Diagnostics) { +func (n *nodeExpandPlannableResource) expandKnownModule(globalCtx EvalContext, resAddr addrs.AbsResource, imports addrs.Map[addrs.AbsResourceInstance, cty.Value], g *Graph) (addrs.Set[addrs.AbsResourceInstance], addrs.Set[addrs.PartialExpandedResource], addrs.Set[addrs.AbsResourceInstance], tfdiags.Diagnostics) { var diags tfdiags.Diagnostics moduleCtx := evalContextForModuleInstance(globalCtx, resAddr.Module) @@ -208,7 +210,7 @@ func (n *nodeExpandPlannableResource) expandKnownModule(globalCtx EvalContext, r return knownResources, partialResources, maybeOrphanResources, diags } -func (n *nodeExpandPlannableResource) knownModuleSubgraph(ctx EvalContext, addr addrs.AbsResource, knownInstKeys []addrs.InstanceKey, haveUnknownKeys bool, imports addrs.Map[addrs.AbsResourceInstance, string]) (*Graph, addrs.Set[addrs.AbsResourceInstance], tfdiags.Diagnostics) { +func (n *nodeExpandPlannableResource) knownModuleSubgraph(ctx EvalContext, addr addrs.AbsResource, knownInstKeys []addrs.InstanceKey, haveUnknownKeys bool, imports addrs.Map[addrs.AbsResourceInstance, cty.Value]) (*Graph, addrs.Set[addrs.AbsResourceInstance], tfdiags.Diagnostics) { var diags tfdiags.Diagnostics if n.Config == nil && n.generateConfigPath != "" && imports.Len() == 0 { @@ -272,7 +274,7 @@ func (n *nodeExpandPlannableResource) knownModuleSubgraph(ctx EvalContext, addr // to a known instance but we have unknown keys so we don't // know for sure that it's been deleted. maybeOrphans.Add(addr.Instance(key)) - graph.Add(n.concreteResource(addrs.MakeMap[addrs.AbsResourceInstance, string](), true)(NewNodeAbstractResourceInstance(addr.Instance(key)))) + graph.Add(n.concreteResource(addrs.MakeMap[addrs.AbsResourceInstance, cty.Value](), true)(NewNodeAbstractResourceInstance(addr.Instance(key)))) continue } diff --git a/internal/terraform/node_resource_plan.go b/internal/terraform/node_resource_plan.go index 3e257375b8..77fc190855 100644 --- a/internal/terraform/node_resource_plan.go +++ b/internal/terraform/node_resource_plan.go @@ -9,6 +9,7 @@ import ( "strings" "github.com/hashicorp/hcl/v2" + "github.com/zclconf/go-cty/cty" "github.com/hashicorp/terraform/internal/addrs" "github.com/hashicorp/terraform/internal/dag" @@ -113,33 +114,36 @@ func (n *nodeExpandPlannableResource) DynamicExpand(ctx EvalContext) (*Graph, tf expander := ctx.InstanceExpander() moduleInstances := expander.ExpandModule(n.Addr.Module, false) - // Expand the imports for this resource. - // TODO: Add support for unknown instances in import blocks. - imports, importDiags := n.expandResourceImports(ctx) - diags = diags.Append(importDiags) - // The possibility of partial-expanded modules and resources is guarded by a // top-level option for the whole plan, so that we can preserve mainline // behavior for the modules runtime. So, we currently branch off into an // entirely-separate codepath in those situations, at the expense of // duplicating some of the logic for behavior this method would normally // handle. - if ctx.Deferrals().DeferralAllowed() { + if ctx.Deferrals().DeferralAllowed() { // Expand the imports for this resource. + // TODO: Add support for unknown instances in import blocks. + imports, importDiags := n.expandResourceImports(ctx, true) + diags = diags.Append(importDiags) + pem := expander.UnknownModuleInstances(n.Addr.Module, false) g, expandDiags := n.dynamicExpandPartial(ctx, moduleInstances, pem, imports) diags = diags.Append(expandDiags) return g, diags } + // Expand the imports for this resource. + imports, importDiags := n.expandResourceImports(ctx, false) + diags = diags.Append(importDiags) + g, expandDiags := n.dynamicExpand(ctx, moduleInstances, imports) diags = diags.Append(expandDiags) return g, diags } // Import blocks are expanded in conjunction with their associated resource block. -func (n *nodeExpandPlannableResource) expandResourceImports(ctx EvalContext) (addrs.Map[addrs.AbsResourceInstance, string], tfdiags.Diagnostics) { +func (n *nodeExpandPlannableResource) expandResourceImports(ctx EvalContext, allowUnknown bool) (addrs.Map[addrs.AbsResourceInstance, cty.Value], tfdiags.Diagnostics) { // Imports maps the target address to an import ID. - imports := addrs.MakeMap[addrs.AbsResourceInstance, string]() + imports := addrs.MakeMap[addrs.AbsResourceInstance, cty.Value]() var diags tfdiags.Diagnostics if len(n.importTargets) == 0 { @@ -155,7 +159,7 @@ func (n *nodeExpandPlannableResource) expandResourceImports(ctx EvalContext) (ad // if we have a legacy addr, it was supplied on the commandline so // there is nothing to expand if !imp.LegacyAddr.Equal(addrs.AbsResourceInstance{}) { - imports.Put(imp.LegacyAddr, imp.IDString) + imports.Put(imp.LegacyAddr, cty.StringVal(imp.IDString)) return imports, diags } @@ -165,7 +169,7 @@ func (n *nodeExpandPlannableResource) expandResourceImports(ctx EvalContext) (ad } if imp.Config.ForEach == nil { - importID, evalDiags := evaluateImportIdExpression(imp.Config.ID, ctx, EvalDataForNoInstanceKey) + importID, evalDiags := evaluateImportIdExpression(imp.Config.ID, ctx, EvalDataForNoInstanceKey, allowUnknown) diags = diags.Append(evalDiags) if diags.HasErrors() { return imports, diags @@ -198,7 +202,7 @@ func (n *nodeExpandPlannableResource) expandResourceImports(ctx EvalContext) (ad return imports, diags } - importID, evalDiags := evaluateImportIdExpression(imp.Config.ID, ctx, keyData) + importID, evalDiags := evaluateImportIdExpression(imp.Config.ID, ctx, keyData, allowUnknown) diags = diags.Append(evalDiags) if diags.HasErrors() { return imports, diags @@ -227,7 +231,7 @@ func (n *nodeExpandPlannableResource) expandResourceImports(ctx EvalContext) (ad // This function is only called from within the dynamicExpand method, the // import validation is inlined within the dynamicExpandPartial method for the // alternate code path. -func (n *nodeExpandPlannableResource) validateExpandedImportTargets(expandedImports addrs.Map[addrs.AbsResourceInstance, string], expandedInstances addrs.Set[addrs.Checkable]) tfdiags.Diagnostics { +func (n *nodeExpandPlannableResource) validateExpandedImportTargets(expandedImports addrs.Map[addrs.AbsResourceInstance, cty.Value], expandedInstances addrs.Set[addrs.Checkable]) tfdiags.Diagnostics { var diags tfdiags.Diagnostics for _, addr := range expandedImports.Keys() { @@ -244,7 +248,7 @@ func (n *nodeExpandPlannableResource) validateExpandedImportTargets(expandedImpo return diags } -func (n *nodeExpandPlannableResource) dynamicExpand(ctx EvalContext, moduleInstances []addrs.ModuleInstance, imports addrs.Map[addrs.AbsResourceInstance, string]) (*Graph, tfdiags.Diagnostics) { +func (n *nodeExpandPlannableResource) dynamicExpand(ctx EvalContext, moduleInstances []addrs.ModuleInstance, imports addrs.Map[addrs.AbsResourceInstance, cty.Value]) (*Graph, tfdiags.Diagnostics) { var g Graph var diags tfdiags.Diagnostics @@ -331,7 +335,7 @@ func (n *nodeExpandPlannableResource) dynamicExpand(ctx EvalContext, moduleInsta // within, the caller must register the final superset instAddrs with the // checks subsystem so that it knows the fully expanded set of checkable // object instances for this resource instance. -func (n *nodeExpandPlannableResource) expandResourceInstances(globalCtx EvalContext, resAddr addrs.AbsResource, imports addrs.Map[addrs.AbsResourceInstance, string], g *Graph) ([]addrs.AbsResourceInstance, tfdiags.Diagnostics) { +func (n *nodeExpandPlannableResource) expandResourceInstances(globalCtx EvalContext, resAddr addrs.AbsResource, imports addrs.Map[addrs.AbsResourceInstance, cty.Value], g *Graph) ([]addrs.AbsResourceInstance, tfdiags.Diagnostics) { var diags tfdiags.Diagnostics // The rest of our work here needs to know which module instance it's @@ -385,7 +389,7 @@ func (n *nodeExpandPlannableResource) expandResourceInstances(globalCtx EvalCont return instanceAddrs, diags } -func (n *nodeExpandPlannableResource) resourceInstanceSubgraph(ctx EvalContext, addr addrs.AbsResource, instanceAddrs []addrs.AbsResourceInstance, imports addrs.Map[addrs.AbsResourceInstance, string]) (*Graph, tfdiags.Diagnostics) { +func (n *nodeExpandPlannableResource) resourceInstanceSubgraph(ctx EvalContext, addr addrs.AbsResource, instanceAddrs []addrs.AbsResourceInstance, imports addrs.Map[addrs.AbsResourceInstance, cty.Value]) (*Graph, tfdiags.Diagnostics) { var diags tfdiags.Diagnostics if n.Config == nil && n.generateConfigPath != "" && imports.Len() == 0 { @@ -444,7 +448,7 @@ func (n *nodeExpandPlannableResource) resourceInstanceSubgraph(ctx EvalContext, return graph, diags } -func (n *nodeExpandPlannableResource) concreteResource(imports addrs.Map[addrs.AbsResourceInstance, string], skipPlanChanges bool) func(*NodeAbstractResourceInstance) dag.Vertex { +func (n *nodeExpandPlannableResource) concreteResource(imports addrs.Map[addrs.AbsResourceInstance, cty.Value], skipPlanChanges bool) func(*NodeAbstractResourceInstance) dag.Vertex { return func(a *NodeAbstractResourceInstance) dag.Vertex { var m *NodePlannableResourceInstance @@ -454,7 +458,7 @@ func (n *nodeExpandPlannableResource) concreteResource(imports addrs.Map[addrs.A if importTarget.LegacyAddr.Equal(a.Addr) { return &graphNodeImportState{ Addr: importTarget.LegacyAddr, - ID: imports.Get(importTarget.LegacyAddr), + ID: imports.Get(importTarget.LegacyAddr).AsString(), ResolvedProvider: n.ResolvedProvider, } } @@ -485,9 +489,7 @@ func (n *nodeExpandPlannableResource) concreteResource(imports addrs.Map[addrs.A importID, ok := imports.GetOk(a.Addr) if ok { - m.importTarget = ImportTarget{ - IDString: importID, - } + m.importTarget = importID } return m diff --git a/internal/terraform/node_resource_plan_instance.go b/internal/terraform/node_resource_plan_instance.go index 046a6ff964..e4eff4f64e 100644 --- a/internal/terraform/node_resource_plan_instance.go +++ b/internal/terraform/node_resource_plan_instance.go @@ -52,7 +52,7 @@ type NodePlannableResourceInstance struct { // importTarget, if populated, contains the information necessary to plan // an import of this resource. - importTarget ImportTarget + importTarget cty.Value } var ( @@ -172,15 +172,25 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext) } } - importing := n.importTarget.IDString != "" && !n.preDestroyRefresh - importId := n.importTarget.IDString + importing := n.importTarget != cty.NilVal && !n.preDestroyRefresh var deferred *providers.Deferred // If the resource is to be imported, we now ask the provider for an Import // and a Refresh, and save the resulting state to instanceRefreshState. + if importing { - instanceRefreshState, deferred, diags = n.importState(ctx, addr, importId, provider, providerSchema) + if n.importTarget.IsKnown() { + var importDiags tfdiags.Diagnostics + instanceRefreshState, deferred, importDiags = n.importState(ctx, addr, n.importTarget.AsString(), provider, providerSchema) + diags = diags.Append(importDiags) + } else { + // Otherwise, just mark the resource as deferred without trying to + // import it. + deferred = &providers.Deferred{ + Reason: providers.DeferredReasonResourceConfigUnknown, + } + } } else { var readDiags tfdiags.Diagnostics instanceRefreshState, readDiags = n.readResourceInstanceState(ctx, addr) @@ -315,7 +325,7 @@ func (n *NodePlannableResourceInstance) managedResourceExecute(ctx EvalContext) } if importing { - change.Importing = &plans.Importing{ID: importId} + change.Importing = &plans.Importing{ID: n.importTarget} } // FIXME: here we udpate the change to reflect the reason for @@ -663,7 +673,7 @@ func (n *NodePlannableResourceInstance) importState(ctx EvalContext, addr addrs. "Import returned null resource", fmt.Sprintf("While attempting to import with ID %s, the provider"+ "returned an instance with no state.", - n.importTarget.IDString, + importId, ), ))