-
-
Notifications
You must be signed in to change notification settings - Fork 981
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Locals #802
Locals #802
Changes from 8 commits
73e3c3e
cb445c4
521c6ee
12610aa
d763e80
4661f90
9eceb15
9a46cd6
3601cfe
a107c89
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,15 +2,16 @@ package config | |
|
||
import ( | ||
"fmt" | ||
"github.com/hashicorp/hcl2/gohcl" | ||
"github.com/hashicorp/hcl2/hcl" | ||
"github.com/hashicorp/hcl2/hclparse" | ||
"github.com/zclconf/go-cty/cty" | ||
"os" | ||
"path/filepath" | ||
"reflect" | ||
"strings" | ||
|
||
"github.com/hashicorp/hcl2/gohcl" | ||
"github.com/hashicorp/hcl2/hcl" | ||
"github.com/hashicorp/hcl2/hclparse" | ||
"github.com/zclconf/go-cty/cty" | ||
|
||
"github.com/gruntwork-io/terragrunt/errors" | ||
"github.com/gruntwork-io/terragrunt/options" | ||
"github.com/gruntwork-io/terragrunt/remote" | ||
|
@@ -28,6 +29,7 @@ type TerragruntConfig struct { | |
Skip bool | ||
IamRole string | ||
Inputs map[string]interface{} | ||
Locals map[string]interface{} | ||
} | ||
|
||
func (conf *TerragruntConfig) String() string { | ||
|
@@ -45,6 +47,15 @@ type terragruntConfigFile struct { | |
PreventDestroy *bool `hcl:"prevent_destroy,attr"` | ||
Skip *bool `hcl:"skip,attr"` | ||
IamRole *string `hcl:"iam_role,attr"` | ||
|
||
// This should be ignored | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why ignored? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This needs to be skipped here because However, we don't want to completely omit the existence of it because we want a syntax error if we have blocks that terragrunt doesn't expect (e.g typos). Hence it is added here as an attribute but the struct won't attempt to parse anything in it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps expand the comment a bit to explain this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
Locals *terragruntLocal `hcl:"locals,block"` | ||
} | ||
|
||
// We use a struct designed to not parse the block, as locals are parsed and decoded using a special routine that allows | ||
// references to the other locals in the same block. | ||
type terragruntLocal struct { | ||
Remain hcl.Body `hcl:",remain"` | ||
} | ||
|
||
type terragruntInclude struct { | ||
|
@@ -240,7 +251,8 @@ func ParseConfigFile(filename string, terragruntOptions *options.TerragruntOptio | |
// Parse the Terragrunt config contained in the given string and merge it with the given include config (if any) | ||
func ParseConfigString(configString string, terragruntOptions *options.TerragruntOptions, includeFromChild *IncludeConfig, filename string) (*TerragruntConfig, error) { | ||
// Parse the HCL string into an AST body that can be decoded multiple times later without having to re-parse | ||
file, err := parseHcl(configString, filename) | ||
parser := hclparse.NewParser() | ||
file, err := parseHcl(parser, configString, filename) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -251,6 +263,13 @@ func ParseConfigString(configString string, terragruntOptions *options.Terragrun | |
return nil, err | ||
} | ||
|
||
// Evaluate all the expressions in the locals block separately and generate the variables list to use in the | ||
// evaluation context. | ||
locals, err := evaluateLocalsBlock(terragruntOptions, parser, file, filename) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
var includeForDecode *IncludeConfig = nil | ||
if terragruntInclude.Include != nil && includeFromChild != nil { | ||
return nil, errors.WithStackTrace(TooManyLevelsOfInheritance{ | ||
|
@@ -266,7 +285,7 @@ func ParseConfigString(configString string, terragruntOptions *options.Terragrun | |
|
||
// Decode the rest of the config, passing in this config's `include` block or the child's `include` block, whichever | ||
// is appropriate | ||
terragruntConfigFile, err := decodeAsTerragruntConfigFile(file, filename, terragruntOptions, includeForDecode) | ||
terragruntConfigFile, err := decodeAsTerragruntConfigFile(file, filename, terragruntOptions, includeForDecode, locals) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
@@ -299,24 +318,37 @@ func ParseConfigString(configString string, terragruntOptions *options.Terragrun | |
// an include block) | ||
func decodeAsTerragruntInclude(file *hcl.File, filename string, terragruntOptions *options.TerragruntOptions) (*terragruntInclude, error) { | ||
terragruntInclude := terragruntInclude{} | ||
err := decodeHcl(file, filename, &terragruntInclude, terragruntOptions, nil) | ||
err := decodeHcl(file, filename, &terragruntInclude, terragruntOptions, nil, nil) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah good point! Updated the evaluation order so it can be there. |
||
if err != nil { | ||
return nil, err | ||
} | ||
return &terragruntInclude, nil | ||
} | ||
|
||
func decodeAsTerragruntConfigFile(file *hcl.File, filename string, terragruntOptions *options.TerragruntOptions, include *IncludeConfig) (*terragruntConfigFile, error) { | ||
func decodeAsTerragruntConfigFile( | ||
file *hcl.File, | ||
filename string, | ||
terragruntOptions *options.TerragruntOptions, | ||
include *IncludeConfig, | ||
locals map[string]cty.Value, | ||
) (*terragruntConfigFile, error) { | ||
terragruntConfig := terragruntConfigFile{} | ||
err := decodeHcl(file, filename, &terragruntConfig, terragruntOptions, include) | ||
err := decodeHcl(file, filename, &terragruntConfig, terragruntOptions, include, locals) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &terragruntConfig, nil | ||
} | ||
|
||
// decodeHcl uses the HCL2 parser to decode the parsed HCL into the struct specified by out. | ||
func decodeHcl(file *hcl.File, filename string, out interface{}, terragruntOptions *options.TerragruntOptions, include *IncludeConfig) (err error) { | ||
func decodeHcl( | ||
file *hcl.File, | ||
filename string, | ||
out interface{}, | ||
terragruntOptions *options.TerragruntOptions, | ||
include *IncludeConfig, | ||
locals map[string]cty.Value, | ||
) (err error) { | ||
// The HCL2 parser and especially cty conversions will panic in many types of errors, so we have to recover from | ||
// those panics here and convert them to normal errors | ||
defer func() { | ||
|
@@ -325,7 +357,13 @@ func decodeHcl(file *hcl.File, filename string, out interface{}, terragruntOptio | |
} | ||
}() | ||
|
||
evalContext := CreateTerragruntEvalContext(filename, terragruntOptions, include) | ||
// Convert locals to a cty object for use in the evaluation context. Otherwise, we can't bind the whole map under | ||
// the name `local`. | ||
localsAsCty, err := convertLocalsMapToCtyVal(locals) | ||
if err != nil { | ||
return err | ||
} | ||
evalContext := CreateTerragruntEvalContext(filename, terragruntOptions, include, localsAsCty) | ||
|
||
decodeDiagnostics := gohcl.DecodeBody(file.Body, evalContext, out) | ||
if decodeDiagnostics != nil && decodeDiagnostics.HasErrors() { | ||
|
@@ -336,7 +374,7 @@ func decodeHcl(file *hcl.File, filename string, out interface{}, terragruntOptio | |
} | ||
|
||
// parseHcl uses the HCL2 parser to parse the given string into an HCL file body. | ||
func parseHcl(hcl string, filename string) (file *hcl.File, err error) { | ||
func parseHcl(parser *hclparse.Parser, hcl string, filename string) (file *hcl.File, err error) { | ||
// The HCL2 parser and especially cty conversions will panic in many types of errors, so we have to recover from | ||
// those panics here and convert them to normal errors | ||
defer func() { | ||
|
@@ -345,8 +383,6 @@ func parseHcl(hcl string, filename string) (file *hcl.File, err error) { | |
} | ||
}() | ||
|
||
parser := hclparse.NewParser() | ||
|
||
file, parseDiagnostics := parser.ParseHCL([]byte(hcl), filename) | ||
if parseDiagnostics != nil && parseDiagnostics.HasErrors() { | ||
return nil, parseDiagnostics | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thx for adding 👍