Hammed
Hammed

Reputation: 1557

Template body contains invalid JSON: invalid character

I've got a CloudFormation template that creates an SNS topic and subscription

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Resources" : {
      "EmailSNSTopic": {
        "Type" : "AWS::SNS::Topic",
        "Properties" : {
          "DisplayName" : "${display_name}"
        }
      },
      "MySubscription": {
        "Type": "AWS::SNS::Subscription",
        "Properties": {
          "TopicArn" : { "Ref" : "EmailSNSTopic" },
          "${details}"
        }
      }
    },
      "Outputs" : {
        "ARN" : {
          "Description" : "Email SNS Topic ARN",
          "Value" : { "Ref" : "EmailSNSTopic" }
        }
      }
}

Which I'm trying to call via terrform.

But I keep getting this error Error: "template_body" contains an invalid JSON: invalid character '{' looking for beginning of object key string

My Terraform configuration looks like this.

provider "aws" {
  region = "eu-west-2"
}

data "template_file" "sns_stack" {
  template = file("${path.module}/templates/email-sns-stack.json.tpl")
  vars = {
    display_name  = var.display_name
    details = join(",", formatlist("{ \"Endpoint\": \"%s\", \"Protocol\": \"%s\"  }", var.email_list, var.protocol))
  }
}

resource "aws_cloudformation_stack" "sns_topic" {
  name          = var.stack_name
  template_body = data.template_file.sns_stack.rendered
  tags = merge(
    map("Name", var.stack_name)
  )
}

And my variables.tf looks like this

  default     = "Admin"
}
variable "email_list" {
  default = [
    "[email protected]",
    "[email protected]"
  ]
}

variable "protocol" {
  default     = "email"
}
variable "stack_name" {
  default     = "sns-test"
}

I expect that ${details} should spit out my Endpoint and Protocol but it doesn't.

What am I doing wrong?

Upvotes: 1

Views: 3729

Answers (1)

Marcin
Marcin

Reputation: 238199

What you want to achieve is rather complex, but doable. You can do this using the following template:

{
    "AWSTemplateFormatVersion": "2010-09-09",
    "Resources" :  ${jsonencode(
        merge({for idx, email_address in email_list: 
        "EmailSubs${idx}" => {
          Type = "AWS::SNS::Subscription"
          Properties = {
                "Endpoint" = email_address
                "Protocol" = protocol
                "TopicArn" = { "Ref" = "EmailSNSTopic" }      
          }      
      }},
      {
        "EmailSNSTopic" = {
        "Type" = "AWS::SNS::Topic",
        "Properties" = {
          "DisplayName" = "${display_name}"
        }
      }}
      
      ))},
  "Outputs" : {
        "ARN" : {
          "Description" : "Email SNS Topic ARN",
          "Value" : { "Ref" : "EmailSNSTopic" }
        }
      }      
        
}

and TF code:

locals {

  template_body = templatefile("./email-sns-stack2.json.tpl", {
    display_name  = var.display_name
    email_list = var.email_list
    protocol = var.protocol
   })

}

resource "aws_cloudformation_stack" "sns_topic" {
  name          = var.stack_name
  template_body = local.template_body
  tags = merge(
    map("Name", var.stack_name)
  )
}

Upvotes: 1

Related Questions