Terraform 系列-批量创建资源时如何根据某个字段判断是否创建

系列文章

概述

前文 Grafana 系列 - Grafana Terraform Provider 基础 介绍了使用 Grafana Terraform Provider 创建 Datasource.

这几天碰到这么一个现实需求:

使用 Terraform 批量创建日志数据源时, 有的数据源类型是 ElasticSearch, 有些是 Opensearch. 那么, 如何根据某个字段(如:es_type)判断是否创建?

另外, 建议您先阅读前一篇文章: Terraform 系列 - 使用 for-each 对本地 json 进行迭代 方便快速了解上下文背景.

创建数据源的数据来源是个 json, json 通过前一篇文章的转换, 格式类似于这样:

json 复制代码
{
    "dev": 
    {
        "env_name": "dev",
        "prom_url": "http://dev-prom.example.com",
        "jaeger_url": "http://dev-jaeger.example.com",
        "es_url": "http://dev-es.example.com:9200",
        "es_type": "elasticsearch"
    },
    "test": 
    {
        "env_name": "test",
        "prom_url": "http://test-prom.example.com",
        "jaeger_url": "http://test-jaeger.example.com",
        "es_url": "http://test-es.example.com:9200",
        "es_type": "opensearch"
    }
}

该如何实现?🤔

解决方案

使用: for 循环 + if 重构 map.

具体如下:

  • 批量创建资源时,通过 for_each, 进行批量创建。
  • 但是在 for_each 时, 通过 for 循环 + if 重构 map, 通过 local.env.es_type 判断是否创建.

具体如下:

Terraform 复制代码
locals {
  # 将 json 文件转换为 对象  
  user_data = jsondecode(file("${path.module}/env-details.json"))
  # 构造一个 map
  # key 是 env_name
  # value 又是一个 map, 其 key 是 grafana datasource type, value 是 url
  envs = { for env in local.user_data : env.env_name =>
    {
      prometheus = env.prom_url
      # 利用 ${} 构造新的 url
      jaeger     = "${env.jaeger_url}/trace/"
      es         = env.es_url
      es_type    = env.es_type
    }
  }
}


resource "grafana_data_source" "elasticsearch" {
  for_each = {
    for env_name, env_info in local.envs : env_name => env_info
    if env_info.es_type == "elasticsearch"
  }

  type          = "elasticsearch"
  name          = "${each.key}_es"
  uid           = "${each.key}_es"
  url           = each.value.es
  database_name = "[example.*-]YYYY.MM.DD"

  json_data_encoded = jsonencode({
    esVersion = "6.0.0"

    interval = "Daily"
    includeFrozen              = false
    maxConcurrentShardRequests = 256
    timeField                  = "@timestamp"

    logLevelField   = "level"
    logMessageField = "message"
  })
}

resource "grafana_data_source" "opensearch" {
  for_each = {
    for env_name, env_info in local.envs : env_name => env_info
    if env_info.es_type == "opensearch"
  }

  type = "grafana-opensearch-datasource"
  name = "${each.key}_opensearch"
  uid  = "${each.key}_opensearch"
  url  = each.value.es
  basic_auth_enabled  = true
  basic_auth_username = "readonly"

  json_data_encoded = jsonencode({
    database = "[example.*-]YYYY.MM.DD"
    version  = "6.8.0"
    flavor   = "elasticsearch"

    interval = "Daily"
    pplEnabled                 = true
    maxConcurrentShardRequests = 256
    timeField                  = "@timestamp"

    logLevelField   = "level"
    logMessageField = "message"
  })

  secure_json_data_encoded = jsonencode({
    basicAuthPassword = "Changeme!"
  })
}

不要看到这么长的代码就头晕, 很多跟本次没啥关系. 实现的关键就在于如下代码段:

Terraform 复制代码
  for_each = {
    for env_name, env_info in local.envs : env_name => env_info
    if env_info.es_type == "elasticsearch"
  }

还是很直白易懂的, 就不详细说明了. 如果 es_typeelasticsearch, 才把这个对象构造到 map 中.

之后, 对于不同的 DataSource type, 会有不同的参数, 如上文:

  • Opensearch 具有和 ES 不同的 type, Opensearch 加了认证
  • Opensearch 里是 database 字段而不是 database_name
  • Opensearch 里额外还有 flavor 字段和 pplEnabled 字段.

解决方案二

如果您的原始数据, 或者构造后的 localslist 而不是 map.

那么也可以使用: count + condition ? true_val : false_val 条件表达式完成同样的功能.

示例如下:

通过 var.cloudflare 的值是 true 还是 false 来判断.

Terraform 复制代码
resource "cloudflare_record" "record" {
  count = var.cloudflare ? 1 : 0
  zone_id = "${data.cloudflare_zones.domain.zones[0].id}"
  name    = "${var.subdomain}"
  value   = "${var.origin_server}"
  type    = "CNAME"
  ttl     = 1
  proxied = true
}

关键点是: count = var.cloudflare ? 1 : 0 条件表达式.

也很清晰明了.

完成🎉🎉🎉

📚️参考文档

三人行, 必有我师; 知识共享, 天下为公. 本文由东风微鸣技术博客 EWhisper.cn 编写.

相关推荐
木鱼时刻13 小时前
容器与 Kubernetes 基本概念与架构
容器·架构·kubernetes
chuanauc1 天前
Kubernets K8s 学习
java·学习·kubernetes
庸子1 天前
基于Jenkins和Kubernetes构建DevOps自动化运维管理平台
运维·kubernetes·jenkins
李白你好2 天前
高级运维!Kubernetes(K8S)常用命令的整理集合
运维·容器·kubernetes
Connie14512 天前
k8s多集群管理中的联邦和舰队如何理解?
云原生·容器·kubernetes
伤不起bb2 天前
Kubernetes 服务发布基础
云原生·容器·kubernetes
别骂我h2 天前
Kubernetes服务发布基础
云原生·容器·kubernetes
weixin_399380692 天前
k8s一键部署tongweb企业版7049m6(by why+lqw)
java·linux·运维·服务器·云原生·容器·kubernetes
斯普信专业组3 天前
K8s环境下基于Nginx WebDAV与TLS/SSL的文件上传下载部署指南
nginx·kubernetes·ssl
&如歌的行板&3 天前
如何在postman中动态请求k8s中的pod ip(基于nacos)
云原生·容器·kubernetes