Terraform JSON требует, чтобы подсеть Azure, вложенная в объект виртуальной сети Azure, имела идентификатор, но не позволяет его установить.

TL; DR: JSON Terraform Azure Vnet требует, чтобы вложенные подсети имели идентификатор, но при предоставлении идентификатора возникают ошибки.

Фон

У меня есть учетная запись Azure, в которой есть множество ресурсов, которые были созданы вне канала, но теперь клиент хочет, чтобы мы управляли всеми ресурсами в терраформе. К счастью, в terraform есть способ импорта ресурсов, и даже прекрасное руководство демонстрирует, как импортировать ресурсы и генерировать необходимую конфигурацию (https://learn.hashicorp.com/tutorials/terraform/state-import).

После того, как я импортировал ресурсы, я запускаю команду tf show -no-color -json > main.tf.json, чтобы сгенерировать тело конфигурации. Я выгружаю его в формате JSON, потому что после запуска tf show вам необходимо изменить некоторые выходные данные, чтобы результаты были действительным файлом конфигурации terraform.

После запуска tf show у меня есть сценарий, который изменяет данные, внося некоторые изменения в структуру JSON и удаляя атрибуты, которые необходимо удалить или изменить.

Эта проблема

Возникающая проблема заключается в том, что после очистки вывода, сгенерированного tf show при запуске, tf validate или любой другой командой, требующей проверки, я получаю сообщение об ошибке, в котором говорится, что атрибут id требуется для элементов в массиве JSON подсети в azurerm_virtual_network JSON объект. Однако, когда я добавляю идентификатор, я получаю сообщение об ошибке, в котором говорится, что id не может быть указан для объекта JSON подсети Azure.

Обратите внимание, что это происходит только тогда, когда я использую файл .tf.json, если я использую обычный файл tf, никаких проблем не возникает.

Код

Версия Terraform: Terraform v0.13.5

Версия поставщика: azurerm v2.38.0

Вот конфигурация JSON terraform, которая демонстрирует проблему

    {
        "resource": {
            "azurerm_virtual_network": {
                "gork_vnet": {
                    "address_space": [
                        "10.0.0.0/16"
                    ],
                    "location": "westus2",
                    "name": "gork_vnet",
                    "resource_group_name": "mork_rg",
                    "subnet": [
                        {
                            "address_prefix": "10.0.0.0/24",
                            "name": "cunning_brutality",
                            "security_group": ""
                        }
                    ]
                }
            }
        }
    }

Произведена ошибка:

Error: Incorrect attribute value type

  on main.tf.json line 22, in [1].resource.azurerm_virtual_network.gork_vnet:
  22:                     "subnet": [
  23:                         {
  24:                             "address_prefix": "10.0.0.0/24",
  25:                             "name": "cunning_brutality",
  26:                             "security_group": ""
  27:                         }
  28:                     ]

Inappropriate value for attribute "subnet": element 0: attribute "id" is
required.

Если я добавлю идентификатор, я получу эту ошибку

Error: "subnet.0.id": this field cannot be set

  on main.tf.json line 30, in [1].resource.azurerm_virtual_network.gork_vnet:
  30:                 }

Кроме того, следует отметить, что в соответствии с документами TF, JSON фактически должен быть структурирован как

                    "subnet": [
                        {
                            "cunning_brutality": {
                                "address_prefix": "10.0.0.0/24",
                                "name": "cunning_brutality",
                                "security_group": ""
                            }
                        }
                    ]

Но это порождает ошибку

Inappropriate value for attribute "subnet": element 0: attributes
"address_prefix", "id", "name", and "security_group" are required.

Заключение

К сожалению, мой анализ кода не дал ничего особенно поучительного, согласно всей документации, это должно сработать. Так что любое направление или руководство будут очень благодарны.


person hpoe    schedule 02.12.2020    source источник


Ответы (2)


После проверки я тоже столкнулся с тем же результатом. В качестве обходного пути вы можете создать подсеть как отдельный блок вместо вложенного аргумента в файле JSON.

Например,

{
    "resource": {
      "azurerm_virtual_network":{
        "example":{
            "address_space": [
                "10.0.0.0/16"
              ],

              "dns_servers": [],
 
              "location": "eastus",
              "name": "wer5rnis6vnet",
              "resource_group_name": "nancyarm"

        }
      },
      "azurerm_subnet":{
        "example":{
            "name": "wer5rnis6subnet",
            "resource_group_name": "nancyarm",
            "virtual_network_name" : "wer5rnis6vnet",
            "address_prefixes": ["10.0.0.0/24"]
        }
    }
    }
      
}

