【问题标题】:Retrieve id of remotely triggered jenkins job检索远程触发的詹金斯作业的 id
【发布时间】:2014-07-01 09:50:24
【问题描述】:

我正在通过 http POST 请求从 jenkins 外部触发参数化 Jenkins:

我在作业配置中启用了可以从外部触发作业,我可以通过向 jenkins 发送包含如下内容的请求来真正触发它:

发布
http://myJenkins.com/myJob/buildWithParameters?token=MYTOKEN 参数:SCREEN_SIZE:27

触发创建作业会返回成功的 201 CREATED http 响应。

我的问题是我不知道所创建的构建作业的 ID。我想监控工作的状态。为了做到这一点,我需要知道 id。否则,如果我只接受该工作的最新版本,我可能会做错工作。

是否有可靠的方法来获取已创建作业的 id?

【问题讨论】:

    标签: jenkins


    【解决方案1】:

    自 Jenkins 1.519 起,将构建排入队列会以 Location 中的 URL 响应,将您指向构建队列中的项目:

    $ nc localhost 8666
    POST /jenkins/job/morgRemote/buildWithParameters?jenkins_status=1&jenkins_sleep=20&token=morgRemote HTTP/1.1
    Host: localhost:8666
    
    HTTP/1.1 201 Created
    Location: http://localhost:8666/jenkins/queue/item/39/
    Content-Length: 0
    Server: Jetty(winstone-2.8)
    

    现在,如果您将api/json(或api/xml 等)添加到它的末尾(因此在此示例中为http://localhost:8666/jenkins/queue/item/39/api/json),那么您将获得一个包含给定构建ID 的文档工作。对于 json,检索到的对象具有 executable 属性,而后者又具有 numberurl 属性。 number 是给定作业的构建 ID(此处为 35),url 是 jenkins 构建页面 url。

    {
      "actions" : [
        {
          "parameters" : [
            {
              "name" : "jenkins_status",
              "value" : "1"
            },
            {
              "name" : "jenkins_sleep",
              "value" : "20"
            }
          ]
        },
        {
          "causes" : [
            {
              "shortDescription" : "Started by remote host 127.0.0.1",
              "addr" : "127.0.0.1",
              "note" : null
            }
          ]
        }
      ],
      "blocked" : false,
      "buildable" : false,
      "id" : 39,
      "inQueueSince" : 1423993879845,
      "params" : "\njenkins_status=1\njenkins_sleep=20",
      "stuck" : false,
      "task" : {
        "name" : "morgRemote",
        "url" : "http://localhost:8666/jenkins/job/morgRemote/",
        "color" : "red"
      },
      "url" : "queue/item/39/",
      "why" : null,
      "cancelled" : false,
      "executable" : {
        "number" : 35,
        "url" : "http://localhost:8666/jenkins/job/morgRemote/35/"
      }
    }
    

    注意两件事:

    • 构建队列中的非活动项目会在几分钟后被垃圾回收,因此您应该尽快检索构建 ID
    • 默认情况下,将项目添加到队列直到获得构建 ID 之间需要几秒钟。在此期间,executablecanceled 属性将丢失,why 将不为空。您可以通过修改“安静期”设置或 jenkins 全局配置在作业配置的“高级项目选项”中更改此行为。

      ...
      "url" : "queue/item/39/",
      "why" : "In the quiet period. Expires in 2.4 sec",
      "timestamp" : 1423993879845
    }
    

    【讨论】:

    • 感谢您的回答!这部分对我有用。我在 v1.559 上,如果我有一个非参数化构建并使用 /build 我得到了位置。当我使用 buildWithParameters 我得到一个错误......预期。在参数化构建中,我没有得到正确的位置。如果我使用 /build,我会得到工作 url,如果我使用 buildWithParameters,我会在 Location 标头中一无所获。有什么想法吗?
    • 关于尽快检索构建 ID,因为队列项目将被垃圾收集,请参阅此问题:issues.jenkins-ci.org/browse/JENKINS-31039
    • “默认情况下,将项目添加到队列直到获得构建 ID 之间需要几秒钟” - 实际上可能需要几秒钟、几小时或几天!在 Jenkins 找到并分配执行者来运行该作业之前,该作业没有内部版本号。
    • 仅供参考:我在 Jenkins 版本。 2.138.4 配置了 1 秒的静默期。如果在安静期,“可执行”部分将不会出现,并且 1.5 秒的延迟不足("why" 将是 "???")。在读取 url 之前添加 5s 延迟解决了它。
    【解决方案2】:

    更新:

    other answer 是在我的大约 8 个月后添加的。我当时不知道响应中的 location 标头。在某些情况下,这听起来确实是一个不错的选择。也就是说,根据答案中的警告和 cmets(尤其是围绕 parameterized 构建),看来这个答案在某些情况下仍然有用。

    原答案:

    不幸的是,他们没有让这一切变得尽可能简单。例如,通过返回一个 JSON 响应,其中包含 id 之类的信息。

    但是,我相信一个可靠的解决方法是利用 URL 中的 cause 参数来触发构建,并在该原因中添加 独特的文本,您可以稍后对其进行解析以确定您从自动化中触发了它。

    为了进一步独特化特定作业,以防多个同时运行,即使来自您的自动化,也包括某种类型的唯一 ID(它可能只是来自您的序列 ID RDBMS 或类似的)在 cause 参数中。

    然后,您可以使用 JSON API 获取有关您正在远程触发的作业 的信息。同样,它有点间接,但可行:

    点击表单的 URL:

    http://<server>:<port>/job/<jobname>/lastBuild/api/json
    

    您可以添加?pretty=true 以在浏览器中进行漂亮的打印,以提高可读性。

    这将为您提供上次构建的 JSON。它将在 actions 属性中包含 causes 属性,并且在其中(在另一个名为 shortDescription 的嵌套属性中)您会找到 原因 您添加的参数,如果这是您触发的构建之一。

    您可以解析出特殊的静态文本和生成的 ID 以查看它们是否匹配。如果他们这样做了,那么您也可以从 JSON 中获取 Jenkins id(搜索嵌套的 buildNumber)。

    如果该构建根本不是由您的自动化触发的,或者是,但 ID 不匹配,您可以对 N - 1 个构建重复该过程,直到找到您想要的正在寻找。

    JSON 格式如下:

    http://<server>:<port>/job/<jobname>/<buildNumber>/api/json
    

    【讨论】:

    • 能否请您详细说明如何添加cause 参数?我搜索了 Jenkins 文档,但找不到对此参数的任何引用。
    • 这是您在用于通过 curl 或类似方式触发构建的 URL 中指定的参数。例如将参数cause=foo_100 添加到URL。
    • 很好的回应!当您在构建历史记录中搜索唯一 ID 时,可能会出现竞争条件,即触发的作业执行仍在队列中。您可以通过使用 201 创建的响应中包含的位置来避免这种情况,并基本上等待它离开队列。
    【解决方案3】:

    原来构建具有原始队列 ID。此外,您可以仅使用您的队列 ID 查询构建并轮询它,直到您获得结果,因为 404 通常应该暗示它已排队。

    从 Location 标头中提取队列 ID,例如39

    /jenkins/queue/item/39/
    

    使用该队列号重复查询构建,直到得到答案

    "http://{jenkins}job/{job}/api/xml?tree=builds[number,queueId]&xpath=//build[queueId=\"{queueId}\"]";
    
    <build>
      <number>411</number>
      <queueId>39</queueId>
    </build>
    

    从此结果中,您可以使用 xpath /build/number/text() 提取内部版本号

    (注意我不能在网址中使用&amp;xpath=//build[queueId={queueId}]/number/text(),因为"primitive XPath result sets forbidden; implement jenkins.security.SecureRequester"

    这与轮询队列 api 以获取“可执行”构建一样蹩脚。一个优点是端点将持续更长时间 - 直到构建被删除,与任意时间(似乎是大约 5 分钟)相比。

    【讨论】:

    • 谢谢!此外,xpath 的东西让事情变得更容易,不需要 JSON 解析器来找到正确的数据。
    【解决方案4】:

    我能够使用 Java Jenkins api 来实现您正在寻找的东西。 https://github.com/jenkinsci/java-client-api

    示例代码:

    JenkinsServer jenkinsServer = new JenkinsServer(newURI("http://yourJenkinsServer:8080/"));
    JobWithDetails smokeTestJob = jenkinsServer.getJob("YourJobName");        
    Map<String,String> jobParams = new HashMap<String,String>();
    QueueReference queueReference = smokeTestJob.build(jobParams);
    
    do {
      Thread.sleep(2000L);
      queueItem = jenkinsServer.getQueueItem(queueReference);
      log("Job still in queue"+queueItem.getExecutable());
      } while (queueItem.getExecutable() == null);
    
    Build build = jenkinsServer.getBuild(queueItem);
    
    while(build.details().isBuilding()){
      log("Job still running");
      Thread.sleep(10000L);
    }
    
    log("Result="+build.details().getResult());
    

    【讨论】:

      【解决方案5】:

      想要使用 Location 标头添加到 morgwai 答案中。

      我刚刚解决了这个问题。 Location 标头之后的关键是轮询作业队列条目,直到它有一个“可执行”条目,该条目给出了已启动的作业编号。

      我首先看到的一个类似问题没有完全回答问题,我给出了完整的答案:

      https://stackoverflow.com/a/48531874/9291603

      来自 Jenkins 作业队列条目的 JSON 和可执行条目:

      {
          "_class": "hudson.model.Queue$LeftItem",
          "actions": [
              {
                  "_class": "hudson.model.CauseAction",
                  "causes": [
                      {
                          "_class": "hudson.model.Cause$RemoteCause",
                          "addr": "10.20.30.60",
                          "note": null,
                          "shortDescription": "Started by remote host 10.20.30.60"
                      }
                  ]
              }
          ],
          "blocked": false,
          "buildable": false,
          "cancelled": false,
          "executable": {
              "_class": "org.jenkinsci.plugins.workflow.job.WorkflowRun",
              "number": 45,
              "url": "http://192.168.115.187:8080/job/rf_systest/45/"
          },
          "id": 95,
          "inQueueSince": 1517342648136,
          "params": "",
          "stuck": false,
          "task": {
              "_class": "org.jenkinsci.plugins.workflow.job.WorkflowJob",
              "color": "blue_anime",
              "name": "rf_systest",
              "url": "http://192.168.115.187:8080/job/rf_systest/"
          },
          "url": "queue/item/95/",
          "why": null
      }
      

      【讨论】:

        猜你喜欢
        • 2018-12-20
        • 2015-10-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多