DevOps-7:Jenkins API介绍

这篇具有很好参考价值的文章主要介绍了DevOps-7:Jenkins API介绍。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言:

为什么要使用Jenkins的API?
我在使用Jenkins的过程中,觉得Jenkins的UI还是有不少问题的:

  • UI性能差,尤其是有一些任务在构建中时,UI非常卡顿,等个十来秒都正常,极端时甚至会崩溃;
  • 权限管理功能薄弱,虽然有Role-based Authorization Strategy类似的插件提供了角色管理,但是还是不太好用;
  • 一些需要人工介入的能力扩展不太方便,比如发布前需要比对数据库表结构并支持人工忽略时,就不好扩展。

如上,因此我还是比较推荐自行开发一个发布系统,自行实现权限能力和一些扩展,通过调用Jenkins的构建API和状态API完成项目的发布和管理操作,包括历史和审计相关能力。


API认证方式说明

Jenkins的API认证支持两种方式,

  • 第一种是使用账号密码进行认证,这种请求会报错:Error 403 No valid crumb was included in the request,需要在所有请求之前先获取crumb,再把crumb添加在后续请求的Header里,参考:https://stackoverflow.com/questions/44711696/jenkins-403-no-valid-crumb-was-included-in-the-request
  • 第二种是在Jenkins生成一个Token,在API请求里使用这个Token代替密码,这种不会存在crumb问题,生成用户Token的方法,在Jenkins首页左侧->People->对应用户->Configure->Add new Token
    jenkins api,DevOps,Java,jenkins,devops,运维,feign

官方API文档介绍

  • 安装完成Jenkins之后,直接访问 http://你的Jenkins域名/api 就可以看到API的介绍了,这里会有创建Job和复制Job等API介绍。
  • 进入具体的某个job,在url后面直接添加 /api,就可以看到这个job的API介绍,如 http://你的Jenkins域名/job/具体job名/api 这里会有删除Job、启动Job构建、禁用/启用Job等API介绍。

Java调用API说明

网上也有一些封装好的Maven库可以使用,我都是直接用feign去调用,下面就以feign的代码进行举例说明:

feign类基础定义

  • 定义一个配置类,返回Jenkins的认证信息(建议使用Jenkins用户token方案)
class MultipartSupportConfig {
    @Value("${jenkins.username:}") // yml里配置的jenkins用户名
    private String jenkinsUser;
    @Value("${jenkins.password:}") // yml里配置的jenkins用户token
    private String jenkinsPassword;
    
    @Bean
    public Contract feignContract() {
        return new Contract.Default();
    }

    @Bean
    public BasicAuthRequestInterceptor basicAuthorizationInterceptor() {
        return new BasicAuthRequestInterceptor(jenkinsUser, jenkinsPassword);
    }
}
  • 定义feignClient类,指向上面的配置类:
@FeignClient(value = "jenkins", url = "${jenkins.worker.url}", configuration = JenkinsFeign.MultipartSupportConfig.class)
public interface JenkinsFeign {
    // 具体的jenkins API方法定义
}

常用Jenkins API方法声明

注:通过feign调用Jenkins,不能用RequestMapping注解,不太记得为啥了,当时是出了很多问题,包括JobName的拼接之类,所以最后采用了RequestLine注解实现,你也可以再使用RequestMapping验证看看。
以下是API方法声明:文章来源地址https://www.toymoban.com/news/detail-631696.html

  • crumb头信息获取接口
    如果你直接使用Jenkins用户名和密码作为API请求认证方式,那么在所有API调用的Header里,都要有crumb值,这个接口就是用于获取crumb值的(注:不推荐使用)
