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

readYaml读取存在的deploy.placement路径返回null问题咨询

问题排查:Jenkins解析YAML时嵌套路径返回null的问题

问题场景

我有一个Docker Compose YAML文件:

version: '3.9'
services:
  test_service:
    image: 10.3.0.4:5000/test_service:latest
    hostname: test_service
    stop_grace_period: 5m
    deploy:
      placement:
        constraints:
        - node.labels.worker == true

同时有一段Jenkinsfile代码用于解析该YAML:

steps{
    script{
        def my_yml = readYaml file: "docker-compose.yml"
        def req = ''
        def req_list = ["stop_grace_period", "deploy.placement"]
        for (item in req_list) {
            echo "${item}"
            req = my_yml.services."${MICROSERVICE}"."${item}"
            if (req == null) {
                echo "Fail"
            }
        }
    }
}           

问题:解析stop_grace_period时能正常获取值,但解析deploy.placement时返回null,尽管该路径在YAML中存在。


原因分析

Jenkins的readYaml步骤会将YAML解析为嵌套的Groovy Map对象,而非支持点号直接访问的扁平化结构。当你用"deploy.placement"作为键名时,Groovy会尝试在my_yml.services."${MICROSERVICE}"这个Map里查找键名为字符串"deploy.placement"的条目,而非先访问deploy子Map再读取其中的placement键,自然找不到对应值,返回null。

而stop_grace_period是一级键,直接用字符串键名访问就能命中,因此可以正常工作。


解决方法

有两种可行的处理方式:

方法1:拆分嵌套路径,逐层访问Map

将嵌套路径拆分为多级键,依次访问Map的层级:

steps{
    script{
        def my_yml = readYaml file: "docker-compose.yml"
        def service_config = my_yml.services."${MICROSERVICE}"
        
        // 处理stop_grace_period
        def stop_grace = service_config.stop_grace_period
        if (stop_grace == null) {
            echo "stop_grace_period Fail"
        }
        
        // 处理deploy.placement,用安全导航运算符避免空指针
        def placement = service_config?.deploy?.placement
        if (placement == null) {
            echo "deploy.placement Fail"
        }
    }
}

其中?.是安全导航运算符,可避免中间某一级为null时抛出空指针异常。

方法2:编写通用工具函数解析点分隔路径

如果需要批量处理多个点分隔的路径,可以编写工具函数递归解析嵌套Map:

steps{
    script{
        def my_yml = readYaml file: "docker-compose.yml"
        def service_config = my_yml.services."${MICROSERVICE}"
        
        // 定义解析点分隔路径的工具函数
        def getNestedValue(Map map, String path) {
            def keys = path.split("\\.")
            def current = map
            for (key in keys) {
                if (current == null || !(current instanceof Map)) {
                    return null
                }
                current = current[key]
            }
            return current
        }
        
        def req_list = ["stop_grace_period", "deploy.placement"]
        for (item in req_list) {
            echo "${item}"
            def req = getNestedValue(service_config, item)
            if (req == null) {
                echo "Fail"
            }
        }
    }
}

该函数会将路径按点拆分,逐层遍历Map,最终返回对应值,适配批量处理需求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:55:02