iac_modules/skills/terraform-yaml-render-pattern/SKILL.md
Haitao Pan 3a8065e6f0 refactor(vultr-vps): split declaration / shared templates / shared scripts
- config/resources/ai-workspace-hosts.yaml: resource declaration (moved from env)
- templates/: shared provider.tf, variables.tf, cloud-init.yaml + hosts.tf.j2,
  inventory.ini.j2 (render copies the .tf/config into the env workdir)
- scripts/generate.py + provision.sh: shared composition logic, parameterized
  by --resources/--workdir (no longer duplicated per env)
- envs/ai-workspace/: degraded to a terraform workdir (only README/.gitignore
  tracked; rendered artifacts + tfstate gitignored)
- AGENTS.md + terraform-yaml-render-pattern skill updated to the layered layout

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 21:21:45 +08:00

4.8 KiB
Raw Blame History

Skill: terraform-yaml-render-pattern

Purpose

约束性规范:在 iac_modules/terraform-hcl-standard/** 下编排可批量创建的资源 (典型如多主机 VPS必须采用「YAML 描述 → Python+Jinja2 渲染显式 HCL 块 → Terraform apply → Python 合并生成 CMDB/Inventory」的范式不得在 HCL 内做循环。

这是 binding skill与本文件冲突的写法一律以本文件为准。 配套约束见 iac_modules/terraform-hcl-standard/AGENTS.md

参考实现(基准,新 env 照此结构落地):terraform-hcl-standard/vultr-vps/envs/ai-workspace/

Pattern强制数据流

hosts.yaml (唯一人工入口:资源描述 / CMDB 源)
   │  generate.py render   —— 循环在 Python+Jinja2 侧完成
   ├─▶ generated_hosts.tf            每实例/每 key 一个独立显式 module/resource/data 块
   └─▶ terraform.auto.tfvars.json ──▶ variables.tf   (global 段 -> 变量)
        │
        ▼  terraform apply
   output "cmdb_runtime"  (仅运行时事实ip / instance_id / 解析后的 os_id)
        │  generate.py inventory  —— 合并 YAML 静态字段 + 运行时输出
        ├─▶ cmdb.json        (IaC ↔ Ansible 契约)
        └─▶ inventory.ini
                 │
                 ▼  Ansible 动态 inventory: playbooks/inventory/terraform_cmdb.py (只读 cmdb.json)

Rules

MUST NOT

  • 不在 env 的 .tf 中使用 for_each / count / dynamic
  • 不用 templatefile() + %{ for } / %{ if } 等 HCL 模板控制结构做渲染。

MUST

  • 资源信息由 env 内 hosts.yaml 描述;多份资源由 Jinja2 展开为多个命名唯一的显式块
  • YAML 全局段经 terraform.auto.tfvars.json 传给 variables.tf;逐实例字段由 Jinja2 进 .tf
  • 机密走环境变量(如 TF_VAR_vultr_api_key禁止写入 YAML/tfvars公钥可入 YAML。
  • 共享 scripts/generate.py--resources/--workdir 参数化)提供 renderinventory 两个子命令(职责见上图);不在每个 env 各放一份。
  • Terraform 只输出运行时才确定的事实静态字段os_name/plan/groups/host_vars…由 Python 合并。
  • 渲染产物(generated_hosts.tfterraform.auto.tfvars.jsoncmdb.jsoninventory.ini 加入 .gitignore,不入库。
  • inventory.ini 中含空格的 host_var 值加引号(key="a b c")。
  • Ansible 动态 inventory 只消费 cmdb.json,不直接耦合 tfstateIaC 变更后重跑 generate.py inventory

SHOULD

  • 复用 modules/compute 等既有模块,不在 env 内重写 provider 资源。
  • 每个用到 provider 的子模块声明 required_providers(含正确 source)。
  • OS 用 data "vultr_os"os_name 解析 os_id,避免硬编码漂移 ID解析不到时允许直接给 os_id

Reference Layout按职责分层

声明 / 可复用模板 / 组合三层分离env 目录只保留组合逻辑:

<provider>-vps/
  config/resources/<name>-hosts.yaml   # 声明:唯一人工入口 global / ssh_keys / hosts
  templates/                           # 共享:可复用 .tf 与 Jinja2 模板
    provider.tf  variables.tf  cloud-init.yaml   # 共享 .tf/配置render 时拷入 workdir
    hosts.tf.j2  inventory.ini.j2                # 渲染模板
  scripts/                             # 共享:组合逻辑(不依赖具体 env
    generate.py                        # render + inventory--resources / --workdir 参数化
    provision.sh                       # 一键 render -> apply -> inventory -> (可选) ansible
  modules/<resource>/                  # 复用的资源模块
  envs/<name>/                         # 运行目录terraform workdir
    README.md  .gitignore              # 唯二入库文件;其余为渲染产物 + tfstate
  # 渲染产物(落 workdir、不入库provider.tf / variables.tf / cloud-init.yaml /
  #   generated_hosts.tf / terraform.auto.tfvars.json / cmdb.json / inventory.ini

三层共享:声明config/resources/可复用 .tf 与模板templates/组合逻辑scripts/env 退化为运行目录。scripts/generate.py rendertemplates/ 下的 provider/variables/cloud-init 拷入 workdir、渲染出 generated_hosts.tf 使 workdir 成为可独立 terraform 的根模块。新增一套主机只加一个 config/resources/*.yaml

  • 一个 workdir复用同一 scripts/templates。

Operator Checklist提交前自检

  • terraform fmt 无 diffterraform validate 通过。
  • python3 generate.py render 产出合法 .tfvalidate 通过)。
  • 生成的 inventory.ini 能被 ansible-inventory -i <file> --graph 正确解析。
  • 渲染产物已被 .gitignore 忽略;机密未入库。
  • HCL 内无 for_each/count/dynamic/templatefile 控制结构。