You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Jenkins Groovy构建Terraform API请求Payload报错排查

解决Terraform Cloud API Runs请求Payload格式错误问题

问题背景

在Jenkinsfile的Groovy代码中,遍历Workspace名称列表获取对应Terraform Cloud Workspace ID后,构建Runs请求的JSON Payload格式错误,导致API返回400 Bad Request。期望生成包含多个Workspace ID的合规Payload结构:

{
    "data": {
        "attributes": {
            "is-destroy": false,
            "message": "Trigger runs from Jenkins"
        },
        "type": "runs",
        "relationships": {
            "workspace": {
                "data": [
                    {"id": "id1", "type": "workspaces"},
                    {"id": "id2", "type": "workspaces"},
                    {"id": "id3", "type": "workspaces"}
                ]
            }
        }
    }
}

错误原因分析

原代码存在以下问题:

  • buildPayload函数错误地用JsonSlurper解析getWorkspaceId的返回值(该函数返回的是List<String>,无需JSON解析)
  • 循环中每次重新定义Payload并提前return,导致仅生成第一个ID的结构,未遍历所有ID
  • message字段未赋值,存在JSON语法错误
  • 未将所有ID组装成合规的数组结构

修正后的代码

1. 修正Workspace ID获取函数

仅修正变量名拼写错误(原Listworkspace应为List workspace),其余逻辑保留:

def getWorkspaceIds() {
    def result = []
    List workspace.each { workspaceName ->
        def response = httpRequest(
            customHeaders: [
                [ name: "Authorization", value: "Bearer " + env.BEARER_TOKEN ], 
                [ name: "Content-Type", value: "application/vnd.api+json" ]
            ],
            url: "https://app.terraform.io/api/v2/organizations/${TF_ORGNAME}/workspaces/${workspaceName}"
        )
        
        def data = new JsonSlurper().parseText(response.content)
        println("Workspace Id for ${workspaceName}: " + data.data.id)
        result << data.data.id
    }
    return result
}

2. 正确构建Payload的函数(推荐使用JsonBuilder)

使用Groovy内置的JsonBuilder自动处理JSON语法,避免手动拼接错误:

def buildPayload() {
    def workspaceIds = getWorkspaceIds()
    def triggerMessage = "Trigger runs from Jenkins" // 可根据需求自定义
    
    def jsonBuilder = new groovy.json.JsonBuilder()
    jsonBuilder {
        data {
            attributes {
                'is-destroy' false // 带连字符的key需用字符串形式
                message triggerMessage
            }
            type "runs"
            relationships {
                workspace {
                    data workspaceIds.collect { id ->
                        [id: id, type: "workspaces"]
                    }
                }
            }
        }
    }
    
    return jsonBuilder.toPrettyString() // 生成格式化JSON,便于调试
}

备选:手动字符串拼接方式(不推荐,易出错)

若偏好手动拼接字符串,需正确组装ID数组:

def buildPayload() {
    def workspaceIds = getWorkspaceIds()
    def triggerMessage = "Trigger runs from Jenkins"
    
    // 组装所有Workspace ID对应的JSON对象字符串
    def workspaceDataEntries = workspaceIds.collect { 
        "{\"id\": \"$it\", \"type\": \"workspaces\"}" 
    }.join(",\n                    ")
    
    def payload = """
{
    "data": {
        "attributes": {
            "is-destroy": false,
            "message": "$triggerMessage"
        },
        "type": "runs",
        "relationships": {
            "workspace": {
                "data": [
                    $workspaceDataEntries
                ]
            }
        }
    }
}
    """.trim()
    
    return payload
}

关键修正点

  • 移除不必要的JsonSlurper解析,直接使用getWorkspaceIds返回的List
  • 用collect方法将所有ID转换为要求的对象结构,组装成完整数组
  • 补充message字段的有效值,修复JSON语法错误
  • 避免循环中提前return,确保所有ID被包含在Payload中

内容的提问来源于stack exchange,提问作者green_car

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 20:30:43