Terraform 将计数为[0或1]的资源的属性传递给模块-可能吗?

Terraform 将计数为[0或1]的资源的属性传递给模块-可能吗?,terraform,Terraform,地形0.12.13,azurerm提供商1.35 一些背景:我有一组Azure应用程序服务,托管在Azure位置的资源组中的应用程序服务计划中。我现在需要在不同的Azure位置复制此堆栈,并添加一些额外的资源,如流量管理器、CNAMEs等,以实现高可用性。在体系结构上,我们有主要资源,然后在次要区域中有次要资源的较小子集(并非所有资源都需要复制)。并非每个部署都需要高可用性,因此我需要能够在运行时实例化或不实例化辅助设备 因为我想成为一名优秀的软件工程师,所以我创建了模块来实例化大部分内容——一

地形0.12.13,azurerm提供商1.35

一些背景:我有一组Azure应用程序服务,托管在Azure位置的资源组中的应用程序服务计划中。我现在需要在不同的Azure位置复制此堆栈,并添加一些额外的资源,如流量管理器、CNAMEs等,以实现高可用性。在体系结构上,我们有主要资源,然后在次要区域中有次要资源的较小子集(并非所有资源都需要复制)。并非每个部署都需要高可用性,因此我需要能够在运行时实例化或不实例化辅助设备

因为我想成为一名优秀的软件工程师,所以我创建了模块来实例化大部分内容——一个用于应用程序服务,一个用于应用程序服务计划,一个用于流量管理器,等等

我现在遇到的问题是,我正在使用旧的计数+三元运算符技巧来控制是否创建辅助资源,这是破坏性的,因为1)count还不允许作为模块元参数,2)我不知道如何将导出的属性作为输入变量从count元参数控制的资源传递给模块

下面的代码可能会更清楚地说明这一点

resource "azurerm_resource_group" "appservices_secondary" {
  name     = "foo-services-ca-${local.secondary_release_stage_name}-${var.pipeline}-rg"
  location = local.secondary_location

  count = var.enable_high_availability ? 1 : 0
}

# Create the app service plan to host the secondary app services
module "plan_secondary" {
  source                     = "./app_service_plan"
  release_stage_name         = local.secondary_release_stage_name

  # HERE'S THE PROBLEMATIC LINE
  appsvc_resource_group_name = azurerm_resource_group.appservices_secondary[0].name

  location                   = local.secondary_location
  pipeline                   = var.pipeline
}
如果计数解析为1(
var.enable\u high\u availability=true
),则一切正常。 如果计数解析为0(
var.enable\u high\u availability=false
),则
terraform plan
失败:

Error: Invalid index

  on .terraform\modules\services\secondary.tf line 25, in module "plan_secondary":
  25:   appsvc_resource_group_name = azurerm_resource_group.appservices_secondary[0].name
    |----------------
    | azurerm_resource_group.appservices_secondary is empty tuple

The given key does not identify an element in this collection value.
如果我将输入变量值更改为
azurerm\u resource\u group.appservices\u secondary.name
,那么它将不会通过
terraform validate
,因为它识别出它需要
[count.index]


有没有简单的方法来解决这个问题?我越来越认为这是一个设计问题,我应该用count=[1..2]而不是count=1(主要)和count=[0 | | 1](次要)构建模块但这需要我重写所有模块,如果有一些巧妙的解决方法,我希望避免这种情况。

为了解决这个问题,您可以使用
appsvc\u资源组\u名称的条件表达式
来提供一些替代值,以便在
azurerm\u资源组.appservices\u secondary
资源
计数=0

  appsvc_resource_group_name = length(azurerm_resource_group.appservices_secondary) > 0 ? azurerm_resource_group.appservices_secondary[0].name : "default-value"
看起来,在禁用高可用性的情况下,此其他模块不可用。在这种情况下,您可能希望将该变量定义为可选变量,默认值为
null
,以便您可以识别该变量何时未在模块中设置:

variable "appsvc_resource_group_name" {
  type    = string
  default = null
}
在配置的其他地方,您可以测试
var.appsvc\u resource\u group\u name!=null
以查看是否已启用


当遵循以下步骤时,我可能会使用以下两种策略之一将其构建为两个模块:

  • 一个模块用于构建“正常”(非HA)堆栈,另一个模块用于构建HA堆栈,然后根据特定配置是需要正常模式还是HA模式,在每个配置的根模块中选择要使用的模块
  • 或者,如果HA堆栈始终是“正常”堆栈的超集,则为正常堆栈设置一个模块,然后为另一个模块使用第一个模块的输出并描述HA模式所需的扩展资源
下面是第二种方法的示例,只是为了说明我的意思:

module "primary_example" {
  source = "./primary_example"

  # whatever arguments are needed
}

module "secondary_example" {
  source = "./secondary_example"

  # Make sure the primary module exports as outputs all of the
  # values required to extend to HA mode, and then just pass
  # that whole object through to secondary.
  primary = module.primary_example
}
在不需要HA模式的配置中,您可以省略
模块“secondary\u example”

模块组合模式是将配置分解为描述一个自包含功能的小块,然后让根模块从这些功能中选择与之相关的任何子集,并以适当的方式将它们连接起来


在这种情况下,我将非HA基础设施视为一种能力,然后将该基础设施的HA扩展视为第二种能力,这取决于第一种能力,以依赖项反转方式将它们连接在一起,这样HA扩展就可以假定非HA部署已经存在,并且有关它的信息将由其调用者传入。

如果未应用
azurerm\u resource\u group.appservices\u secondary
,您是否有一个默认值作为输入?如果是,我可以提供解决方案。如果不是的话,这可能是不可能的。我想我可以这样做-请让我知道你有什么。这在功能上等同于我将要发布的答案,所以继续使用这个。我最终找到了有条件的部分,但这个答案的其余部分实际上比我原来问题的解决方案更有价值。谢谢