前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >解决 Jenkins Artifactory Plugin 在 AIX 上传制品失败的问题

解决 Jenkins Artifactory Plugin 在 AIX 上传制品失败的问题

作者头像
Peter Shen
发布2020-06-12 15:46:15
1.8K0
发布2020-06-12 15:46:15
举报
文章被收录于专栏:持续集成持续集成

❝本文对于同样在 AIX 遇到这个问题的人会非常有帮助。不要被标题无聊到,解决问题的过程值得参考。 ❞

分享一个花了两天时间才解决的一个问题:使用 Jenkins Artifactory 插件上传制品到 https 协议的企业级的 Artifactory 失败。该问题只在 AIX 平台上出现的,其他 Windows,Linux, Unix 均正常。

前言

最近计划将之前使用的 Artifactory OSS(开源版)迁移到 Aritifactory Enterprise(企业版)上。为什么要做迁移?这里有一个 Artifactory 对比的矩阵图 https://www.jfrog.com/confluence/display/JFROG/Artifactory+Comparison+Matrix

简单来说,开源版缺少与 CI 工具集成时常用的 REST API 功能,比如以下常用功能

  • 设置保留策略(Retention)。设置上传的制品保留几天等,达到定期清理的目的。
  • 提升(Promote)。通过自动化测试的制品会被提升到 stage(待测试)仓库,通过手工测试的提升到 release(发布)仓库。
  • 设置属性(set properties)。对于通过不同阶段的制品通过 CI 集成进行属性的设置。

正好公司已经有企业版了,那就开始迁移吧。本以为会很顺利的完成,没想到唯独在 IBM 的 AIX 出现上传制品失败的问题。

❝环境信息

  • Jenkins ver. 2.176.3
  • Artifactory Plugin 3.6.2
  • Enterprise Artifactory 6.9.060900900
  • AIX 7.1 && java version 1.8.0

以下是去掉了无相关的信息的错误日志。

代码语言:javascript
复制
[consumer_0] Deploying artifact: https://artifactory.company.com/artifactory/...
Error occurred for request GET /artifactory/api/system/version HTTP/1.1: A system call received a parameter that is not valid. (Read failed).
Error occurred for request PUT /artifactory/... HTTP/1.1: A system call received a parameter that is not valid. (Read failed).
Error occurred for request PUT /artifactory/... HTTP/1.1: A system call received a parameter that is not valid. (Read failed).
 Caused by: java.net.SocketException: A system call received a parameter that is not valid. (Read failed)
  at java.net.SocketInputStream.socketRead(SocketInputStream.java:127)
  at java.net.SocketInputStream.read(SocketInputStream.java:182)
  at java.net.SocketInputStream.read(SocketInputStream.java:152)
  at com.ibm.jsse2.a.a(a.java:227)
  ... ...
  at com.ibm.jsse2.as.startHandshake(as.java:454)
  ... ...
Failed uploading artifacts by spec

很奇怪会出现上述问题,从开源版的 Artifactory 迁移到企业版的 Artifactory,它们之间最直接的区别是使用了不同的传输协议,前者是 http 后者是 https。

❝HTTPS 其实是有两部分组成:HTTP + SSL/TLS,也就是在 HTTP 上又加了一层处理加密信息的模块,因此更安全。 ❞

本以为 Google 一下就能找到此类问题的解决办法,可惜这个问题在其他平台都没有,只有 AIX 上才有,肯定这个 AIX 有什么“过人之处”和其他 Linux/Unix 不一样。

curl 替代

由于上述问题重现在需要重新构建,比较花时间,就先试试直接用 curl 命令来调用 Artifactory REST API 看看结果。

做了以下测试,查看 Artifactory 的版本

代码语言:javascript
复制
curl  https://artifactory.company.com/artifactory/api/system/version
curl: (35) Unknown SSL protocol error in connection to artifactory.company.com:443

