Skip to content
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

adding function to extract terraform vars from var file #733

Merged
merged 9 commits into from
Feb 15, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ require (
github.com/google/uuid v1.1.1
github.com/gruntwork-io/gruntwork-cli v0.7.0
github.com/hashicorp/go-multierror v1.1.0
github.com/hashicorp/hcl v1.0.0
github.com/imdario/mergo v0.3.7 // indirect
github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a
github.com/jstemmer/go-junit-report v0.9.1
Expand Down
1 change: 1 addition & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
Expand Down
29 changes: 29 additions & 0 deletions modules/terraform/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,32 @@ type UnexpectedOutputType struct {
func (err UnexpectedOutputType) Error() string {
return fmt.Sprintf("Expected output '%s' to be of type '%s' but got '%s'", err.Key, err.ExpectedType, err.ActualType)
}

// VarFileNotFound is an error that occurs when a var file cannot be found in an option's VarFile list
type VarFileNotFound struct {
Path string
}

func (err VarFileNotFound) Error() string {
return fmt.Sprintf("Var file '%s' not found", err.Path)
}

// InputFileKeyNotFound occurs when tfvar file does not contain a value for the key
// specified in the function call
type InputFileKeyNotFound struct {
FilePath string
Key string
}

func (err InputFileKeyNotFound) Error() string {
return fmt.Sprintf("tfvar file %q doesn't contain a value for the key %q", err.FilePath, err.Key)
}

type HclDecodeError struct {
FilePath string
ErrorText string
}

func (err HclDecodeError) Error() string {
return fmt.Sprintf("%s - %s", err.FilePath, err.ErrorText)
}
149 changes: 149 additions & 0 deletions modules/terraform/var-file.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package terraform

import (
"errors"
"fmt"
"io/ioutil"
"reflect"
"testing"

"github.com/hashicorp/hcl"
"github.com/stretchr/testify/require"
)

// GetVariableAsStringFromVarFile Gets the string represention of a variable from a provided input file found in VarFile
// For list or map, use GetVariableAsListFromVarFile or GetVariableAsMapFromVarFile, respectively.
func GetVariableAsStringFromVarFile(t *testing.T, fileName string, key string) string {
result, err := GetVariableAsStringFromVarFileE(t, fileName, key)
require.NoError(t, err)

return result
}

// GetVariableAsStringFromVarFileE Gets the string represention of a variable from a provided input file found in VarFile
// Will return an error if GetAllVariablesFromVarFileE returns an error or the key provided does not exist in the file.
// For list or map, use GetVariableAsListFromVarFile or GetVariableAsMapFromVarFile, respectively.
func GetVariableAsStringFromVarFileE(t *testing.T, fileName string, key string) (string, error) {
var variables map[string]interface{}

err := GetAllVariablesFromVarFileE(t, fileName, &variables)

if err != nil {
return "", err
}

variable, exists := variables[key]

if !exists {
return "", InputFileKeyNotFound{FilePath: fileName, Key: key}
}

return fmt.Sprintf("%v", variable), nil
}

// GetVariableAsMapFromVarFile Gets the map represention of a variable from a provided input file found in VarFile
// Note that this returns a map of strings. For maps containing complex types, use GetAllVariablesFromVarFile.
func GetVariableAsMapFromVarFile(t *testing.T, fileName string, key string) map[string]string {
result, err := GetVariableAsMapFromVarFileE(t, fileName, key)
require.NoError(t, err)

return result
}

// GetVariableAsMapFromVarFileE Gets the map represention of a variable from a provided input file found in VarFile.
// Note that this returns a map of strings. For maps containing complex types, use GetAllVariablesFromVarFile
// Returns an error if GetAllVariablesFromVarFileE returns an error, the key provided does not exist, or the value associated with the key is not a map
func GetVariableAsMapFromVarFileE(t *testing.T, fileName string, key string) (map[string]string, error) {
var variables map[string]interface{}

resultMap := make(map[string]string)
err := GetAllVariablesFromVarFileE(t, fileName, &variables)

if err != nil {
return nil, err
}

variable, exists := variables[key]

if !exists {
return nil, InputFileKeyNotFound{FilePath: fileName, Key: key}
}

if reflect.TypeOf(variable).String() != "[]map[string]interface {}" {
return nil, UnexpectedOutputType{Key: key, ExpectedType: "[]map[string]interface {}", ActualType: reflect.TypeOf(variable).String()}
}

mapKeys := variable.([]map[string]interface{})

if len(mapKeys) == 0 {
return nil, errors.New("no map keys could be found for given map")
}

for mapKey, mapVal := range mapKeys[0] {
resultMap[mapKey] = fmt.Sprintf("%v", mapVal)
}

return resultMap, nil
}

// GetVariableAsListFromVarFile Gets the string list represention of a variable from a provided input file found in VarFile
// Note that this returns a list of strings. For lists containing complex types, use GetAllVariablesFromVarFile.
func GetVariableAsListFromVarFile(t *testing.T, fileName string, key string) []string {
result, err := GetVariableAsListFromVarFileE(t, fileName, key)
require.NoError(t, err)

return result
}

// GetVariableAsListFromVarFileE Gets the string list represention of a variable from a provided input file found in VarFile
// Note that this returns a list of strings. For lists containing complex types, use GetAllVariablesFromVarFile.
// Will return error if GetAllVariablesFromVarFileE returns an error, the key provided does not exist, or the value associated with the key is not a list
func GetVariableAsListFromVarFileE(t *testing.T, fileName string, key string) ([]string, error) {
var variables map[string]interface{}
resultArray := []string{}
err := GetAllVariablesFromVarFileE(t, fileName, &variables)

if err != nil {
return nil, err
}

variable, exists := variables[key]

if !exists {
return nil, InputFileKeyNotFound{FilePath: fileName, Key: key}
}

if reflect.TypeOf(variable).String() != "[]interface {}" {
return nil, UnexpectedOutputType{Key: key, ExpectedType: "[]interface {}", ActualType: reflect.TypeOf(variable).String()}
}

for _, item := range variable.([]interface{}) {
resultArray = append(resultArray, fmt.Sprintf("%v", item))
}

return resultArray, nil
}

// GetAllVariablesFromVarFile Parses all data from a provided input file found in VarFile and stores the result in the value pointed to by out
func GetAllVariablesFromVarFile(t *testing.T, fileName string, out interface{}) {
err := GetAllVariablesFromVarFileE(t, fileName, out)
require.NoError(t, err)
}

// GetAllVariablesFromVarFileE Parses all data from a provided input file found ind in VarFile and stores the result in the value pointed to by out
// Returns an error if the specified file does not exist, the specified file is not readable, or the specified file cannot be decoded from HCL
func GetAllVariablesFromVarFileE(t *testing.T, fileName string, out interface{}) error {
fileContents, err := ioutil.ReadFile(fileName)

if err != nil {
return err
}

err = hcl.Decode(out, string(fileContents))

if err != nil {
return HclDecodeError{FilePath: fileName, ErrorText: err.Error()}
}

return nil
}
Loading