TT Lab
开始
学习 学习路径 课程

Terraform/OpenTofu 基础

应用之前筛掉的三样

在 TT Lab 中继续学习

一句话总结

fmt 检查格式,validate 检查结构。两者都看不到值,这个空缺由 console 来弥补。

为什么需要单独的这些检查

只有应用之后才能发现的事故代价高昂。要生成计划,得先下载 provider、读取状态,如果是远程后端,还要获取锁。但实际发生的错误中,相当一部分只要读一读配置文件就能发现:引用了没有声明的变量、漏掉了必填参数、在字符串的位置放了列表,等等。为这类错误一路走到计划阶段,是一种浪费。

格式的性质则不同。问题不在于错了,而在于各人各样。如果使用配置语言的团队开始开会商定缩进规则,这段时间一去不回,而作为结果的评审 diff 里,满是空白而不是内容。所以工具把标准答案定为唯一的一个。消除争论的余地,就是这条命令的设计意图。

工作原理

tofu fmt 默认会修改文件。如果只想判定,就用检查模式,这时退出码分成三种。

tofu fmt -check -diff -recursive   # 고치지 않고 판정만
# 0 : 고칠 것이 없다
# 3 : 고칠 것이 있다
# 2 : 파일을 읽을 수조차 없다(문법 오류)

在使用门禁时,如果区分 2 和 3,提示信息会友好得多。3 是“请运行一次格式化命令”,2 是“这个文件根本无法解析”。要检查到子目录,需要递归选项——没有它的话,只会检查根目录的文件。

tofu validate 需要 provider 的 schema,所以必须先执行 init。在未初始化的目录中运行,它会说没有 provider。它能发现的有三类。

Reference to undeclared input variable   선언 안 한 var.xxx 참조
Missing required argument                필수 인자 누락
Incorrect attribute value type           스키마와 타입 불일치

也有机器可读的格式。加上 -json,会输出 valid、error_count、warning_count 以及诊断列表,CI 可以直接据此判定,也可以附到评审中。

重要的是它发现不了的东西。validate 既不看状态,也不看实物,更不知道变量的值。所以下面这段配置可以毫无问题地通过。

variable "seed_path" { type = string }

resource "local_file" "out" {
  filename = "${path.module}/out.txt"
  content  = file(var.seed_path)
}

结构完美无缺。但一旦要生成计划,就会在两个地方被拦住。不给值,会说“变量没有设置”;给一个不存在的路径,会说“该路径上没有文件”。这两者都是配置文件之外的事实,静态检查无从得知。通过 validate 并不意味着可以应用。

第三个工具 tofu console 会读取当前目录的变量和 locals,逐行对表达式求值。如果把文件通过管道喂给它,也可以用于非交互场景;遇到第一个错误就会停下来,并以非 0 的码结束。用它来确认容易混淆的类型转换很合适。

"5" + 5      ->  10       산술에서는 문자열이 수로 변환된다
1 == "1"     ->  false    같다 비교에서는 변환되지 않는다

在现场相遇的样子

最常见的是门禁顺序排反了的 CI。如果先运行结构检查,只因为一个语法损坏的文件,就会冒出一堆莫名其妙的错误,真正的原因——“括号没有闭合”——反而被埋没了。如果把格式判定放在前面,就会直接指出那个文件。

第二种是门禁修改了仓库。如果把修改模式放进 CI,检查虽然通过,工作树却被悄悄改变,人事后才会发现自己并没有提交过的变更。门禁中应使用只判定的模式。

第三种是前面说过的误解。“检查全都通过了,为什么 apply 还是炸了”这类问题,有一半是值的问题。静态检查只能保证配置文件的语法和结构,对这些值所指向的真实世界,它什么也不说。所以检查通过之后,仍然要做计划评审。

第四种是不使用 console 的团队。每当表达式有疑问,就反复进行“修改配置、应用、查看结果”的往返,这一圈要花好几分钟,失败了还会让状态处于不上不下的境地。在 console 中一行就能确认,往返就消失了。尤其是发生类型转换的地方——算术与比较、字符串与数字之间——不要凭记忆,当场打印出来看更快。

下一项实验要做什么

走完八个步骤。先创建一个格式不一致的目录树,确认判定的退出码;实际修复之后再次判定;再看语法损坏的文件使退出码又有什么不同。接着生成一次能抓出两个结构错误的机器可读输出;反过来,记录结构完好、却因为值而使计划被拦住两次的情形。最后两步,用 console 确认四个表达式,把其中一个搬到实际配置中并应用,再亲手创建把格式判定和结构检查按顺序串起来的提交前门禁。