
Go 脚本调用 ansible-playbook 时权限和路径容易错
直接 exec.Command("ansible-playbook", ...) 在 CI 或容器里大概率失败,不是语法错,是环境缺失。Ansible 默认读 ~/.ansible.cfg、查 inventory 相对路径、依赖 Python 环境变量 —— Go 进程没继承这些。
- 显式传
-i参数指定 inventory 绝对路径,别用./hosts - 通过
env字段注入关键变量:ANSIBLE_CONFIG、PYTHONPATH(如果用了自定义模块) - 用
cmd.Dir设置工作目录,确保roles/、filter_plugins/能被正确加载 - 错误现象典型:报
"ERROR! the file ./inventory does not exist"或"No module named ansible",其实只是当前 dir 或 env 不对
用 terraform init 前必须处理好 .terraform 目录状态
Go 脚本反复调用 terraform init 很常见,但 Terraform 对 .terraform 目录敏感,残留旧 provider 或 lock 文件会导致静默失败或版本冲突。
- 每次运行前加判断:
if _, err := os.Stat(".terraform"); os.IsExist(err) { os.RemoveAll(".terraform") } - 务必加
-upgrade参数:exec.Command("terraform", "init", "-upgrade"),否则不会更新已存在的 provider - 若用远程 backend,
init可能卡住(比如 S3 权限未配),建议设cmd.WaitTimeout并检查stderr是否含"Failed to load backend" - 注意 Terraform CLI 版本兼容性:Go 脚本里硬编码
0.15+的参数(如-reconfigure)在0.12上会直接报错退出
Go 中解析 terraform output -json 输出要小心空值和类型嵌套
terraform output -json 看似标准 JSON,但实际结构取决于资源定义方式 —— 有些字段是 string,有些是 map[string]interface{},还有些是 null(尤其当资源被 count = 0 跳过时)。
- 别用
json.Unmarshal直接进 struct;先解到map[string]json.RawMessage,再按需解析每个 key - 常见坑:
"value": null在 Go 里反序列化成nil指针,直接取.value.(string)panic - 如果输出含 list(如多个 EIP),Terraform 返回的是
[]interface{},需手动转[]string或[]map[string]interface{},不能靠 struct tag 自动映射 - 示例片段:
var raw map[string]json.RawMessage json.Unmarshal(outBytes, &raw) var v string json.Unmarshal(raw["public_ip"], &v) // 安全取单个字符串值
混合调用 Ansible + Terraform 时状态传递不能只靠 stdout
想让 Go 脚本先跑 Terraform 拿 IP,再喂给 Ansible,很多人直接 cmd.Output() 解析 IP 字符串 —— 一旦 Terraform 输出带 color、debug 日志或换行符,正则就失效。
立即学习“go语言免费学习笔记(深入)”;
- 用
terraform output -json获取结构化数据,比文本解析可靠十倍 - Ansible 的
extra_vars推荐走文件:写入临时vars.json,再用-e @vars.json加载,避免 shell 字符转义问题 - 两个工具的错误码语义不同:
terraform apply失败返回非 0,但ansible-playbook部分失败(如 ignore_errors)仍返回 0 —— 必须检查stderr内容是否含"FAILED"或"error" - 最易忽略的一点:Ansible 的
host_key_checking=False必须显式配置在脚本启动的 env 里,不能只靠用户 home 下的ansible.cfg










