tfc-plan-json
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseTerraform Cloud Plan JSON
Terraform Cloud 计划JSON
Download and analyze structured plan JSON output from Terraform Cloud runs for detailed resource change analysis.
从Terraform Cloud的运行任务中下载并分析结构化的计划JSON输出,以进行详细的资源变更分析。
Prerequisites
前提条件
bash
export TFE_TOKEN="your-api-token" # User or team token with admin workspace access
export TFE_ADDRESS="app.terraform.io" # Optionalbash
export TFE_TOKEN="your-api-token" # 具有工作区管理员权限的用户或团队令牌
export TFE_ADDRESS="app.terraform.io" # 可选Core Commands
核心命令
Download Plan JSON
下载计划JSON
bash
#!/bin/bash
set -euo pipefail
TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2"
RUN_ID="${1:?Usage: $0 <run-id> [output-file]}"
OUTPUT="${2:-plan.json}"bash
#!/bin/bash
set -euo pipefail
TOKEN="${TFE_TOKEN:?TFE_TOKEN未设置}"
BASE_URL="https://${TFE_ADDRESS:-app.terraform.io}/api/v2"
RUN_ID="${1:?使用方式: $0 <运行ID> [输出文件]}"
OUTPUT="${2:-plan.json}"Download with redirect following (API returns 307)
跟随重定向下载(API返回307状态码)
curl -Lsf --header "Authorization: Bearer $TOKEN"
-o "$OUTPUT"
"$BASE_URL/runs/$RUN_ID/plan/json-output"
-o "$OUTPUT"
"$BASE_URL/runs/$RUN_ID/plan/json-output"
echo "Plan JSON saved to: $OUTPUT"
undefinedcurl -Lsf --header "Authorization: Bearer $TOKEN"
-o "$OUTPUT"
"$BASE_URL/runs/$RUN_ID/plan/json-output"
-o "$OUTPUT"
"$BASE_URL/runs/$RUN_ID/plan/json-output"
echo "计划JSON已保存至: $OUTPUT"
undefinedDownload via Plan ID
通过计划ID下载
bash
TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
PLAN_ID="plan-xyz789"
curl -Lsf --header "Authorization: Bearer $TOKEN" \
-o plan.json \
"https://app.terraform.io/api/v2/plans/$PLAN_ID/json-output"bash
TOKEN="${TFE_TOKEN:?TFE_TOKEN未设置}"
PLAN_ID="plan-xyz789"
curl -Lsf --header "Authorization: Bearer $TOKEN" \
-o plan.json \
"https://app.terraform.io/api/v2/plans/$PLAN_ID/json-output"Analysis Commands
分析命令
Resource Change Summary
资源变更汇总
bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq '{
terraform_version: .terraform_version,
format_version: .format_version,
summary: {
create: [.resource_changes[] | select(.change.actions | contains(["create"]))] | length,
update: [.resource_changes[] | select(.change.actions | contains(["update"]))] | length,
delete: [.resource_changes[] | select(.change.actions | contains(["delete"]))] | length,
replace: [.resource_changes[] | select(.change.actions | contains(["delete", "create"]))] | length,
read: [.resource_changes[] | select(.change.actions | contains(["read"]))] | length,
no_op: [.resource_changes[] | select(.change.actions == ["no-op"])] | length
}
}'bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq '{
terraform_version: .terraform_version,
format_version: .format_version,
summary: {
create: [.resource_changes[] | select(.change.actions | contains(["create"]))] | length,
update: [.resource_changes[] | select(.change.actions | contains(["update"]))] | length,
delete: [.resource_changes[] | select(.change.actions | contains(["delete"]))] | length,
replace: [.resource_changes[] | select(.change.actions | contains(["delete", "create"]))] | length,
read: [.resource_changes[] | select(.change.actions | contains(["read"]))] | length,
no_op: [.resource_changes[] | select(.change.actions == ["no-op"])] | length
}
}'List Resources Being Created
列出待创建的资源
bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq -r '.resource_changes[] | select(.change.actions | contains(["create"])) | .address'bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq -r '.resource_changes[] | select(.change.actions | contains(["create"])) | .address'List Resources Being Destroyed
列出待销毁的资源
bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq -r '.resource_changes[] | select(.change.actions | contains(["delete"])) | .address'bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq -r '.resource_changes[] | select(.change.actions | contains(["delete"])) | .address'List Resources Being Updated
列出待更新的资源
bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq -r '.resource_changes[] | select(.change.actions | contains(["update"])) | .address'bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq -r '.resource_changes[] | select(.change.actions | contains(["update"])) | .address'Resources Being Replaced
待替换的资源
bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq -r '.resource_changes[] | select(.change.actions | contains(["delete", "create"])) |
"\(.address) (replace due to: \(.action_reason // "unknown"))"'bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq -r '.resource_changes[] | select(.change.actions | contains(["delete", "create"])) |
"\(.address) (替换原因: \(.action_reason // "未知"))"'Detailed Resource Changes
详细资源变更
bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq '.resource_changes[] | select(.change.actions != ["no-op"]) | {
address: .address,
actions: .change.actions,
before: .change.before,
after: .change.after
}'bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq '.resource_changes[] | select(.change.actions != ["no-op"]) | {
address: .address,
actions: .change.actions,
before: .change.before,
after: .change.after
}'Show What's Changing in a Specific Resource
查看特定资源的变更内容
bash
RESOURCE="aws_instance.web"
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq --arg addr "$RESOURCE" '
.resource_changes[] | select(.address == $addr) | {
address: .address,
actions: .change.actions,
before: .change.before,
after: .change.after,
after_unknown: .change.after_unknown
}'bash
RESOURCE="aws_instance.web"
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq --arg addr "$RESOURCE" '
.resource_changes[] | select(.address == $addr) | {
address: .address,
actions: .change.actions,
before: .change.before,
after: .change.after,
after_unknown: .change.after_unknown
}'Provider Versions Used
使用的提供程序版本
bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq '.configuration.provider_config | to_entries | map({
provider: .key,
version: .value.version_constraint
})'bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq '.configuration.provider_config | to_entries | map({
provider: .key,
version: .value.version_constraint
})'Output Values
输出值
bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq '.output_changes | to_entries | map({
name: .key,
actions: .value.actions,
sensitive: .value.after_sensitive
})'bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq '.output_changes | to_entries | map({
name: .key,
actions: .value.actions,
sensitive: .value.after_sensitive
})'Variables Used
使用的变量
bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq '.variables | keys'bash
curl -Lsf --header "Authorization: Bearer $TFE_TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output" | \
jq '.variables | keys'Complete Analysis Script
完整分析脚本
bash
#!/bin/bash
set -euo pipefail
TOKEN="${TFE_TOKEN:?TFE_TOKEN not set}"
RUN_ID="${1:?Usage: $0 <run-id>}"
PLAN=$(curl -Lsf --header "Authorization: Bearer $TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output")
echo "=== Plan Analysis for $RUN_ID ==="
echo ""
echo "Terraform Version: $(echo "$PLAN" | jq -r '.terraform_version')"
echo ""
echo "Resource Changes:"
echo " Create: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["create"]))] | length')"
echo " Update: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["update"]))] | length')"
echo " Delete: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["delete"]))] | length')"
echo " Replace: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["delete", "create"]))] | length')"
echo ""
echo "Resources to Create:"
echo "$PLAN" | jq -r '.resource_changes[] | select(.change.actions | contains(["create"])) | " - " + .address'
echo ""
echo "Resources to Destroy:"
echo "$PLAN" | jq -r '.resource_changes[] | select(.change.actions | contains(["delete"])) | " - " + .address'
echo ""
echo "Resources to Update:"
echo "$PLAN" | jq -r '.resource_changes[] | select(.change.actions | contains(["update"])) | " - " + .address'bash
#!/bin/bash
set -euo pipefail
TOKEN="${TFE_TOKEN:?TFE_TOKEN未设置}"
RUN_ID="${1:?使用方式: $0 <运行ID>}"
PLAN=$(curl -Lsf --header "Authorization: Bearer $TOKEN" \
"https://app.terraform.io/api/v2/runs/$RUN_ID/plan/json-output")
echo "=== 运行ID $RUN_ID 的计划分析 ==="
echo ""
echo "Terraform版本: $(echo "$PLAN" | jq -r '.terraform_version')"
echo ""
echo "资源变更统计:"
echo " 创建: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["create"]))] | length')"
echo " 更新: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["update"]))] | length')"
echo " 删除: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["delete"]))] | length')"
echo " 替换: $(echo "$PLAN" | jq '[.resource_changes[] | select(.change.actions | contains(["delete", "create"]))] | length')"
echo ""
echo "待创建的资源:"
echo "$PLAN" | jq -r '.resource_changes[] | select(.change.actions | contains(["create"])) | " - " + .address'
echo ""
echo "待销毁的资源:"
echo "$PLAN" | jq -r '.resource_changes[] | select(.change.actions | contains(["delete"])) | " - " + .address'
echo ""
echo "待更新的资源:"
echo "$PLAN" | jq -r '.resource_changes[] | select(.change.actions | contains(["update"])) | " - " + .address'Plan JSON Structure
计划JSON结构
The plan JSON output follows Terraform's JSON plan format:
json
{
"format_version": "1.2",
"terraform_version": "1.5.0",
"planned_values": { ... },
"resource_changes": [
{
"address": "aws_instance.web",
"mode": "managed",
"type": "aws_instance",
"name": "web",
"provider_name": "registry.terraform.io/hashicorp/aws",
"change": {
"actions": ["create"],
"before": null,
"after": { ... },
"after_unknown": { ... },
"before_sensitive": false,
"after_sensitive": { ... }
}
}
],
"output_changes": { ... },
"configuration": { ... },
"variables": { ... }
}计划JSON输出遵循Terraform的JSON计划格式:
json
{
"format_version": "1.2",
"terraform_version": "1.5.0",
"planned_values": { ... },
"resource_changes": [
{
"address": "aws_instance.web",
"mode": "managed",
"type": "aws_instance",
"name": "web",
"provider_name": "registry.terraform.io/hashicorp/aws",
"change": {
"actions": ["create"],
"before": null,
"after": { ... },
"after_unknown": { ... },
"before_sensitive": false,
"after_sensitive": { ... }
}
}
],
"output_changes": { ... },
"configuration": { ... },
"variables": { ... }
}Change Actions
变更操作
- - Resource will be created
["create"] - - Resource will be destroyed
["delete"] - - Resource will be updated in-place
["update"] - - Resource will be replaced
["delete", "create"] - - Data source will be read
["read"] - - No changes
["no-op"]
- - 资源将被创建
["create"] - - 资源将被销毁
["delete"] - - 资源将被就地更新
["update"] - - 资源将被替换
["delete", "create"] - - 将读取数据源
["read"] - - 无变更
["no-op"]
Important Notes
重要说明
- Requires Terraform 0.12+ for JSON output support
- Returns 204 No Content if plan hasn't completed yet
- Follow redirects - API returns HTTP 307 to temporary download URL
- Temporary URL - Download URL is valid for ~1 minute
- Admin access required - Need admin permissions on the workspace
- 需要Terraform 0.12+ 以支持JSON输出
- 返回204 No Content 表示计划尚未完成
- 跟随重定向 - API会返回HTTP 307重定向到临时下载链接
- 临时链接 - 下载链接的有效期约为1分钟
- 需要管理员权限 - 需拥有工作区的管理员权限
Error Handling
错误处理
204 No Content
204 No Content
Plan hasn't completed yet. Check run status first.
计划尚未完成,请先检查运行状态。
401 Unauthorized
401 Unauthorized
Token lacks admin workspace access or is invalid.
令牌无效或缺少工作区管理员权限。
404 Not Found
404 Not Found
Run doesn't exist or you don't have permission.
运行任务不存在或您无访问权限。
See Also
相关链接
- : Get plan/apply logs (human-readable)
tfc-run-logs - : Quick status check for a run
tfc-run-status - : List recent runs in a workspace
tfc-list-runs
- : 获取计划/应用日志(人类可读格式)
tfc-run-logs - : 快速检查运行任务状态
tfc-run-status - : 列出工作区中的近期运行任务
tfc-list-runs