// 直接请求后续接口会报错: Error 403 No valid crumb was included in the request
// 这个方法就是获取crumb数据的,再在后续请求头里添加 Jenkins-Crumb: xxx
@RequestLine("GET /crumbIssuer/api/json")
String getCrumb();
  • 启动Job构建接口,加入队列
    此接口用于启动某个job的构建,启动成功后,会在响应header里,返回加入到Jenkins的队列序号信息。
    后续需要根据这个队列序号,去查找真正的构建任务编号数据。
    注1:如果该Job配置了This project is parameterized,则必须在方法参数列表里增加这个Job的Parameter值,
    如果调用时未提供对应参数,则会用空值传递给Jenkins(旧版本里会报错,说未提供某某参数,我现在的版本2.361.2不会报错,直接用空值启动)
    注2:如果该Job无任何参数,请使用API: /job/{jenkinsName}/build
/**
 * 启动job构建
 * @param jenkinsName Jenkins的job名,用于url拼接
 * @param pack_env job的参数1:构建环境:test/prev/prod
 * @param publish_branch job的参数2:使用的git分支名
 * @param is_publish job的参数3:是否直接发布
 * @param version_desc job的参数4:发布说明
 * @return 没有响应body,只有header,如:
 * Headers:
 *   content-length: 0
 *   date: Fri, 23 Dec 2022 06:05:01 GMT
 *   location: http://10.100.72.165:8080/queue/item/79/
 *   server: Jetty(10.0.11)
 *   x-content-type-options: nosniff
 */
@RequestLine("POST /job/{jenkinsName}/buildWithParameters")
@Headers("Content-Type: application/x-www-form-urlencoded")
ResponseEntity<String> startDeploy(
        @Param("jenkinsName") String jenkinsName,
        @Param("pack_env") String pack_env,
        @Param("publish_branch") String publish_branch,
        @Param("is_publish") String is_publish,
        @Param("version_desc") String version_desc
);
  • 根据startDeploy方法返回的队列ID,查询真实任务构建ID(buildNum)接口
    队列ID表示还在排队,并没有启动,要轮询此接口,得到buildNum再访问后续接口。
/**
 * buildWithParameters方法启动构建,得到的只是QueueId,不是Job任务号BuildNum。
 * Jenkins会在队列中等待一个可用的线程,再真的启动Job。
 * 此方法就是根据QueueId去查询启动的Job任务号。
 * 注:需要不断轮询,直到结果出现如下结果为止
 * "executable":{"_class":"hudson.model.FreeStyleBuild","number":142,
 * @param queueId 队列id
 * @return json字符串
 */
@RequestLine("GET /queue/item/{queueId}/api/json")
HashMap<String, Object> queueItem(@Param("queueId") String queueId);
  • 根据任务构建ID(buildNum) 查询构建进度文本结果的接口
    这个文本结果,用于展示Jenkins工作的中间过程数据。
/**
 * 获取某一次构建的进度文本结果信息.
 * 注:也可以用/logText/progressiveText接口,或 /consoleText接口,但是缺少时间数据
 *
 * @param jenkinsName JOB名
 * @param buildNum    具体的构建序列号,可以是字符串"lastBuild",表示最后一次构建。
 * @param start       从第几个字节开始获取,默认0
 * @return 构建过程html数据,用于展示时,建议套上标签<pre> </pre>
 */
@RequestLine("GET /job/{jenkinsName}/{buildNum}/logText/progressiveHtml?start={start}")
String getBuildProgressive(@Param("jenkinsName") String jenkinsName,
                           @Param("buildNum") int buildNum,
                           @Param("start") int start);
  • 根据任务构建ID(buildNum) 查询构建是否完成的接口
    如果返回值的isBuilding为false,表示构建结束了,去看看成功还是失败吧。
/**
 * 获取某一次构建的进展信息。
 * 需要轮询,直到结果出现:"building":false,表示构建结束
 *
 * @param jenkinsName JOB名
 * @param number      具体的构建序列号,可以是字符串"lastBuild",表示最后一次构建。
 * @return json字符串
 */
@RequestLine("GET /job/{jenkinsName}/{number}/api/json?tree=*,executor[*],actions[parameters[*]]")
JenkinsBuildInfo getBuildInfo(@Param("jenkinsName") String jenkinsName,
                              @Param("number") int number);

一个Jenkins JOB的完整构建代码过程

