Jenkins APIを通してジョブを登録する

JenkinsのジョブをAPIから登録したい要件があったので、調べて見ました。

## 環境構築

### Jenkins コンテナの起動とセットアップ

Docker を使って Jenkins コンテナを起動します。(latestを指定していますが、確認した時のJenkinsのバージョンは2.60.3でした)

```docker-compose.yml
version: '2'

services:
  jenkins:
    restart: always
    image: jenkins:latest
    environment:
      - JENKINS_OPTS=--prefix=/jenkins
    volumes:
      - ./data/jenkins/jenkins:/var/jenkins_home
    ports:
      - "13080:8080"
```

```
$ docker-compose up -d
$ docker ps | grep jenkins
b8f18f187de9        jenkins:latest               "/bin/tini -- /usr/l…"   3 hours ago         Up 3 hours          50000/tcp, 0.0.0.0:13080->8080/tcp       jenkins_jenkins_1
```

コンテナが起動したので、 http://localhost:13080/jenkins/ にアクセスします。
`/var/jenkins_home/secrets/initialAdminPassword` の内容を入力するよう、求められるので、以下のように確認します。

```
$ docker exec -it b8f18f187de9 bash
jenkins@b8f18f187de9:/$ cat /var/jenkins_home/secrets/initialAdminPassword
fcaed6cf3b5d4439b3cf0d65c3a5e878
```

その後、セットアップウィザードに従い、各種プラグインをインストールします。

### ジョブ作成

適当にジョブを作成します。
ここでは `echo "Hello, Jenkins!"` するだけの「hello template」というジョブを作成することにします

## Jenkins APIへのアクセス

[How to create a job using the REST API and cURL? &ndash; CloudBees Support](https://support.cloudbees.com/hc/en-us/articles/220857567-How-to-create-a-job-using-the-REST-API-and-cURL-) を参考に一つ一つ確認していきます。

### APIトークンの取得

Jenkins APIを利用するためには、APIトークンが必要です。Jenkinsにログイン後、右上のユーザー名 > 設定をクリックし、APIトークンを表示します。すると、以下のように、User ID と ＡＰＩ トークンを取得できます。

```
User ID: admin
API トークン: 34285bf2ae047ea8ae6c2b5b795be623
```

### ジョブ一覧を取得する

`/api/json` にアクセスすると json　形式でジョブの情報が得られました。また、BASIC認証が掛かっているので、上記の User ID と　API トークンをユーザー名、パスワードとして認証します。

```
$ curl --user 'admin:34285bf2ae047ea8ae6c2b5b795be623' -s http://localhost:13080/jenkins/api/json | jq -r ".jobs[]"
{
  "_class": "hudson.model.FreeStyleProject",
  "name": "hello template",
  "url": "http://localhost:13080/jenkins/job/hello%20template/",
  "color": "blue"
}
```

### ジョブ単体の情報を取得する

`/job/{JOB名}/api/json` にアクセスするとジョブ単体の情報が得られます。

```
$ curl --user 'admin:34285bf2ae047ea8ae6c2b5b795be623' -s http://localhost:13080/jenkins/job/hello%20template/api/json|jq
{
  "_class": "hudson.model.FreeStyleProject",
  "actions": [
    {},
    {},
    {
      "_class": "com.cloudbees.plugins.credentials.ViewCredentialsAction"
    }
  ],
  "description": "",
  "displayName": "hello template",
  "displayNameOrNull": null,
  "fullDisplayName": "hello template",
  "fullName": "hello template",
(以下略)
```

### ジョブの設定を取得する

このジョブの設定を取得し、 `mylocalconfig.xml` というファイルに出力します。

```
$ curl --user 'admin:34285bf2ae047ea8ae6c2b5b795be623' -s http://localhost:13080/jenkins/job/hello%20template/config.xml -o mylocalconfig.xml
```

以下のような内容のファイルが出力されました。

```mylocalconfig.xml
<?xml version='1.0' encoding='UTF-8'?>
<project>
  <description></description>
  <keepDependencies>false</keepDependencies>
  <properties/>
  <scm class="hudson.scm.NullSCM"/>
  <canRoam>true</canRoam>
  <disabled>false</disabled>
  <blockBuildWhenDownstreamBuilding>false</blockBuildWhenDownstreamBuilding>
  <blockBuildWhenUpstreamBuilding>false</blockBuildWhenUpstreamBuilding>
  <triggers/>
  <concurrentBuild>false</concurrentBuild>
  <builders>
    <hudson.tasks.Shell>
      <command>echo &quot;Chao, Jenkins!&quot;</command>
    </hudson.tasks.Shell>
  </builders>
  <publishers/>
  <buildWrappers/>
</project>
```


### ジョブを登録する

`/createItem` からジョブを登録できるのですが、その前に CSRF対策として CRUMB(トークン?) を取得しておきます。(CSRF対策を無効化することもできますが、当然脆弱になりますのでお勧めしません)

```
CRUMB=$(curl --user 'admin:34285bf2ae047ea8ae6c2b5b795be623' -s 'http://localhost:13080/jenkins/crumbIssuer/api/xml?xpath=concat(//crumbRequestField,":",//crumb)')
$ echo $CRUMB
Jenkins-Crumb:2a9e2016ee523dd2ea1c7d8a262509fe
```

では、 `mylocalconfig.xml` の内容を `yourJobName` という名前でジョブを作成します。

```
$ curl --user 'admin:34285bf2ae047ea8ae6c2b5b795be623' -s -XPOST 'http://localhost:13080/jenkins/createItem?name=yourJobName' --data-binary @mylocalconfig.xml -H "$CRUMB" -H "Content-Type:text/xml"
```

GUIからジョブが無事に登録できたことが確認できました。
ちなみに、CRUMBを指定しないと、以下のようなエラーになります。

```
Error 403 No valid crumb was included in the request
```

## 参考

* [How to create a job using the REST API and cURL? &ndash; CloudBees Support](https://support.cloudbees.com/hc/en-us/articles/220857567-How-to-create-a-job-using-the-REST-API-and-cURL-)
* [Jenkins APIを使ってジョブのテンプレートから新しいジョブを作成する - Qiita](https://qiita.com/tkit/items/2fde39a8909feecf47db)
* [Jenkins  APIでジョブ情報を取得する - Qiita](https://qiita.com/tamikura@github/items/033ab9180561b6232509)