mirror of
https://github.com/opentffoundation/opentf.git
synced 2025-12-19 17:59:05 -05:00
Module expander for enabled field
Signed-off-by: Diogenes Fernandes <diofeher@gmail.com>
This commit is contained in:
committed by
Diógenes Fernandes
parent
ca53b2521d
commit
732623f604
@@ -38,6 +38,7 @@ type ModuleCall struct {
|
|||||||
|
|
||||||
Count hcl.Expression
|
Count hcl.Expression
|
||||||
ForEach hcl.Expression
|
ForEach hcl.Expression
|
||||||
|
Enabled hcl.Expression
|
||||||
|
|
||||||
Providers []PassedProviderConfig
|
Providers []PassedProviderConfig
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,12 @@ func (e *Expander) SetModuleSingle(parentAddr addrs.ModuleInstance, callAddr add
|
|||||||
e.setModuleExpansion(parentAddr, callAddr, expansionSingleVal)
|
e.setModuleExpansion(parentAddr, callAddr, expansionSingleVal)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SetModuleEnabled records that the given module call inside the given parent
|
||||||
|
// module uses the "enabled" lifecycle repetition argument, with the given value.
|
||||||
|
func (e *Expander) SetModuleEnabled(parentAddr addrs.ModuleInstance, callAddr addrs.ModuleCall, enabled bool) {
|
||||||
|
e.setModuleExpansion(parentAddr, callAddr, expansionEnabled(enabled))
|
||||||
|
}
|
||||||
|
|
||||||
// SetModuleCount records that the given module call inside the given parent
|
// SetModuleCount records that the given module call inside the given parent
|
||||||
// module instance uses the "count" repetition argument, with the given value.
|
// module instance uses the "count" repetition argument, with the given value.
|
||||||
func (e *Expander) SetModuleCount(parentAddr addrs.ModuleInstance, callAddr addrs.ModuleCall, count int) {
|
func (e *Expander) SetModuleCount(parentAddr addrs.ModuleInstance, callAddr addrs.ModuleCall, count int) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ func TestExpander(t *testing.T) {
|
|||||||
count2ModuleAddr := addrs.ModuleCall{Name: "count2"}
|
count2ModuleAddr := addrs.ModuleCall{Name: "count2"}
|
||||||
count0ModuleAddr := addrs.ModuleCall{Name: "count0"}
|
count0ModuleAddr := addrs.ModuleCall{Name: "count0"}
|
||||||
forEachModuleAddr := addrs.ModuleCall{Name: "for_each"}
|
forEachModuleAddr := addrs.ModuleCall{Name: "for_each"}
|
||||||
|
enabledModuleAddr := addrs.ModuleCall{Name: "enabled"}
|
||||||
singleResourceAddr := addrs.Resource{
|
singleResourceAddr := addrs.Resource{
|
||||||
Mode: addrs.ManagedResourceMode,
|
Mode: addrs.ManagedResourceMode,
|
||||||
Type: "test",
|
Type: "test",
|
||||||
@@ -42,6 +43,11 @@ func TestExpander(t *testing.T) {
|
|||||||
Type: "test",
|
Type: "test",
|
||||||
Name: "for_each",
|
Name: "for_each",
|
||||||
}
|
}
|
||||||
|
enabledResourceAddr := addrs.Resource{
|
||||||
|
Mode: addrs.ManagedResourceMode,
|
||||||
|
Type: "test",
|
||||||
|
Name: "enabled",
|
||||||
|
}
|
||||||
eachMap := map[string]cty.Value{
|
eachMap := map[string]cty.Value{
|
||||||
"a": cty.NumberIntVal(1),
|
"a": cty.NumberIntVal(1),
|
||||||
"b": cty.NumberIntVal(2),
|
"b": cty.NumberIntVal(2),
|
||||||
@@ -88,6 +94,7 @@ func TestExpander(t *testing.T) {
|
|||||||
ex.SetResourceCount(addrs.RootModuleInstance, count2ResourceAddr, 2)
|
ex.SetResourceCount(addrs.RootModuleInstance, count2ResourceAddr, 2)
|
||||||
ex.SetResourceCount(addrs.RootModuleInstance, count0ResourceAddr, 0)
|
ex.SetResourceCount(addrs.RootModuleInstance, count0ResourceAddr, 0)
|
||||||
ex.SetResourceForEach(addrs.RootModuleInstance, forEachResourceAddr, eachMap)
|
ex.SetResourceForEach(addrs.RootModuleInstance, forEachResourceAddr, eachMap)
|
||||||
|
ex.SetResourceEnabled(addrs.RootModuleInstance, enabledResourceAddr, true)
|
||||||
|
|
||||||
ex.SetModuleSingle(addrs.RootModuleInstance, singleModuleAddr)
|
ex.SetModuleSingle(addrs.RootModuleInstance, singleModuleAddr)
|
||||||
{
|
{
|
||||||
@@ -97,6 +104,12 @@ func TestExpander(t *testing.T) {
|
|||||||
ex.SetResourceCount(moduleInstanceAddr, count2ResourceAddr, 2)
|
ex.SetResourceCount(moduleInstanceAddr, count2ResourceAddr, 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ex.SetModuleEnabled(addrs.RootModuleInstance, enabledModuleAddr, true)
|
||||||
|
{
|
||||||
|
moduleInstanceAddr := addrs.RootModuleInstance.Child("enabled", addrs.NoKey)
|
||||||
|
ex.SetResourceSingle(moduleInstanceAddr, singleResourceAddr)
|
||||||
|
}
|
||||||
|
|
||||||
ex.SetModuleCount(addrs.RootModuleInstance, count2ModuleAddr, 2)
|
ex.SetModuleCount(addrs.RootModuleInstance, count2ModuleAddr, 2)
|
||||||
for i1 := 0; i1 < 2; i1++ {
|
for i1 := 0; i1 < 2; i1++ {
|
||||||
moduleInstanceAddr := addrs.RootModuleInstance.Child("count2", addrs.IntKey(i1))
|
moduleInstanceAddr := addrs.RootModuleInstance.Child("count2", addrs.IntKey(i1))
|
||||||
@@ -146,6 +159,19 @@ func TestExpander(t *testing.T) {
|
|||||||
t.Errorf("wrong result\n%s", diff)
|
t.Errorf("wrong result\n%s", diff)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("resource enabled", func(t *testing.T) {
|
||||||
|
got := ex.ExpandModuleResource(
|
||||||
|
addrs.RootModule,
|
||||||
|
enabledResourceAddr,
|
||||||
|
)
|
||||||
|
want := []addrs.AbsResourceInstance{
|
||||||
|
mustAbsResourceInstanceAddr(`test.enabled`),
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(want, got); diff != "" {
|
||||||
|
t.Errorf("wrong result\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
t.Run("resource count2", func(t *testing.T) {
|
t.Run("resource count2", func(t *testing.T) {
|
||||||
got := ex.ExpandModuleResource(
|
got := ex.ExpandModuleResource(
|
||||||
addrs.RootModule,
|
addrs.RootModule,
|
||||||
@@ -169,6 +195,18 @@ func TestExpander(t *testing.T) {
|
|||||||
t.Errorf("wrong result\n%s", diff)
|
t.Errorf("wrong result\n%s", diff)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
t.Run("resource enabled", func(t *testing.T) {
|
||||||
|
got := ex.ExpandModuleResource(
|
||||||
|
addrs.RootModule,
|
||||||
|
enabledResourceAddr,
|
||||||
|
)
|
||||||
|
want := []addrs.AbsResourceInstance{
|
||||||
|
mustAbsResourceInstanceAddr(`test.enabled`),
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(want, got); diff != "" {
|
||||||
|
t.Errorf("wrong result\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
t.Run("resource for_each", func(t *testing.T) {
|
t.Run("resource for_each", func(t *testing.T) {
|
||||||
got := ex.ExpandModuleResource(
|
got := ex.ExpandModuleResource(
|
||||||
addrs.RootModule,
|
addrs.RootModule,
|
||||||
@@ -191,6 +229,16 @@ func TestExpander(t *testing.T) {
|
|||||||
t.Errorf("wrong result\n%s", diff)
|
t.Errorf("wrong result\n%s", diff)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("module enabled", func(t *testing.T) {
|
||||||
|
got := ex.ExpandModule(addrs.RootModule.Child("enabled"))
|
||||||
|
want := []addrs.ModuleInstance{
|
||||||
|
mustModuleInstanceAddr(`module.enabled`),
|
||||||
|
}
|
||||||
|
if diff := cmp.Diff(want, got); diff != "" {
|
||||||
|
t.Errorf("wrong result\n%s", diff)
|
||||||
|
}
|
||||||
|
})
|
||||||
t.Run("module single resource single", func(t *testing.T) {
|
t.Run("module single resource single", func(t *testing.T) {
|
||||||
got := ex.ExpandModuleResource(
|
got := ex.ExpandModuleResource(
|
||||||
mustModuleAddr("single"),
|
mustModuleAddr("single"),
|
||||||
|
|||||||
@@ -565,16 +565,23 @@ func (d *evaluationStateData) GetModule(_ context.Context, addr addrs.ModuleCall
|
|||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
val, ok := moduleInstances[addrs.NoKey]
|
vals, ok := moduleInstances[addrs.NoKey]
|
||||||
if !ok {
|
if !ok {
|
||||||
// create the object if there wasn't one known
|
if callConfig.Enabled == nil {
|
||||||
val = map[string]cty.Value{}
|
// create the object if there wasn't one known
|
||||||
for k := range outputConfigs {
|
vals = map[string]cty.Value{}
|
||||||
val[k] = cty.DynamicVal
|
for k := range outputConfigs {
|
||||||
|
vals[k] = cty.DynamicVal
|
||||||
|
}
|
||||||
|
ret = cty.ObjectVal(vals)
|
||||||
|
} else {
|
||||||
|
// when we're using enabled it's okay to have no
|
||||||
|
// instance, and the entire object is null.
|
||||||
|
ret = cty.NullVal(cty.DynamicPseudoType)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
ret = cty.ObjectVal(vals)
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = cty.ObjectVal(val)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The module won't be expanded during validation, so we need to return an
|
// The module won't be expanded during validation, so we need to return an
|
||||||
|
|||||||
@@ -77,6 +77,10 @@ func (n *nodeExpandModule) References() []*addrs.Reference {
|
|||||||
forEachRefs, _ := lang.ReferencesInExpr(addrs.ParseRef, n.ModuleCall.ForEach)
|
forEachRefs, _ := lang.ReferencesInExpr(addrs.ParseRef, n.ModuleCall.ForEach)
|
||||||
refs = append(refs, forEachRefs...)
|
refs = append(refs, forEachRefs...)
|
||||||
}
|
}
|
||||||
|
if n.ModuleCall.Enabled != nil {
|
||||||
|
enabledRefs, _ := lang.ReferencesInExpr(addrs.ParseRef, n.ModuleCall.Enabled)
|
||||||
|
refs = append(refs, enabledRefs...)
|
||||||
|
}
|
||||||
|
|
||||||
for _, passed := range n.ModuleCall.Providers {
|
for _, passed := range n.ModuleCall.Providers {
|
||||||
if passed.InParent.KeyExpression != nil {
|
if passed.InParent.KeyExpression != nil {
|
||||||
@@ -142,6 +146,23 @@ func (n *nodeExpandModule) Execute(ctx context.Context, evalCtx EvalContext, op
|
|||||||
}
|
}
|
||||||
expander.SetModuleForEach(module, call, forEach)
|
expander.SetModuleForEach(module, call, forEach)
|
||||||
|
|
||||||
|
case n.ModuleCall.Enabled != nil:
|
||||||
|
// For enabled expressions, we need to evaluate in the parent module context
|
||||||
|
// since the expression may reference variables defined in the parent module. e.g.
|
||||||
|
// variable "on" { type = bool }
|
||||||
|
// module "mod1" {
|
||||||
|
// source = "./mod1"
|
||||||
|
// lifecycle {
|
||||||
|
// enabled = var.on
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
parentEvalCtx := evalCtx.WithPath(module.Parent())
|
||||||
|
enabled, enDiags := evaluateEnabledExpression(ctx, n.ModuleCall.Enabled, parentEvalCtx)
|
||||||
|
diags = diags.Append(enDiags)
|
||||||
|
if diags.HasErrors() {
|
||||||
|
return diags
|
||||||
|
}
|
||||||
|
expander.SetModuleEnabled(module, call, enabled)
|
||||||
default:
|
default:
|
||||||
expander.SetModuleSingle(module, call)
|
expander.SetModuleSingle(module, call)
|
||||||
}
|
}
|
||||||
|
|||||||
19
internal/tofu/testdata/apply-enabled-module/apply-enabled-module.tf
vendored
Normal file
19
internal/tofu/testdata/apply-enabled-module/apply-enabled-module.tf
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
variable "on" {
|
||||||
|
type = bool
|
||||||
|
}
|
||||||
|
|
||||||
|
module "mod1" {
|
||||||
|
source = "./mod1"
|
||||||
|
|
||||||
|
lifecycle {
|
||||||
|
enabled = var.on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
output "result" {
|
||||||
|
// This is in a 1-tuple just because OpenTofu treats a fully-null
|
||||||
|
// root module output value as if it wasn't declared at all,
|
||||||
|
// but we want to make sure we're actually testing the result
|
||||||
|
// of this resource directly.
|
||||||
|
value = [try(module.mod1.result, "")]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user