主頁 >  其他 > Terraform 系列-使用 for-each 對本地 json 進行迭代

Terraform 系列-使用 for-each 對本地 json 進行迭代

2023-06-26 08:29:07 其他

系列文章

  • Terraform 系列文章
  • Grafana 系列文章

概述

前文 Grafana 系列 - Grafana Terraform Provider 基礎 介紹了使用 Grafana Terraform Provider 創建 Datasource.

現在有這么一個現實需求:

有大量的同型別 (type) 的 datasource 需要批量添加,而且這些 datasource 的基本資訊是以 json 的格式已經存在,

需要對 json 進行決議/精簡/重構等操作并將 json 作為 Terraform 的 datasource.

Json 的格式可能類似于這樣:

[
    {
        "env_name": "dev",
        "prom_url": "http://dev-prom.example.com",
        "es_url": "http://dev-es.example.com:9200",
        "jaeger_url": "http://dev-jaeger.example.com"
    },
    {
        "env_name": "test",
        "prom_url": "http://test-prom.example.com",
        "es_url": "http://test-es.example.com:9200",
        "jaeger_url": "http://test-jaeger.example.com"
    }
]

??Notes:

舉一反三,后面的解決方案也適用于其他任意 Json 格式,

該如何實作???

解決方案

通過 Terraform 的 locals jsondecode for 回圈 和 for_each 實作,

具體如下:

  • 構造一個 local 變數
  • local 變數從 .json 檔案中讀取并內容并通過 jsondecode + file 將 json 檔案解碼為 object
  • 使用 for 回圈,將 object 根據當前需求調整,將例子中 env_name 作為 key, 將其他作為 value
  • 批量創建資源時,通過 for_each, 進行批量創建,

基本概念

locals

locals 為 運算式 指定一個名稱,所以你可以在一個模塊中多次使用這個名稱,而不用重復運算式,

如果你熟悉傳統的編程語言,把 Terraform 模塊比作函式定義可能會很有用:

  • variables(輸入變數) 就像函式的引數,
  • outputs(輸出值) 就像函式的回傳值,
  • locals 就像一個函式的臨時本地變數(區域值),

一旦宣告了一個本地值,你可以在 運算式 中以local.<NAME>的形式參考它,

本地值有助于避免在配置中多次重復相同的值或運算式,只有在一個單一的值或結果被用于許多地方的情況下,才可以適度地使用本地值,能夠在一個中心位置輕松地改變數值是本地值的關鍵優勢

file 函式

file讀取指定路徑下的檔案內容,并將其作為 string 回傳,

> file("${path.module}/hello.txt")
Hello World

jsondecode 函式

jsondecode將一個給定的 string 解釋為 JSON,回傳該字串的解碼結果,

該函式以如下方式將 JSON 值映射到 Terraform 語言 type:

JSON type Terraform type
String string
Number number
Boolean bool
Object object(...)的屬性型別根據此表確定
Array tuple(...)的元素型別根據此表確定
Null Terraform 語言的 null

Terraform 語言的自動型別轉換規則意味著你通常不需要擔心一個給定的值到底會產生什么型別,只需以直觀的方式使用結果即可,

> jsondecode("{\"hello\": \"world\"}")
{
  "hello" = "world"
}
> jsondecode("true")
true

jsonencode 執行相反的操作,將一個 string 編碼為 JSON,

for 運算式

一個for運算式通過轉換另一個復雜型別的值來創建一個復雜型別的值,輸入值中的每個元素可以對應于結果中的一個或零個值,并且可以使用一個任意的運算式來將每個輸入元素轉化為輸出元素,

例如,如果var.list是一個字串的串列,那么下面的運算式將產生一個全大寫字母的字串的元組:

[for s in var.list : upper(s)]

這個for運算式遍歷了var.list中的每個元素,然后評估運算式upper(s),將s設定為每個相應的元素,然后它用所有執行該運算式的結果按相同的順序建立一個新的元組值,

一個for運算式的輸入(在in關鍵字之后給出)可以是一個串列,一個集合,一個元組,一個 map,或者一個物件 (object),

上面的例子顯示了一個只有一個臨時符號sfor運算式,但是一個for運算式可以選擇宣告一對臨時符號,以便也使用每個專案的鍵或索引:

[for k, v in var.map : length(k) + length(v)]

對于 map 或物件型別,像上面那樣,k符號是指當前元素的鍵或屬性名稱,你也可以對串列和 map 使用雙符號形式,在這種情況下,額外的符號是每個元素的索引,從 0 開始,常規的符號名稱是iidx,除非選擇一個很有幫助的更具體的名稱:

