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

时间:2019-11-11 03:31:53

标签: terraform

Terraform 0.12.13,Azurerm提供程序1.35

某些背景:我有一组Azure App Services,它们托管在Azure位置的资源组中的App Service计划中。现在,我需要在另一个Azure位置中复制此堆栈,并添加一些其他资源(例如流量管理器和CNAME,等等)以实现高可用性。从体系结构上讲,我们具有主资源,然后在辅助区域中拥有较小的辅助资源子集(并非所有内容都需要重复)。并非每个部署都需要高可用性,因此我需要能够在运行时实例化或不实例化Secondaries。

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

我现在遇到的问题是,我正在使用旧的count +三元运算符把戏来控制是否创建了辅助资源,并且这样做很麻烦,因为1)尚未将count用作模块元参数,并且2)我不知道如何将导出的属性从计数元参数控制的资源传递到模块作为输入变量。

以下代码可以使这一点更加清楚。

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
}

如果count解析为1(var.enable_high_availability = true),则一切正常。 如果计数解析为0(var.enable_high_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_resource_group.appservices_secondary.name,那么它将不会通过terraform validate,因为它会识别出需要[count.index]

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

1 个答案:

答案 0 :(得分:1)

为了解决此问题,您可以为appsvc_resource_group_name使用条件表达式,以提供一些azurerm_resource_group.appservices_secondary资源具有count = 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_resource_group_name != null以查看其是否已启用。


在遵循the module composition patterns时,我可能会使用以下两种策略之一将其构建为两个模块:

  • 一个用于构建“普通”(非HA)堆栈的模块,另一个用于构建HA堆栈的模块,然后根据特定配置是否需要常规或正常配置,在每个配置的根模块中选择使用哪个模块高可用性模式。
  • 或者,如果HA堆栈始终是“正常”堆栈的超集,请为该正常堆栈提供一个模块,然后再使用另一个模块,该模块使用第一个模块的输出并描述HA模式所需的扩展资源。 / li>

这是其中第二种方法的一个例子,只是为了说明我的意思:

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模式的配置中,您可以省略module "secondary_example"

模块组成模式是将配置分解成描述一个独立功能的小块,然后让根模块从那些功能中选择任何相关的子集,然后以适当的方式进行连接。

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