【问题标题】:create terraform resource (S3 Bucket Object) if already doesn't exists如果已经不存在,则创建 terraform 资源(S3 存储桶对象)
【发布时间】:2021-08-01 13:45:30
【问题描述】:

根据数据源输出条件创建terraform资源。

大家好, 我想在 Terraform 中实现以下要求。

要求:

我想在 s3 存储桶中创建对象(使用 key_name)。
在创建对象之前需要使用数据源检查具有相同键的对象是否已经存在。
如果它已经存在,则不要创建对象。如果没有,请在 s3 存储桶中创建对象。

源代码

variable "key_name" {
  default = "test.txt"
}
variable "bucket_name" {
  default = "test-bucket-654321"
}

data "aws_s3_bucket_objects" "my_objects" {
  bucket = var.bucket_name
}

locals {
  key_present = anytrue([
    for key in data.aws_s3_bucket_objects.my_objects.keys: key == var.key_name
  ])
}

resource "aws_s3_bucket_object" "examplebucket_object" {
  count = local.key_present ? 0 : 1
  
  key     = var.key_name
  bucket  = var.bucket_name
  content = "Test Value"
}

output "my_objects" {
  value = data.aws_s3_bucket_objects.my_objects.keys
}
output "key_present" {
  value = local.key_present
}

假设,key is 在桶中不存在(例如,它是一个没有对象的新桶)

  1. 第一次应用时,它会在存储桶中创建对象。
  2. 在应用 2ns 时间时,它会销毁存储桶中创建的对象。
  3. 第三次应用时,它会在存储桶中创建对象。

第一次,数据源返回空值。所以它会在存储桶中创建对象。
第二次,数据源返回创建的对象名称。所以密钥已经存在,它会破坏桶中的对象。

同样,它每奇数次创建对象,每偶数次销毁创建的对象。

输出:

ubuntu@test-instance:~$ terraform apply --auto-approve
aws_s3_bucket_object.examplebucket_object[0]: Creating...
aws_s3_bucket_object.examplebucket_object[0]: Creation complete after 0s [id=test.txt]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:
key_present = false
my_objects = tolist([])

ubuntu@test-instance:~$ terraform apply --auto-approve
aws_s3_bucket_object.examplebucket_object[0]: Refreshing state... [id=test.txt]
aws_s3_bucket_object.examplebucket_object[0]: Destroying... [id=test.txt]
aws_s3_bucket_object.examplebucket_object[0]: Destruction complete after 0s

Apply complete! Resources: 0 added, 0 changed, 1 destroyed.

Outputs:
key_present = true
my_objects = tolist([
  "test.txt",
])

谁能给我基于数据源输出创建 terraform 资源的解决方案?

【问题讨论】:

  • 你当前的代码有什么问题?

标签: terraform


【解决方案1】:

您上面的代码所做的是,在每次偶数迭代中,条件元参数表达式 count = local.key_present ? 0 : 1 的计算结果为 0,因此您正在命令 terraform 创建 显式 0 数量的资源.

每次偶数迭代,您对 examplebucket_object 的 terraform 配置实际上变成:

resource "aws_s3_bucket_object" "examplebucket_object" {
  count = 0
  
  key     = var.key_name
  bucket  = var.bucket_name
  content = "Test Value"
}

上面的逻辑实际上是在命令 Terraform 删除 examplebucket_object

Terraform 被设计为 幂等,如果资源已经在 Terraform 管理下(状态的一部分),Terraform 会发现并且不会重新配置相同的资源(假设正在应用相同的配置,但您的情况并非如此。)

因此,在您的情况下,您的 Terraform 配置正在根据找到的先前状态更改预期目标状态,这解释了您的难题。

一般情况下你要考虑这种情况:

  1. 如果您希望从一开始就通过 Terraform 管理资源的生命周期,那么您不需要进行任何数据源查询和条件检查。

  2. 如果您希望偶尔遇到现有资源并希望将它们置于 Terraform 管理之下,您需要做的是通过 terraform import 将这些资源导入状态。

    • 目前aws_s3_bucket_object不支持terraform import,但有一个pull-request开放。

注意:

我建议您按照 Terraform 官方文档中的 Conditional Creation of Objects 中所述实施 Dependency Inversion 方法:

我们建议应用依赖反转方法:让模块通过输入变量接受它需要的对象作为参数,而不是尝试编写一个自身尝试检测是否存在并在不存在时创建它的模块。

这与 Terraform 的声明式风格一致:我们不是创建具有复杂条件分支的模块,而是直接描述应该已经存在的内容以及我们希望 Terraform 自己管理的内容。

【讨论】:

    猜你喜欢
    • 2018-08-28
    • 2022-01-10
    • 2021-04-05
    • 1970-01-01
    • 2020-04-16
    • 2021-08-14
    • 2020-07-16
    • 2023-03-07
    相关资源
    最近更新 更多