mirror of
https://github.com/opentofu/opentofu.git
synced 2025-02-25 18:45:20 -06:00
Fix function refs in variable validation (#2052)
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
This commit is contained in:
parent
d36220e44c
commit
7cacb9f066
@ -41,6 +41,11 @@ issues:
|
|||||||
linters:
|
linters:
|
||||||
- funlen
|
- funlen
|
||||||
- dupl
|
- dupl
|
||||||
|
- revive
|
||||||
|
- path: (.+)_test.go
|
||||||
|
text: "ST1003"
|
||||||
|
- path: (.+)_test.go
|
||||||
|
text: "var-naming: don't use underscores in Go names"
|
||||||
|
|
||||||
linters:
|
linters:
|
||||||
disable-all: true
|
disable-all: true
|
||||||
|
@ -2487,3 +2487,84 @@ locals {
|
|||||||
t.Fatalf("expected deprecated warning, got: %q\n", warn)
|
t.Fatalf("expected deprecated warning, got: %q\n", warn)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TextContext2Validate_providerFunctions(t *testing.T) {
|
||||||
|
p := testProvider("aws")
|
||||||
|
p.GetProviderSchemaResponse = &providers.GetProviderSchemaResponse{
|
||||||
|
Functions: map[string]providers.FunctionSpec{
|
||||||
|
"arn_parse": providers.FunctionSpec{
|
||||||
|
Parameters: []providers.FunctionParameterSpec{{
|
||||||
|
Name: "arn",
|
||||||
|
Type: cty.String,
|
||||||
|
}},
|
||||||
|
Return: cty.Bool,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
p.CallFunctionResponse = &providers.CallFunctionResponse{
|
||||||
|
Result: cty.True,
|
||||||
|
}
|
||||||
|
m := testModuleInline(t, map[string]string{
|
||||||
|
"main.tf": `
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
aws = ">=5.70.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
provider "aws" {
|
||||||
|
region="us-east-1"
|
||||||
|
}
|
||||||
|
|
||||||
|
module "mod" {
|
||||||
|
source = "./mod"
|
||||||
|
providers = {
|
||||||
|
aws = aws
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
"mod/mod.tf": `
|
||||||
|
terraform {
|
||||||
|
required_providers {
|
||||||
|
aws = ">=5.70.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "obfmod" {
|
||||||
|
type = object({
|
||||||
|
arns = optional(list(string))
|
||||||
|
})
|
||||||
|
description = "Configuration for xxx."
|
||||||
|
|
||||||
|
validation {
|
||||||
|
condition = alltrue([
|
||||||
|
for arn in var.obfmod.arns: can(provider::aws::arn_parse(arn))
|
||||||
|
])
|
||||||
|
error_message = "All arns MUST BE a valid AWS ARN format."
|
||||||
|
}
|
||||||
|
|
||||||
|
default = {
|
||||||
|
arns = [
|
||||||
|
"arn:partition:service:region:account-id:resource-id",
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
})
|
||||||
|
|
||||||
|
ctx := testContext2(t, &ContextOpts{
|
||||||
|
Providers: map[addrs.Provider]providers.Factory{
|
||||||
|
addrs.NewDefaultProvider("aws"): testProviderFuncFixed(p),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
diags := ctx.Validate(m)
|
||||||
|
warn := diags.ErrWithWarnings().Error()
|
||||||
|
if !strings.Contains(warn, `The attribute "foo" is deprecated`) {
|
||||||
|
t.Fatalf("expected deprecated warning, got: %q\n", warn)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !p.CallFunctionCalled {
|
||||||
|
t.Fatalf("Expected function call")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -91,16 +91,27 @@ func (n *nodeExpandModuleVariable) ModulePath() addrs.Module {
|
|||||||
|
|
||||||
// GraphNodeReferencer
|
// GraphNodeReferencer
|
||||||
func (n *nodeExpandModuleVariable) References() []*addrs.Reference {
|
func (n *nodeExpandModuleVariable) References() []*addrs.Reference {
|
||||||
|
var refs []*addrs.Reference
|
||||||
|
if n.Config != nil {
|
||||||
|
// These references will ignore GraphNodeReferenceOutside and are used by the ProviderFunctionTransformer and lang.Scope.evalContext
|
||||||
|
// It's an odd pattern, but it works
|
||||||
|
for _, validation := range n.Config.Validations {
|
||||||
|
condFuncs, _ := lang.ProviderFunctionsInExpr(addrs.ParseRef, validation.Condition)
|
||||||
|
refs = append(refs, condFuncs...)
|
||||||
|
errFuncs, _ := lang.ProviderFunctionsInExpr(addrs.ParseRef, validation.ErrorMessage)
|
||||||
|
refs = append(refs, errFuncs...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If we have no value expression, we cannot depend on anything.
|
// If we have no value expression, we cannot depend on anything.
|
||||||
if n.Expr == nil {
|
if n.Expr == nil {
|
||||||
return nil
|
return refs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Variables in the root don't depend on anything, because their values
|
// Variables in the root don't depend on anything, because their values
|
||||||
// are gathered prior to the graph walk and recorded in the context.
|
// are gathered prior to the graph walk and recorded in the context.
|
||||||
if len(n.Module) == 0 {
|
if len(n.Module) == 0 {
|
||||||
return nil
|
return refs
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, we depend on anything referenced by our value expression.
|
// Otherwise, we depend on anything referenced by our value expression.
|
||||||
@ -113,7 +124,9 @@ func (n *nodeExpandModuleVariable) References() []*addrs.Reference {
|
|||||||
// where our associated variable was declared, which is correct because
|
// where our associated variable was declared, which is correct because
|
||||||
// our value expression is assigned within a "module" block in the parent
|
// our value expression is assigned within a "module" block in the parent
|
||||||
// module.
|
// module.
|
||||||
refs, _ := lang.ReferencesInExpr(addrs.ParseRef, n.Expr)
|
outerRefs, _ := lang.ReferencesInExpr(addrs.ParseRef, n.Expr)
|
||||||
|
refs = append(refs, outerRefs...)
|
||||||
|
|
||||||
return refs
|
return refs
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,23 +180,6 @@ func (n *nodeModuleVariable) ModulePath() addrs.Module {
|
|||||||
return n.Addr.Module.Module()
|
return n.Addr.Module.Module()
|
||||||
}
|
}
|
||||||
|
|
||||||
// GraphNodeReferencer
|
|
||||||
func (n *nodeModuleVariable) References() []*addrs.Reference {
|
|
||||||
// This is identical to NodeRootVariable.References
|
|
||||||
var refs []*addrs.Reference
|
|
||||||
|
|
||||||
if n.Config != nil {
|
|
||||||
for _, validation := range n.Config.Validations {
|
|
||||||
condFuncs, _ := lang.ProviderFunctionsInExpr(addrs.ParseRef, validation.Condition)
|
|
||||||
refs = append(refs, condFuncs...)
|
|
||||||
errFuncs, _ := lang.ProviderFunctionsInExpr(addrs.ParseRef, validation.ErrorMessage)
|
|
||||||
refs = append(refs, errFuncs...)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return refs
|
|
||||||
}
|
|
||||||
|
|
||||||
// GraphNodeExecutable
|
// GraphNodeExecutable
|
||||||
func (n *nodeModuleVariable) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
func (n *nodeModuleVariable) Execute(ctx EvalContext, op walkOperation) (diags tfdiags.Diagnostics) {
|
||||||
log.Printf("[TRACE] nodeModuleVariable: evaluating %s", n.Addr)
|
log.Printf("[TRACE] nodeModuleVariable: evaluating %s", n.Addr)
|
||||||
|
Loading…
Reference in New Issue
Block a user