使用 Terraform External Data Source 產出一串連續日期的列表
上週在寫 Terraform 的時候遇到一個問題,給定一個開始日期與結束日期,要如何在 Terraform 中產出一串由開始日期到結束日期的日期列表?
我的專案中有一個設定檔案 settings.json
,其中設定了開始日期與結束日期。
{
"start_date": "2022-09-01",
"end_date": "2022-09-05"
}
使用 Terraform 提供的 file()
與 jsondecode()
,可以將 JSON 中的每個值,都轉成 Terraform 語言中對應的 Type。
locals {
settings = jsondecode(file("./settings.json"))
}
之後就可以使用 local.settings
來存取 JSON 設定檔案的資料。
local.settings.start_date # 2022-09-01
local.settings.end_date # 2022-09-05
我想利用剛剛取得的開始日期與結束日期,也就是 start_date
與 end_date
,在 Terraform 中產出一串由開始日期到結束日期的日期列表,如下方的結果。
[
"2022-09-01",
"2022-09-02",
"2022-09-03",
"2022-09-04",
"2022-09-05"
]
翻找了一下文件,發現 Terraform 目前只提供四種時間處理方法。
formatdata()
:將時間戳轉成你想要的格式,提供的時間戳格式必須符合 RFC 3339。
> formatdate("DD MMM YYYY hh:mm ZZZ", "2018-01-02T23:12:01Z")
02 Jan 2018 23:12 UTC
> formatdate("EEEE, DD-MMM-YY hh:mm:ss ZZZ", "2018-01-02T23:12:01Z")
Tuesday, 02-Jan-18 23:12:01 UTC
timeadd()
:根據提供的時間戳與想要加上的時間返回一個新的時間戳,返回的時間格式符合 RFC 3339。
> timeadd("2017-11-22T00:00:00Z", "10m")
2017-11-22T00:10:00Z
timecmp()
:將兩個時間做比較,若前者比後者晚則返回數字 1
,相反則返回數字 -1
,相等則返回 0
。
> timecmp("2017-11-22T00:00:00Z", "2017-11-22T00:00:00Z")
0
> timecmp("2017-11-22T00:00:00Z", "2017-11-22T01:00:00Z")
-1
> timecmp("2017-11-22T01:00:00Z", "2017-11-22T00:00:00Z")
1
timestamp()
:產出現在的時間戳,時間戳格式符合 RFC 3339。
> timestamp()
2018-05-13T07:44:12Z
仔細看了每個方法的內容,我感覺似乎很難用這些方法來產出一個日期陣列。問了一下公司經驗豐富的大大,他表示這部分可以使用 external data source 去做
Terraform External Data Source
根據官方文件,external data source 的方法,簡單來說就是請別人協助。我們可以將資料傳遞給其他程式語言處理,處理完之後再傳回 Terraform。
有一點需要注意的是,external data source 產出的資料需要符合 Terraform 的 map(string) 格式。
使用的程式語言可以是 Shell Script 或是 Python,這邊以 Python 當作範例。
首先新增一個 Python 程式碼檔案 date_dict_generator.py
,程式碼需要傳入開始時間與結束時間參數,並產出一個日期列表。
import datetime
import json
import sys
# 讀取傳入的 JSON 參數
input = sys.stdin.read()
input_json = json.loads(input)
# 取得開始日期
start_date = datetime.datetime.strptime(
input_json.get('start_date'), '%Y-%m-%d')
# 取得結束日期
end_date = datetime.datetime.strptime(
input_json.get('end_date'), '%Y-%m-%d')
delta = datetime.timedelta(days=1)
# 宣告一個新的空 Dictionary
date_dict = {}
# 使用回圈,每跑一次開始時間 + 1 天,直到開始日期與結束日期相等為止
while start_date <= end_date:
# 將日期當作元素的 key 與 value ,並放入剛剛宣告的 Dictionary
date_dict[start_date.strftime('%Y%m%d')] = start_date.strftime('%Y%m%d')
start_date += delta
json_string = json.dumps(date_dict, indent=2)
# 將日期列表以 JSON 格式印出才會回傳給 Terraform
print(json_string)
exteranl data source 的結果必須是 Terraform 的 map(string)
格式,也就是 string key 對應 string value。
文章中一開始提到的日期列表,屬於 Terraform 的 set(string)
格式,因此是不行的
[
"2022-09-01",
"2022-09-02",
"2022-09-03",
"2022-09-04",
"2022-09-05"
]
可以稍微調整一下加上與 value 相同的 key 變成 map(string)
格式。
{
"2022-09-01": "2022-09-01",
"2022-09-02": "2022-09-02",
"2022-09-03": "2022-09-03",
"2022-09-04": "2022-09-04",
"2022-09-05": "2022-09-05"
}
最後在 Terraform 中定義一個 external data source,並定義要執行的指令,query
參數可以傳入一個 JSON 格式的參數給外部程式使用,這傳入了開始日期與結束日期,後續就可以在 Python 程式中做計算。
data "external" "date_dict_generator" {
program = ["python3", "${path.module}/date_dict_generator.py"]
query = {
start_date = local.settings.start_date
end_date = local.settings.end_date
}
}
完成之後就可以使用下方的語法取得 Python 運算後的結果。
data.external.date_dict_generator.result