在Jenkinsfile shell中转义JSON字符串

时间:2018-09-13 11:20:41

标签: jenkins groovy jenkins-plugins jenkins-pipeline

我正在尝试将jenkinsfile中的json-string转义,但是我在线检查的示例有点复杂。

sshagent(credentials: ['keypair']) {
            sh """
                ssh ansible@ansible-server \
                '
# vars
src_env="${params.source_env}"
dest_env="${params.destination_env}"
src_prefix="${params.source_s3_prefix}"
dest_prefix="${params.destination_s3_prefix}"
region="${region}"
ch="${ch}"
aws_account="${aws_account}"

# Run ECS task
echo "---- Run ECS task ----"
task_id=$(aws ecs run-task \
  --cluster cluster-\${ch}-\${dest_env} \
  --task-definition \$td_id \
  --region \${region} \
  --overrides {\\\"containerOverrides\\\": [{\\\"name\\\": \\\"s3-sync\\\", \\\"environment\\\": [{\\\"name\\\": \\\"SRC_ENV\\\", \\\"value\\\": \\\"$${src_env}\\\"}, {\\\"name\\\": \\\"DEST_ENV\\\", \\\"value\\\": \\\"$${dest_env}\\\"}, {\\\"name\\\": \\\"SRC_PREFIX\\\", \\\"value\\\": \\\"$${src_prefix}\\\"}, {\\\"name\\\": \\\"DEST_PREFIX\\\", \\\"value\\\": \\\"$${dest_prefix}\\\"}]}], \\\"taskRoleArn\\\":  \\\"arn:aws:iam::$${aws_account}:role/$${ch}-$${dest_env}\\\"} \
  --query 'tasks[0].taskArn' \
  --output text | cut -d'/' -f 2)

                '
            """
}

因此,问题在于转义以下json字符串:

--overrides {\\\"containerOverrides\\\": [{\\\"name\\\": \\\"s3-sync\\\", \\\"environment\\\": [{\\\"name\\\": \\\"SRC_ENV\\\", \\\"value\\\": \\\"$${src_env}\\\"}, {\\\"name\\\": \\\"DEST_ENV\\\", \\\"value\\\": \\\"$${dest_env}\\\"}, {\\\"name\\\": \\\"SRC_PREFIX\\\", \\\"value\\\": \\\"$${src_prefix}\\\"}, {\\\"name\\\": \\\"DEST_PREFIX\\\", \\\"value\\\": \\\"$${dest_prefix}\\\"}]}], \\\"taskRoleArn\\\":  \\\"arn:aws:iam::$${aws_account}:role/$${ch}-$${dest_env}\\\"} \

有什么帮助吗?我尝试了许多不同的方法,但是似乎没有任何效果。

2 个答案:

答案 0 :(得分:1)

我建议您不要在ssh之后尝试对所有变量求值,而应将shh命令作为shell脚本求值的一部分来计算。

在常规情况下,如果使用双引号(单引号或三引号),则$之后的任何内容都将得到评估/替换。因此,您只需在您的Shell脚本中使用的每个变量之前添加一个$,该变量将在Shell脚本甚至运行之前得到评估。您还需要转义所有不想在字符串处理过程中进行评估的$

特别是对于json blob,我建议在包含覆盖的shell脚本之外创建一个映射,然后将该变量转换为json字符串。这样,您不必担心使用正确数量的\(尽管您可以在三引号字符串中使用单引号而不进行转义),并且管道文件更易读。

这是我的写法:

sshagent(credentials: ['keypair']) {

  // ch is defined is defined somewhere in the pipeline
  // aws_account is also defined somewhere in the pipeline

  def overrides = [
    containerOverrides: [
      [
        environment: [
          [
            name: "SRC_ENV",
            value: params.source_env
          ],
          [
            name: "DEST_ENV",
            value: params.destination_env
          ],
          [
            name: "SRC_PREFIX",
            value: params.source_s3_prefix
          ],
          [
            name: "DEST_PREFIX",
            value: params.destination_s3_prefix
          ]
        ],
        name: "s3-sync"
      ]
    ],
    taskRoleArn: "arn:aws:iam::${aws_account}:role/${ch}-${params.destination_env}"
  ]


  sh """
    ssh ansible@ansible-server \
    '
# Run ECS task
echo "---- Run ECS task ----"
task_id=\$(aws ecs run-task \
  --cluster cluster-${ch}-${params.destination_env} \
  --task-definition \$td_id \
  --region ${region} \
  --overrides ${groovy.json.JsonOutput.toJson(overrides)} \
  --query 'tasks[0].taskArn' \
  --output text | cut -d'/' -f 2)
    '
  """
}

请注意,我没有转义要替换字符串处理的任何变量,而只转义了

task_id=\$(aws ecs run-task \

这样aws ecs run-task ...会在执行ssh脚本时运行(而不是在评估字符串时运行)。

答案 1 :(得分:1)

基于Vasiliki Siakka的回答,我预先解析了json参数,并转义了json字符串中的双引号,以避免在ssh命令中将其删除。因此,对我有用的解决方案如下:

sshagent(credentials: ['keypair']) {

  // ch is defined is defined somewhere in the pipeline
  // aws_account is also defined somewhere in the pipeline

  def overrides = [
    containerOverrides: [
      [
        environment: [
          [
            name: "SRC_ENV",
            value: params.source_env
          ],
          [
            name: "DEST_ENV",
            value: params.destination_env
          ],
          [
            name: "SRC_PREFIX",
            value: params.source_s3_prefix
          ],
          [
            name: "DEST_PREFIX",
            value: params.destination_s3_prefix
          ]
        ],
        name: "s3-sync"
      ]
    ],
    taskRoleArn: "arn:aws:iam::${aws_account}:role/${ch}-${params.destination_env}"
  ]

  def parsed_overrides = groovy.json.JsonOutput.toJson(overrides).replace("\"", "\\\"")



  sh """
      ssh ansible@ansible-server \
      '
# Run ECS task
echo "---- Run ECS task ----"
task_id=\$(aws ecs run-task \
  --cluster cluster-${ch}-${params.destination_env} \
  --task-definition \$td_id \
  --region ${region} \
  --overrides "${parsed_overrides}" \
  --query 'tasks[0].taskArn' \
  --output text | cut -d'/' -f 2)
      '
    """
}