[for i, v in var.list : "${i} is ${v}"]

索引或關鍵符號總是可選的,如果你在for關鍵字后面只指定一個符號,那么這個符號將總是代表輸入集合的每個元素的值,

for運算式周圍的括號的型別決定了它產生的結果的型別,

上面的例子使用[],產生一個元組,如果你用{}代替,結果是一個物件,你必須提供兩個結果運算式,用=>符號分開:

{for s in var.list : s => upper(s)}

這個運算式產生一個物件,其屬性是來自var.list的原始元素,其相應的值是大寫版本,例如,產生的值可能如下:

{
  foo = "FOO"
  bar = "BAR"
  baz = "BAZ"
}

單獨的for運算式只能產生一個物件值或一個元組值,但 Terraform 的自動型別轉換規則意味著你通常可以在期望使用串列、map 和集合 (set) 的地方使用其結果,

一個 for 運算式也可以包括一個可選的 if 子句來過濾源集合中的元素,產生一個比源值更少元素的值:

[for s in var.list : upper(s) if s != ""]

for運算式中過濾集合的一個常見原因是根據一些標準將一個源集合分成兩個獨立的集合,例如,如果輸入的var.users是一個物件的映射,其中每個物件都有一個屬性is_admin,那么你可能希望產生包含管理員和非管理員物件的單獨映射:

variable "users" {
  type = map(object({
    is_admin = bool
  }))
}

locals {
  admin_users = {
    for name, user in var.users : name => user
    if user.is_admin
  }
  regular_users = {
    for name, user in var.users : name => user
    if !user.is_admin
  }
}

因為for運算式可以從無序型別(map、物件、集合 set)轉換為有序型別(串列、元祖),Terraform 必須為無序集合的元素選擇一個隱含的排序,

對于 map 和物件,Terraform 通過鍵或屬性名稱對元素進行排序,使用詞法排序,

對于字串的集合,Terraform 按其值排序,使用詞法排序,

for運算式機制是為了在運算式中從其他集合值中構建集合值,然后你可以將其分配給期待復雜值的單個資源引數,

for_each 元引數

默認情況下,一個 資源塊 配置一個真實的基礎設施物件(同樣,一個 模塊塊 將一個子模塊的內容納入一次配置),然而,有時你想管理幾個類似的物件(比如一個固定的計算實體池),而不需要為每個物件單獨寫一個塊,Terraform 有兩種方法可以做到這一點: countfor_each

如果一個資源或模塊塊包括一個for_each引數,其值是一個 map 或字串集合,Terraform 為該 map 或字串集合的每個成員創建一個實體,

版本說明: for_each是在 Terraform 0.12.6 中添加的,Terraform 0.13 中增加了對for_each 的模塊支持;以前的版本只能在資源中使用它,

注意:一個特定的資源或模塊塊不能同時使用countfor_each

for_each是 Terraform 語言定義的一個元引數,它可以與模塊和每一種資源型別一起使用,

for_each 元引數接受一個 map 或字串集合,并為該 map 或字串集合的每個專案創建一個實體,每個實體都有一個獨特的基礎設施物件與之相關聯,每個實體都在應用配置時被單獨創建、更新或銷毀,

Map:

resource "azurerm_resource_group" "rg" {
  for_each = {
    a_group = "eastus"
    another_group = "westus2"
  }
  name     = each.key
  location = each.value
}

字串集合:

resource "aws_iam_user" "the-accounts" {
  for_each = toset( ["Todd", "James", "Alice", "Dottie"] )
  name     = each.key
}

在設定了for_each 的區塊中,運算式中還有一個each物件,所以你可以修改每個實體的配置,這個物件有兩個屬性:

  • each.key - 這個實體對應的 map 鍵(或集合成員),
  • each.value - 該實體對應的 map 值,(如果提供了一個集合,這與each.key相同,)

for_each 被設定時,Terraform 區分了區塊本身和與之相關的多個資源或模塊實體,實體由提供給for_each的值中的一個 map 鍵(或集合成員)來識別,

  • <TYPE>.<NAME>module.<NAME> (例如,azurerm_resource_group.rg) 代表這個塊,
  • <TYPE>.<NAME>[<KEY>]module.<NAME>[<KEY>] (例如,azurerm_resource_group.rg["a_group"], azurerm_resource_group.rg["another_group"], etc.) 代表獨立的實體

這與沒有countfor_each的資源和模塊不同,它們可以在沒有索引或鍵的情況下被參考,

