How to properly nest a for loop inside a HEREDOC when using jsonencode

Hi All,

I need a little guidance here as to the best/correct approach to dealing with this issue.

The goal is to create a more dynamic template for a resource (will be part of a larger module. The template output needs to be valid json and therefore, per recommendations in this issue I moved jsonencode function inside my template file.
So far all has worked well and I was able to have a couple of for loops inside there as well with [ for X in Y: ${X} ],
In essence, something like:

${jsonencode({
    "widgets": [
        {
            "height": 4,
            "width": 8,
            "y": 0,
            "x": 0,
            "type": "metric",
            "properties": {
                "metrics": [ for node in nodes :
                    [ "AWS/ElastiCache", "CPUUtilization", "CacheClusterId", "${node}", { "period": 300, "stat": "Average" } ]
                ],
                "legend": {
                    "position": "bottom"
                },
                "region": region,
                "liveData": false,
                "title": "CPUUtilization: Average"
            }
        }
    ]
})}

However, now I needed to add a conditional, and that meant that most of my template needed to be moved to a HEREDOC string. My initial attempt was something like:

${jsonencode({
       "widgets": [
( enabled ? (
<<-EOT
        {
            "height": 4,
            "width": 8,
            "y": 0,
            "x": 0,
            "type": "metric",
            "properties": {
                "metrics": [ for node in nodes : <= Problem is here. Complains about   |
                                                                                       v
                    [ "AWS/ElastiCache", "CPUUtilization", "CacheClusterId",       "${node}", { "period": 300, "stat": "Average" } ]
                ],
                "legend": {
                    "position": "bottom"
                },
                "region": region,
                "liveData": false,
                "title": "CPUUtilization: Average"
            }
        }
    ]
EOT 
) : ( {} )
})}

However I can’t use the above, because Terraform complains about not having node in the vars map, and therefore I moved to directives once again %{for X in Y}, but this now brings me to the same problem described in the above issue, the trailing comma.

${jsonencode({
       "widgets": [
( enabled ? (
<<-EOT
        {
            "height": 4,
            "width": 8,
            "y": 0,
            "x": 0,
            "type": "metric",
            "properties": {
                "metrics": [ 
%{ for node in nodes ~}
                    [ "AWS/ElastiCache", "CPUUtilization", "CacheClusterId",       "${node}", { "period": 300, "stat": "Average" } ]
%{endfor ~}
                ],
                "legend": {
                    "position": "bottom"
                },
                "region": region,
                "liveData": false,
                "title": "CPUUtilization: Average"
            }
        }
    ]
EOT 
) : ( {} )
})}

Is this the correct approach? If so, how do I deal with the trailing comma? Would appreciate some insights here,

TIA,
PL

Hi @pslobo,

If you want to filter out some or all of the attributes of your object based on a condition then you can do that with a for expression that has an if clause:

{ for k, v in input_object : k => v if enabled }

input_object could be a direct, inline object expression in your case, since it seems like you had the object written inline in the jsonencode argument before.

Thanks, was aware of that. However, in this case, the conditional is for the whole text, of which the loop is part of. So in essence, If true, it’s going to generate some text that has a loop inside it. If false, does nothing. So, in this situation, can’t really use that filter. Thanks though for the suggestion