【问题标题】:Terraform - How to use conditionally created resource's output in conditional operator?Terraform - 如何在条件运算符中使用有条件创建的资源输出?
【发布时间】:2019-10-08 23:06:10
【问题描述】:

如果用户不提供 vpc id,我必须创建 aws_vpc 资源。之后,我应该使用该 VPC 创建资源。

现在,我在创建 aws_vpc 资源时应用条件。例如,仅当existing_vpc 为 false 时才创建 VPC:

count                = "${var.existing_vpc ? 0 : 1}"

接下来,例如,我必须在 VPC 中创建节点。如果existing_vpc 为真,则使用var.vpc_id,否则使用从aws_vpc 资源计算的VPC ID。

但是,问题是,如果 existing_vpc 为真,aws_vpc 将不会创建新资源,并且三元条件无论如何都会尝试检查是否正在创建 aws_vpc 资源。如果它没有被创建,则 terraform 错误。

aws_subnet 上使用条件运算符时的错误示例:

Resource 'aws_subnet.xyz-subnet' not found for variable 'aws_subnet.xyz-subnet.id'

导致错误的代码是:

subnet_id = "${var.existing_vpc ? var.subnet_id : aws_subnet.xyz-subnet.id}"

如果两者相互依赖,我们如何创建条件资源并基于它们为其他配置赋值?

【问题讨论】:

  • 您的问题的直接答案是在即将发布的 0.12 版本中使用 null。间接的答案是,听起来应该重做代码条件和组织以避免这个问题,因为 subnet_id 的三元组似乎应该不同。
  • 好吧,我的提供商目前不支持 0.12。所以,我必须继续使用 0.11.x。有什么办法可以完成这项工作?

标签: terraform terraform-provider-aws


【解决方案1】:

您可以按如下方式访问动态创建的模块和资源

output "vpc_id" {
  value = length(module.vpc) > 0 ? module.vpc[*].id : null
}
  • 如果 count = 0,则输出为空
  • 如果 count > 0,则输出为 vpc id 列表

如果 count = 1 并且您希望接收单个 vpc id,您可以指定:

output "vpc_id" {
  value = length(module.vpc) > 0 ? one(module.vpc).id : null
}

【讨论】:

  • “ONE”函数仅在 Terraform v0.15 及更高版本中可用。
【解决方案2】:

以下示例展示了如何选择性地指定是否创建资源(使用条件运算符),并展示了在未创建资源时如何处理返回的输出。这恰好是使用模块完成的,并使用object 变量的元素作为标志来指示是否应该创建资源。

但要具体回答您的问题,您可以使用条件运算符,如下所示:


    output "module_id" {
       value = var.module_config.skip == true ? null : format("%v",null_resource.null.*.id)
    }

并在调用 main.tf 中访问输出:

module "use_conditionals" {
    source = "../../scratch/conditionals-modules/m2" # << Change to your directory
    a = module.skipped_module.module_id # Doesn't exist, so might need to handle that.
    b = module.notskipped_module.module_id
    c = module.default_module.module_id
}

完整示例如下。注意:这是使用 terraform v0.14.2


# root/main.tf
provider "null" {}

module "skipped_module" {
    source = "../../scratch/conditionals-modules/m1" # << Change to your directory
    module_config = { 
        skip = true         # explicitly skip this module.
        name = "skipped" 
    }
}

module "notskipped_module" {
    source = "../../scratch/conditionals-modules/m1" # << Change to your directory
    module_config = { 
        skip = false        # explicitly don't skip this module.
        name = "notskipped"
    }
}

module "default_module" {
    source = "../../scratch/conditionals-modules/m1" # << Change to your directory
    # The default position is, don't skip. see m1/variables.tf
}

module "use_conditionals" {
    source = "../../scratch/conditionals-modules/m2" # << Change to your directory
    a = module.skipped_module.module_id
    b = module.notskipped_module.module_id
    c = module.default_module.module_id
}

# root/outputs.tf
output skipped_module_name_and_id {
    value = module.skipped_module.module_name_and_id
}

output notskipped_module_name_and_id {
    value = module.notskipped_module.module_name_and_id
}

output default_module_name_and_id {
    value = module.default_module.module_name_and_id
}

模块


# m1/main.tf
resource "null_resource" "null" {
    count = var.module_config.skip ? 0 : 1 # If skip == true, then don't create the resource.

    provisioner "local-exec" {
        command = <<EOT
        #!/usr/bin/env bash
        echo "null resource, var.module_config.name: ${var.module_config.name}"
EOT
    }
}

# m1/variables.tf
variable "module_config" {
    type = object ({ 
        skip = bool, 
        name = string 
    })
    default = {
        skip = false
        name = "<NAME>"
        }
}

# m1/outputs.tf
output "module_name_and_id" {
   value = var.module_config.skip == true ? "SKIPPED" : format(
      "%s id:%v",
      var.module_config.name, 
      null_resource.null.*.id
   )
}

output "module_id" {
      value = var.module_config.skip == true ? null : format("%v",null_resource.null.*.id)
}

【讨论】:

    【解决方案3】:

    当您使用更现代版本的 terraform 时,此处的当前答案很有帮助,但正如 OP here 所指出的,当您使用

    请参阅 more info 的 terraform 项目中的相关问题,了解为什么旧版本需要以下内容。

    但为了避免链接失效,我将使用 OPs 示例 subnet_id 参数并使用 github 问题中的答案。

    subnet_id = "${element(compact(concat(aws_subnet.xyz-subnet.*.id, list(var.subnet_id))),0)}"
    

    由内而外:

    1. concat 将 splat 输出列表加入到 list(var.subnet_id) ——根据后台链接“当 count = 0 时,“splat 语法”扩展为一个空列表”
    2. compact 将删除空项
    3. element 只会在 compact 收到空的 splat 输出时返回您的 var.subnet_id。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-26
      • 2018-01-21
      • 2021-11-20
      • 2021-12-21
      • 2020-11-10
      • 2020-05-30
      • 2017-12-09
      相关资源
      最近更新 更多