【AAP】ansible.controllerコレクション使ってワークフロージョブテンプレートを作る

この記事は[エーピーコミュニケーションズ Advent Calendar 2024](https://qiita.com/advent-calendar/2024/ap-com) 24日目のエントリです。

## はじめに
AAPの設定をAnsibleから行えるansible.controllerコレクションでは、認証情報やジョブテンプレートはもちろん、ワークフロージョブテンプレートも作成することができます。  
今回はこのコレクションを使ってワークフロージョブテンプレートを作成してみます。

## 環境
AWS EC2: m5.large  
ansible-core: 2.15.13
AAP Version: 2.5

## コレクションのインストール
ansible.controllerコレクションはデフォルトではインストールできないので下準備をします。  
具体的には`ansible-galaxy`コマンドでコレクションをインストールする際の参照先を切り替える作業を実施します。  

参考：

https://tekunabe.hatenablog.jp/entry/2020/12/27/ansible_galaxy_automation_hub

### 接続用トークンの取得
以下のページにログインして[Ansible] -> [Automation Hub] -> [Connect to Hub]に移動します。  

https://console.redhat.com/

「トークンの読み込み」をクリックし、表示されるトークンを控えておく。  
![20241128103952.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3902042/2f6c3aea-8af1-9198-114c-c501adadb49c.jpeg)


### ansible.cfgの設定
`ansible-galaxy`の参照先の変更はAnsibleの設定ファイルである`ansible.cfg`で行います。  
`ansible.cfg`に以下を追記します。(ない場合は作成)  
\<TOKEN\>のところにAutomation Hubで取得したトークンを張る。  
```
[galaxy]
server_list = automation_hub

[galaxy_server.automation_hub]
url=https://console.redhat.com/api/automation-hub/content/published/
auth_url=https://sso.redhat.com/auth/realms/redhat-external/protocol/openid-connect/token
token=<TOKEN>
```
### ansible.controllerのインストール
下準備が終わったのでコレクションのインストールします。  
インストール方法はシンプルに`ansible-galaxy collection install <コレクション名>`でOK。  
コレクションの[ページ](https://console.redhat.com/ansible/automation-hub/repo/published/ansible/controller/)に書いてあるコマンドを実行。

> `ansible-galaxy collection install ansible.controller`

```basic
$ ansible-galaxy collection install ansible.controller
Starting galaxy collection install process
Process install dependency map
Starting collection install process
Downloading https://console.redhat.com/api/automation-hub/v3/plugin/ansible/content/published/collections/artifacts/ansible-controller-4.6.2.tar.gz to /home/ec2-user/.ansible/tmp/ansible-local-3845h2typ3zt/tmpwc5w_9mf/ansible-controller-4.6.2-hf4ecdq0
Installing 'ansible.controller:4.6.2' to '/home/ec2-user/.ansible/collections/ansible_collections/ansible/controller'
ansible.controller:4.6.2 was installed successfully

$ ansible-galaxy collection list | grep ansible.controller
ansible.controller            4.6.2  
```
無事インストール完了。  

※AAP2.5からAPIのURLが変わっているので、インストールするコレクションのバージョンは使用するAAPやコントローラのバージョンに合わせる必要があります。
コレクションのバージョンを指定してインストールする場合は `ansible-galaxy collection install ansible.controller==4.6.3`のように指定します。  


## インベントリ等について
ジョブテンプレートを動かすためにはインベントリやプロジェクトなどが必要ですが、今回の主題はワークフロージョブテンプレートの作成なためここはスキップします。  
AAPインストール時から存在する`Demo Inventory`や`Demo Project`を使ってジョブテンプレートを作ります。  

## ジョブテンプレートの作成
ワークフロージョブテンプレートはジョブテンプレートを数珠繋ぎにするものなのでまずはジョブテンプレートを作成。  
今回はジョブテンプレートもコレクションを使って作ってみます。  
ジョブテンプレートを作成するためには`job_template`モジュールを使用します。
例としてはこんな形。  
```yaml
---
- name: create job template
  ansible.controller.job_template:
    name: "job template name"
    job_type: "run"
    inventory: "Inventory name"
    project: "Project name"
    playbook: "Playbook name"
    state: "present"
    execution_environment: "ee name"
```
GUIからジョブテンプレートを作成する時に指定するものをオプションで与えているだけなので分かりやすい。  
## 一度動作確認
まだ本題に入ってないですが、ここで一度AAPへの接続確認も兼ねて動作確認をしておきます。
使うPlaybookは以下。  
```yaml
---
- hosts: localhost
  connection: local
  gather_facts: false

  environment:
    CONTROLLER_HOST: https://localhost
    CONTROLLER_USERNAME: admin
    CONTROLLER_PASSWORD: hogefuga
    CONTROLLER_VERIFY_SSL: false


  tasks:
    - name: create job template
      ansible.controller.job_template:
        name: "job_template_1"
        job_type: "run"
        inventory: "Demo Inventory"
        project: "Demo Project"
        playbook: "hello_world.yml"
        state: "present"
        credential: "Demo Credential"
        execution_environment: "Default execution environment"
```
環境変数で定義しているAAPへの接続情報が平文なのは分かりやすさ重視ということで...

実行。  
```basic
ansible-playbook create_job_template.yml 

PLAY [localhost] ****************************************************

TASK [create job template] *****************************************
changed: [localhost]

PLAY RECAP ********************************************************
localhost                  : ok=1    changed=1    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
```
成功。  

AAPから確認してみます。  
![20241128115154.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3902042/d215c2b7-54e0-2257-730f-cc6350f75fb5.jpeg)

作成されていることが確認できました。  

## ワークフロージョブテンプレートを作る
さきほど書いたタスクで作成されるジョブテンプレートを元にしてワークフロージョブテンプレートを作ります。  
使用するのは`workflow_job_template`と`workflow_job_template_node`モジュールの2つ。  
簡単にそれぞれを説明すると以下のようになります。  

* `workflow_job_template`  
ワークフロージョブテンプレートそのものを作成するためのモジュール。  

* `workflow_job_template_node`  
既にあるワークフロージョブテンプレートのノードの編集をするためのモジュール。

なお、`workflow_job_template`モジュールだけでもノードを記述することができますが、専用モジュールである`workflow_job_template_node`を使った方がより(個人的には)シンプルに記述できます。

### ワークフローを作るPlaybook
ほぼExampleのままですがこんな感じ。  
 ノードを直列に3つ繋ぎ、真ん中に承認ノードを配置したワークフローができあがる。
```yaml
- name: Create a workflow job template　    # ワークフロージョブテンプレートを作成
  ansible.controller.workflow_job_template:
    name: my-workflow-job-template
    organization: Default

- name: Create 1st node                     # 1つ目のノードを作成
  ansible.controller.workflow_job_template_node:
    identifier: my-first-node
    workflow_job_template: my-workflow-job-template
    unified_job_template: job_template_1
    organization: Default

- name: Create 2nd approval node           # 2つ目のノードを作成(承認ノード)
  ansible.controller.workflow_job_template_node:
    identifier: my-second-approval-node
    workflow_job_template: my-workflow-job-template
    organization: Default
    approval_node:
      description: "Do this?"
      name: my-second-approval-node
      timeout: 3600

- name: Create 3rd node                    # 3つ目のノードを作成
  ansible.controller.workflow_job_template_node:
    identifier: my-third-node
    workflow_job_template: my-workflow-job-template
    unified_job_template: job_template_2
    organization: Default

- name: Link 1st node to 2nd Approval node # 1つ目のノードが成功したら2つ目のノードを実行するよう接続
  ansible.controller.workflow_job_template_node:
    identifier: my-first-node
    workflow_job_template: my-workflow-job-template
    organization: Default
    success_nodes:
      - my-second-approval-node

- name: Link 2nd Approval Node 3rd node    # 2つ目のノードが成功したら3つ目のノードを実行するよう接続
  ansible.controller.workflow_job_template_node:
    identifier: my-second-approval-node
    workflow_job_template: my-workflow-job-template
    organization: Default
    success_nodes:
      - my-third-node
```
実行するとこんなワークフローが作成されます。  
![20241128140128.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3902042/cff564e5-7ddb-decd-eb6d-5f8d3426bf49.jpeg)


ちなみに、さきほど実行したPlaybookでノードの接続を定義したタスクがないと以下のようなすべてのノードがStartに接続されるワークフローが出来上がります。  
![20241128141701.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3902042/92ebfe8c-af56-2581-5a89-339151a0ff34.jpeg)



## 分岐させてみる
さきほどのものは直列でしたが成功か失敗かで分岐する形にしてみます。  
失敗した際、実行させるようにしたいため、`success_nodes`ではなく`failure_nodes`で繋ぎます。  
以下のタスクをさきほどのPlaybookに追記します。
```yaml
- name: Create 4th node
  ansible.controller.workflow_job_template_node:
    identifier: my-Fourth-node
    workflow_job_template: my-workflow-job-template
    unified_job_template: job_template_3
    organization: Default

- name: Link 2nd Approval Node 4th node
  ansible.controller.workflow_job_template_node:
    identifier: my-second-approval-node
    workflow_job_template: my-workflow-job-template
    organization: Default
    failure_nodes:
      - my-Fourth-node
```

生成物。  
![20241128142626.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3902042/606baf59-647c-ed9c-f648-3f163fd4bb75.jpeg)

承認ノードで許可された場合と拒否された場合で処理を変えるようにできた。  

<details><summary>一応動作確認</summary>
承認するVer.

![20241128143040.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3902042/469cb290-037e-165e-6f19-78c588d99154.jpeg)

拒否するVer.
![20241128143044.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3902042/309bbbee-bfdf-17cb-4172-cf48b9429cf4.jpeg)


動作確認OK
</details>

## おわりに
今回は`ansible.controller`コレクションを使いAAPのワークフロージョブテンプレートを作成してみました。
今回はワークフロージョブテンプレートにフォーカスしましたが、認証情報やプロジェクトなどAAPの設定はほとんどできるので、よく使う設定をPlaybookとして残しておけば初期設定が簡単できるようになります。


## 参考(再掲)

https://console.redhat.com/ansible/automation-hub/repo/published/ansible/controller/

https://tekunabe.hatenablog.jp/entry/2020/12/27/ansible_galaxy_automation_hub



## おまけ
間に承認ノードを入れた3ノード直列のワークフローを`workflow_job_template`だけで作ってみる。  
```yaml
- name: create workflow job template
  ansible.controller.workflow_job_template:
    state: present
    name: "demo_workflow_job_template"
    workflow_nodes:
      - identifier: my-first-node
        unified_job_template:
          name: "job_template_1"
          type: job_template
        related:
          success_nodes: 
            - identifier: my-second-approval-node

      - identifier: my-second-approval-node
        unified_job_template:
          description: "Do this?"
          timeout: 3600
          name: approval
          type: workflow_approval              
        related:
          success_nodes:
            - identifier: my-third-node

      - identifier: my-third-node
        unified_job_template:
          name: "job_template_2"
          type: job_template
```
このタスクにより作成されるワークフロージョブテンプレートはこちら。  
![20241128144347.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3902042/f168e67a-6bed-7066-10a4-a3f346657e05.jpeg)
  
同じものが作成されるように書いたので当然ですが、同じワークフローが作成されます。  
「`workflow_job_template`だけで書くより`workflow_job_template_node`を使った方がシンプルに書けるよ」と思ってんですが、別にこっちでも割とシンプルに書けますね。。。
もっと複雑なワークフローだと話は変わるかもしれません。