如何优雅替换Terraform HTTP数据源内容中的多个字符串?
替代Terraform嵌套replace的优雅实现方案
你现在用Terraform拉取远程的all.yml文件,靠嵌套replace来替换字符串,但要替换的内容多了之后,嵌套写法会越来越乱、难维护。这里给你几种更清爽的实现方式:
原代码参考:
data "http" "all_yml" { url = "https://raw.githubusercontent.com/kubespray/kubespray/master/inventory/sample/group_vars/all/all.yml" } resource "local_file" "all_yml" { content = replace(replace(data.http.all_yml.body, "/# - 8.8/", " - 8.8"), "/# upstream_dns_servers/", "upstream_dns_servers") filename = local.all_conf_file }
方法1:用映射表+迭代替换(最推荐)
先在locals里定义所有替换规则的键值对,然后用reduce函数循环执行替换,新增规则直接加键值对就行,清晰又好维护:
data "http" "all_yml" { url = "https://raw.githubusercontent.com/kubespray/kubespray/master/inventory/sample/group_vars/all/all.yml" } locals { # 把所有替换规则写在这:左边是匹配的正则,右边是替换后的内容 replacements = { "/# - 8.8/" = " - 8.8" "/# upstream_dns_servers/" = "upstream_dns_servers" # 要加新的替换?直接在这加一行就行,比如: # "/# some_other_config/" = "some_other_config" } # 自动迭代执行所有替换 transformed_content = reduce(data.http.all_yml.body, acc, repl_key, repl_val) { return replace(acc, repl_key, repl_val) } } resource "local_file" "all_yml" { content = local.transformed_content filename = local.all_conf_file }
方法2:用模板文件(适合大幅修改内容)
如果不光是替换字符串,还要调整内容结构,那就写个本地模板文件,直接在模板里写好最终要的内容,再用templatefile调用:
- 先在你的Terraform目录下创建
all.yml.tpl模板文件,示例内容:
# 保留原文件其他内容,直接修改需要调整的部分 upstream_dns_servers: - 8.8.8.8 - 8.8.4.4 # 其他原文件内容可以直接复制过来修改,或者用变量动态传入
- Terraform代码调用模板:
data "http" "all_yml" { url = "https://raw.githubusercontent.com/kubespray/kubespray/master/inventory/sample/group_vars/all/all.yml" } resource "local_file" "all_yml" { content = templatefile("${path.module}/all.yml.tpl", { # 如果需要从原文件提取部分内容动态插入模板,在这里定义变量就行 # 比如:original_some_config = regex(data.http.all_yml.body, "/some_config: (.*)/") }) filename = local.all_conf_file }
注:这种方式适合需要重构内容结构的场景,单纯替换字符串的话,方法1更轻量。
方法3:批量处理同类型替换(比如批量去注释)
如果要替换的都是同一种类型(比如批量去掉行首的#),可以用regexset匹配所有目标行,统一处理:
data "http" "all_yml" { url = "https://raw.githubusercontent.com/kubespray/kubespray/master/inventory/sample/group_vars/all/all.yml" } locals { # 定义所有需要去掉注释的行的正则 comment_lines = regexset([ "/# - 8.8/", "/# upstream_dns_servers/" ]) # 按行遍历,匹配到的行就去掉行首的# transformed_content = [for line in split("\n", data.http.all_yml.body) : regexset.matches(local.comment_lines, line) ? replace(line, "^#", "") : line ] } resource "local_file" "all_yml" { content = join("\n", local.transformed_content) filename = local.all_conf_file }
内容的提问来源于stack exchange,提问作者ChrisAdkin
相关产品推荐
相关产品推荐

