Jenkins pipeline脚本编程遇到的问题总结
创始人
2024-06-03 01:18:54
0

Json序列化对象失败的问题

背景

想要封装一个复杂的对象,然后序列化成json,通过请求工具发送Post请求。因为手动去拼接一个复杂的json很容易出现问题,所以想法是:先封装成对象,然后序列化成json。

过程与现象

网上一般推荐的方法如下:

def toJson(Object obj){return JsonOutput.toJson(input)
}

所以我也兴致冲冲的这样写了,但是结果非常不如人意。现象是:我直接运行用groovy代码的main方法跑起来是没有问题的,正常序列化成功;但是在Jenkins pipeline环境下的时候就总是会序列化成一个空对象(即总是返回:{})。

于是在网上搜索各种资料,最后发现很少类似的资料,最后在询问ChatGPT才找到一些关键的线索,ChatGPT回复如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

总的来说就是get/set方法可能会产生的是动态属性,动态属性在Pipeline中是没法序列化了,所以肯定就是空对象了。

按照这个线索,我不停的测试发现了问题的原因。结论就是:在groovy类定义中如果我们手动重写了get/set方法就会导致对象序列化失败。可能重写了get/set方法在groovy中就是动态属性。

结论与解决办法

在groovy类定义中如果我们不要重写了get/set方法,只要定义属性就好了,groovy定义了属性就自动会有get/set方法。

在测试过程中也发现了几个关于类定义需要注意的点,如下:

  1. 不要写内部静态类,写内部静态类,可能会发生new对象的时候,找不到类信息;

  2. 不要将类写在一个文件里面,不然也会发生找不到类的情况,总的来说就是一个类一个文件;

  3. 定义的类最好是实现Serializable接口,否则也可能在脚本传递中报没法序列化的错误;

  4. 在pipeline里面最好是类似直接写json的方式去定义一个复杂对象,因为脚本化,基本类的复用性不是很强,注意在groovy中是[]包裹不是{}包裹。类定义如下:

    def newPostJson(timestamp, sign, title, author, dateStr, projectName, env,buildNumber, jobUrl, detailLog) {def testBody = [timestamp: timestamp,sign     : sign,msg_type : "interactive",card     : [type: "template",data: [template_id      : "ctp_AAumzLoL5YIf",template_variable: [title      : title,author     : author,time       : dateStr,projectName: projectName,env        : env,buildNumber: buildNumber,projectUrl : jobUrl,content    : detailLog]]]]return JsonOutput.toJson(testBody)}
    

空数组定义和Java的有区别,导致报错的问题

背景

请求接口的时候,有些接口需要做签名,并且需要指定sha256算法签名。

过程与现象