Из документации Terraform о Terraform 0.12 и более поздних версиях. Все, что может быть выражено в собственном синтаксисе, также может быть выражено в синтаксисе JSON, но некоторые конструкции сложнее представить в JSON из-за ограничений грамматики JSON. Прочтите Спецификацию синтаксиса HCL JSON.

В этом случае вы также можете выбрать конфигурацию Cherry-pick. Вы можете добавить недостающие обязательные атрибуты, которые вызвали ошибки в вашем плане, в соответствии с выходными данными шоу terraform.

Например,

resource "azurerm_virtual_network" "example" {


  address_space         = [
        "10.0.0.0/16",
    ]
  
    location              = "eastus"
    name                  = "gork_vnet"
    resource_group_name   = "mork_rg"
    subnet                {
            address_prefix = "10.0.0.0/24"
            name           = "cunning_brutality"
            security_group = ""
        }

}
person Nancy Xiong    schedule 02.12.2020
comment
Привет, спасибо за вклад. Я рад знать, что это не просто я схожу с ума. Я решил, что постараюсь не извлекать подсеть в отдельный блок, поскольку это значительно увеличивает сложность имеющегося у меня сценария. Причина, по которой я не хочу работать с выбором вишен, заключается в том, что объем ресурсов, которые необходимо импортировать, огромен, и это свело бы на нет многое из того, что я надеялся на выполнение сценария. Тем не менее, спасибо за дополнительную информацию и проверку. Ура, приятель! - person hpoe; 02.12.2020
comment
Привет, если проблема будет устранена, вы можете принять один ответ. - person Nancy Xiong; 07.12.2020

Если конфигурация не будет поддерживаться автоматизированными системами на постоянной основе, я бы предупредил, что кто-то, кто просит что-то поддерживать с помощью Terraform, вероятно, ожидает собственного синтаксиса Terraform, а не JSON, потому что этот синтаксис часто считается, что людям будет легче читать и поддерживать в будущем.

С учетом сказанного, если вы действительно намереваетесь использовать JSON, тогда существуют различные правила того, как альтернативный синтаксис JSON соответствует собственному синтаксису, потому что JSON имеет меньше конструкций и, следовательно, конкретная структура JSON может интерпретироваться как одна из множества различных структур собственного синтаксиса в зависимости от контекста.

К сожалению, в этом случае кажется, что документация для azurerm_virtual_network неверна или, по крайней мере, неполна. От ссылки на реализация этого типа ресурса Я вижу, что этот subnet аргумент имеет особое наследие Включен режим Attributes as Blocks, что заставляет Terraform интерпретировать его иначе, что обратно совместимо с некоторыми неожиданными шаблонами из более старых версий Terraform.

Поскольку вы используете синтаксис JSON, подраздел Атрибуты as Blocks In JSON Syntax актуален в вашем случае. Здесь мы видим, что атрибуты с этим устаревшим режимом обработки представлены в JSON с помощью правила сопоставления выражений JSON, а не правила сопоставления блока, что означает, что каждый объект в вашем массиве JSON должен быть допустимым значением типа объекта, выбранного поставщиком для этого блока. Схема для этого типа объекта включает атрибут с именем id, который обычно можно опустить в собственном синтаксисе, но должен быть явно установлен на null в синтаксисе JSON, чтобы результирующее значение было правильного типа:

{
   ...
   "subnet": [
     {
        "address_prefix": "10.0.0.0/24",
        "name": "cunning_brutality",
        "security_group": "",
        "id": null
     }
   ]
   ...
}

Документация поставщика должна упоминать, когда аргумент использует устаревший режим синтаксического анализа, и ссылаться на соответствующую документацию, поэтому отсутствие упоминания этого, возможно, является ошибкой в ​​документации azurerm_virtual_network, о которой вы можете сообщить разработчикам поставщика в репозиторий GitHub поставщика. Но помимо этого, я надеюсь, что этот дополнительный совет, приведенный выше, поможет заставить это работать, если вы не можете использовать более общий собственный синтаксис, в котором эта особая причуда не применяется.

person Martin Atkins    schedule 03.12.2020