private final JenkinsFeign jenkinsFeign;

private void startProjectBuild(String jenkinsName) {
    ResponseEntity response = jenkinsFeign.startDeploy(jenkinsName, "test", "origin/master", "true", "aaa");
    String queueId = getQueueId(response);
    // 轮询,直到构建启动
    int taskNum = getTaskNumber(queueId);
    // 轮询,直到构建结束
    waitTaskFinish(jenkinsName, taskNum);
}

// 获取Jenkins响应里的队列ID
private String getQueueId(ResponseEntity response) {
    String location = response.getHeaders().getFirst("location");
    // location参考 http://10.100.72.165:8080/queue/item/37/ 最后一个数字是队列ID
    String[] split = location.split("/");
    return split[split.length - 1];
}

// 根据Jenkins的QueueId,循环查找执行中的TaskId,如果任务处于Pending状态时,会返回0
private int getTaskNumber(String queueId) {
    int times = 0;
    while (times < 10) {
        ThreadHelper.sleep(3000);
        HashMap<String, Object> map = jenkinsFeign.queueItem(queueId);
        Object objExe = map.get("executable");
        if (objExe != null) {
            Object ret = ((Map<String, Object>) objExe).get("number");
            if (ret != null)
                return (int) ret;
        }
        times++;
    }
    return 0;
}

// 循环等待Jenkins任务构建结束
private String waitTaskFinish(String jenkinsName, int taskNum) {
    while (true) {
        ThreadHelper.sleep(10000);
        JenkinsBuildInfo info = jenkinsFeign.getBuildInfo(jenkinsName, taskNum);
        if (!info.isBuilding()) {
            return info.getResult();
        }
    }
}

附:我在用的完整FeignClient类定义

import com.zixun.zixunops.builds.jenkins.dtos.JenkinsBuildInfo;
import feign.Contract;
import feign.Headers;
import feign.Param;
import feign.RequestLine;
import feign.auth.BasicAuthRequestInterceptor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;

import java.util.HashMap;

@FeignClient(value = "jenkins", url = "${jenkins.worker.url}", configuration = JenkinsFeign.MultipartSupportConfig.class)
public interface JenkinsFeign {

    // 直接请求后续接口会报错: Error 403 No valid crumb was included in the request
    // 这个方法就是获取crumb数据的,再在后续请求头里添加 Jenkins-Crumb: xxx
    @RequestLine("GET /crumbIssuer/api/json")
    String getCrumb();

    /**
     * 启动job构建
     *
     * @param jenkinsName    Jenkins的job名,用于url拼接
     * @param pack_env       job的参数1:构建环境:test/prev/prod
     * @param publish_branch job的参数2:使用的git分支名
     * @param is_publish     job的参数3:是否直接发布
     * @param version_desc   job的参数4:发布说明
     * @return 没有响应body,只有header,如:
     * Headers:
     * content-length: 0
     * date: Fri, 23 Dec 2022 06:05:01 GMT
     * location: http://10.100.72.165:8080/queue/item/79/
     * server: Jetty(10.0.11)
     * x-content-type-options: nosniff
     */
    @RequestLine("POST /job/{jenkinsName}/buildWithParameters")
    @Headers("Content-Type: application/x-www-form-urlencoded")
    ResponseEntity<String> startDeploy(
            @Param("jenkinsName") String jenkinsName,
            @Param("pack_env") String pack_env,
            @Param("publish_branch") String publish_branch,
            @Param("is_publish") String is_publish,
            @Param("version_desc") String version_desc
    );

    /**
     * buildWithParameters方法启动构建,得到的只是QueueId,不是Job任务号BuildNum。
     * Jenkins会在队列中等待一个可用的线程,再真的启动Job。
     * 此方法就是根据QueueId去查询启动的Job任务号。
     * 注:需要不断轮询,直到结果出现如下结果为止
     * "executable":{"_class":"hudson.model.FreeStyleBuild","number":142,
     *
     * @param queueId 队列id
     * @return json字符串
     */
    @RequestLine("GET /queue/item/{queueId}/api/json")
    HashMap<String, Object> queueItem(@Param("queueId") String queueId);


