LabHub
学习 学习路径 课程

基础设施即代码

幂等的资源保障脚本

在 LabHub 中继续学习

目标

编写能够保证目录、文件、文本行和权限状态的幂等脚本,连续应用两次,并以 changed 变为 0 来证明幂等性。最后再加入状态文件、漂移检测与锁。

为什么重要

幂等性是指多次执行同一操作,结果仍然相同;它保证自动化任务可以安全地重新运行。证明方法是连续应用两次,观察第二次 plan 是否没有变更。破坏幂等性的地方几乎总是固定的:不用专用模块,而是通过 shell 或 command 直接执行命令;以及用 >> 追加文本行。因此,本实验中的所有脚本都采用相同骨架:“修改之前先检查”。最后添加的状态文件与锁,可以让你亲自理解真实 IaC 工具为何需要这些附属机制。

步骤

  1. 创建 /root/iac2/ensure_dir.sh <경로>。目录不存在时创建并输出 changed,已存在时输出 unchanged。两种情况的退出码都为 0。输出必须是只包含该单词的一行(评分会把 unchanged 与整行精确比较)。
  2. 创建 /root/iac2/ensure_file.sh <경로> <내용>。文件不存在或内容不同时写入内容并输出 changed,内容已经相同时输出 unchanged
  3. 创建 /root/iac2/ensure_line.sh <파일> "<줄>"。该行已经精确存在时输出 unchanged;存在同一键(行中第一个单词)的其他行时,在原位置替换为新行并输出 changed;完全不存在时追加到末尾并输出 changed。无论执行多少次,该行在文件中都必须恰好存在一份,其他行则保持不变。
  4. 创建 /root/iac2/ensure_mode.sh <파일> <8진수모드>。通过 stat -c %a 读取当前权限;不同时执行 chmod 并输出 changed,相同时输出 unchanged。文件不存在时返回非 0 退出码。
  5. 创建 /root/iac2/run.sh。使用上述四个脚本恰好保证 4 个资源(例如目录 1 个 + 文件 2 个 + 权限 1 个)。最后一行按 unchanged=<수> changed=<수> 的顺序输出汇总。把第一次运行输出保存到 /root/iac2/run1.txt,紧接着把第二次运行输出保存到 /root/iac2/run2.txt。第一次运行的 changed 必须不小于 1,第二次运行的汇总必须是 unchanged=4 changed=0
  6. 创建 /root/iac2/state.json。在 resources 数组中记录刚才保证的资源(至少 2 个),每个元素包含 pathtypefiledir)和 sha256type 不是 dir 的项目必须对应真实存在的文件,且 sha256 值必须与 sha256sum <경로> 输出的第一个字段完全相同。顶层还要包含 applied_at(应用时间)。
  7. 创建 /root/iac2/drift.sh <상태파일>。读取参数指定的状态文件,验证其中记录的资源。全部一致时退出码为 0;内容变化或文件消失时,输出不一致的路径并返回非 0 退出码。对于 typedir 的项目,只检查是否存在。
  8. 创建 /root/iac2/apply-lock.sh。锁文件路径从 LOCK_FILE 环境变量读取,未设置时使用 /root/iac2/.lock。如果没有锁,就通过条件创建获得锁;完成工作并正常退出时必须将其删除(退出码为 0,不能残留锁文件)。已经锁定时不要等待,而应立即以退出码 2 失败,并输出包含 lock 一词的消息。此时绝不能删除其他进程的锁文件。

参考

保证目录状态

创建 /root/iac2/ensure_dir.sh <경로>。目录不存在时创建并输出 changed,已存在时输出 unchanged。两种情况的退出码都为 0。输出必须是只包含该单词的一行(评分会把 unchanged 与整行精确比较)。

ensure_dir.sh <경로> 应在目录不存在时创建并输出 changed,已存在时输出 unchanged。两种情况的退出码都为 0。输出必须是只包含该单词的一行。评分会把 unchanged 与整行精确比较。

保证文件内容

创建 /root/iac2/ensure_file.sh <경로> <내용>。文件不存在或内容不同时写入内容并输出 changed,内容已经相同时输出 unchanged

