Terraform external数据源调用bash脚本报jq空迭代错误如何解决
报错原因排查与解决方案
核心报错原因
data "external"数据源有强制协议要求:执行的脚本输出到stdout的所有内容必须是单层JSON键值对结构,不能直接输出公钥字符串,也不能有多余的空行、日志内容- 脚本中通过
terraform console获取变量的方式在Terraform运行生命周期中不可靠:执行external数据源时可能存在工作目录不一致、变量未完全渲染、状态锁等问题,导致拿到的do_token为空。curl请求权限异常返回的响应中没有ssh_keys字段,jq遍历null时直接抛出你遇到的报错 - droplet资源中引用external数据源的方式错误,不能直接引用整个数据源对象,需要从
result属性中读取对应输出字段
修复步骤
- 修改external数据源定义,将token通过内置参数传递给脚本,不要在脚本内自行读取变量:
data "external" "fetchssh" { program = ["bash", "${path.module}/get_ssh_key.sh"] query = { do_token = var.do-token } }
- 重写bash脚本,适配external数据源的输入输出规则:
#!/bin/bash set -euo pipefail # 读取Terraform通过stdin传入的JSON参数,提取token DO_TOKEN=$(jq -r '.do_token') # 请求接口获取公钥 PUB_KEY=$(curl -X GET -s -H "Authorization: Bearer ${DO_TOKEN}" "https://api.digitalocean.com/v2/account/keys?page=1" | jq -r --arg queryname "User's key" '.ssh_keys[] | select(.name == $queryname).public_key') # 输出符合要求的JSON格式结果 jq -n --arg pub_key "$PUB_KEY" '{"public_key": $pub_key}'
- 修正droplet资源的公钥引用方式:
resource "digitalocean_droplet" "web" { image = "ubuntu-18-04-x64" name = "web-1" region = "lon1" size = "s-1vcpu-1gb" tags = [digitalocean_tag.devops.id, digitalocean_tag.your_email.id] ssh_keys = [digitalocean_ssh_key.user.id, data.external.fetchssh.result.public_key] }
额外排查点
- 确认你的DO token已开通
account:read权限,无权限时接口返回的响应没有ssh_keys字段也会触发相同报错 - 可临时在curl命令后加
tee /tmp/do_api_res.json把接口返回内容写入本地文件,执行terraform plan后查看文件内容确认请求是否正常
内容的提问来源于stack exchange,提问作者PatrickHellman
相关产品推荐
相关产品推荐