String & Template

字串是 Terraform 中最復雜的一種文字表達,也是最常用的一種,

Terraform 同時支持字串的引號語法和 heredoc 語法,這兩種語法都支持用于插值和操作文本的模板序列,

帶引號的字串是一系列由雙引號字符(")劃定的字符,

有兩個不使用反斜線的特殊轉義序列:

Sequence Replacement
$${ 字面意思是${,不會開始一個插值序列,
%%{ 字面意思是%{,不會開始一個模板指令序列,

${ ... }序列是一個插值,它評估標記之間給出的運算式,如果有必要,將結果轉換為字串,然后將其插入到最終的字串中:

"Hello, ${var.name}!"

在上面的例子中,命名的物件var.name被訪問,其值被插入到字串中,產生的結果類似 "Hello, Juan!",

%{ ... } 序列是一個指令,它允許有條件的結果和對集合的迭代,類似于條件和for運算式,

以下指令被支持:

  • %{if <BOOL>}/%{else}/%{endif}指令根據一個 bool 運算式的值在兩個模板之間進行選擇:

    "Hello, %{ if var.name != "" }${var.name}%{ else }unnamed%{ endif }!"
    

    else部分可以省略,在這種情況下,如果條件運算式回傳false,結果就是一個空字串,

  • %{for <NAME> in <COLLECTION>}/%{endfor}指令在給定的集合或結構值的元素上進行迭代,對每個元素評估一次給定的模板,將結果串聯起來:

    <<EOT
    %{ for ip in aws_instance.example.*.private_ip }
    server ${ip}
    %{ endfor }
    EOT
    

實戰

需求:

有大量的同型別 (type) 的 datasource 需要批量添加,而且這些 datasource 的基本資訊是以 json 的格式已經存在,

需要對 json 進行決議/精簡/重構等操作并將 json 作為 Terraform 的 datasource.

Json 的格式可能類似于這樣:

[
    {
        "env_name": "dev",
        "prom_url": "http://dev-prom.example.com",
        "es_url": "http://dev-es.example.com:9200",
        "jaeger_url": "http://dev-jaeger.example.com"
    },
    {
        "env_name": "test",
        "prom_url": "http://test-prom.example.com",
        "es_url": "http://test-es.example.com:9200",
        "jaeger_url": "http://test-jaeger.example.com"
    }
]

解決方案

  • 構造一個 local 變數
  • local 變數從 .json 檔案中讀取并內容并通過 jsondecode + file 將 json 檔案解碼為 object
  • 使用 for 回圈,將 object 根據當前需求調整,將例子中 env 作為 key, 將其他作為 value
  • 批量創建資源時,通過 for_each, 進行批量創建,

串起來, 最終如下:

locals {
  # 將 json 檔案轉換為 物件  
  user_data = https://www.cnblogs.com/east4ming/archive/2023/06/25/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
    }
  }
}

resource "grafana_data_source" "prometheus" {
  # 通過 for_each 迭代
  for_each = local.envs

  type = "prometheus"
  name = "${each.key}_prom"
  uid  = "${each.key}_prom"
  url  = each.value.prometheus

  json_data_encoded = jsonencode({
    httpMethod = "POST"
  })
}

resource "grafana_data_source" "jaeger" {
  for_each = local.envs

  type = "jaeger"
  name = "${each.key}_jaeger"
  uid  = "${each.key}_jaeger"
  url  = each.value.jaeger
}

resource "grafana_data_source" "elasticsearch" {
  for_each = local.envs

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

完成??????

???參考檔案

  • Overview - Configuration Language | Terraform | HashiCorp Developer
  • Terraform: Using for-each in Terraform to iterate through local JSON (copyprogramming.com)
  • automation - Iterate over Json using Terraform - Stack Overflow
  • Using data returned by jsondecode and iterate over the results in a for_each loop - Terraform - HashiCorp Discuss
  • How to Use Terraform's 'for_each', with Examples - The New Stack

三人行, 必有我師; 知識共享, 天下為公. 本文由東風微鳴技術博客 EWhisper.cn 撰寫.

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/555936.html

標籤:其他

上一篇:密碼學概念科普(加密演算法、數字簽名、散列函式、HMAC)

下一篇:返回列表

標籤雲
其他(161585) Python(38248) JavaScript(25513) Java(18259) C(15238) 區塊鏈(8272) C#(7972) AI(7469) 爪哇(7425) MySQL(7266) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4606) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2437) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1971) 功能(1967) Web開發(1951) C++(1942) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • Terraform 系列-使用 for-each 對本地 json 進行迭代

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

    uj5u.com 2023-06-26 08:29:07 more
  • 密碼學概念科普(加密演算法、數字簽名、散列函式、HMAC)

    ## 密碼散列函式 密碼散列函式 (Cryptographic hash function),是一個單向函式,輸入訊息,輸出摘要。主要特點是: - 只能根據訊息計算摘要,很難根據摘要反推訊息 - 改變訊息,摘要一定會跟著改變 - 對于不同的訊息,計算出的摘要幾乎不可能相同 根據散列函式的上述特點,可 ......

    uj5u.com 2023-06-26 08:29:02 more
  • 為醫生打造專屬數字分身!華為云聯合萬木健康打造醫療醫學科普和患

    摘要:如今,醫生出鏡的視頻已經成為喜聞樂見的醫學科普和患者教育手段,但醫生難以抽出時間拍攝、拍攝時間較長、成本較高等制作痛點也日益凸顯。對此,國內首個醫生AI數字人運營服務商——成都萬木健康科技有限公司找到了破局之法。 本文分享自華為云社區《為醫生打造專屬數字分身!華為云聯合萬木健康打造醫療醫學科普 ......

    uj5u.com 2023-06-26 08:28:31 more
  • 深度Q網路:DQN專案實戰CartPole-v0

    摘要:相比于Q learning,DQN本質上是為了適應更為復雜的環境,并且經過不斷的改良迭代,到了Nature DQN(即Volodymyr Mnih發表的Nature論文)這里才算是基本完善。 本文分享自華為云社區《強化學習從基礎到進階-案例與實踐[4.1]:深度Q網路-DQN專案實戰CartP ......

    uj5u.com 2023-06-26 08:28:22 more
  • KubeSphere 社區雙周報 | OpenFunction 發布 v1.1.1 | 2023.6.9-

    KubeSphere 社區雙周報主要整理展示新增的貢獻者名單和證書、新增的講師證書以及兩周內提交過 commit 的貢獻者,并對近期重要的 PR 進行決議,同時還包含了線上/線下活動和布道推廣等一系列社區動態。 本次雙周報涵蓋時間為:2023.6.9-6.22。 ## 貢獻者名單 ![](https ......

    uj5u.com 2023-06-26 08:27:47 more
  • 如何重繪 DNS 快取 (macOS, Linux, Windows)

    如何重繪 DNS 快取 (macOS, Linux, Windows) Unix Linux Windows 如何重繪 DNS 快取 (macOS, FreeBSD, RHEL, CentOS, Debian, Ubuntu, Windows) 請訪問原文鏈接:,查看最新版。原創作品,轉載請保留出處 ......

    uj5u.com 2023-06-26 08:27:01 more
  • C++ 核心指南之資源管理(中)

    > C++ 核心指南(C++ Core Guidelines)是由 Bjarne Stroustrup、Herb Sutter 等頂尖 C++ 專家創建的一份 C++ 指南、規則及最佳實踐。旨在幫助大家正確、高效地使用“現代 C++”。 > > 這份指南側重于介面、資源管理、記憶體管理、并發等 Hig ......

    uj5u.com 2023-06-26 08:26:21 more
  • Note of Introduction to Bioorganic Chemistry and Chemical Bi

    ## Chapter 1: The Fundamentals of Chemical Biology (第 1 章 化學生物學基礎) ### 1.0 INTRODUCTION (引子) #### 1.0.1 Why organize a book on chemical biology around ......

    uj5u.com 2023-06-26 08:20:37 more
  • Midjouney限時免費體驗

    免費體驗Midjourney:https://www.topgpt.one;常見的繪畫風格:室內設計、兒童插畫、表情包制作相關風格都有介紹如何制作,midjourney的強大,只有在使用的時候才能充分體驗。若您想要獲得Midjourney中英對照辭典,請在公眾號回復“mj辭典”。AI已經滲透到各行各... ......

    uj5u.com 2023-06-26 08:14:42 more
  • Python控制流程盤點及高級用法、神秘技巧大揭秘!

    在這篇文章中我們將全面深入地介紹 Python 的控制流程,包括條件陳述句、回圈結構和例外處理等關鍵部分,尤其會將串列決議、生成器、裝飾器等高級用法一網打盡。此外,我還將分享一些獨特的見解和研究發現,希望能給你帶來新的啟發。文章的結尾,我們將有一個 "One More Thing" 環節,我會分享一個 ......

    uj5u.com 2023-06-26 08:09:08 more