    /**
     * 获取某一次构建的进度文本结果信息.
     * 注:也可以用/logText/progressiveText接口,或 /consoleText接口,但是缺少时间数据
     *
     * @param jenkinsName JOB名
     * @param buildNum    具体的构建序列号,可以是字符串"lastBuild",表示最后一次构建。
     * @param start       从第几个字节开始获取,默认0
     * @return 构建过程html数据,用于展示时,建议套上标签<pre> </pre>
     */
    @RequestLine("GET /job/{jenkinsName}/{buildNum}/logText/progressiveHtml?start={start}")
    String getBuildProgressive(@Param("jenkinsName") String jenkinsName,
                               @Param("buildNum") int buildNum,
                               @Param("start") int start);

    /**
     * 获取某一次构建的进展信息。
     * 需要轮询,直到结果出现:"building":false,表示构建结束
     *
     * @param jenkinsName JOB名
     * @param number      具体的构建序列号,可以是字符串"lastBuild",表示最后一次构建。
     * @return json字符串
     */
    @RequestLine("GET /job/{jenkinsName}/{number}/api/json?tree=*,executor[*],actions[parameters[*]]")
    JenkinsBuildInfo getBuildInfo(@Param("jenkinsName") String jenkinsName,
                                  @Param("number") int number);

    // 获取job的配置,可以用于备份
    @RequestLine("GET /job/{jenkinsName}/config.xml")
    String getJobConfig(@Param("jenkinsName") String jenkinsName);
    
    // 创建job
    @RequestLine("POST /createItem?name={jenkinsName}")
    @Headers("Content-Type: application/xml")
    void createJob(@Param("jenkinsName") String jenkinsName, String config);

    // 删除job
    @RequestLine("POST /job/{jenkinsName}/doDelete")
    void deleteJob(@Param("jenkinsName") String jenkinsName);

    // 更新job的配置
    @RequestLine("POST /job/{jenkinsName}/config.xml")
    @Headers("Content-Type: application/x-www-form-urlencoded")
    void updateJobConfig(@Param("jenkinsName") String jenkinsName, String config);


    class MultipartSupportConfig {
        @Value("${jenkins.worker.username:}")
        private String jenkinsUser;
        @Value("${jenkins.worker.password:}")
        private String jenkinsPassword;

        @Bean
        public Contract feignContract() {
            return new Contract.Default();
        }

        @Bean
        public BasicAuthRequestInterceptor basicAuthorizationInterceptor() {
            return new BasicAuthRequestInterceptor(jenkinsUser, jenkinsPassword);
        }
    }
}

