Refactor hcl2_upgrade (#10787)

This commit is contained in:
Megan Marsh 2021-03-19 02:24:49 -07:00 committed by GitHub
parent 4242cf3151
commit 502708b86a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 63 additions and 47 deletions

View File

@ -270,11 +270,7 @@ func (uc UnhandleableArgumentError) Error() string {
# Visit %s for more infos.`, uc.Call, uc.Correspondance, uc.Docs) # Visit %s for more infos.`, uc.Call, uc.Correspondance, uc.Docs)
} }
// transposeTemplatingCalls executes parts of blocks as go template files and replaces func fallbackReturn(err error, s []byte) []byte {
// their result with their hcl2 variant. If something goes wrong the template
// containing the go template string is returned.
func transposeTemplatingCalls(s []byte) []byte {
fallbackReturn := func(err error) []byte {
if strings.Contains(err.Error(), "unhandled") { if strings.Contains(err.Error(), "unhandled") {
return append([]byte(fmt.Sprintf("\n# %s\n", err)), s...) return append([]byte(fmt.Sprintf("\n# %s\n", err)), s...)
} }
@ -282,6 +278,10 @@ func transposeTemplatingCalls(s []byte) []byte {
return append([]byte(fmt.Sprintf("\n# could not parse template for following block: %q\n", err)), s...) return append([]byte(fmt.Sprintf("\n# could not parse template for following block: %q\n", err)), s...)
} }
// transposeTemplatingCalls executes parts of blocks as go template files and replaces
// their result with their hcl2 variant. If something goes wrong the template
// containing the go template string is returned.
func transposeTemplatingCalls(s []byte) []byte {
funcErrors := &multierror.Error{ funcErrors := &multierror.Error{
ErrorFormat: func(es []error) string { ErrorFormat: func(es []error) string {
if len(es) == 1 { if len(es) == 1 {
@ -437,14 +437,14 @@ func transposeTemplatingCalls(s []byte) []byte {
Parse(string(s)) Parse(string(s))
if err != nil { if err != nil {
return fallbackReturn(err) return fallbackReturn(err, s)
} }
str := &bytes.Buffer{} str := &bytes.Buffer{}
// PASSTHROUGHS is a map of variable-specific golang text template fields // PASSTHROUGHS is a map of variable-specific golang text template fields
// that should remain in the text template format. // that should remain in the text template format.
if err := tpl.Execute(str, PASSTHROUGHS); err != nil { if err := tpl.Execute(str, PASSTHROUGHS); err != nil {
return fallbackReturn(err) return fallbackReturn(err, s)
} }
out := str.Bytes() out := str.Bytes()
@ -461,14 +461,6 @@ func transposeTemplatingCalls(s []byte) []byte {
// In variableTransposeTemplatingCalls the definition of aws_secretsmanager function will create a data source // In variableTransposeTemplatingCalls the definition of aws_secretsmanager function will create a data source
// with the same name as the variable. // with the same name as the variable.
func variableTransposeTemplatingCalls(s []byte) (isLocal bool, body []byte) { func variableTransposeTemplatingCalls(s []byte) (isLocal bool, body []byte) {
fallbackReturn := func(err error) []byte {
if strings.Contains(err.Error(), "unhandled") {
return append([]byte(fmt.Sprintf("\n# %s\n", err)), s...)
}
return append([]byte(fmt.Sprintf("\n# could not parse template for following block: %q\n", err)), s...)
}
setIsLocal := func(a ...string) string { setIsLocal := func(a ...string) string {
isLocal = true isLocal = true
return "" return ""
@ -510,14 +502,14 @@ func variableTransposeTemplatingCalls(s []byte) (isLocal bool, body []byte) {
Parse(string(s)) Parse(string(s))
if err != nil { if err != nil {
return isLocal, fallbackReturn(err) return isLocal, fallbackReturn(err, s)
} }
str := &bytes.Buffer{} str := &bytes.Buffer{}
// PASSTHROUGHS is a map of variable-specific golang text template fields // PASSTHROUGHS is a map of variable-specific golang text template fields
// that should remain in the text template format. // that should remain in the text template format.
if err := tpl.Execute(str, PASSTHROUGHS); err != nil { if err := tpl.Execute(str, PASSTHROUGHS); err != nil {
return isLocal, fallbackReturn(err) return isLocal, fallbackReturn(err, s)
} }
return isLocal, str.Bytes() return isLocal, str.Bytes()
@ -682,12 +674,49 @@ type VariableParser struct {
localsOut []byte localsOut []byte
} }
func makeLocal(variable *template.Variable, sensitive bool, localBody *hclwrite.Body, localsContent *hclwrite.File, hasLocals *bool) []byte {
if sensitive {
// Create Local block because this is sensitive
sensitiveLocalContent := hclwrite.NewEmptyFile()
body := sensitiveLocalContent.Body()
body.AppendNewline()
sensitiveLocalBody := body.AppendNewBlock("local", []string{variable.Key}).Body()
sensitiveLocalBody.SetAttributeValue("sensitive", cty.BoolVal(true))
sensitiveLocalBody.SetAttributeValue("expression", hcl2shim.HCL2ValueFromConfigValue(variable.Default))
localsVariableMap[variable.Key] = "local"
return sensitiveLocalContent.Bytes()
}
localBody.SetAttributeValue(variable.Key, hcl2shim.HCL2ValueFromConfigValue(variable.Default))
localsVariableMap[variable.Key] = "locals"
*hasLocals = true
return []byte{}
}
func makeVariable(variable *template.Variable, sensitive bool) []byte {
variablesContent := hclwrite.NewEmptyFile()
variablesBody := variablesContent.Body()
variablesBody.AppendNewline()
variableBody := variablesBody.AppendNewBlock("variable", []string{variable.Key}).Body()
variableBody.SetAttributeRaw("type", hclwrite.Tokens{&hclwrite.Token{Bytes: []byte("string")}})
if variable.Default != "" || !variable.Required {
shimmed := hcl2shim.HCL2ValueFromConfigValue(variable.Default)
variableBody.SetAttributeValue("default", shimmed)
}
if sensitive {
variableBody.SetAttributeValue("sensitive", cty.BoolVal(true))
}
return variablesContent.Bytes()
}
func (p *VariableParser) Parse(tpl *template.Template) error { func (p *VariableParser) Parse(tpl *template.Template) error {
// OutPut Locals and Local blocks // Output Locals and Local blocks
localsContent := hclwrite.NewEmptyFile() localsContent := hclwrite.NewEmptyFile()
localsBody := localsContent.Body() localsBody := localsContent.Body()
localsBody.AppendNewline() localsBody.AppendNewline()
localBody := localsBody.AppendNewBlock("locals", nil).Body() localBody := localsBody.AppendNewBlock("locals", nil).Body()
hasLocals := false
if len(p.variablesOut) == 0 { if len(p.variablesOut) == 0 {
p.variablesOut = []byte{} p.variablesOut = []byte{}
@ -707,47 +736,34 @@ func (p *VariableParser) Parse(tpl *template.Template) error {
}) })
} }
hasLocals := false
for _, variable := range variables { for _, variable := range variables {
variablesContent := hclwrite.NewEmptyFile() // Create new HCL2 "variables" block, and populate the "value"
variablesBody := variablesContent.Body() // field with the "Default" value from the JSON variable.
variablesBody.AppendNewline()
variableBody := variablesBody.AppendNewBlock("variable", []string{variable.Key}).Body()
variableBody.SetAttributeRaw("type", hclwrite.Tokens{&hclwrite.Token{Bytes: []byte("string")}})
if variable.Default != "" || !variable.Required { // Interpolate Jsonval first as an hcl variable to determine if it is
variableBody.SetAttributeValue("default", hcl2shim.HCL2ValueFromConfigValue(variable.Default)) // a local.
} isLocal, _ := variableTransposeTemplatingCalls([]byte(variable.Default))
sensitive := false sensitive := false
if isSensitiveVariable(variable.Key, tpl.SensitiveVariables) { if isSensitiveVariable(variable.Key, tpl.SensitiveVariables) {
sensitive = true sensitive = true
variableBody.SetAttributeValue("sensitive", cty.BoolVal(true))
} }
isLocal, out := variableTransposeTemplatingCalls(variablesContent.Bytes()) // Create final HCL block and append.
if isLocal { if isLocal {
if sensitive { sensitiveBlocks := makeLocal(variable, sensitive, localBody, localsContent, &hasLocals)
// Create Local block because this is sensitive if len(sensitiveBlocks) > 0 {
localContent := hclwrite.NewEmptyFile() p.localsOut = append(p.localsOut, transposeTemplatingCalls(sensitiveBlocks)...)
body := localContent.Body() }
body.AppendNewline()
localBody := body.AppendNewBlock("local", []string{variable.Key}).Body()
localBody.SetAttributeValue("sensitive", cty.BoolVal(true))
localBody.SetAttributeValue("expression", hcl2shim.HCL2ValueFromConfigValue(variable.Default))
p.localsOut = append(p.localsOut, transposeTemplatingCalls(localContent.Bytes())...)
localsVariableMap[variable.Key] = "local"
continue
}
localBody.SetAttributeValue(variable.Key, hcl2shim.HCL2ValueFromConfigValue(variable.Default))
localsVariableMap[variable.Key] = "locals"
hasLocals = true
continue continue
} }
varbytes := makeVariable(variable, sensitive)
_, out := variableTransposeTemplatingCalls(varbytes)
p.variablesOut = append(p.variablesOut, out...) p.variablesOut = append(p.variablesOut, out...)
} }
if hasLocals { if hasLocals == true {
p.localsOut = append(p.localsOut, transposeTemplatingCalls(localsContent.Bytes())...) p.localsOut = append(p.localsOut, transposeTemplatingCalls(localsContent.Bytes())...)
} }
return nil return nil
} }