Terraform - 根据条件创建或不创建资源

时间:2021-03-30 13:34:16

标签: terraform terraform-provider-aws

我需要在指定的环境中创建我的资源。例如,如果我有一个尚未准备好用于生产的 AWS Lambda,我需要它仅存在于开发环境中。有没有很好的方法来做到这一点?我知道可以将 count 设置为 0,但我不确定如何将此决定级联到其他资源。

例如,我有一个 AWS Lambda 资源,并且 count 设置为 0。

resource "aws_lambda_function" "example_lambda" {
  count ? local.is_production ? 0 : 1
}

如何将这个决定级联到依赖于上述 AWS Lambda 的其他资源?

假设我有一个 S3 Bucket,它将调用 Lambda 函数。

resource "aws_s3_bucket" "example_bucket" {
  bucket = "bucket_name"
}

resource "aws_lambda_permission" "example_bucket_etl" {
  statement_id  = "AllowExecutionFromS3Bucket"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.example_lambda.arn
  principal     = "s3.amazonaws.com"
  source_arn    = aws_s3_bucket.example_bucket.arn
}

resource "aws_s3_bucket_notification" "bucket_notification" {
  bucket = aws_s3_bucket.example_bucket.id

  lambda_function {
    lambda_function_arn = aws_lambda_function.example_lambda.arn
    events              = ["s3:ObjectCreated:*"]
    filter_prefix       = "example_bucket/"
    filter_suffix       = ".txt"
  
  lambda_function {
    lambda_function_arn = aws_lambda_function.another_lambda_function.arn
    events              = ["s3:ObjectCreated:*"]    
    filter_prefix       = "another_example_bucket/"
    filter_suffix       = ".txt"
  }
}

2 个答案:

答案 0 :(得分:3)

您可以对多个资源使用相同的计数变量。一个更好更清晰的方法是将所有资源添加到一个模块中,如果这在您的代码中是可能的。 https://www.terraform.io/docs/language/meta-arguments/count.html

答案 1 :(得分:1)

当您在 count 块中使用 resource 时,Terraform 会将对该资源的其他引用视为生成代表该资源的每个实例的对象列表。

由于该值只是一个普通的列表值,您可以取其长度以简明扼要地写下“每个 X 应该有一个 Y”的本质陈述,或者在您的特定情况下“应该有一个”每个 lambda 函数的 lambda 权限”。

例如:

resource "aws_lambda_function" "example" {
  count = local.is_production ? 0 : 1

  # ...
}

resource "aws_lambda_permission" "example_bucket_etl" {
  count = length(aws_lambda_function.example)

  function_name = aws_lambda_function.example[count.index].name
  # ...
}

aws_lambda_permission 配置中,我们首先将计数设置为 aws_lambda_function.example 的计数,这告诉 Terraform 我们希望这些计数始终匹配。该连接有助于 Terraform 了解如何解决增加或减少计数的情况,提示生成的创建/销毁操作需要按特定顺序发生才能有效。然后我们使用 count.index 来引用其他资源的索引,在这种情况下它只会为零,但再次帮助 Terraform 在验证期间理解我们的意图。

lambda_function 中的 aws_s3_bucket_notification 嵌套块需要稍微不同的策略,因为在这种情况下,我们不会为每个 lambda 函数创建单独的资源实例,而是仅在单个内部生成一些动态配置块资源实例。对于这种情况,我们可以使用 dynamic blocks 作为一种宏来根据集合的元素生成多个块:

resource "aws_s3_bucket_notification" "bucket_notification" {
  bucket = aws_s3_bucket.example_bucket.id

  dynamic "lambda_function" {
    for_each = aws_lambda_function.example
    content {
      # "lambda_function" in this block is the iterator
      # symbol, so lambda_function.value refers to the
      # current element of aws_lambda_function.example.
      lambda_function_arn = lambda_function.value.arn
      # ...
    }
  }
}

这再次依赖于 aws_lambda_function.example 是一个对象列表这一事实,但以不同的方式:我们要求 Terraform 为 lambda_function 的每个元素生成一个 aws_lambda_function.example 块,将 lambda_function.value 设置为与每个块对应的整个 aws_lambda_function 对象。因此,我们可以从该对象访问 .arn 属性以获取我们需要填充块内的 lambda_function_arn 参数的相应 ARN。

同样,对于这种情况,只会有零个或一个 lambda 函数对象,因此只有零个或一个 lambda_function 块,但在这两种情况下,这种模式都可以推广到 count 的其他值,确保所有这些都将随着您的配置的发展而保持一致。