解决“应用后已知”问题 – 如何检查变量是否未知?

问题描述 投票:0回答:1

我正在尝试解决我面临的“申请后已知”问题。 确切地说,这是我正在处理的代码:

resource "azurerm_security_center_storage_defender" "defender_for_storage" {
  for_each = {
    for id in [
      azurerm_storage_account.backups.id,
      azurerm_storage_account.media_blobs.id,
    ] : id => id
  }
  storage_account_id                          = each.value
  malware_scanning_on_upload_enabled          = true
  malware_scanning_on_upload_cap_gb_per_month = 10
  sensitive_data_discovery_enabled            = true
}

错误:

╷
│ Error: Invalid for_each argument
│ 
│   on storage.tf line 291, in resource "azurerm_security_center_storage_defender" "defender_for_storage":
│  291:   for_each = {
│  292:     for id in [
│  293:       azurerm_storage_account.backups.id,
│  294:       azurerm_storage_account.media_blobs.id,
│  295:     ] : id => id
│  296:   }
│     ├────────────────
│     │ azurerm_storage_account.backups.id is "***"
│     │ azurerm_storage_account.media_blobs.id is a string, known only after apply
│ 
│ The "for_each" map includes keys derived from resource attributes that
│ cannot be determined until apply, and so Terraform cannot determine the
│ full set of keys that will identify the instances of this resource.
│ 
│ When working with unknown values in for_each, it's better to define the map
│ keys statically in your configuration and place apply-time results only in
│ the map values.
│ 
│ Alternatively, you could use the -target planning option to first apply
│ only the resources that the for_each value depends on, and then apply a
│ second time to fully converge.
╵

这里的问题是存储帐户可能尚不存在,因此在这种情况下无法创建“defender_for_storage”,但如果我删除代码,让 Terraform 创建存储帐户,然后将代码添加回来,它就会起作用.

我知道上面的特定示例还有其他解决方案(例如使用

-target
或不使用
for_each
),但我专门寻找“应用后已知”的解决方案并根据这些值创建资源。

我的建议是做这样的事情:

resource "azurerm_security_center_storage_defender" "defender_for_storage" {
  for_each = {
    for id in [
      isunknown(azurerm_storage_account.backups.id) ? "" : azurerm_storage_account.backups.id,
      isunknown(azurerm_storage_account.media_blobs.id) ? "" : azurerm_storage_account.media_blobs.id,
    ] : id => id if id != ""
  }
  storage_account_id                          = each.value
  malware_scanning_on_upload_enabled          = true
  malware_scanning_on_upload_cap_gb_per_month = 10
  sensitive_data_discovery_enabled            = true
}

在这种情况下,Terraform 中的特殊函数

isunknown
对于尚不存在的存储帐户将默认为
""
,过滤掉未知的帐户,然后继续处理存在的帐户。 然后我可以再次运行它,它将创建剩余的资源,不会出现错误。

我的目标是避免每次部署时都必须更改代码,因为有多个环境使用相同的代码,这确实会弄乱 Git 历史记录。

使用

-target
会使部署的确定性降低并且容易出错,并且必须添加额外的工作流程,所有这些都增加了部署过程的额外工作和不确定性(就错误和前进的能力而言),这应该理想情况下,无论使用什么状态,都只需单击一下即可。

terraform
1个回答
0
投票

“已知性”不会作为您可以在 Terraform 中编程的东西公开,因为这会破坏这样的承诺:当您应用计划时,Terraform 要么按照计划执行,要么返回一个错误来解释为什么它不能。 (这将引入在计划和应用阶段之间发生值变化的可能性,而 Terraform 的执行模型依赖于这种可能性。)

错误消息为您提供了两种选择。您已经排除了

-target
选项,但就您而言,我认为另一个选项更适用:“静态定义地图键”。

例如:

  for_each = {
    backups     = azurerm_storage_account.backups.id
    media_blobs = azurerm_storage_account.media_blobs.id
  }

这将声明两个具有已知实例键的实例:

  • azurerm_security_center_storage_defender.defender_for_storage["backups"]
  • azurerm_security_center_storage_defender.defender_for_storage["media_blobs"]

每一个都会配置相应的存储帐户id。

© www.soinside.com 2019 - 2024. All rights reserved.