Terraform: 'INVALID_JSON_DESCRIPTION: недопустимый символ без кавычек

У меня есть сценарий Terraform step_function, который вызывает функцию Lambda для отправки электронной почты. Я хочу отправить тело письма в виде такой переменной:

  data "template_file" "start_es_email" {
    template = "${file("email_template/start_es.html")}"
  }

  data "template_file" "start_template" {
    template = "${file("step_function/start_stepfunction.json")}"

    vars = {
      aws_region            = "${var.aws_region}",
      ses_sender            = "${var.ses_sender}"
      ses_destination_email = "${var.ses_destination_emails}"
      ses_body_html         = "${data.template_file.start_es_email.rendered}"
    }
  }

Это содержимое файла start_es.html, это простой HTML-контент:

<html>
<body>
<h1>ElasticSearch cluster started and ready</h1>
<p>
The ElasticSearch cluster has started and ready to use
</p>
</body>
</html>

Это ресурс функции состояния:

resource "aws_sfn_state_machine" "start_cluster" {
  name     = "start-es-sfn-${var.environment}"
  role_arn = "${aws_iam_role.step_function_iam_role.arn}"

  definition = "${data.template_file.start_template.rendered}"
}

И это то, что у меня есть в файле json функции состояния:

"SendSuccessEmail": {
      "Type": "Task",
      "Resource": "${lambda_notification}",
      "Parameters": {
        "SES_SENDER": "${ses_sender}",
        "SES_DESTINATION_EMAIL": "${ses_destination_email}",
        "SUBJECT": "${ses_subject}",
        "BODY_HTML": "${ses_body_html}"
      },
      "End": true
    },

Теперь при вызове terraform apply я получаю эту ошибку:

Ошибка: InvalidDefinition: недопустимое определение конечного автомата: 'INVALID_JSON_DESCRIPTION: Недопустимый символ без кавычек ((CTRL-CHAR, код 10)): для включения в строковое значение необходимо экранировать с помощью обратной косой черты

Я попытался сделать html-контент одной строкой вот так:

<html><body><h1>ElasticSearch cluster started and ready</h1><p>The ElasticSearch cluster has started and ready to use</p></body></html>

и он работает нормально, но читать и поддерживать такой файл нехорошо.

Есть ли способ решить эту проблему?

Спасибо.


person user1297406    schedule 21.08.2019    source источник


Ответы (2)


Судя по предоставленной вами информации, создается впечатление, что отображаемый шаблон имеет недопустимый символ, который необходимо экранировать. Управляющий символ 10 - это перевод строки. Поэтому каждую новую строку нужно экранировать обратной косой чертой. Вы создали этот html-файл в приложении Windows, таком как notepad ++ или подобное? Я бы попробовал создать его в редакторе VSCode или Linux, например vim или nano.

В качестве альтернативы вы можете попытаться избежать перевода строки, используя '\\ n' или '\ n' без галочки в конце каждой строки текста. Я не сталкивался с этим раньше, поэтому я не совсем уверен, как правильно заставить Terraform сотрудничать. Маршаллинг JSON с помощью Terraform иногда может быть затруднен.

Что я могу вам сказать, вот почему вы получаете CC10, и он работает, когда вы размещаете всю информацию в одной строке.

person Michael Quale    schedule 21.08.2019
comment
Привет, спасибо за ответ, я использую Visual Studio Code в Linux Fedora. Теперь я попытался отредактировать файл с помощью Vi, и я попробовал многострочный, у меня такая же ошибка. Я также попытался вставить \ n и \\ n и в конце каждой строки и то же самое. Кстати вы имели в виду это:? ‹Html› \ n ‹body› \ n .... - person user1297406; 21.08.2019
comment
Не только в конце строк в теле сообщения. Например ‹h1› Кластер ElasticSearch запущен и готов \\ n ‹/h1› - person Michael Quale; 21.08.2019

Если вы используете Terraform v0.12 или можете обновиться до него, вы можете избежать этой проблемы, используя функцию _ 1_:

resource "aws_sfn_state_machine" "start_cluster" {
  name     = "start-es-sfn-${var.environment}"
  role_arn = aws_iam_role.step_function_iam_role.arn

  definition = jsonencode({
    "SendSuccessEmail": {
      "Type": "Task",
      "Resource": lambda_notification,
      "Parameters": {
        "SES_SENDER": var.ses_sender,
        "SES_DESTINATION_EMAIL": var.ses_destination_emails,
        "SUBJECT": var.ses_subject,
        "BODY_HTML": data.template_file.start_es_email.rendered,
      },
      "End": true,
    },
  })
}

Используя jsonencode, вы можете позволить Terraform позаботиться о кодировке JSON. Он увидит, что в значении data.template_file.start_es_email.rendered есть символы новой строки, и автоматически превратит их в \n. Если нет конкретной причины, по которой вам нужно точно контролировать форматирование данных, я бы рекомендовал всегда использовать jsonencode для генерации JSON в Terraform, а не использовать строковые шаблоны.

Хотя Terraform 0.11 действительно имеет функцию jsonencode, это гораздо более упрощенная реализация, которая не даст правильного результата в данной конкретной ситуации.

person Martin Atkins    schedule 21.08.2019
comment
это гораздо более элегантное решение. Я должен помнить об этом, когда мы переводим наши проекты на v0.12 ~ - person Michael Quale; 21.08.2019
comment
Спасибо за решение, я уже работаю над Terraform 0.12. Я пробовал, но теперь получаю эту ошибку: Ошибка: InvalidDefinition: Недействительное определение конечного автомата: 'SCHEMA_VALIDATION_FAILED: Ожидаемое значение типа [ОБЪЕКТ] в /' - person user1297406; 22.08.2019
comment
Я передаю весь визуализированный файл шаблона в state_machine вот так: definition = jsonencode ($ {data.template_file.start_services_template.rendered}) - person user1297406; 22.08.2019