【问题标题】:Terraform check if resource exists before creating itTerraform 在创建资源之前检查资源是否存在
【发布时间】:2022-04-25 16:14:49
【问题描述】:

Terraform 有没有办法在尝试创建之前检查 Google Cloud 中的资源是否存在?

我想在工作期间检查以下资源是否存在于我的 CircleCI CI/CD 管道中。我可以访问终端命令、bash 和 gcloud 命令。如果资源确实存在,我想使用它们。如果它们不存在,我想创建它们。我在 CircleCI 的 config.yml 中执行此逻辑作为我可以访问终端命令和 bash 的步骤。我的目标是在需要时在 GCP 中创建必要的基础架构(资源),否则在创建时使用它们,而不会在我的 CI/CD 构建中出现 Terraform 错误。

如果我尝试创建一个已经存在的资源,Terraform 应用将导致错误提示“您已经拥有此资源”,现在我的 CI/CD 作业失败。

以下是描述我试图获取的资源的伪代码。

resource "google_artifact_registry_repository" "main" {
  # this is the repo for hosting my Docker images
  # it does not have a data source afaik because it is beta
}

对于我的 google_artifact_registry_repository 资源。我的一种方法是使用数据源块进行 Terraform 应用,并查看是否返回值。问题在于 google_artifact_registry_repository 没有数据源块。因此,我必须使用资源块创建此资源一次,之后的每个 CI/CD 构建都可以依赖它。是否有解决方法可以读取它存在?

resource "google_storage_bucket" "bucket" {
  # bucket containing the folder below
}

resource "google_storage_bucket_object" "content_folder" {
  # folder containing Terraform default.tfstate for my Cloud Run Service
}

我的 google_storage_bucketgoogle_storage_bucket_object 资源。如果我使用数据源块执行 Terraform 应用以查看这些是否存在,我遇到的一个问题是当找不到资源时,Terraform 需要永远返回该状态。如果我能在 10 到 15 秒之内确定资源是否存在,如果不存在则假设这些资源不存在,那就太好了。

data "google_storage_bucket" "bucket" {
  # bucket containing the folder below
}

output bucket {
  value = data.google_storage_bucket.bucket
}

当资源存在时,我可以使用 Terraform 输出存储桶来获取该值。如果不存在,Terraform 需要很长时间才能返回响应。对此有何想法?

【问题讨论】:

  • 这里的理想路径是将这些资源导入状态并使用 TF 进行管理。
  • 我试过了。我遇到的问题是我正在导入一个不存在的资源(云存储桶)。 Terraform 导入会挂起,或者花了很长时间我没有等待它完成。我希望这个脚本等待更多分钟。如果资源不存在并且我知道,那么我可以创建资源。如果资源存在,那么我可以导入它。我需要先知道资源是否存在,以确定是否需要导入。

标签: terraform terraform-provider-gcp


【解决方案1】:

TF 没有任何内置工具来检查是否存在预先存在的资源,因为这不是 TF 的本意。但是,您可以创建自己的custom data source

使用自定义数据源,您可以编写所需的任何逻辑,包括检查预先存在的资源并将该信息返回给 TF 以供将来使用。

【讨论】:

  • 感谢您分享此内容。我不知道 Terraform 中的外部数据源。我可以看到使用 bash 脚本、python 和 JavaScript 的示例。我编写了一个快速 bash 脚本来调用 gsutil 来获取我的 GCP Cloud Storage 存储桶。我认为这会奏效。谢谢!
【解决方案2】:

这对我有用:

  1. 创建数据
data "gitlab_user" "user" {
  for_each = local.users
  username = each.value.user_name 
}
  1. 创建资源
resource "gitlab_user" "user" {
  for_each       = local.users
  name           = each.key
  username       = data.gitlab_user.user[each.key].username != null ? data.gitlab_user.user[each.key].username : split("@", each.value.user_email)[0]
  email          = each.value.user_email
  reset_password = data.gitlab_user.user[each.key].username != null ? false : true
}

附言

变量

variable "users_info" {
  type = list(
    object(
      {
        name         = string
        user_name    = string
        user_email   = string
        access_level = string
        expires_at   = string
        group_name   = string
      }
    )
  )
  description = "List of users and their access to team's groups for newcommers"
}

当地人

locals {
  users  = { for user in var.users_info : user.name => user }
}

【讨论】:

  • 不,不行,我用 aws_iam_role 试过了
【解决方案3】:

感谢 Marcin 的建议,我有一个工作示例,说明如何使用 Terraform 的 external data sources 检查 GCP 中是否存在资源的问题。这是一种行之有效的方法。我相信还有其他方法。

我有一个 CircleCI config.yml,我有一个使用运行命令和 bash 的工作。从 bash 中,我将初始化/应用一个 Terraform 脚本来检查我的资源是否存在,如下所示。

data "external" "get_bucket" {
  program = ["bash","gcp.sh"]
  query = {
    bucket_name = var.bucket_name
  }
}

output "bucket" {
  value = data.external.get_bucket.result.name
}

然后在我的 gcp.sh 中,我使用 gsutil 来获取我的存储桶(如果存在)。

#!/bin/bash

eval "$(jq -r '@sh "BUCKET_NAME=\(.bucket_name)"')"
bucket=$(gsutil ls gs://$BUCKET_NAME)

if [[ ${#bucket} -gt 0 ]]; then
  jq -n --arg name "" '{name:"'$BUCKET_NAME'"}'
else
  jq -n --arg name "" '{name:""}'
fi

然后在我的 CircleCI config.yml 中,我将它们放在一起。

terraform init
terraform apply -auto-approve -var bucket_name=my-bucket
bucket=$(terraform output bucket)

此时我检查是否返回了存储桶名称,并根据该名称确定如何进行。

【讨论】:

  • 所以事实上你可以在没有 terraform 的情况下做同样的事情?您可以在 yaml 文件级别调用 bash 脚本,而不是为此调用 terraform。据我了解,你在你的情况下调用了 terraform 2 次?第一次知道是否存在,然后第二次将之前的输出作为第二次调用的输入
猜你喜欢
  • 2022-07-28
  • 1970-01-01
  • 2021-10-30
  • 1970-01-01
  • 1970-01-01
  • 2021-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多