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

terraform,系列,批量,创建,资源,如何,根据,某个,字段,判断,是否 · 浏览次数 : 25

小编点评

## 批量创建日志数据源的示例 使用 for_each 对 local json 进行迭代,根据某个字段判断是否创建。 **代码示例:** ```terraform locals { # 将 json 文件转换为对象 user_data = jsondecode(file("\"${path.module}/env-details.json\")") # 构造一个 map 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 } 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" }) secure_json_data_encoded = jsonencode({ basicAuthPassword = "Changeme!" }) } resource "grafana_data_source" "opensearch" { for_each = { for env_name, env_info in local.envs : env_name => env_info } 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" }) } ``` **说明:** * `local.envs` 是一个 map,其中每个 key 代表一个 env 的名称,每个 value 是一个 map,其中包含该 env 的相关信息。 * `if env_info.es_type == "elasticsearch"` 判断是否创建 ElasticSearch 数据源。 * `var.cloudflare` 是一个变量,用于控制是否创建cloudflare 数据源。

正文

系列文章

概述

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

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

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

另外, 建议您先阅读前一篇文章: Terraform 系列 - 使用 for-each 对本地 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 判断是否创建.

具体如下:

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!"
  })
}

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

  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 来判断.

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 条件表达式.

也很清晰明了.

完成🎉🎉🎉

📚️参考文档

与Terraform 系列-批量创建资源时如何根据某个字段判断是否创建相似的内容:

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

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

Terraform 系列-Terraform 项目的典型文件布局

系列文章 👉 Terraform 系列文章 典型文件布局 - modules/ - services/ - webserver-cluster/ - examples/ - main.tf - outputs.tf - vars.tf - user-data.sh - README.md - [

Terraform 系列-什么是 IaC?

聊到 Terraform, 必然绕不开 IaC 这个概念?那么,什么是 IaC?

Terraform 系列-Terraform 简介

系列文章 👉 Terraform 系列文章 前言 最近在使用 Terraform 来置备 OCI 的 Always Free Tier, 发现它非常好用。总结学习下:Terraform 的基础知识。 什么是 Terraform? Terraform 是一种基础架构即代码(IaC)工具,可让您安全高

Terraform 系列-Terraform Cloud 比 Terraform OSS 有哪些增强?

系列文章 👉 Terraform 系列文章 前言 最近在使用 Terraform Cloud 来置备 OCI 的 Always Free Tier, 发现它非常好用,相比 Terraform OSS, 用起来省心多了。 也借此总结学习下:Terraform Cloud 比 Terraform OS

Terraform 系列-使用 for-each 对本地 json 进行迭代

## 系列文章 * [Terraform 系列文章](https://ewhisper.cn/tags/Terraform/) * [Grafana 系列文章](https://ewhisper.cn/tags/Grafana/) ## 概述 前文 [Grafana 系列 - Grafana Ter

Grafana系列-GaC-1-Grafana即代码的几种实现方式

## 系列文章 * [Grafana 系列文章](https://ewhisper.cn/tags/Grafana/) * [Terraform 系列文章](https://ewhisper.cn/tags/Terraform/) ## 概述 GaC(Grafana as Code, Grafana

Grafana 系列-GaC-2-Grafana Terraform Provider 基础

本文为系列文章-Grafana GaC(Grafana 即代码) 的第二篇 - Grafana Terraform Provider 基础。

Terraform 新手村指南,萌新必读!

基础设施即代码(IaC)是指使用代码和软件开发技术来配置和管理基础设施的实践。IaC 背后的逻辑是尽量消除手动配置基础设施和资源的需求,比如服务器、负载均衡以及数据库等。由于基础设施是整个软件开发流程的一个组成部分,并且与应用交付更紧密地联系在一起,因此让基础设施的更改更容易交付十分重要。 使用代码

Terraform 改善基础架构的十个最佳实践

Terraform 是一种非常流行的开源 IaC(基础设施即代码)工具,用于定义和提供完整的基础设施。Terraform 于 2014 年推出,其采用率已在全球范围内快速增长,越来越多的开发人员正在学习 Terraform 并尝试在其组织中部署基础设施。 如果您已经开始使用 Terraform,则必