-
Notifications
You must be signed in to change notification settings - Fork 977
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
Key inconsistency in project-factory #2516
Conversation
Projects configured in `folders_data_path` have their filename as key, whereas those from `projects_data_path` have their path, relative to `projects_data_path` as key. This causes different behavior when defining `local.projects` and subsequently calling `module.projects`, unless `name` is specified.
Great debugging work on non-trivial project factory use cases. :) Let me read this and approve, if tests fail just ping here if you end up struggling with our framework and I'll try to help or fix those myself. |
TFlint does not like What if you set a harmless attribute in the empty YAML files instead? Something like |
Wow, I'm actually impressed by that response speed 😀 The Linter doesn't seem to like my However, when verifying in
|
Heh, FAST tests also fail with the same error. The tf type checker behaves badly with maps in ternaries and other situations, reading the map as an object and enforcing the same type on both sides which clearly does not work. What if you skipped the fix for null files, and just used a workaround in that case? A bit suboptimal but better than risking breaking the project factory, which has a very fragile balance in its locals that cost us a lot of trouble. |
Hm, evaluating with
So apparently it's both object, however, Practically speaking, most projects files in To me it seems, that having type |
It still seems like a lot of trouble for a tiny corner case: as you write above projects will almost always have a parent set. Why don't you split changes so the key fix can go in, and we then take the time to figure out if a solid approach for |
Fair enough - I removed the commit for |
This Pull Request addresses two issues I stumbled upon, while working with your nice and shiny framework.
Inconsistent Map Keys for Project Files
Projects configured in
folders_data_path
have their filename as key (see code, do note the use ofbasename()
to get only the filename), whereas those fromprojects_data_path
have their entire path, relative toprojects_data_path
, as key (see code, do note the absence ofbasename()
).This causes project files from the two sources to be key'ed differently, which has some implications down the line.
local.projects
is eventually constructed here, thename
attribute each YAML file is looked up. If not set, the function resorts to the map-key, which is the filename for project files fromfolders_data_path
and the full relative path for project files fromprojects_data_path
.projects_data_path
, unlessname
was specified in the file. Aslocal.projects
is used as map for invokingmodule.projects
, this key-change destroys and re-creates projects. This does not happen, if the project file resides anywhere infolders_data_path
, since their key is only the filename (basename()
was used).module.projects
on a project YAML fromprojects_data_path
without specifiedname
attribute will cause a mis-construction of theproject_id
. Moduleproject
will be handed the map-key asname
for the project, which is used together withprefix
asproject_id
. But if the project YAML file happens to reside in a sub-directory, the path will not only contain its filename, but also its parent-folder separated by a/
. This causes an error (admittedly in thetf plan
stage) which outputs that theproject_id
is invalid (it may look like thisprefix-subdir/projectname
). However, this error is not very verbose and unintuitive in this case, since omittingname
in project files fromfolders_data_path
works perfectly fine, as the key is always just the filename and a perfectly finename
/project_id
.Solution
The PR uses
basename()
for files fromprojects_data_path
too, causing the behavior to be identical andname
to be an optional setting, just like with files fromfolders_data_path
, which is consistent, in my opinion.One implication is, that files from
folders_data_path
can now overwrite entries fetched fromprojects_data_path
, if they happen to use the samename
(or filename, in case noname
is specified), due to the merge-order, see thismerge()
-call.Null when decoding empty YAML files
Another minor detail I noticed was that Terraform returns
null
when usingyamldecode()
on a file that only contains---
to indicate the start of the YAML document. An empty project YAML is a perfectly fine configuration, since the filename is used asname
and everything else may be added by default values or overrides.However, parsing an empty YAML document will place
null
as value in factory-projects.tf:25 and factory-projects.tf:34. This causes an error, when this value is used inlookup()
at factory-projects.tf:50, sincelookup()
does not acceptnull
as parameterInputMap
.Interestingly enough, this also happens only to project files from
projects_data_path
, since those fromfolders_data_path
aremerge()
d with{parent = dirname(f) ...}
at factory-projects.tf:24.merge()
actually acceptsnull
as argument, treating it as{ }
, so there is always at least a map/object present as value for those project files. This is inconsistent behavior, in my opinion and YAML objects from project files should be sanitized to be at least{ }
instead ofnull
, allowing empty project files for bothfolders_data_path
andprojects_data_path
.Solution
I added a second commit to my PR, which wraps
yamldecode()
incoalesce()
resorting to{ }
should theyamldecode()
invocation returnnull
, making the behavior consistent for both cases.Checklist
I applicable, I acknowledge that I have:
terraform fmt
on all modified filestools/tfdoc.py