Skip to content

Commit

Permalink
Merge pull request #733 from alpacamybags118/varfile_extract
Browse files Browse the repository at this point in the history
adding function to extract terraform vars from var file
  • Loading branch information
brikis98 authored Feb 15, 2021
2 parents 1a5b3ae + 8192f26 commit 88ba3f0
Show file tree
Hide file tree
Showing 5 changed files with 425 additions and 0 deletions.
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

0 comments on commit 88ba3f0

Please sign in to comment.