到了这里,关于DevOps-7:Jenkins API介绍的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • DevOps极速入门丨Gitlab丨Jenkins丨harbor丨CICD丨自动化丨运维开发

    DevOps极速入门丨Gitlab丨Jenkins丨harbor丨CICD丨自动化丨运维开发

    一、DevOps介绍 软件开发最开始是由两个团队组成: 开发计划由开发团队从头开始设计和整体系统的构建。需要系统不停的迭代更新。 运维团队将开发团队的Code进行测试后部署上线。希望系统稳定安全运行。 这看似两个目标不同的团队需要协同完成一个软件的开发。 在开发

    2023年04月18日
    浏览(11)
  • DevOps-Jenkins

    DevOps-Jenkins

    Jenkins是一个可扩展的持续集成引擎,是一个开源软件项目,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。 官网 场景一 研发人员上传开发好的代码到github代码仓库 需要将代码下载nginx服务器部署 手动下载再部署/使用脚本下载在部署 场景二 静态IP(可以上

    2024年02月15日
    浏览(34)
  • DevOps持续集成-Jenkins(2)

    DevOps持续集成-Jenkins(2)

    DevOps概述 软件开发最初是由两个团队共同组成:(没有采用DevOps之前) 开发团队 :从头开始设计和整体系统的构建(编写代码)。需要系统不停的迭代更新。 运维团队 :将开发团队的代码进行测试通过后再部署上线。确保系统稳定运行。 没有采用DevOps的缺点: 这看似两个

    2024年02月08日
    浏览(20)
  • DevOps持续集成-Jenkins(4)

    DevOps持续集成-Jenkins(4)

    DevOps概述 软件开发最初是由两个团队共同组成:(没有采用DevOps之前) 开发团队 :从头开始设计和整体系统的构建(编写代码)。需要系统不停的迭代更新。 运维团队 :将开发团队的代码进行测试通过后再部署上线。确保系统稳定运行。 没有采用DevOps的缺点: 这看似两个

    2024年02月08日
    浏览(21)
  • 【DevOps视频笔记】8. Jenkins 配置

    【DevOps视频笔记】8. Jenkins 配置

    一、Jenkins 入门配置 1. 工具 / 插件 介绍 二、插件和工具配置 1. 配置 JDK 和 Maven Stage 1:将服务器中 JDK 和 Maven 映射到 jenkins 容器中 Stage 2:jenkins 全局配置中 -- 指定JAVA_HOME目录 Stage 3:jenkins 全局配置中 -- 指定MAVEN_HOME目录 2. 配置 Publish Over SSH Stage 1:添加 SSH Servers Stage 2:设置

    2024年02月11日
    浏览(10)
  • 【DEVOPS】Jenkins使用问题 - 控制台输出乱码

    【DEVOPS】Jenkins使用问题 - 控制台输出乱码

    部门内部对于Jenkins的使用采取的是Master + Slave Work Node的方式,即作为Master节点的Jenkins只负责任务调度,具体的操作由对应的Slave Work Node去执行。 最近团队成员反馈一个问题:一个Linux系统的Slave Work Node的编译日志输出中,中文部分均为乱码(如下图),这造成问题排查效率

    2024年02月11日
    浏览(112)
  • DevOps-Jenkins-CI持续集成操作

    DevOps-Jenkins-CI持续集成操作

    创建个web项目 我这里直接用Spring Web自动生成的demos 启动项目,访问展示如下默认页面信息 在项目下新建docker目录,新增Dockerfile、docker-compose.yml文件 Dockerfile文件,将mytest.jar 复制到容器的/usr/local/目录下,在/usr/local执行命令java -jar mytest.jar docker-compose.yml文件,当前目录以D

    2024年03月13日
    浏览(23)
  • 【云原生 • DevOps】一文掌握持续集成工具 Jenkins

    【云原生 • DevOps】一文掌握持续集成工具 Jenkins

    目录 一、持续集成工具 Jenkins 介绍 1. 什么是持续集成 2. Jenkins 介绍 二、Jenkins 的安装与部署 1. 安装 Jenkins 2. 本地访问 Jenkins 3. 插件的安装 4. 卸载 Jenkins 三、Jenkins 全局配置 1. Git 的安装与配置 2. JDK 的安装与配置 3. maven 的安装与配置 三、将代码上传至 Git 服务器 1. Gogs 的搭

    2024年02月03日
    浏览(17)
  • 基于jenkins+k8s实现devops

    基于jenkins+k8s实现devops

    由于jenkins运行在k8s上能够更好的利用动态agent进行构建。所以写了个部署教程,亲测无坑 1、创建ns kubectl create namespace devops 2、kubectl apply -f jenkins.yml 注意:镜像建议使用最新版本,因为jenkin平台默认提供了最新的插件,且无法选择版本,所以如果jenkins版本过低会导致插件不

    2024年02月06日
    浏览(15)
  • 【DevOps-08-3】Jenkins容器内部使用Docker

    【DevOps-08-3】Jenkins容器内部使用Docker

    构建镜像和发布镜像到harbor都需要使用到docker命令。而在Jenkins容器内部安装Docker官方推荐直接采用宿主机带的Docker即可。 设置Jenkins容器使用宿主机Docker。

    2024年01月16日
    浏览(22)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包