Remove interpolation-only warning
These interpolations are removed when upgrading using 0.12upgrade, and are removed in terraform fmt in many cases
This commit is contained in:
parent
3da5d2bdf6
commit
fa7c3d7e10
|
@ -2,5 +2,5 @@ module "super#module" {
|
||||||
}
|
}
|
||||||
|
|
||||||
module "super" {
|
module "super" {
|
||||||
source = "${var.modulename}"
|
source = var.modulename
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"valid": false,
|
"valid": false,
|
||||||
"error_count": 6,
|
"error_count": 6,
|
||||||
"warning_count": 1,
|
"warning_count": 0,
|
||||||
"diagnostics": [
|
"diagnostics": [
|
||||||
{
|
{
|
||||||
"severity": "error",
|
"severity": "error",
|
||||||
|
@ -40,9 +40,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"severity": "warning",
|
"severity": "error",
|
||||||
"summary": "Interpolation-only expressions are deprecated",
|
"summary": "Variables not allowed",
|
||||||
"detail": "Terraform 0.11 and earlier required all non-constant expressions to be provided via interpolation syntax, but this pattern is now deprecated. To silence this warning, remove the \"${ sequence from the start and the }\" sequence from the end of this expression, leaving just the inner expression.\n\nTemplate interpolation syntax is still used to construct strings from expressions when the template includes multiple interpolation sequences or a mixture of literal strings and interpolations. This deprecation applies only to templates that consist entirely of a single interpolation sequence.",
|
"detail": "Variables may not be used here.",
|
||||||
"range": {
|
"range": {
|
||||||
"filename": "testdata/validate-invalid/incorrectmodulename/main.tf",
|
"filename": "testdata/validate-invalid/incorrectmodulename/main.tf",
|
||||||
"start": {
|
"start": {
|
||||||
|
@ -51,27 +51,9 @@
|
||||||
"byte": 55
|
"byte": 55
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 5,
|
|
||||||
"column": 31,
|
|
||||||
"byte": 74
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"severity": "error",
|
|
||||||
"summary": "Variables not allowed",
|
|
||||||
"detail": "Variables may not be used here.",
|
|
||||||
"range": {
|
|
||||||
"filename": "testdata/validate-invalid/incorrectmodulename/main.tf",
|
|
||||||
"start": {
|
|
||||||
"line": 5,
|
"line": 5,
|
||||||
"column": 15,
|
"column": 15,
|
||||||
"byte": 58
|
"byte": 58
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"line": 5,
|
|
||||||
"column": 18,
|
|
||||||
"byte": 61
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -88,8 +70,8 @@
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 5,
|
"line": 5,
|
||||||
"column": 31,
|
"column": 26,
|
||||||
"byte": 74
|
"byte": 69
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,6 +3,6 @@ resource "test_instance" "foo" {
|
||||||
|
|
||||||
network_interface {
|
network_interface {
|
||||||
device_index = 0
|
device_index = 0
|
||||||
description = "${var.description}"
|
description = var.description
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
{
|
{
|
||||||
"valid": false,
|
"valid": false,
|
||||||
"error_count": 1,
|
"error_count": 1,
|
||||||
"warning_count": 1,
|
"warning_count": 0,
|
||||||
"diagnostics": [
|
"diagnostics": [
|
||||||
{
|
{
|
||||||
"severity": "warning",
|
"severity": "error",
|
||||||
"summary": "Interpolation-only expressions are deprecated",
|
"summary": "Reference to undeclared input variable",
|
||||||
"detail": "Terraform 0.11 and earlier required all non-constant expressions to be provided via interpolation syntax, but this pattern is now deprecated. To silence this warning, remove the \"${ sequence from the start and the }\" sequence from the end of this expression, leaving just the inner expression.\n\nTemplate interpolation syntax is still used to construct strings from expressions when the template includes multiple interpolation sequences or a mixture of literal strings and interpolations. This deprecation applies only to templates that consist entirely of a single interpolation sequence.",
|
"detail": "An input variable with the name \"description\" has not been declared. This variable can be declared with a variable \"description\" {} block.",
|
||||||
"range": {
|
"range": {
|
||||||
"filename": "testdata/validate-invalid/missing_var/main.tf",
|
"filename": "testdata/validate-invalid/missing_var/main.tf",
|
||||||
"start": {
|
"start": {
|
||||||
|
@ -16,26 +16,8 @@
|
||||||
},
|
},
|
||||||
"end": {
|
"end": {
|
||||||
"line": 6,
|
"line": 6,
|
||||||
"column": 41,
|
"column": 36,
|
||||||
"byte": 137
|
"byte": 132
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"severity": "error",
|
|
||||||
"summary": "Reference to undeclared input variable",
|
|
||||||
"detail": "An input variable with the name \"description\" has not been declared. This variable can be declared with a variable \"description\" {} block.",
|
|
||||||
"range": {
|
|
||||||
"filename": "testdata/validate-invalid/missing_var/main.tf",
|
|
||||||
"start": {
|
|
||||||
"line": 6,
|
|
||||||
"column": 24,
|
|
||||||
"byte": 120
|
|
||||||
},
|
|
||||||
"end": {
|
|
||||||
"line": 6,
|
|
||||||
"column": 39,
|
|
||||||
"byte": 135
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -107,121 +107,3 @@ func shimIsIgnoreChangesStar(expr hcl.Expression) bool {
|
||||||
}
|
}
|
||||||
return val.AsString() == "*"
|
return val.AsString() == "*"
|
||||||
}
|
}
|
||||||
|
|
||||||
// warnForDeprecatedInterpolations returns warning diagnostics if the given
|
|
||||||
// body can be proven to contain attributes whose expressions are native
|
|
||||||
// syntax expressions consisting entirely of a single template interpolation,
|
|
||||||
// which is a deprecated way to include a non-literal value in configuration.
|
|
||||||
//
|
|
||||||
// This is a best-effort sort of thing which relies on the physical HCL native
|
|
||||||
// syntax AST, so it might not catch everything. The main goal is to catch the
|
|
||||||
// "obvious" cases in order to help spread awareness that this old form is
|
|
||||||
// deprecated, when folks copy it from older examples they've found on the
|
|
||||||
// internet that were written for Terraform 0.11 or earlier.
|
|
||||||
func warnForDeprecatedInterpolationsInBody(body hcl.Body) hcl.Diagnostics {
|
|
||||||
var diags hcl.Diagnostics
|
|
||||||
|
|
||||||
nativeBody, ok := body.(*hclsyntax.Body)
|
|
||||||
if !ok {
|
|
||||||
// If it's not native syntax then we've nothing to do here.
|
|
||||||
return diags
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, attr := range nativeBody.Attributes {
|
|
||||||
moreDiags := warnForDeprecatedInterpolationsInExpr(attr.Expr)
|
|
||||||
diags = append(diags, moreDiags...)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, block := range nativeBody.Blocks {
|
|
||||||
// We'll also go hunting in nested blocks
|
|
||||||
moreDiags := warnForDeprecatedInterpolationsInBody(block.Body)
|
|
||||||
diags = append(diags, moreDiags...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return diags
|
|
||||||
}
|
|
||||||
|
|
||||||
func warnForDeprecatedInterpolationsInExpr(expr hcl.Expression) hcl.Diagnostics {
|
|
||||||
node, ok := expr.(hclsyntax.Node)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
walker := warnForDeprecatedInterpolationsWalker{
|
|
||||||
// create some capacity so that we can deal with simple expressions
|
|
||||||
// without any further allocation during our walk.
|
|
||||||
contextStack: make([]warnForDeprecatedInterpolationsContext, 0, 16),
|
|
||||||
}
|
|
||||||
return hclsyntax.Walk(node, &walker)
|
|
||||||
}
|
|
||||||
|
|
||||||
// warnForDeprecatedInterpolationsWalker is an implementation of
|
|
||||||
// hclsyntax.Walker that we use to generate deprecation warnings for template
|
|
||||||
// expressions that consist entirely of a single interpolation directive.
|
|
||||||
// That's always redundant in Terraform v0.12 and later, but tends to show up
|
|
||||||
// when people work from examples written for Terraform v0.11 or earlier.
|
|
||||||
type warnForDeprecatedInterpolationsWalker struct {
|
|
||||||
contextStack []warnForDeprecatedInterpolationsContext
|
|
||||||
}
|
|
||||||
|
|
||||||
var _ hclsyntax.Walker = (*warnForDeprecatedInterpolationsWalker)(nil)
|
|
||||||
|
|
||||||
type warnForDeprecatedInterpolationsContext int
|
|
||||||
|
|
||||||
const (
|
|
||||||
warnForDeprecatedInterpolationsNormal warnForDeprecatedInterpolationsContext = 0
|
|
||||||
warnForDeprecatedInterpolationsObjKey warnForDeprecatedInterpolationsContext = 1
|
|
||||||
)
|
|
||||||
|
|
||||||
func (w *warnForDeprecatedInterpolationsWalker) Enter(node hclsyntax.Node) hcl.Diagnostics {
|
|
||||||
var diags hcl.Diagnostics
|
|
||||||
|
|
||||||
context := warnForDeprecatedInterpolationsNormal
|
|
||||||
switch node := node.(type) {
|
|
||||||
case *hclsyntax.ObjectConsKeyExpr:
|
|
||||||
context = warnForDeprecatedInterpolationsObjKey
|
|
||||||
case *hclsyntax.TemplateWrapExpr:
|
|
||||||
// hclsyntax.TemplateWrapExpr is a special node type used by HCL only
|
|
||||||
// for the situation where a template is just a single interpolation,
|
|
||||||
// so we don't need to do anything further to distinguish that
|
|
||||||
// situation. ("normal" templates are *hclsyntax.TemplateExpr.)
|
|
||||||
|
|
||||||
const summary = "Interpolation-only expressions are deprecated"
|
|
||||||
switch w.currentContext() {
|
|
||||||
case warnForDeprecatedInterpolationsObjKey:
|
|
||||||
// This case requires a different resolution in order to retain
|
|
||||||
// the same meaning, so we have a different detail message for
|
|
||||||
// it.
|
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
|
||||||
Severity: hcl.DiagWarning,
|
|
||||||
Summary: summary,
|
|
||||||
Detail: "Terraform 0.11 and earlier required all non-constant expressions to be provided via interpolation syntax, but this pattern is now deprecated.\n\nTo silence this warning, replace the \"${ opening sequence and the }\" closing sequence with opening and closing parentheses respectively. Parentheses are needed here to mark this as an expression to be evaluated, rather than as a literal string key.\n\nTemplate interpolation syntax is still used to construct strings from expressions when the template includes multiple interpolation sequences or a mixture of literal strings and interpolations. This deprecation applies only to templates that consist entirely of a single interpolation sequence.",
|
|
||||||
Subject: node.Range().Ptr(),
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
diags = append(diags, &hcl.Diagnostic{
|
|
||||||
Severity: hcl.DiagWarning,
|
|
||||||
Summary: summary,
|
|
||||||
Detail: "Terraform 0.11 and earlier required all non-constant expressions to be provided via interpolation syntax, but this pattern is now deprecated. To silence this warning, remove the \"${ sequence from the start and the }\" sequence from the end of this expression, leaving just the inner expression.\n\nTemplate interpolation syntax is still used to construct strings from expressions when the template includes multiple interpolation sequences or a mixture of literal strings and interpolations. This deprecation applies only to templates that consist entirely of a single interpolation sequence.",
|
|
||||||
Subject: node.Range().Ptr(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Note the context of the current node for when we potentially visit
|
|
||||||
// child nodes.
|
|
||||||
w.contextStack = append(w.contextStack, context)
|
|
||||||
return diags
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *warnForDeprecatedInterpolationsWalker) Exit(node hclsyntax.Node) hcl.Diagnostics {
|
|
||||||
w.contextStack = w.contextStack[:len(w.contextStack)-1]
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *warnForDeprecatedInterpolationsWalker) currentContext() warnForDeprecatedInterpolationsContext {
|
|
||||||
if len(w.contextStack) == 0 {
|
|
||||||
return warnForDeprecatedInterpolationsNormal
|
|
||||||
}
|
|
||||||
return w.contextStack[len(w.contextStack)-1]
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
package configs
|
|
||||||
|
|
||||||
import (
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/hashicorp/hcl/v2"
|
|
||||||
"github.com/hashicorp/hcl/v2/hclsyntax"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestWarnForDeprecatedInterpolationsInExpr(t *testing.T) {
|
|
||||||
tests := []struct {
|
|
||||||
Expr string
|
|
||||||
WantSubstr string
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
`"${foo}"`,
|
|
||||||
"leaving just the inner expression",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
`{"${foo}" = 1}`,
|
|
||||||
// Special message for object key expressions, because just
|
|
||||||
// removing the interpolation markers would change the meaning
|
|
||||||
// in that context.
|
|
||||||
"opening and closing parentheses respectively",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
`{upper("${foo}") = 1}`,
|
|
||||||
// But no special message if the template is just descended from an
|
|
||||||
// object key, because the special interpretation applies only to
|
|
||||||
// a naked reference in te object key position.
|
|
||||||
"leaving just the inner expression",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, test := range tests {
|
|
||||||
t.Run(test.Expr, func(t *testing.T) {
|
|
||||||
expr, diags := hclsyntax.ParseExpression([]byte(test.Expr), "", hcl.InitialPos)
|
|
||||||
if diags.HasErrors() {
|
|
||||||
t.Fatalf("parse error: %s", diags.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
diags = warnForDeprecatedInterpolationsInExpr(expr)
|
|
||||||
if !diagWarningsContainSubstring(diags, test.WantSubstr) {
|
|
||||||
t.Errorf("wrong warning message\nwant detail substring: %s\ngot: %s", test.WantSubstr, diags.Error())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func diagWarningsContainSubstring(diags hcl.Diagnostics, want string) bool {
|
|
||||||
for _, diag := range diags {
|
|
||||||
if diag.Severity != hcl.DiagWarning {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.Contains(diag.Detail, want) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
|
@ -33,11 +33,6 @@ type ModuleCall struct {
|
||||||
func decodeModuleBlock(block *hcl.Block, override bool) (*ModuleCall, hcl.Diagnostics) {
|
func decodeModuleBlock(block *hcl.Block, override bool) (*ModuleCall, hcl.Diagnostics) {
|
||||||
var diags hcl.Diagnostics
|
var diags hcl.Diagnostics
|
||||||
|
|
||||||
// Produce deprecation messages for any pre-0.12-style
|
|
||||||
// single-interpolation-only expressions.
|
|
||||||
moreDiags := warnForDeprecatedInterpolationsInBody(block.Body)
|
|
||||||
diags = append(diags, moreDiags...)
|
|
||||||
|
|
||||||
mc := &ModuleCall{
|
mc := &ModuleCall{
|
||||||
Name: block.Labels[0],
|
Name: block.Labels[0],
|
||||||
DeclRange: block.DefRange,
|
DeclRange: block.DefRange,
|
||||||
|
|
|
@ -453,11 +453,6 @@ func decodeOutputBlock(block *hcl.Block, override bool) (*Output, hcl.Diagnostic
|
||||||
schema = schemaForOverrides(schema)
|
schema = schemaForOverrides(schema)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produce deprecation messages for any pre-0.12-style
|
|
||||||
// single-interpolation-only expressions.
|
|
||||||
moreDiags := warnForDeprecatedInterpolationsInBody(block.Body)
|
|
||||||
diags = append(diags, moreDiags...)
|
|
||||||
|
|
||||||
content, moreDiags := block.Body.Content(schema)
|
content, moreDiags := block.Body.Content(schema)
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
|
|
||||||
|
@ -522,11 +517,6 @@ func decodeLocalsBlock(block *hcl.Block) ([]*Local, hcl.Diagnostics) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produce deprecation messages for any pre-0.12-style
|
|
||||||
// single-interpolation-only expressions.
|
|
||||||
moreDiags := warnForDeprecatedInterpolationsInExpr(attr.Expr)
|
|
||||||
diags = append(diags, moreDiags...)
|
|
||||||
|
|
||||||
locals = append(locals, &Local{
|
locals = append(locals, &Local{
|
||||||
Name: name,
|
Name: name,
|
||||||
Expr: attr.Expr,
|
Expr: attr.Expr,
|
||||||
|
|
|
@ -30,13 +30,6 @@ type Provider struct {
|
||||||
func decodeProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
|
func decodeProviderBlock(block *hcl.Block) (*Provider, hcl.Diagnostics) {
|
||||||
var diags hcl.Diagnostics
|
var diags hcl.Diagnostics
|
||||||
|
|
||||||
// Produce deprecation messages for any pre-0.12-style
|
|
||||||
// single-interpolation-only expressions. We do this up front here because
|
|
||||||
// then we can also catch instances inside special blocks like "connection",
|
|
||||||
// before PartialContent extracts them.
|
|
||||||
moreDiags := warnForDeprecatedInterpolationsInBody(block.Body)
|
|
||||||
diags = append(diags, moreDiags...)
|
|
||||||
|
|
||||||
content, config, moreDiags := block.Body.PartialContent(providerBlockSchema)
|
content, config, moreDiags := block.Body.PartialContent(providerBlockSchema)
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
|
|
||||||
|
|
|
@ -92,13 +92,6 @@ func decodeResourceBlock(block *hcl.Block) (*Resource, hcl.Diagnostics) {
|
||||||
Managed: &ManagedResource{},
|
Managed: &ManagedResource{},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produce deprecation messages for any pre-0.12-style
|
|
||||||
// single-interpolation-only expressions. We do this up front here because
|
|
||||||
// then we can also catch instances inside special blocks like "connection",
|
|
||||||
// before PartialContent extracts them.
|
|
||||||
moreDiags := warnForDeprecatedInterpolationsInBody(block.Body)
|
|
||||||
diags = append(diags, moreDiags...)
|
|
||||||
|
|
||||||
content, remain, moreDiags := block.Body.PartialContent(resourceBlockSchema)
|
content, remain, moreDiags := block.Body.PartialContent(resourceBlockSchema)
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
r.Config = remain
|
r.Config = remain
|
||||||
|
@ -303,11 +296,6 @@ func decodeDataBlock(block *hcl.Block) (*Resource, hcl.Diagnostics) {
|
||||||
TypeRange: block.LabelRanges[0],
|
TypeRange: block.LabelRanges[0],
|
||||||
}
|
}
|
||||||
|
|
||||||
// Produce deprecation messages for any pre-0.12-style
|
|
||||||
// single-interpolation-only expressions.
|
|
||||||
moreDiags := warnForDeprecatedInterpolationsInBody(block.Body)
|
|
||||||
diags = append(diags, moreDiags...)
|
|
||||||
|
|
||||||
content, remain, moreDiags := block.Body.PartialContent(dataBlockSchema)
|
content, remain, moreDiags := block.Body.PartialContent(dataBlockSchema)
|
||||||
diags = append(diags, moreDiags...)
|
diags = append(diags, moreDiags...)
|
||||||
r.Config = remain
|
r.Config = remain
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
# It's redundant to write an expression that is just a single template
|
|
||||||
# interpolation with another expression inside, like "${foo}", but it
|
|
||||||
# was required before Terraform v0.12 and so there are lots of existing
|
|
||||||
# examples out there using that style.
|
|
||||||
#
|
|
||||||
# We are generating warnings for that situation in order to guide those
|
|
||||||
# who are following old examples toward the new idiom.
|
|
||||||
|
|
||||||
variable "triggers" {
|
|
||||||
type = "map" # WARNING: Quoted type constraints are deprecated
|
|
||||||
}
|
|
||||||
|
|
||||||
provider "null" {
|
|
||||||
foo = "${var.triggers["foo"]}" # WARNING: Interpolation-only expressions are deprecated
|
|
||||||
}
|
|
||||||
|
|
||||||
resource "null_resource" "a" {
|
|
||||||
triggers = "${var.triggers}" # WARNING: Interpolation-only expressions are deprecated
|
|
||||||
|
|
||||||
connection {
|
|
||||||
type = "ssh"
|
|
||||||
host = "${var.triggers["host"]}" # WARNING: Interpolation-only expressions are deprecated
|
|
||||||
}
|
|
||||||
|
|
||||||
provisioner "local-exec" {
|
|
||||||
single = "${var.triggers["greeting"]}" # WARNING: Interpolation-only expressions are deprecated
|
|
||||||
|
|
||||||
# No warning for this one, because there's more than just one interpolation
|
|
||||||
# in the template.
|
|
||||||
template = " ${var.triggers["greeting"]} "
|
|
||||||
|
|
||||||
wrapped = ["${var.triggers["greeting"]}"] # WARNING: Interpolation-only expressions are deprecated
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module "foo" {
|
|
||||||
source = "./foo"
|
|
||||||
foo = "${var.foo}" # WARNING: Interpolation-only expressions are deprecated
|
|
||||||
}
|
|
||||||
|
|
||||||
data "null_data_source" "b" {
|
|
||||||
inputs = {
|
|
||||||
host = "${var.triggers["host"]}" # WARNING: Interpolation-only expressions are deprecated
|
|
||||||
}
|
|
||||||
|
|
||||||
has_computed_default = "${var.foo}" # WARNING: Interpolation-only expressions are deprecated
|
|
||||||
}
|
|
||||||
|
|
||||||
output "output" {
|
|
||||||
value = "${var.foo}" # WARNING: Interpolation-only expressions are deprecated
|
|
||||||
}
|
|
||||||
|
|
||||||
locals {
|
|
||||||
foo = "${var.foo}" # WARNING: Interpolation-only expressions are deprecated
|
|
||||||
}
|
|
Loading…
Reference in New Issue