Terraform JSON要求嵌套在Azure Vnet对象中的Azure子网具有ID,但不允许对其进行设置

Terraform JSON要求嵌套在Azure Vnet对象中的Azure子网具有ID,但不允许对其进行设置,terraform,terraform-provider-azure,terraform0.12+,vnet,Terraform,Terraform Provider Azure,Terraform0.12+,Vnet,TL;DR:JSON Terraform Azure Vnet要求嵌套子网具有ID,但提供ID时会出错 背景 我有一个Azure帐户,它有一堆带外创建的资源,但现在客户希望我们以terraform管理所有资源。幸运的是terraform有一种导入资源的方法,甚至还有一个可爱的教程演示了如何导入资源并生成必要的配置() 导入资源后,我运行命令tfshow-no color-json>main.tf.json来生成配置的主体。我将其转储到JSON中,因为一旦运行了tfshow,您就需要修改一些输出,

TL;DR:JSON Terraform Azure Vnet要求嵌套子网具有ID,但提供ID时会出错

背景 我有一个Azure帐户,它有一堆带外创建的资源,但现在客户希望我们以terraform管理所有资源。幸运的是terraform有一种导入资源的方法,甚至还有一个可爱的教程演示了如何导入资源并生成必要的配置()

导入资源后,我运行命令
tfshow-no color-json>main.tf.json
来生成配置的主体。我将其转储到JSON中,因为一旦运行了
tfshow
,您就需要修改一些输出,以使结果成为有效的terraform配置文件

在运行
tfshow
之后,我有一个脚本,该脚本将对JSON的结构进行一些更改,并删除要删除或更改的属性

问题 所面临的问题是,当我运行时,在清理由
tf show
生成的输出之后,
tf validate
或任何其他需要验证的命令我得到一个错误,指出
id
属性对于
azurerm\u virtual\u网络中的子网JSON数组中的元素是必需的。但是,当我添加id时,我会收到一个错误,说明无法为Azure子网JSON对象指定
id

请注意,重要的是,只有在使用
.tf.json
文件时才会发生这种情况,如果使用常规
tf
文件,则不会出现任何问题

代码 地形版本:地形v0.13.5

提供程序版本:azurerm v2.38.0

下面是一个TerraformJSON配置,演示了这个问题

    {
        "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.
如果我添加id,则会出现此错误

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.
结论
不幸的是,根据所有的文档,我的代码探索没有发现任何特别有启发性的东西。因此,任何方向或指导都将不胜感激。

经过我的验证,我也将面临同样的结果。作为一种解决方法,您可以将子网创建为单独的块,而不是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"]
        }
    }
    }
      
}
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 = ""
        }

}
从地形到地形0.12及更高版本。可以用本机语法表示的所有内容也可以用JSON语法表示,但由于JSON语法的限制,某些构造在JSON中表示起来更复杂。阅读

在这种情况下,您还可以选择Cherry pick配置。您可以根据terraform show输出添加导致计划中出现错误的缺少的必需属性

比如说,

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

}

除非配置将由自动化系统持续维护,否则我要提醒的是,要求使用Terraform进行维护的人可能期望Terraform的本机语法,而不是JSON,因为这种语法在将来通常被认为更易于阅读和维护

话虽如此,如果您确实打算使用JSON,那么对于替代JSON语法如何与本机语法相对应,有各种规则,因为JSON的结构较少,因此特定的JSON结构可以根据上下文解释为许多不同的本机语法结构之一

不幸的是,在这种情况下,
azurerm_virtual_network
的文档似乎不正确,或者至少不完整。通过参考,我可以看到这个
子网
参数启用了特殊的遗留功能,这迫使Terraform以不同的方式解释它,与旧Terraform版本中的一些意外模式向后兼容

因为您使用的是JSON语法,所以本小节与您的案例相关。我们可以看到,具有这种遗留处理模式的属性在JSON中使用而不是块映射规则表示,这意味着JSON数组中的每个对象都必须是提供者为该块选择的对象类型的有效值。该对象类型的模式包括一个名为
id
的属性,该属性在本机语法中通常可以省略,但在JSON语法中必须显式设置为
null
,以便生成的值的类型正确:

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

提供者文档应该提到当一个参数使用传统解析模式并链接到相关文档时,不必提及这是代码中的一个bug。但除此之外,如果您不能使用更常见的本机语法,而这种特殊的怪癖不适用,我希望上面的额外提示有助于实现这一点。

您好,谢谢您的输入。我很高兴知道这不仅仅是我疯了。我想我应该尽量避免将子网提取到它自己的块中,因为这会显著增加脚本的复杂性。我不想进行樱桃采摘的原因是,必须导入的资源量非常大,这样做会抵消我希望脚本实现的许多功能。不过,感谢您提供更多的见解和验证。干杯,伙计!您好,如果此问题已解决,您可以接受一个答案。