Home > Net >  Terraform aws dynamodb item - preparation of data
Terraform aws dynamodb item - preparation of data

Time:03-15

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}"}
    }
   }] }

})
  
  ])
  • Related