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

#terraform #terraform-provider-azure #terraform0.12 #vnet

#terraform #terraform-provider-azure #terraform0.12 #виртуальная сеть

Вопрос:

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

Предыстория

У меня есть учетная запись Azure, в которой есть куча ресурсов, созданных вне диапазона, но теперь клиент хочет, чтобы мы управляли всеми ресурсами в terraform. К счастью, у 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 when I run, tf validate или любой другой командой, требующей проверки, я получаю сообщение об ошибке, в котором говорится, что id атрибут требуется для элементов в массиве subnet JSON в объекте azurerm_virtual_network JSON. Однако, когда я добавляю идентификатор, я получаю сообщение об ошибке, в котором говорится, что an id не может быть указан для объекта JSON подсети Azure.

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

Код

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

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

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

     {
        "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.
 

Заключение

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

Ответ №1:

После моей проверки я также сталкиваюсь с тем же результатом. В качестве обходного пути вы можете создать подсеть как отдельный блок вместо вложенного аргумента в файле 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 docs о Terraform 0.12 и более поздних версиях. Все, что может быть выражено в собственном синтаксисе, также может быть выражено в синтаксисе JSON, но некоторые конструкции сложнее представить в JSON из-за ограничений грамматики JSON. Прочитайте спецификацию синтаксиса HCL JSON.

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

Например,

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

}
 

Комментарии:

1. Привет, спасибо за ввод. Я рад знать, что это не только я схожу с ума. Я решил, что постараюсь не извлекать подсеть в ее собственный блок, поскольку это значительно увеличивает сложность моего скрипта. Причина, по которой я не хочу работать с выбором вишни, заключается в том, что объем ресурсов, которые необходимо импортировать, огромен, и это сведет на нет многое из того, что я надеялся выполнить с помощью скрипта. Тем не менее, спасибо за дополнительную информацию и проверку. Приветствую, приятель!

2. Привет, если эта проблема устранена, вы можете принять один ответ.

Ответ №2:

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

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

К сожалению, в этом случае кажется, что документация для azurerm_virtual_network неверна или, по крайней мере, неполная. Из ссылки на реализацию этого типа ресурса я вижу, что в этом subnet аргументе включен специальный устаревший режим «Атрибуты как блоки», который заставляет Terraform интерпретировать его по-другому, что обратно совместимо с некоторыми неожиданными шаблонами из старых версий Terraform.

Поскольку вы используете синтаксис JSON, атрибуты подраздела как блоки в синтаксисе JSON актуальны в вашем случае. Мы можем видеть, что атрибуты с этим устаревшим режимом обработки представлены в 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 поставщика. Но это в стороне, я надеюсь, что этот дополнительный совет выше поможет заставить это работать, если вы не можете использовать более распространенный собственный синтаксис, где эта особая особенность не применяется.