Skip to content

Commit

Permalink
refactor: Refactored variables term to inputs
Browse files Browse the repository at this point in the history
  • Loading branch information
ofekatr committed Mar 1, 2022
1 parent a4bba79 commit c4fe055
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 201 deletions.
2 changes: 1 addition & 1 deletion scripts/opa/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func runOpa() {
return nil, err
}

input, err := terraform.ParseHclToJson(filePath, string(content), terraform.VariableMap{})
input, err := terraform.ParseHclToJson(filePath, string(content), terraform.ModuleVariables{})
if err != nil {
return nil, err
}
Expand Down
33 changes: 19 additions & 14 deletions terraform/hcl2json.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package terraform

import (
"encoding/json"

"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
)
Expand All @@ -13,15 +14,15 @@ func ParseModule(files map[string]interface{}) map[string]interface{} {
parsedFiles := make(map[string]interface{})
debugLogs := make(map[string]interface{})

variablesMaps := map[string]VariableMap{}
inputsByFile := InputsByFile{}
for fileName, fileContentInterface := range files {
if isValidVariableFile(fileName) {
if isValidInputsFile(fileName) {
// need to use interface{} for gopherjs, so cast it back to string
fileContent, ok := fileContentInterface.(string)
if !ok {
continue
}
variableMap, err := extractVariables(fileName, fileContent)
inputsMap, err := extractInputs(fileName, fileContent)
if err != nil {
// skip non-user errors
if isUserError(err) {
Expand All @@ -30,17 +31,21 @@ func ParseModule(files map[string]interface{}) map[string]interface{} {
}
continue
}
variablesMaps[fileName] = variableMap
inputsByFile[fileName] = inputsMap
}
}

// merge variables so they can be used across multiple files
variableMap := mergeVariables(variablesMaps)
// merge inputs so they can be used across multiple files
inputsMap := mergeInputs(inputsByFile)

vars := ModuleVariables{
inputs: inputsMap,
}

for fileName, fileContent := range files {
// failedFiles contains user errors so if the file failed at extract time, we don't try to parse it
if isValidTerraformFile(fileName) && failedFiles[fileName] == nil {
parsedJson, err := parseHclToJson(fileName, fileContent.(string), variableMap)
parsedJson, err := parseHclToJson(fileName, fileContent.(string), vars)
if err != nil {
// skip non-user errors
if isUserError(err) {
Expand All @@ -60,23 +65,23 @@ func ParseModule(files map[string]interface{}) map[string]interface{} {
}
}

// extractVariables extracts the variables from the provided file
var extractVariables = func(fileName string, fileContent string) (VariableMap, error) {
// extractInputs extracts the input values from the provided file
var extractInputs = func(fileName string, fileContent string) (ValueMap, error) {
file, diagnostics := hclsyntax.ParseConfig([]byte(fileContent), fileName, hcl.Pos{Line: 1, Column: 1})
if diagnostics.HasErrors() {
return VariableMap{}, createInvalidHCLError(diagnostics.Errs())
return ValueMap{}, createInvalidHCLError(diagnostics.Errs())
}

variables, diagnostics := extractFromFile(fileName, file)
fileInputsMap, diagnostics := extractInputsFromFile(fileName, file)
if diagnostics.HasErrors() {
return VariableMap{}, createInvalidHCLError(diagnostics.Errs())
return ValueMap{}, createInvalidHCLError(diagnostics.Errs())
}

return variables, nil
return fileInputsMap, nil
}

// ParseHclToJson parses a provided HCL file to JSON and dereferences any known variables using the provided variables
func ParseHclToJson(fileName string, fileContent string, variables VariableMap) (string, error) {
func ParseHclToJson(fileName string, fileContent string, variables ModuleVariables) (string, error) {
file, diagnostics := hclsyntax.ParseConfig([]byte(fileContent), fileName, hcl.Pos{Line: 1, Column: 1})
if diagnostics.HasErrors() {
return "", createInvalidHCLError(diagnostics.Errs())
Expand Down
95 changes: 35 additions & 60 deletions terraform/hcl2json_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestParseHCL2JSONSuccess(t *testing.T) {
type test struct {
name string
input string
variables VariableMap
variables ModuleVariables
expected string
}

Expand Down Expand Up @@ -367,10 +367,10 @@ variable "region" {
}
}
}`,
variables: VariableMap{
"var": cty.ObjectVal(VariableMap{
variables: ModuleVariables{
inputs: ValueMap{
"instance_name": cty.StringVal("test"),
}),
},
},
},
{
Expand All @@ -397,10 +397,10 @@ variable "region" {
}
}
}`,
variables: VariableMap{
"local": cty.ObjectVal(VariableMap{
variables: ModuleVariables{
locals: ValueMap{
"instance_name": cty.StringVal("test"),
}),
},
},
},
{
Expand All @@ -418,10 +418,10 @@ variable "region" {
}
}
}`,
variables: VariableMap{
"local": cty.ObjectVal(VariableMap{
variables: ModuleVariables{
locals: ValueMap{
"instance_name": cty.StringVal("test"),
}),
},
},
},
{
Expand All @@ -435,10 +435,10 @@ variable "region" {
"test": "test"
}
}`,
variables: VariableMap{
"local": cty.ObjectVal(VariableMap{
variables: ModuleVariables{
locals: ValueMap{
"instance_name": cty.StringVal("test"),
}),
},
},
},
{
Expand All @@ -460,11 +460,11 @@ locals {
}
}
}`,
variables: VariableMap{
"local": cty.ObjectVal(VariableMap{
variables: ModuleVariables{
locals: ValueMap{
"test1": cty.StringVal("a"),
"test2": cty.StringVal("b"),
}),
},
},
},
{
Expand All @@ -491,10 +491,10 @@ locals {
}
}
}`,
variables: VariableMap{
"var": cty.ObjectVal(VariableMap{
variables: ModuleVariables{
inputs: ValueMap{
"wrong_name": cty.StringVal("test"),
}),
},
},
},
}
Expand Down Expand Up @@ -527,15 +527,15 @@ block "label_one" {

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
_, err := ParseHclToJson("test", tc.input, nil)
_, err := ParseHclToJson("test", tc.input, ModuleVariables{})
require.NotNil(t, err)
assert.Equal(t, tc.expected, err.Error())
assert.True(t, isUserError(err))
})
}
}

func TestExtractVariablesSuccess(t *testing.T) {
func TestExtractInputsSuccess(t *testing.T) {
type TestInput struct {
fileName string
fileContent string
Expand All @@ -544,7 +544,7 @@ func TestExtractVariablesSuccess(t *testing.T) {
type test struct {
name string
input TestInput
expected VariableMap
expected ValueMap
}
tests := []test{
{
Expand All @@ -556,12 +556,7 @@ func TestExtractVariablesSuccess(t *testing.T) {
type = "string"
}`,
},
expected: VariableMap{
"var": cty.ObjectVal(VariableMap{}),
"local": cty.ObjectVal(VariableMap{
"dummy": cty.StringVal("dummy"),
}),
},
expected: ValueMap{},
},
{
name: "Simple variable block with default",
Expand All @@ -573,13 +568,8 @@ func TestExtractVariablesSuccess(t *testing.T) {
default = "test"
}`,
},
expected: VariableMap{
"var": cty.ObjectVal(VariableMap{
"test": cty.StringVal("test"),
}),
"local": cty.ObjectVal(VariableMap{
"dummy": cty.StringVal("dummy"),
}),
expected: ValueMap{
"test": cty.StringVal("test"),
},
},
{
Expand All @@ -592,12 +582,7 @@ func TestExtractVariablesSuccess(t *testing.T) {
default = null
}`,
},
expected: VariableMap{
"var": cty.ObjectVal(VariableMap{}),
"local": cty.ObjectVal(VariableMap{
"dummy": cty.StringVal("dummy"),
}),
},
expected: ValueMap{},
},
{
name: "Two variable one with null value and the other with valid value",
Expand All @@ -614,13 +599,8 @@ func TestExtractVariablesSuccess(t *testing.T) {
default = "test"
}`,
},
expected: VariableMap{
"var": cty.ObjectVal(VariableMap{
"test": cty.StringVal("test"),
}),
"local": cty.ObjectVal(VariableMap{
"dummy": cty.StringVal("dummy"),
}),
expected: ValueMap{
"test": cty.StringVal("test"),
},
},
{
Expand All @@ -633,18 +613,13 @@ func TestExtractVariablesSuccess(t *testing.T) {
default = "us-central1"
}`,
},
expected: VariableMap{
"var": cty.ObjectVal(VariableMap{}),
"local": cty.ObjectVal(VariableMap{
"dummy": cty.StringVal("dummy"),
}),
},
expected: ValueMap{},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
actual, err := extractVariables(tc.input.fileName, tc.input.fileContent)
actual, err := extractInputs(tc.input.fileName, tc.input.fileContent)
require.Nil(t, err)
assert.Equal(t, tc.expected, actual)
})
Expand Down Expand Up @@ -960,23 +935,23 @@ variable "dummy" {
defer func() {
parseHclToJson = oldParseHclToJson
}()
parseHclToJson = func(fileName string, fileContent string, variableMap VariableMap) (string, error) {
parseHclToJson = func(fileName string, fileContent string, variableMap ModuleVariables) (string, error) {
if fileName == "fail.tf" {
return "", tc.parseErr
}
return oldParseHclToJson(fileName, fileContent, variableMap)
}
}
if tc.extractErr != nil {
oldExtractVariables := extractVariables
oldExtractInputs := extractInputs
defer func() {
extractVariables = oldExtractVariables
extractInputs = oldExtractInputs
}()
extractVariables = func(fileName string, fileContent string) (VariableMap, error) {
extractInputs = func(fileName string, fileContent string) (ValueMap, error) {
if fileName == "fail.tf" {
return nil, tc.extractErr
}
return oldExtractVariables(fileName, fileContent)
return oldExtractInputs(fileName, fileContent)
}
}
actual := ParseModule(tc.files)
Expand Down
29 changes: 23 additions & 6 deletions terraform/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ package terraform

import (
"fmt"
"strings"

"github.com/zclconf/go-cty/cty"
ctyconvert "github.com/zclconf/go-cty/cty/convert"
ctyjson "github.com/zclconf/go-cty/cty/json"
"strings"

"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/hclsyntax"
Expand All @@ -19,20 +20,36 @@ type Options struct {

type Parser struct {
bytes []byte
variables VariableMap
variables ValueMap
options Options
}

type NewParserParams struct {
bytes []byte
variables ModuleVariables
options Options
}

type JSON = map[string]interface{}

func parseFile(file *hcl.File, variables VariableMap) (JSON, error) {
parser := Parser{
func NewParser(params NewParserParams) Parser {
return Parser{
bytes: params.bytes,
variables: ValueMap{
"var": cty.ObjectVal(params.variables.inputs),
"local": cty.ObjectVal(params.variables.locals),
},
options: params.options,
}
}

func parseFile(file *hcl.File, variables ModuleVariables) (JSON, error) {
parser := NewParser(NewParserParams{
bytes: file.Bytes,
variables: variables,
options: Options{
Simplify: true,
},
}
}})

body, ok := file.Body.(*hclsyntax.Body)
if !ok {
Expand Down
2 changes: 1 addition & 1 deletion terraform/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func isTerraformTfvarsFile(fileName string) bool {
return fileName == DEFAULT_TFVARS || strings.HasSuffix(osFileName, fmt.Sprintf("/%s", DEFAULT_TFVARS))
}

func isValidVariableFile(fileName string) bool {
func isValidInputsFile(fileName string) bool {
if isTerraformTfvarsFile(fileName) {
return true
}
Expand Down
Loading

0 comments on commit c4fe055

Please sign in to comment.