很自然就知道百度,google代码;基本代码如下:

    private static def sha256(String body, String secret) {//使用HmacSHA256算法计算签名Mac mac = Mac.getInstance("HmacSHA256")mac.init(new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), "HmacSHA256"))byte[] signData = mac.doFinal(body.getBytes(StandardCharsets.UTF_8))return new String(Base64.getEncoder().encode(signData))}

但是这次刚刚好签名的内容比较特殊,对一个空字节数组做签名,代码如下:

    private static def feishuSign(String secret) {String stringToSign = (System.currentTimeMillis() / 1000) + "/n" + secret//使用HmacSHA256算法计算签名Mac mac = Mac.getInstance("HmacSHA256")mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"))byte[] signData = mac.doFinal(new byte[]{})return new String(Base64.getEncoder().encode(signData))}

现象就是:代码编辑器不会报错,但是运行的时候就会报错。 错误如下截图:
在这里插入图片描述
然后我将代码转换成java代码,直接运行也是不会报错的。

结论与解决办法

后来尝试了很多次,我后来想到直接定义一个0元素数组是否跟上面定义一致呢?于是在java测试了一下,结果是一致的。最后代码改动如下:

    private static def feishuSign(String secret) {String stringToSign = (System.currentTimeMillis() / 1000) + "/n" + secret//使用HmacSHA256算法计算签名Mac mac = Mac.getInstance("HmacSHA256")mac.init(new SecretKeySpec(stringToSign.getBytes(StandardCharsets.UTF_8), "HmacSHA256"))byte[] signData = mac.doFinal(new byte[0])return new String(Base64.getEncoder().encode(signData))}

就不会报错了,并且结果也是正确的。

CPS的问题

就是有些方法,可能不安全,就会被jenkins的sandbox拦截不让执行,一般错误描述如下:

Scripts not permitted to use staticMethod groovy.json.JsonOutput toJson java.lang.Object. Administrators can decide whether to approve or reject this signature.
[Pipeline] }
[Pipeline] // script
Post stage
[Pipeline] script
[Pipeline] {
[Pipeline] httpRequest
[Pipeline] }
[Pipeline] // script
[Pipeline] }
[Pipeline] // stage
[Pipeline] }
[Pipeline] // withEnv
[Pipeline] }
[Pipeline] // node
[Pipeline] End of Pipeline
org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException: Scripts not permitted to use staticMethod groovy.json.JsonOutput toJson java.lang.Objectat org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.StaticWhitelist.rejectStaticMethod(StaticWhitelist.java:243)at org.jenkinsci.plugins.scriptsecurity.sandbox.groovy.SandboxInterceptor.onStaticCall(SandboxInterceptor.java:212)at org.kohsuke.groovy.sandbox.impl.Checker$2.call(Checker.java:214)at org.kohsuke.groovy.sandbox.impl.Checker.checkedStaticCall(Checker.java:218)at org.kohsuke.groovy.sandbox.impl.Checker.checkedCall(Checker.java:120)at com.cloudbees.groovy.cps.sandbox.SandboxInvoker.methodCall(SandboxInvoker.java:17)at WorkflowScript.run(WorkflowScript:73)at ___cps.transform___(Native Method)at com.cloudbees.groovy.cps.impl.ContinuationGroup.methodCall(ContinuationGroup.java:90)at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.dispatchOrArg(FunctionCallBlock.java:113)at com.cloudbees.groovy.cps.impl.FunctionCallBlock$ContinuationImpl.fixArg(FunctionCallBlock.java:83)at sun.reflect.GeneratedMethodAccessor366.invoke(Unknown Source)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at com.cloudbees.groovy.cps.impl.ContinuationPtr$ContinuationImpl.receive(ContinuationPtr.java:72)at com.cloudbees.groovy.cps.impl.LocalVariableBlock$LocalVariable.get(LocalVariableBlock.java:38)at com.cloudbees.groovy.cps.LValueBlock$GetAdapter.receive(LValueBlock.java:30)at com.cloudbees.groovy.cps.impl.LocalVariableBlock.evalLValue(LocalVariableBlock.java:27)at com.cloudbees.groovy.cps.LValueBlock$BlockImpl.eval(LValueBlock.java:55)at com.cloudbees.groovy.cps.LValueBlock.eval(LValueBlock.java:16)at com.cloudbees.groovy.cps.Next.step(Next.java:83)at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:177)at com.cloudbees.groovy.cps.Continuable$1.call(Continuable.java:166)at org.codehaus.groovy.runtime.GroovyCategorySupport$ThreadCategoryInfo.use(GroovyCategorySupport.java:136)at org.codehaus.groovy.runtime.GroovyCategorySupport.use(GroovyCategorySupport.java:275)at com.cloudbees.groovy.cps.Continuable.run0(Continuable.java:166)at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.access$001(SandboxContinuable.java:18)at org.jenkinsci.plugins.workflow.cps.SandboxContinuable.run0(SandboxContinuable.java:51)at org.jenkinsci.plugins.workflow.cps.CpsThread.runNextChunk(CpsThread.java:187)at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.run(CpsThreadGroup.java:420)at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup.access$400(CpsThreadGroup.java:95)at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:330)at org.jenkinsci.plugins.workflow.cps.CpsThreadGroup$2.call(CpsThreadGroup.java:294)at org.jenkinsci.plugins.workflow.cps.CpsVmExecutorService$2.call(CpsVmExecutorService.java:67)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at hudson.remoting.SingleLaneExecutorService$1.run(SingleLaneExecutorService.java:139)at jenkins.util.ContextResettingExecutorService$1.run(ContextResettingExecutorService.java:28)at jenkins.security.ImpersonatingExecutorService$1.run(ImpersonatingExecutorService.java:68)at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)at java.util.concurrent.FutureTask.run(FutureTask.java:266)at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)at java.lang.Thread.run(Thread.java:750)
Finished: FAILURE

解决办法

方法一

按照提示点击即可,操作方法如截图:
在这里插入图片描述
到里面页面同意申请即可
在这里插入图片描述
本人这个已经同意过了,所以没有通过申请的按钮。

方法二

对调用的方法打上注解:@NonCPS,例如:

@NonCPS
static def toJson(Object input) {JsonOutput.toJson(input)
}

方法三

手动去系统添加执行权限,操作方法如截图:
在这里插入图片描述
在这里插入图片描述
去里面提交申请执行即可

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...