-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
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
adding function to extract terraform vars from var file #733
Conversation
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.
Thanks for the PR!
A few thoughts:
- What is the use case you have for this? I'd like to hear concrete details to make sure we're adding support for the right thing.
- Following from the previous question, my guess is that it makes more sense to have a method to read a single value from a var file, rather than the whole var file. That way, you can parse it as a specific type (instead of
interface{}
), and use that value explicitly (whereas using the entire file seems unlikely). But again, this depends on the particular use case. - Please see our error handling guidelines.
- Please make sure to run
goimports
.
Thanks for the feedback @brikis98 ! As for the use case, I have found frequently that I've wanted to access a setting I've set in a tfvars file later in a test for use in comparison for assertion/validation. For example, I was changing a module that exposes an option to set a CNAME record. I was planning to use the value we set the CNAME record to for some validation. Since I couldn't access the value from the tfvars file, I had to end up taking it out and hard-code the value in the test and pass in both the var file and that individual var into the terraform options. So, while this functionally isn't needed since you can get around cases where you do need to access certain variables, you would always need to hard-code them into your test and add additional code to import both a var and a var file in your terraform options. (unless I'm totally missing another way to do this). Overall my argument is this functionality would allow you to not have to write additional code for use cases like this and keeps configuration more separated from the code. Hopefully what I'm saying makes sense 🤣 If you are OK with adding this, I'll go ahead and address the additional feedback you provided. |
Makes sense to me! |
Crap, pushed too soon lol. Don't review yet - still need to update/add tests. |
bdf8ed1
to
258eb4e
Compare
@brikis98 happy (late) new year! I finally got a chance to come back to refactoring this PR a bit. I decided to structure it more like the output module and provide different functions for getting input file values as their different types (string, map, list), along with adding some new error types. |
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.
Thanks! Left some comments/thoughts on the API.
modules/terraform/errors.go
Outdated
type InputFileKeyNotFound string | ||
|
||
func (err InputFileKeyNotFound) Error() string { | ||
return fmt.Sprintf("tfvar file doesn't contain a value for the key %q", string(err)) |
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.
NIT: Could the error message include the path to the tfvar file?
modules/terraform/options.go
Outdated
return nil, err | ||
} | ||
|
||
_, exists := variables[key] |
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.
NIT: any reason not to store the returned value here instead of looking up variables[key]
multiple times below?
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.
Good catch, will update.
modules/terraform/options.go
Outdated
} | ||
|
||
if reflect.TypeOf(variables[key]).String() != "[]map[string]interface {}" { | ||
return nil, UnexpectedOutputType{Key: key, ExpectedType: "map", ActualType: reflect.TypeOf(variables[key]).String()} |
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.
ExpectedType
is misleading here, as you're actually looking for []map[string]interface {}
...
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.
Ah, good catch! Probably a bad copy-paste :P
modules/terraform/options.go
Outdated
return nil, UnexpectedOutputType{Key: key, ExpectedType: "map", ActualType: reflect.TypeOf(variables[key]).String()} | ||
} | ||
|
||
mapKeys := variables[key].([]map[string]interface{})[0] |
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.
Check that the slice is not empty before looking up index 0 to avoid a potential panic.
modules/terraform/options.go
Outdated
return fmt.Sprintf("%v", variable), nil | ||
} | ||
|
||
// GetVariableAsMapFromVarFile Gets the map represention of a variable from a provided input file found in VarFile |
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.
NIT: in both descriptions, it's probably worth calling out that this is specifically a map of strings. For maps with more complicated nested types, or other types in general, use GetAllVariablesFromVarFile
.
modules/terraform/options.go
Outdated
return resultMap, nil | ||
} | ||
|
||
// GetVariableAsListFromVarFile Gets the string list represention of a variable from a provided input file found in VarFile |
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.
Same note here that this only works for lists of strings and to use GetAllVariablesFromVarFile
for more complicated types.
modules/terraform/options.go
Outdated
return nil, err | ||
} | ||
|
||
if _, exists := variables[key]; !exists { |
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.
Same NIT here about storing the return value instead of looking it up again several times below.
modules/terraform/options.go
Outdated
} | ||
|
||
// GetAllVariablesFromVarFile Parses all data from a provided input file found in VarFile and returns them as a key-value map | ||
func GetAllVariablesFromVarFile(t *testing.T, option *Options, fileName string) map[string]interface{} { |
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.
A map[string]interface{}
is a bit unwiedly and error prone to use, as you have to cast all the values within the map. What are your thoughts instead on an interface like:
func GetAllVariablesFromVarFile(t *testing.T, option *Options, fileName string, returnValue interface{})
Where returnValue
is a pointer the user can pass in with any custom struct, and we will parse the tfvar file into that struct, including all the types within it. This is similar to OutputStruct
.
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.
That's valid. It would certainly make it easier for the user. I did see to minimize using pointers in the best practices for this repo and this is a bit unique compared to the other functions, but it probably makes sense given the complexity of the return type.
modules/terraform/options.go
Outdated
|
||
// GetAllVariablesFromVarFileE Parses all data from a provided input file found ind in VarFile and returns them as a key-value map | ||
// Retursn 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, option *Options, fileName string) (map[string]interface{}, error) { |
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.
Why take in a fileName
and option
struct, and have to search for the file within it, rather than take in solely the path directly to a var file? This applies to all the methods in this PR.
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.
That makes sense. I think I wanted to use the options struct since I was originally thinking in just the scope of what is provided to options, but its just adding more unneeded logic. I'll adjust this.
Thank you for the feedback! I'll get to making the updates later this week. |
@brikis98 I addressed all your feedback! I do have one thought, though, that I wanted to run by you. With these changes, it seems like maybe this code doesn't quite fit into the options file since it no longer interfaces with the options object. Maybe should be separated into its own module, like |
Sorry for the delay. Agreed it doesn't quite fit into |
Updated to move the code to a different file! |
Great, thanks! Would you mind rebasing on master? I can then kick off tests. |
Co-authored-by: Yevgeniy Brikman <[email protected]>
3746aad
to
d1985c0
Compare
Done! @brikis98 |
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.
Apologies, found two more NITs, and then we're good!
modules/terraform/var-file_test.go
Outdated
if err == nil { | ||
t.FailNow() | ||
} |
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.
NIT: use require.Error
instead.
Co-authored-by: Yevgeniy Brikman <[email protected]>
Updated! |
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.
LGTM! I'll kick off tests now.
Hm, looks like a test not related to my code changes failed
|
Ah, looks like it might be using an instance that isn't valid? |
Yup, it's an unrelated intermittent issue in some AWS regions: #783. All other tests passed, so I'm going to merge, and we'll deal with that issue later. Thanks! |
This PR adds the following functionality to the terraform Options module:
This is my first time contributing to this repo, so I tried to follow the style guides and everything to the best of my ability. Any feedback would be greatly appreciated!