From 6fad32b033ec06f78d496cd9cff600431907639c Mon Sep 17 00:00:00 2001 From: Martin Atkins Date: Thu, 29 Feb 2024 11:28:14 -0800 Subject: [PATCH] configs: Variables and outputs can be "ephemeral" When the ephemeral_values experiment is active, a module author can designate individual input variables and output values as being "ephemeral", which doesn't currently do anything but in future commits will represent that the values can be used only in locations that don't require Terraform to persist the value as part of state snapshots or saved plan files. --- internal/configs/experiments.go | 23 +++++++++++++++++++ internal/configs/module_merge.go | 8 +++++++ internal/configs/named_values.go | 22 ++++++++++++++++++ internal/configs/parser_config_test.go | 9 ++++++++ .../warning-files/ephemeral_inputs_outputs.tf | 21 +++++++++++++++++ 5 files changed, 83 insertions(+) create mode 100644 internal/configs/testdata/warning-files/ephemeral_inputs_outputs.tf diff --git a/internal/configs/experiments.go b/internal/configs/experiments.go index 163e75e6d1..d3fd6a4e59 100644 --- a/internal/configs/experiments.go +++ b/internal/configs/experiments.go @@ -208,5 +208,28 @@ func checkModuleExperiments(m *Module) hcl.Diagnostics { } */ + if !m.ActiveExperiments.Has(experiments.EphemeralValues) { + for _, oc := range m.Outputs { + if oc.EphemeralSet { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Ephemeral values are experimental", + Detail: "This feature is currently an opt-in experiment, subject to change in future releases based on feedback.\n\nActivate the feature for this module by adding ephemeral_values to the list of active experiments.", + Subject: oc.DeclRange.Ptr(), + }) + } + } + for _, vc := range m.Variables { + if vc.EphemeralSet { + diags = append(diags, &hcl.Diagnostic{ + Severity: hcl.DiagError, + Summary: "Ephemeral values are experimental", + Detail: "This feature is currently an opt-in experiment, subject to change in future releases based on feedback.\n\nActivate the feature for this module by adding ephemeral_values to the list of active experiments.", + Subject: vc.DeclRange.Ptr(), + }) + } + } + } + return diags } diff --git a/internal/configs/module_merge.go b/internal/configs/module_merge.go index 01c3f2088c..42e956e5db 100644 --- a/internal/configs/module_merge.go +++ b/internal/configs/module_merge.go @@ -49,6 +49,10 @@ func (v *Variable) merge(ov *Variable) hcl.Diagnostics { v.Sensitive = ov.Sensitive v.SensitiveSet = ov.SensitiveSet } + if ov.EphemeralSet { + v.Ephemeral = ov.Ephemeral + v.EphemeralSet = ov.EphemeralSet + } if ov.Default != cty.NilVal { v.Default = ov.Default } @@ -148,6 +152,10 @@ func (o *Output) merge(oo *Output) hcl.Diagnostics { o.Sensitive = oo.Sensitive o.SensitiveSet = oo.SensitiveSet } + if oo.EphemeralSet { + o.Ephemeral = oo.Ephemeral + o.EphemeralSet = oo.EphemeralSet + } // We don't allow depends_on to be overridden because that is likely to // cause confusing misbehavior. diff --git a/internal/configs/named_values.go b/internal/configs/named_values.go index 43a624d9d8..ad82960fe3 100644 --- a/internal/configs/named_values.go +++ b/internal/configs/named_values.go @@ -35,9 +35,11 @@ type Variable struct { ParsingMode VariableParsingMode Validations []*CheckRule Sensitive bool + Ephemeral bool DescriptionSet bool SensitiveSet bool + EphemeralSet bool // Nullable indicates that null is a valid value for this variable. Setting // Nullable to false means that the module can expect this variable to @@ -120,6 +122,12 @@ func decodeVariableBlock(block *hcl.Block, override bool) (*Variable, hcl.Diagno v.SensitiveSet = true } + if attr, exists := content.Attributes["ephemeral"]; exists { + valDiags := gohcl.DecodeExpression(attr.Expr, nil, &v.Ephemeral) + diags = append(diags, valDiags...) + v.EphemeralSet = true + } + if attr, exists := content.Attributes["nullable"]; exists { valDiags := gohcl.DecodeExpression(attr.Expr, nil, &v.Nullable) diags = append(diags, valDiags...) @@ -332,11 +340,13 @@ type Output struct { Expr hcl.Expression DependsOn []hcl.Traversal Sensitive bool + Ephemeral bool Preconditions []*CheckRule DescriptionSet bool SensitiveSet bool + EphemeralSet bool DeclRange hcl.Range } @@ -382,6 +392,12 @@ func decodeOutputBlock(block *hcl.Block, override bool) (*Output, hcl.Diagnostic o.SensitiveSet = true } + if attr, exists := content.Attributes["ephemeral"]; exists { + valDiags := gohcl.DecodeExpression(attr.Expr, nil, &o.Ephemeral) + diags = append(diags, valDiags...) + o.EphemeralSet = true + } + if attr, exists := content.Attributes["depends_on"]; exists { deps, depsDiags := decodeDependsOn(attr) diags = append(diags, depsDiags...) @@ -473,6 +489,9 @@ var variableBlockSchema = &hcl.BodySchema{ { Name: "sensitive", }, + { + Name: "ephemeral", + }, { Name: "nullable", }, @@ -499,6 +518,9 @@ var outputBlockSchema = &hcl.BodySchema{ { Name: "sensitive", }, + { + Name: "ephemeral", + }, }, Blocks: []hcl.BlockHeaderSchema{ {Type: "precondition"}, diff --git a/internal/configs/parser_config_test.go b/internal/configs/parser_config_test.go index c305cd1fab..e85bfa2da2 100644 --- a/internal/configs/parser_config_test.go +++ b/internal/configs/parser_config_test.go @@ -192,18 +192,27 @@ func TestParserLoadConfigFileWarning(t *testing.T) { sc := bufio.NewScanner(bytes.NewReader(src)) wantWarnings := make(map[int]string) lineNum := 1 + allowExperiments := false for sc.Scan() { lineText := sc.Text() if idx := strings.Index(lineText, marker); idx != -1 { summaryText := lineText[idx+len(marker):] wantWarnings[lineNum] = summaryText } + if lineText == "# ALLOW-LANGUAGE-EXPERIMENTS" { + allowExperiments = true + } lineNum++ } parser := testParser(map[string]string{ name: string(src), }) + // Some inputs use a special comment to request that they be + // permitted to use language experiments. We typically use that + // to test that the experiment opt-in is working and is causing + // the expected "you are using experimental features" warning. + parser.AllowLanguageExperiments(allowExperiments) _, diags := parser.LoadConfigFile(name) if diags.HasErrors() { diff --git a/internal/configs/testdata/warning-files/ephemeral_inputs_outputs.tf b/internal/configs/testdata/warning-files/ephemeral_inputs_outputs.tf new file mode 100644 index 0000000000..feedccd606 --- /dev/null +++ b/internal/configs/testdata/warning-files/ephemeral_inputs_outputs.tf @@ -0,0 +1,21 @@ +# ALLOW-LANGUAGE-EXPERIMENTS + +# If the ephemeral_values features get stabilized, this test input will fail +# due to the experiment being concluded, in which case it might make sense to +# move this file to valid-files and remove the experiment opt-in +# +# If this experiment is removed without stabilizing it then this will fail +# and should be removed altogether. + +terraform { + experiments = [ephemeral_values] # WARNING: Experimental feature "ephemeral_values" is active +} + +variable "in" { + ephemeral = true +} + +output "out" { + ephemeral = true + value = var.in +}