mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-11 00:22:32 -06:00
0d1e6cd5f0
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
141 lines
4.1 KiB
Go
141 lines
4.1 KiB
Go
// Copyright (c) The OpenTofu Authors
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
// Copyright (c) 2023 HashiCorp, Inc.
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
package configs
|
|
|
|
import (
|
|
"fmt"
|
|
|
|
"github.com/hashicorp/hcl/v2"
|
|
"github.com/hashicorp/hcl/v2/gohcl"
|
|
"github.com/hashicorp/hcl/v2/hcldec"
|
|
"github.com/opentofu/opentofu/internal/addrs"
|
|
"github.com/opentofu/opentofu/internal/lang"
|
|
"github.com/opentofu/opentofu/internal/lang/marks"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
// StaticIdentifier holds a Referenceable item and where it was declared
|
|
type StaticIdentifier struct {
|
|
Module addrs.Module
|
|
Subject string
|
|
DeclRange hcl.Range
|
|
}
|
|
|
|
func (ref StaticIdentifier) String() string {
|
|
val := ref.Subject
|
|
if len(ref.Module) != 0 {
|
|
val = ref.Module.String() + ":" + val
|
|
}
|
|
return val
|
|
}
|
|
|
|
type StaticModuleVariables func(v *Variable) (cty.Value, hcl.Diagnostics)
|
|
|
|
// StaticModuleCall contains the information required to call a given module
|
|
type StaticModuleCall struct {
|
|
addr addrs.Module
|
|
vars StaticModuleVariables
|
|
rootPath string
|
|
workspace string
|
|
}
|
|
|
|
func NewStaticModuleCall(addr addrs.Module, vars StaticModuleVariables, rootPath string, workspace string) StaticModuleCall {
|
|
return StaticModuleCall{
|
|
addr: addr,
|
|
vars: vars,
|
|
rootPath: rootPath,
|
|
workspace: workspace,
|
|
}
|
|
}
|
|
|
|
func (s StaticModuleCall) WithVariables(vars StaticModuleVariables) StaticModuleCall {
|
|
return StaticModuleCall{
|
|
addr: s.addr,
|
|
vars: vars,
|
|
rootPath: s.rootPath,
|
|
workspace: s.workspace,
|
|
}
|
|
}
|
|
|
|
// only used in testing
|
|
func RootModuleCallForTesting() StaticModuleCall {
|
|
return NewStaticModuleCall(addrs.RootModule, func(_ *Variable) (cty.Value, hcl.Diagnostics) {
|
|
panic("Variables have not been configured for this test!")
|
|
}, "<testing>", "")
|
|
}
|
|
|
|
// A static evaluator contains the information required to build a EvalContext
|
|
// which only understands "static" (non-state) data. Internally, it relies
|
|
// on staticData
|
|
type StaticEvaluator struct {
|
|
call StaticModuleCall
|
|
cfg *Module
|
|
}
|
|
|
|
// Creates a static evaluator based from the given module and module call
|
|
func NewStaticEvaluator(mod *Module, call StaticModuleCall) *StaticEvaluator {
|
|
return &StaticEvaluator{
|
|
call: call,
|
|
cfg: mod,
|
|
}
|
|
}
|
|
|
|
func (s *StaticEvaluator) scope(ident StaticIdentifier) *lang.Scope {
|
|
return newStaticScope(s, ident)
|
|
}
|
|
|
|
func (s StaticEvaluator) Evaluate(expr hcl.Expression, ident StaticIdentifier) (cty.Value, hcl.Diagnostics) {
|
|
val, diags := s.scope(ident).EvalExpr(expr, cty.DynamicPseudoType)
|
|
return val, diags.ToHCL()
|
|
}
|
|
|
|
func (s StaticEvaluator) DecodeExpression(expr hcl.Expression, ident StaticIdentifier, val any) hcl.Diagnostics {
|
|
srcVal, diags := s.Evaluate(expr, ident)
|
|
if diags.HasErrors() {
|
|
return diags
|
|
}
|
|
|
|
if marks.Contains(srcVal, marks.Sensitive) {
|
|
return diags.Append(&hcl.Diagnostic{
|
|
Severity: hcl.DiagError,
|
|
Summary: "Sensitive value not allowed",
|
|
Detail: fmt.Sprintf("Sensitive values, or values derived from sensitive values, cannot be used as %s.", ident.String()),
|
|
Subject: expr.Range().Ptr(),
|
|
})
|
|
}
|
|
|
|
return diags.Extend(gohcl.DecodeValue(srcVal, expr.StartRange(), expr.Range(), val))
|
|
}
|
|
|
|
func (s StaticEvaluator) DecodeBlock(body hcl.Body, spec hcldec.Spec, ident StaticIdentifier) (cty.Value, hcl.Diagnostics) {
|
|
var diags hcl.Diagnostics
|
|
|
|
refs, refsDiags := lang.References(addrs.ParseRef, hcldec.Variables(body, spec))
|
|
diags = append(diags, refsDiags.ToHCL()...)
|
|
if diags.HasErrors() {
|
|
return cty.DynamicVal, diags
|
|
}
|
|
|
|
ctx, ctxDiags := s.scope(ident).EvalContext(refs)
|
|
diags = append(diags, ctxDiags.ToHCL()...)
|
|
if diags.HasErrors() {
|
|
return cty.DynamicVal, diags
|
|
}
|
|
|
|
val, valDiags := hcldec.Decode(body, spec, ctx)
|
|
diags = append(diags, valDiags...)
|
|
return val, diags
|
|
}
|
|
|
|
func (s StaticEvaluator) EvalContext(ident StaticIdentifier, refs []*addrs.Reference) (*hcl.EvalContext, hcl.Diagnostics) {
|
|
return s.EvalContextWithParent(nil, ident, refs)
|
|
}
|
|
|
|
func (s StaticEvaluator) EvalContextWithParent(parent *hcl.EvalContext, ident StaticIdentifier, refs []*addrs.Reference) (*hcl.EvalContext, hcl.Diagnostics) {
|
|
evalCtx, diags := s.scope(ident).EvalContextWithParent(parent, refs)
|
|
return evalCtx, diags.ToHCL()
|
|
}
|