azure - 无法在 Terraform 中同时创建多个 Azure 防火墙规则集

标签 azure terraform firewall race-condition terraform-provider-azure

我的 Terraform 代码的架构大致如下:

module "firewall_hub" {
  # This creates the Azure Firewall resource

  source      = "/path/to/module/a"
  # attribute = value...
}

module "firewall_spoke" {
  # This creates, amongst other things, firewall rule sets

  source      = "/path/to/module/b"
  hub         = module.firewall_hub
  # attribute = value...
}

module "another_firewall_spoke" {
  # This creates, amongst other things, firewall rule sets

  source      = "/path/to/module/c"
  hub         = module.firewall_hub
  # attribute = value...
}

即,Azure 防火墙资源在 module.firewall_hub 中创建,用作 module.firewall_spokemodule.another_firewall_spoke 的输入> 创建必要的资源并将防火墙规则集注入(inject)防火墙资源。重要的是,规则集在分支模块之间是互斥的,并且被设计成它们的优先级不重叠。

当我尝试部署此代码(构建或销毁)时,Azure 抛出错误:

Error: deleting Application Rule Collection "XXX" from Firewall "XXX (Resource Group "XXX"): network.AzureFirewallsClient#CreateOrUpdate: Failure sending request: StatusCode=0 -- Original Error: autorest/azure: Service returned an error. Status= Code="AnotherOperationInProgress" Message="Another operation on this or dependent resource is in progress. To retrieve status of the operation use uri: https://management.azure.com/subscriptions/XXX" Details=[]

我的工作假设是,即使规则集是互斥的,也不能同时针对同一防火墙发出防火墙规则集的多个创建/更新/删除请求。事实上,如果您在部署失败后等待一分钟左右并重新启动它(无需更改任何 Terraform 代码或手动更新 Azure 中的资源),它将愉快地继续运行,不会出现错误并成功完成。

为了测试我的假设,我尝试通过强制模块序列化来解决这个问题:

module "another_firewall_spoke" {
  # This creates, amongst other things, firewall rule sets

  source      = "/path/to/module/c"
  hub         = module.firewall_hub
  # attribute = value...

  depends_on = [module.firewall_spoke]
}

但是,不幸的是,按照我的模块的编写方式这是不可能的:

Providers cannot be configured within modules using count, for_each or depends_on.

如果没有重写我的模块(不是一个选项),是否可以解决这个竞争条件 - 如果这是问题 - 或者你会认为它是 azurerm 提供程序的错误(即,它应该识别 API 错误响应并等待轮到它,直到超时)?

(Terraform v1.1.7、azurerm v2.96.0)

最佳答案

根据 @silent 向 this answer 举报,我能够使用其中描述的方法解决比赛。

类似这样的事情:

module "firewall_hub" {
  # This creates the Azure Firewall resource

  source      = "/path/to/module/a"
  # attribute = value...
}

module "firewall_spoke" {
  # This creates, amongst other things, firewall rule sets
  # Has an output "blockers" containing resources that cannot be deployed concurrently

  source      = "/path/to/module/b"
  hub         = module.firewall_hub
  # attribute = value...
}

module "another_firewall_spoke" {
  # This creates, amongst other things, firewall rule sets

  source      = "/path/to/module/c"
  hub         = module.firewall_hub
  waits_for   = module.firewall_spoke.blockers
  # attribute = value...
}

因此,技巧是让您的模块导出一个输出,其中包含需要首先部署的所有依赖资源的列表。然后,这可以作为后续模块的输入,通过线程传递到需要 depends_on 值的实际资源。

也就是说,在我的模块深处,资源有:

resource "some_resource" "foo" {
  # attribute = value...

  depends_on = [var.waits_for]
}

使用此方法时需要记住两个重要注意事项:

  1. 模块中的 wait_for 变量必须类型为 anylist(any) 不起作用,因为 Terraform 将此解释为同类列表(很可能不是)。

  2. 奇怪的是,在我看来,depends_on 子句要求您显式使用列表文字(即 [var.waits_for] 而不仅仅是 var .waits_for),即使如果您正在线程处理的变量是一个列表。这不会在我的脑海中进行类型检查,但显然 Terraform 不仅可以接受它,而且它期望它!

关于azure - 无法在 Terraform 中同时创建多个 Azure 防火墙规则集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71750621/

相关文章:

azure - Terraform 工作区不同的变量

ios - 解析服务器:我需要在防火墙中打开哪些端口来发送ios推送通知? (APNS)

跨多个字段的 Azure 搜索模糊建议

azure - 显示从 azure devops 进行二头肌部署期间的错误原因

azure - 转移资源时保留RBAC权限

Linux 每程序防火墙类似于 windows 和 mac 对应物

ubuntu - 如何使用 iptables 保护 docker 容器

sql - 插入值语句只能包含 SQL 数据仓库中的常量文字值或变量引用

networking - 如何使用 cidrsubnet Function 在 Terraform 中分割 CIDR 子网?

amazon-web-services - 地形 : Specifying the working directory when running terraform apply/plan