I'm trying to load data into a dynamodb table from input variables. I'm using locals to manipulate the input data into the correct shape for loading into my table. What seems like a simple thing has
My Variable definition:
variable "templates" {
description = "List of templates available to be used by notifications."
type = list(object({
description = string
html_part = string
text_part = string
template_id = string
subject = string
substitutions = list(object({
name = string
default = string
required = bool
}))
}))
default = []
}
Initialising that variable:
templates = [{
template_id = "TestNotification1"
subject = "This is a test"
description = "Test notification 1"
html_part = <<EOT
<html>
<body>
{{test}} This {{test1}} is {{test2}} the HTML Part
</body>
</html>
EOT
text_part = "This is a test"
substitutions = [{
default = "test"
required = true
name = "test1"
}
]
}]
My attempt to convert the variables into a dynamodb item entry. This is where my problem is.
locals {
templates = tomap([for template in var.templates :
{
"TemplateId": { "S": "${template.template_id}"},
"Type": { "S": "STANDARD"},
"TemplateDescription": { "S": "${template.description}"},
"Subject": { "S": "${template.subject}"},
"HtmlPart": { "S": "${replace(template.html_part,"\n","")}"},
"TextPart": { "S": "${template.text_part}"},
"Substitutions":[for substitution in template.substitutions : {
"Name" : { "S": "${substitution.name}"},
"Required" : { "S": "${substitution.required}"},
"DefaultValue" : { "S": "${substitution.default}"}
}
]
}
])
}
This produces the following error:
Invalid value for "v" parameter: cannot convert tuple to map of any single type.
Loading into dynamodb table (obviously not getting that far):
resource "aws_dynamodb_table_item" "templates" {
table_name = aws_dynamodb_table.default_template_table.name
hash_key = "TemplateId"
for_each = local.templates
item = each.value
}
If I didn't have to do the substitions I could have something like this which works, but I can't figure out how to include my substitutions in this?:
locals {
templates = toset([for template in var.templates :
<<ITEM
{
"TemplateId": { "S": "${template.template_id}"},
"Type": { "S": "STANDARD"},
"TemplateDescription": { "S": "${template.description}"},
"Subject": { "S": "${template.subject}"},
"HtmlPart": { "S": "${replace(template.html_part,"\n","")}"},
"TextPart": { "S": "${template.text_part}"}
}
ITEM
])
}
CodePudding user response:
You can add Substitutions
to your second form using jsonencode
:
templates = toset([for template in var.templates :
<<ITEM
{
"TemplateId": { "S": "${template.template_id}"},
"Type": { "S": "STANDARD"},
"TemplateDescription": { "S": "${template.description}"},
"Subject": { "S": "${template.subject}"},
"HtmlPart": { "S": "${replace(template.html_part,"\n","")}"},
"TextPart": { "S": "${template.text_part}"},
"Substitutions":${jsonencode([for substitution in template.substitutions : {
"Name" : { "S": "${substitution.name}"},
"Required" : { "S": "${substitution.required}"},
"DefaultValue" : { "S": "${substitution.default}"}
}])}
}
ITEM
])
But this is unlikely to work anyway, as TF can't process such a complex data structure and you will end up with cannot unmarshal array
error. The issue has been already reported in TF several times, e.g. here.
Thus you have to simplify your templates
items to be regular flat maps, not nested, or use local-exec
to populate your dynamodb table.
CodePudding user response:
I've solved this. The solution is to jsonencode the whole json object and use the dynamodb L and M Attribute Type for my list of substituion objects.
Note the cannot unmarshall array error appeared to be related to not using the correct Attribute type for an array when inserting into DDB. I found this post useful: How can I store an array into dynamoDB table
locals {
templates = toset([for template in var.templates :
jsonencode({
"TemplateId": { "S": "${template.template_id}"},
"Type": { "S": "STANDARD"},
"TemplateDescription": { "S": "${template.description}"},
"Subject": { "S": "${template.subject}"},
"HtmlPart": { "S": "${replace(template.html_part,"\n","")}"},
"TextPart": { "S": "${template.text_part}"},
"Substitutions":{"L": [for substitution in template.substitutions : {
"M" : {
"Name" : { "S": "${substitution.name}"},
"DefaultValue" : { "S": "${substitution.default}"}
}
}] }
})
])