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.
TF-13085
Martin Atkins 2 years ago
parent 1ef2ad7d4c
commit 6fad32b033

@ -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
}

@ -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.

@ -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"},

@ -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() {

@ -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
}
Loading…
Cancel
Save