Fix import validation with resource reference (unknown value) (#3513)

Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
This commit is contained in:
Christian Mesh 2025-11-19 09:58:35 -05:00 committed by GitHub
parent 8149270787
commit 95d75b3436
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 49 additions and 14 deletions

View file

@ -0,0 +1,11 @@
resource "test_instance" "main" {
}
import {
to = test_instance.main
id = test_instance.reference.ami
}
resource "test_instance" "reference" {
}

View file

@ -187,6 +187,13 @@ func TestUndefinedResourceAsImportTargetShouldSucceed(t *testing.T) {
}
}
func TestDefinedResourceAsImportTargetShouldSucceed(t *testing.T) {
output, code := setupTest(t, "validate-valid/import_defined_resource")
if code != 0 {
t.Fatalf("Should have succeeded: %d\n\n%s", code, output.Stderr())
}
}
func TestDefinedVarAsImportIDShouldSucceed(t *testing.T) {
output, code := setupTest(t, "validate-valid/import_id_defined_var")
if code != 0 {

View file

@ -144,12 +144,12 @@ func (ri *ImportResolver) ValidateImportIDs(ctx context.Context, importTarget *I
}
for _, keyData := range repetitions {
_, evalDiags = evaluateImportIdExpression(importTarget.Config.ID, evalCtx, keyData)
evalDiags = validateImportIdExpression(importTarget.Config.ID, evalCtx, keyData)
diags = diags.Append(evalDiags)
}
} else {
// The import target is singular, no need to expand
_, evalDiags := evaluateImportIdExpression(importTarget.Config.ID, evalCtx, EvalDataForNoInstanceKey)
evalDiags := validateImportIdExpression(importTarget.Config.ID, evalCtx, EvalDataForNoInstanceKey)
diags = diags.Append(evalDiags)
}

View file

@ -20,6 +20,20 @@ import (
)
func evaluateImportIdExpression(expr hcl.Expression, evalCtx EvalContext, keyData instances.RepetitionData) (string, tfdiags.Diagnostics) {
return evaluateImportIdExpressionInner(expr, evalCtx, keyData, false)
}
// Checks for any potential issues in the import id expression, allowing unknowns as this is part
// of the validate phase
func validateImportIdExpression(expr hcl.Expression, evalCtx EvalContext, keyData instances.RepetitionData) tfdiags.Diagnostics {
_, diags := evaluateImportIdExpressionInner(expr, evalCtx, keyData, true)
return diags
}
// This should not be used directly, use one of the wrapping methods above
// Note: When allowUnknown is true, it may return "" as the import id. This is safe as the result is discarded in the validate
// function above
func evaluateImportIdExpressionInner(expr hcl.Expression, evalCtx EvalContext, keyData instances.RepetitionData, allowUnknown bool) (string, tfdiags.Diagnostics) {
var diags tfdiags.Diagnostics
if expr == nil {
@ -48,18 +62,6 @@ func evaluateImportIdExpression(expr hcl.Expression, evalCtx EvalContext, keyDat
})
}
if !importIdVal.IsKnown() {
return "", 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 OpenTofu cannot plan to import this resource.`, // FIXME and what should I do about that?
Subject: expr.Range().Ptr(),
// Expression:
// EvalContext:
Extra: evalchecks.DiagnosticCausedByUnknown(true),
})
}
if importIdVal.HasMark(marks.Sensitive) {
return "", diags.Append(&hcl.Diagnostic{
Severity: hcl.DiagError,
@ -77,6 +79,21 @@ func evaluateImportIdExpression(expr hcl.Expression, evalCtx EvalContext, keyDat
})
}
if !importIdVal.IsKnown() {
if allowUnknown {
return "", diags
}
return "", 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 OpenTofu cannot plan to import this resource.`, // FIXME and what should I do about that?
Subject: expr.Range().Ptr(),
// Expression:
// EvalContext:
Extra: evalchecks.DiagnosticCausedByUnknown(true),
})
}
var importId string
err := gocty.FromCtyValue(importIdVal, &importId)
if err != nil {