ignore unknown function errors during init

we won't have providers during init, so there is no way we can use these to begin with
pull/38497/head
Daniel Schmidt 3 weeks ago
parent bb7491c368
commit 6f3cf2c219
No known key found for this signature in database
GPG Key ID: 377C3A4D62FBBBE2

@ -75,7 +75,7 @@ func (s *Scope) EvalBlock(body hcl.Body, schema *configschema.Block) (cty.Value,
body = blocktoattr.FixUpBlockAttrs(body, schema)
val, evalDiags := hcldec.Decode(body, spec, ctx)
diags = diags.Append(checkForUnknownFunctionDiags(evalDiags))
diags = diags.Append(checkForUnknownFunctionDiags(evalDiags, s.IgnoreUnknownProviderFunctions))
return val, diags
}
@ -153,7 +153,7 @@ func (s *Scope) EvalSelfBlock(body hcl.Body, self cty.Value, schema *configschem
}
val, decDiags := hcldec.Decode(body, schema.DecoderSpec(), ctx)
diags = diags.Append(checkForUnknownFunctionDiags(decDiags))
diags = diags.Append(checkForUnknownFunctionDiags(decDiags, s.IgnoreUnknownProviderFunctions))
return val, diags
}
@ -179,7 +179,7 @@ func (s *Scope) EvalExpr(expr hcl.Expression, wantType cty.Type) (cty.Value, tfd
}
val, evalDiags := expr.Value(ctx)
diags = diags.Append(checkForUnknownFunctionDiags(evalDiags))
diags = diags.Append(checkForUnknownFunctionDiags(evalDiags, s.IgnoreUnknownProviderFunctions))
if wantType != cty.DynamicPseudoType {
var convErr error
@ -524,16 +524,22 @@ func normalizeRefValue(val cty.Value, diags tfdiags.Diagnostics) (cty.Value, tfd
// namespace. The generic unknown function diagnostic from hcl does not direct
// the user on how to remedy the situation in Terraform, and we can give more
// useful information in a few Terraform specific cases here.
func checkForUnknownFunctionDiags(diags hcl.Diagnostics) hcl.Diagnostics {
func checkForUnknownFunctionDiags(diags hcl.Diagnostics, ignoreUnknownProviderFunctions bool) hcl.Diagnostics {
var filteredDiags hcl.Diagnostics
for _, d := range diags {
extra, ok := hcl.DiagnosticExtra[hclsyntax.FunctionCallUnknownDiagExtra](d)
if !ok {
filteredDiags = filteredDiags.Append(d) // we always want to include unrelated diags
continue
}
name := extra.CalledFunctionName()
namespace := extra.CalledFunctionNamespace()
namespaceParts := strings.Split(namespace, "::")
if len(namespaceParts) < 2 {
// we always include diags for unknown regular function calls
filteredDiags = filteredDiags.Append(d)
// no namespace (namespace includes ::, so will have at least 2
// parts), but check if there is a matching name in a provider
// namspace.
@ -550,6 +556,17 @@ func checkForUnknownFunctionDiags(diags hcl.Diagnostics) hcl.Diagnostics {
continue
}
// We might run into provider-defined functions during init. We can't filter out all
// places where they might be used, so we'll just filter out the diagnostics for the
// unknown function calls if we're configured to ignore them. This means that the user will
// just get an unknown value result for any provider function calls, which is fine because
// we won't have any provider functions available at this point anyway.
if ignoreUnknownProviderFunctions {
continue
} else {
filteredDiags = filteredDiags.Append(d)
}
// the diagnostic isn't really shared with anything, and copying would
// still retain the internal pointers, so we're going to modify the
// diagnostic in-place if we want to change the output. Log the original
@ -598,5 +615,5 @@ func checkForUnknownFunctionDiags(diags hcl.Diagnostics) hcl.Diagnostics {
d.Detail = fmt.Sprintf(`There is no function named "%s%s". Ensure that provider name %q is declared in this module's required_providers block, and that this provider offers a function named %q.`, namespace, name, namespaceParts[1], name)
}
return diags
return filteredDiags
}

@ -84,6 +84,12 @@ type Scope struct {
// marked as ephemeral.
// FIXME: plan to officially deprecate this workaround.
ForProvider bool
// IgnoreUnknownProviderFunctions can be set to true to request that any unknown
// functions produce unknown value results rather than an error. This is
// important during a plan phase to avoid generating errors for functions that
// are only available in provider versions that have not yet been selected.
IgnoreUnknownProviderFunctions bool
}
// SetActiveExperiments allows a caller to declare that a set of experiments

@ -93,15 +93,16 @@ type Evaluator struct {
// address.
func (e *Evaluator) Scope(data lang.Data, self addrs.Referenceable, source addrs.Referenceable, extFuncs lang.ExternalFuncs) *lang.Scope {
return &lang.Scope{
Data: data,
ParseRef: addrs.ParseRef,
SelfAddr: self,
SourceAddr: source,
PureOnly: e.Operation != walkApply && e.Operation != walkDestroy && e.Operation != walkEval,
BaseDir: ".", // Always current working directory for now.
PlanTimestamp: e.PlanTimestamp,
ExternalFuncs: extFuncs,
FunctionResults: e.FunctionResults,
Data: data,
ParseRef: addrs.ParseRef,
SelfAddr: self,
SourceAddr: source,
PureOnly: e.Operation != walkApply && e.Operation != walkDestroy && e.Operation != walkEval,
BaseDir: ".", // Always current working directory for now.
PlanTimestamp: e.PlanTimestamp,
ExternalFuncs: extFuncs,
FunctionResults: e.FunctionResults,
IgnoreUnknownProviderFunctions: e.Operation == walkInit,
}
}

Loading…
Cancel
Save