自从去年用上了 Jenkins 进行 CI/CD 之后,工作效率高了不少,摸鱼的时间更多了。不过 Jenkins 好是好,但在功夫网的影响下,插件就是经常更新不成功的,就像下面这样子:
查了不少资料,绝大部分都说把升级站点改了就行
然而并没有什么卵用,只是获取插件列表从这个地方获取而已,安装/更新插件的时候该炸还是得炸。
作为一个有代码洁癖的人,看着有插件更新不了那感觉就像有屎拉不出的难受。于是乎这几个月以来一直是通过上面图中的手动上传插件来进行更新的。可是效率实在是低,一两个插件还好,有时候一堆插件有更新,那一个个上传是真的烦。
最近几天又相对闲了点,察觉到 Jenkins 是有个 REST API 的,那么能不能通过程序化来解决问题呢。尝试了下,算是有个比较满意的解决方案了。
首先,要用 Jenkins REST API 是需要权限的,并不是说随便来个人都可以调用。Jenkins REST API 是通过 token 进行验证的。默认是没有 token 的,需要手动添加。
登录 Jenkins 管理面板,进入管理用户
然后选择一个用户,点击左侧设置,然后添加 token 并且用你的小本本记录下来
这样就为这个用户添加了一个 REST API 的 token 了,后续调用 REST API 带上这个 token 就是了
以 C# 的 HttpClient 为例:
var httpClient = new HttpClient(); httpClient.SetBasicAuthentication("username", "apiToken");
这样写就行了,SetBasicAuthentication 方法来自 IdentityModel 这个 nuget 包。( https://www.nuget.org/packages/IdentityModel/ )
接下来我们要先获取哪些插件是有更新的。
在浏览器中来到 /pluginManager/api/ 这个页面,点开 JSON API。
理论上会得到这么个 JSON:
一堆空白?再看一下文档,加上 depth 参数就好了。加上 depth=1,再次请求 /pluginManager/api/json?pretty=true&depth=1
当前安装的所有插件的信息都返回了。而且这里还返回了 hasUpdate 代表这个插件是否有更新。
用 C# 稍微建个模好了
public class JenkinsPlugin { [JsonProperty("hasUpdate")] public bool HasUpdate { get; set; } [JsonProperty("shortName")] public string ShortName { get; set; } [JsonProperty("url")] public string Url { get; set; } [JsonProperty("version")] public string Version { get; set; } }
接下来假如某个插件有更新的话,那么就下载这个插件的新版本好了,打开清华大学 Jenkins 的镜像页,并转到插件目录 https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/
以 git 插件为例,最新版本的下载地址如下:
https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/git/latest/git.hpi
也就是说某个插件的最新版本在清华大学镜像站的下载地址是
https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/{plugin.shortName}/git/lastest/{plugin.shortName}.hpi
用 C# 撸个下载代码好了:
public class TsinghuaClient { private static readonly HttpClient Client = new HttpClient(); public async Task<byte[]> DownloadPluginAsync(string pluginName) { var url = $"https://mirrors.tuna.tsinghua.edu.cn/jenkins/plugins/{pluginName}/latest/{pluginName}.hpi"; var bytes = await Client.GetByteArrayAsync(url); return bytes; } }
接下来就是把这个传到 Jenkins 上。
以 C# 代码为例就是
using (var content = new MultipartFormDataContent()) { content.Add(new ByteArrayContent(plugin), "name", fileName);// plugin 为 byte[] var response = await client.PostAsync("/pluginManager/uploadPlugin", content); response.EnsureSuccessStatusCode(); }
上传成功的话,状态码是 200 OK。
最后就是要让 Jenkins 安装新版本的插件了,这个只需要重启一下 Jenkins 即可。在浏览器中打开 /api 路径,并滚动到最底部
左边那个是强制重启,右边那个是等待到没任务时再重启。我们用右边那个。
代码撸一下:
public async Task RestartAsync() { var response = await client.PostAsync("/safeRestart", null); Debug.Assert(response.StatusCode == HttpStatusCode.ServiceUnavailable); }
重启指令发送成功后会返回 503 Service Unavailable 的。
总结一下流程就是:
获取已安装插件列表 –> 筛选有更新的插件 –> 到清华大学镜像站下载插件最新版本 –> 上传到 Jenkins –> 重启 Jenkins
顺手撸了个 WPF 的 app,也把源码传上来好了
https://files.cnblogs.com/files/h82258652/JenkinsUpdator.zip
使用的时候注意配置 app.config