# 打开 -v 模式,输出更多信息
bash-4.3$ curl -v  https://artifactory.company.com/artifactory/api/system/version
*   Trying 10.18.12.95...
* Connected to artifactory.company.com (10.18.12.95) port 443 (#0)
* Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* NPN, negotiated HTTP1.1
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (OUT), TLS alert, Server hello (2):
* Unknown SSL protocol error in connection to artifactory.company.com:443
* Closing connection 0
curl: (35) Unknown SSL protocol error in connection to artifactory.company.com:443

果然也出错了,curl 也不行,可能就是执行 curl 命令的时候没有找到指定证书,查了 curl 的 help,有 --cacert 参数可以指定 cacert.pem 文件。

代码语言:javascript
复制
bash-4.3$ curl --cacert /var/ssl/cacert.pem https://artifactory.company.com/artifactory/api/system/version
{
  "version" : "6.9.0",
  "revision" : "60900900",
  "addons" : [ "build", "docker", "vagrant", "replication", "filestore", "plugins", "gems", "composer", "npm", "bower", "git-lfs", "nuget", "debian", "opkg", "rpm", "cocoapods", "conan", "vcs", "pypi", "release-bundle", "replicator", "keys", "chef", "cran", "go", "helm", "rest", "conda", "license", "puppet", "ldap", "sso", "layouts", "properties", "search", "filtered-resources", "p2", "watch", "webstart", "support", "xray" ],
  "license" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}

试了下成功了。

到这里问题已经解决了,只要使用 curl 调用 Artifactory REST API 就能完成上传操作了。但我用的 Jenkins Artifactory Plugin,如果使用 curl 我需要把之前的代码重新再实现一遍,然后再测试,就为了 AIX 一个平台的问题,实在是“懒”的重新开始。本着这样懒惰的性格,还得继续解决 Jenkins 调用 agent 去执行上传失败的问题。

最终解决

设置 SSL_CERT_FILE 环境变量

想试试用上述的办法来解决 Jenkins 的问题。如果能有一个环境变量能设置指定 cacert.pem 文件的路径,那样在 Jenkins 调用 agent 执行上传时候就能找到证书,可能就能解决这个问题了。果然是有这样的环境变量的 SSL_CERT_FILE,设置如下

代码语言:javascript
复制
set SSL_CERT_FILE=/var/ssl/cacert.pem

设置好环境变量之后,通过 curl 调用,再不需要使用 --cacert 参数了。这下看起来有戏了,带着喜悦的心情把这个环境变量加到 agent 机器上,设置如下:

或者可以修改 agent 机器上的 /etc/environment 文件。

结果经测试错误信息依旧,看来 Jenkins 执行的 remote.jar 进行上传时跟本地配置环境没有关联,看来需要从执行 remote.jar 着手,把相应的设置或是环境变量在启动 remote.jar 时传进去。

❝Jenkins 管理 agent 的原理是通过在 agent 上启动一个 remote.jar 实现的 ❞

启动 remote.jar 时设置环境变量

java-D 参数可以完成这一点。

进行了大量的搜索和尝试,最终在 IBM 的官方找到了这篇文档 https://www.ibm.com/support/knowledgecenter/SSYKE2_8.0.0/com.ibm.java.security.component.80.doc/security-component/jsse2Docs/matchsslcontext_tls.html

文档大意是,IBM SDK 系统属性 com.ibm.jsse2.overrideDefaultTLS=[true|false]truefalse 两个值,如果想要与 Oracle SSLContext.getInstance("TLS") 的行为相匹配,请将此属性设置为 true,默认值为 false

下表显示了系统属性对 SSLContext.getInstance("TLS") 的影响

Property value setting

Protocol enabled

false

TLS V1.0

true

TLS V1.0, V1.1, and V1.2

绝大多数的 Java 应用都是使用 Oracle 的 JDK 来开发的,这里要与 Oracle 的行为保持一致;另外 IBM 的 SDK 默认协议只有 TLS V1.0,而上面的 log 可以看到使用的 TLSv1.2 协议,因此需要将属性设置为 true

最终在 Jenkins 的 agent 配置里将 JVM Options 区域加上这句 -Dcom.ibm.jsse2.overrideDefaultTLS=true,断开连接,重新启动 agent,再次执行 Pipeline,成功的把 AIX 上的制品上传到 Artifactory 上了,问题解决了。

总结

遇到问题并解决问题是一件非常爽的事,从中也学到了很多之前不曾了解过的知识,解决问题的过程比 Google 随便查查更让人印象深刻,再遇到类似问题可能就会举一反三了。

另外,凡事如果觉得自己在短时间内没有头绪、自己搞不定的时候尽快寻求有经验的同事的帮助。感谢帮助我的同事们,没有他们的帮助和指导就不能这么快的解决问题。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DevOps攻城狮 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 用 curl 替代
  • 最终解决
    • 设置 SSL_CERT_FILE 环境变量
      • 启动 remote.jar 时设置环境变量
      • 总结
      相关产品与服务
      命令行工具
      腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档