From 4a9d46f9df972215ba2eee180c84966e7537e2fc Mon Sep 17 00:00:00 2001 From: James Bardin Date: Wed, 6 Nov 2024 12:55:51 -0500 Subject: [PATCH] avoid unknowns in OpenEphemeralResource Ephemeral resources can't be opened if the configuration contains unknown values. --- .../ephemeral/ephemeral_resources.go | 5 +++++ internal/terraform/node_resource_ephemeral.go | 21 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/internal/resources/ephemeral/ephemeral_resources.go b/internal/resources/ephemeral/ephemeral_resources.go index 0034579d08..186bbd6c84 100644 --- a/internal/resources/ephemeral/ephemeral_resources.go +++ b/internal/resources/ephemeral/ephemeral_resources.go @@ -212,6 +212,11 @@ type resourceInstanceInternal struct { func (r *resourceInstanceInternal) close(ctx context.Context) tfdiags.Diagnostics { var diags tfdiags.Diagnostics + // if the resource could not be opened, there will not be anything to close either + if r.impl == nil { + return diags + } + // Stop renewing, if indeed we are. If we previously saw any errors during // renewing then they finally get returned here, to be reported along with // any errors during close. diff --git a/internal/terraform/node_resource_ephemeral.go b/internal/terraform/node_resource_ephemeral.go index b57de5ed26..916ba4c9f4 100644 --- a/internal/terraform/node_resource_ephemeral.go +++ b/internal/terraform/node_resource_ephemeral.go @@ -73,6 +73,27 @@ func ephemeralResourceOpen(ctx EvalContext, inp ephemeralResourceInput) (*provid } unmarkedConfigVal, configMarks := configVal.UnmarkDeepWithPaths() + if !unmarkedConfigVal.IsWhollyKnown() { + log.Printf("[DEBUG] ehpemeralResourceOpen: configuration for %s contains unknown values, cannot open resource", inp.addr) + + // We don't know what the result will be, but we need to keep the + // configured attributes for consistent evaluation. We can use the same + // technique we used for data sources to create the plan-time value. + unknownResult := objchange.PlannedDataResourceObject(schema, unmarkedConfigVal) + // add back any configured marks + unknownResult = unknownResult.MarkWithPaths(configMarks) + // and mark the entire value as ephemeral, since it's coming from an ephemeral context. + unknownResult = unknownResult.Mark(marks.Ephemeral) + + // The state of ephemerals all comes from the registered instances, so + // we still need to register something so evaluation doesn't fail. + ephemerals.RegisterInstance(ctx.StopCtx(), inp.addr, ephemeral.ResourceInstanceRegistration{ + Value: unknownResult, + ConfigBody: config.Config, + }) + return nil, diags + } + validateResp := provider.ValidateEphemeralResourceConfig(providers.ValidateEphemeralResourceConfigRequest{ TypeName: inp.addr.Resource.Resource.Type, Config: unmarkedConfigVal,