Gitlab CI: 动态更改流水线定义

101次阅读
没有评论

问题描述

在使用Gitlab CI时,有一个需求是希望能够从阶段A传递信息到阶段B,以便可以动态更改阶段B。
具体要求如下:
– 用户有一个阶段(A),在该阶段中验证terraform计划并检查是否会销毁资源。
– 用户有另一个阶段(B),应用terraform计划,如果阶段A检测到将要销毁资源,则希望手动触发阶段B。
– 当没有资源被销毁时,terraform应用阶段(B)应自动运行。

用户想知道如何将阶段A的信息传递到阶段B。

解决方案

请注意以下操作注意版本差异及修改前做好备份。

方案1

在Gitlab CI中,无法在rules子句中使用dotenv变量的原因是,rules在流水线开始执行之前就会进行评估。

如果你有一个类似以下的rules子句:

rules:
  - if: $CI_COMMIT_TAG === 'v1.0.0'
    when: never
  - when: always

Gitlab CI将执行以下检查:
1. 流水线是否为Tag Pipeline(通过CI_PIPELINE_SOURCE变量判断)?如果不是,则CI_COMMIT_TAG不存在,因此该子句不存在,只有when:always规则。将该任务添加到流水线中。
2. 如果流水线是一个标签流水线,是否tag === 'v1.0.0'?如果是,则使用when:never。不将该任务添加到流水线中。
3. 标签流水线且标签不等于v1.0.0,使用when:never并将该任务添加到流水线中。

所有这些操作都发生在流水线处于created状态之前,因此它不能依赖于在流水线开始运行后创建的变量。

了解了这一点,我将如下解决问题的方法:
将阶段B的任务标记为手动任务,就像它已经是的那样,但是当你想要自动运行它时,从阶段A的任务中调用Gitlab Jobs API来运行阶段B的任务。

这将使用一些API调用:
1. 首先,我们需要获取特定流水线的任务:

curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/$CI_PROJECT_ID/pipelines/$CI_PIPELINE_IID/jobs?scope=manual"

这将返回流水线中所有manual任务。如果你有多个任务,可以通过查看响应中的stagename的值来获取正确的任务。以下是文档中的示例:

[
  {
    "commit": {
      "author_email": "admin@example.com",
      "author_name": "Administrator",
      "created_at": "2015-12-24T16:51:14.000+01:00",
      "id": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
      "message": "Test the CI integration.",
      "short_id": "0ff3ae19",
      "title": "Test the CI integration."
    },
    "coverage": null,
    "allow_failure": false,
    "created_at": "2015-12-24T15:51:21.727Z",
    "started_at": "2015-12-24T17:54:24.729Z",
    "finished_at": "2015-12-24T17:54:24.921Z",
    "duration": 0.192,
    "queued_duration": 0.023,
    "artifacts_expire_at": "2016-01-23T17:54:24.921Z",
    "tag_list": [
      "docker runner", "ubuntu18"
    ],
    "id": 6,
    "name": "rspec:other",
    "pipeline": {
      "id": 6,
      "project_id": 1,
      "ref": "main",
      "sha": "0ff3ae198f8601a285adcf5c0fff204ee6fba5fd",
      "status": "pending"
    },
    "ref": "main",
    "artifacts": [],
    "runner": null,
    "stage": "test",
    "status": "failed",
    "tag": false,
    "web_url": "https://example.com/foo/bar/-/jobs/6",
    "user": {
      "id": 1,
      "name": "Administrator",
      "username": "root",
      "state": "active",
      "avatar_url": "http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon",
      "web_url": "http://gitlab.dev/root",
      "created_at": "2015-12-21T13:14:24.077Z",
      "bio": null,
      "location": null,
      "public_email": "",
      "skype": "",
      "linkedin": "",
      "twitter": "",
      "website_url": "",
      "organization": ""
    }
  }
]
  1. 一旦我们有了任务ID,我们可以调用Play Job API来运行阶段B的任务:
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/$CI_PROJECT_ID/jobs/$ID_OF_STAGE_B_JOB/play"

注意:我们不想在Play Job API中使用预定义变量$CI_JOB_ID,因为那将是阶段A任务的ID,而不是阶段B任务的ID。

以下是有关Pipeline Jobs APIPlay Job API的更多信息和查询参数。

正文完