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

Jenkins Groovy解析Terraform输出出错的问题解决

问题修复与实现方案

核心问题分析

  1. 未定义变量错误:代码中使用了未声明的jsonArray变量,直接触发groovy.lang.MissingPropertyException异常。
  2. 嵌套IP列表处理:获取到的IP是嵌套列表格式[[10.0.253.236], [10.0.253.234], ...],无法直接与VM名称一一匹配。
  3. 跨阶段数据传递问题:currentBuild.description默认存储字符串,直接赋值列表会导致后续读取格式异常。

修改后的完整Pipeline代码

pipeline {
    agent any
    parameters {
        string(name: 'vmNames', defaultValue: 'host-01,host-02,host-03', description: 'Enter VM names (comma-separated)')
        string(name: 'xoaUrl', defaultValue: 'wss://xo.example.com', description: 'Enter XOA URL' )
        string(name: 'xoaUser', defaultValue: 'red.crick', description: 'Enter XOA User' )
    }

    environment {
        TERRAFORM_HOME = tool name: 'terraform', type: 'org.jenkinsci.plugins.terraform.TerraformInstallation'
        PATH = "${TERRAFORM_HOME}:${env.PATH}"
        XOA_URL = "${xoaUrl}"
        XOA_USER = "${xoaUser}"
    }

    stages {
        stage("Terraform init") {        
            // 保留原有逻辑
        }

        stage("Terraform plan") {
            // 保留原有逻辑
        }

        stage("Terraform apply") {
            steps {
                dir('dev/xo/clusters/sandbox') {
                    withCredentials([string(credentialsId: 'XOA_PASSWORD', variable: 'xoaPassword')]) {
                        sh '''
                        export XOA_PASSWORD="${xoaPassword}"
                        terraform apply -parallelism=1 -no-color "theplan"
                        '''
                        script {
                            def output = sh(script: 'terraform output -json', returnStdout: true).trim()
                            echo "output is $output"

                            // 读取嵌套IP列表并扁平化处理
                            def nestedIpAddresses = readJSON(text: output).ip_addresses.value
                            def ipAddresses = nestedIpAddresses.flatten() // 转成一维列表:[10.0.253.236, 10.0.253.234, ...]
                            echo "ipAddresses is $ipAddresses"
                            echo "ipAddresses[0] is ${ipAddresses[0]}"

                            // 将IP列表转为JSON字符串,存入currentBuild.description实现跨阶段传递
                            currentBuild.description = groovy.json.JsonOutput.toJson(ipAddresses)
                        }
                    }
                }
            }
        }

        stage("Set Hostname and Reboot to Get DNS Records Created.") {
            steps {
                script {
                    // 解析currentBuild.description中的JSON字符串,还原为IP列表
                    def ipAddresses = readJSON(text: currentBuild.description)
                    def hostnames = vmNames.split(',').collect { it.trim() } // 分割并去除空格

                    // 检查VM数量与IP数量是否匹配,避免索引越界
                    if (ipAddresses.size() != hostnames.size()) {
                        error "VM数量(${hostnames.size()})与IP数量(${ipAddresses.size()})不匹配,终止流程"
                    }

                    withCredentials([sshUserPrivateKey(credentialsId: 'bpadmin-private-ssh-key', keyFileVariable: 'SSH_PRIVATE_KEY', usernameVariable: 'USER')]) {
                        // 遍历匹配VM名称与对应IP
                        for (int i = 0; i < ipAddresses.size(); i++) {
                            def ipAddress = ipAddresses[i]
                            def hostname = hostnames[i]

                            echo "Setting hostname $hostname for IP address $ipAddress"
                            // 可添加实际设置主机名的SSH命令,示例:
                            // sh '''
                            // ssh -i "${SSH_PRIVATE_KEY}" -o StrictHostKeyChecking=no ${USER}@${ipAddress} "sudo hostnamectl set-hostname ${hostname} && sudo systemctl reboot"
                            // '''
                        }
                    }
                }
            }
        }
    }
}

关键修改说明

  • 扁平化IP列表:使用flatten()方法将嵌套的IP列表转换为一维列表,解决嵌套格式无法直接匹配的问题。
  • 修复未定义变量错误:删除引用未声明jsonArray的代码,改用JsonOutput.toJson()将IP列表转为JSON字符串,通过currentBuild.description实现跨阶段数据传递。
  • 跨阶段数据解析:在后续阶段通过readJSON()将存储的JSON字符串还原为IP列表,保证数据格式正确。
  • 添加边界检查:增加VM数量与IP数量的匹配校验,避免因数量不一致导致的索引越界错误。
  • 优化主机名处理:对分割后的VM名称执行trim()操作,移除可能存在的空格,确保匹配准确性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 22:18:10