使用 ensure_file.sh <경로> <내용>。写入前先与当前内容比较。不存在或不同时写入并输出 changed,相同时不要修改,输出 unchanged。如果无条件写入,就会始终报告 changed,无法证明幂等性。

保证文本行且不重复

创建 /root/iac2/ensure_line.sh <파일> "<줄>"。该行已精确存在时输出 unchanged;存在同一键(行中第一个单词)的其他行时,在原位置替换为新行并输出 changed;完全不存在时追加到末尾并输出 changed。无论执行多少次,该行在文件中都必须恰好存在一份,其他行保持不变。

使用 ensure_line.sh <파일> "<줄>"。如果用 >> 追加,每次执行都会累积文本行。相同行已经存在时输出 unchanged;存在相同键(第一个单词)的其他行时,在原位置替换并输出 changed;不存在时追加到末尾并输出 changed。其他行必须保持不变。

保证权限状态

创建 /root/iac2/ensure_mode.sh <파일> <8진수모드>。通过 stat -c %a 读取当前权限;不同时执行 chmod 并输出 changed,相同时输出 unchanged。文件不存在时返回非 0 退出码。

ensure_mode.sh <파일> <8진수모드> 使用 stat -c %a 读取并比较当前权限。不同时执行 chmod 后输出 changed,相同时输出 unchanged。不要尝试对不存在的文件执行 chmod 后仍报告成功,应先检查文件是否存在。

运行两次以证明幂等性

创建 /root/iac2/run.sh。使用上述四个脚本恰好保证 4 个资源(例如目录 1 个 + 文件 2 个 + 权限 1 个)。最后一行按 unchanged=<수> changed=<수> 的顺序输出汇总。把第一次运行输出保存到 /root/iac2/run1.txt,紧接着把第二次运行输出保存到 /root/iac2/run2.txt。第一次运行的 changed 必须不小于 1,第二次运行的汇总必须是 unchanged=4 changed=0

run.sh 恰好保证 4 个资源,并在最后一行按 unchanged=<수> changed=<수> 的顺序输出汇总。顺序很重要。把第一次运行输出保存到 /root/iac2/run1.txt,紧接着把第二次运行输出保存到 /root/iac2/run2.txt

保存状态文件

创建 /root/iac2/state.json。在 resources 数组中记录刚才保证的资源(至少 2 个),每个元素包含 pathtypefiledir)和 sha256type 不是 dir 的项目必须对应真实存在的文件,且 sha256 值必须与 sha256sum <경로> 输出的第一个字段完全相同。顶层还要包含 applied_at(应用时间)。

/root/iac2/state.json 中记录刚刚应用的资源。每个元素包含 pathtypesha256,文件项目的哈希必须与 sha256sum <경로> 输出的第一个字段完全相同。顶层还要添加 applied_at。必须在运行 run.sh 之后创建,哈希才会一致。

检测漂移

创建 /root/iac2/drift.sh <상태파일>。读取参数指定的状态文件并验证其中记录的资源。全部一致时退出码为 0;内容变化或文件消失时,输出不一致的路径并返回非 0 退出码。对于 typedir 的项目,只检查是否存在。

drift.sh <상태파일> 必须读取参数传入的状态文件。如果硬编码路径,就无法读取评分程序创建的临时状态文件。既要检测内容变化,也要检测文件删除;同时输出不一致的路径,让人知道应该检查什么。

状态锁

创建 /root/iac2/apply-lock.sh。锁文件路径从 LOCK_FILE 环境变量读取,未设置时使用 /root/iac2/.lock。如果没有锁,就通过条件创建获得锁;完成工作并正常退出时必须删除它(退出码为 0,不能残留锁文件)。已经锁定时不要等待,而应立即以退出码 2 失败,并输出包含 lock 一词的消息。此时绝不能删除其他进程的锁文件。

apply-lock.sh 必须遵循 LOCK_FILE 环境变量。没有锁时通过条件创建获得锁,并在正常退出时必须删除它(退出码 0)。已经锁定时不要等待,而应立即以退出码 2 失败,并通过消息说明原因是锁。绝不能删除其他进程的锁文件。