Ansible モジュールに利用したい機能が無い場合の代替手段例の紹介

この記事は、「Ansible Advent Calendar 2022」の17日目の記事です。

皆様いかがお過ごしでしょうか。レッドハットテクニカルサポートの呉と申します。普段は Ansible と RHEL(主に Services )のサポートをしています。

今回は、利用したい機能が Ansible モジュールに見当たらないといった時にあれこれ工夫する一例として、ansible.builtin.uri モジュールを例にしながら触れてみようと思います。

docs.ansible.com

Ansible は本記事の作成時点(2022年12月17日)で実に 3300+ ものモジュールを持ちますが、全ての製品 の全ての機能を網羅しているわけではないため、必要だと思われる機能があればその都度、RFE を上げて実装のリクエストを出す事になります。

Ansible Collections のリポジトリはこちらになります。

github.com

例えば、cisco.nxos の collection で追加してほしい機能等があれば、以下のリポジトリの issue から RFE を作成する事になります。

github.com

尚、RFEは必ず承認されて実装されるものではありません。また、実装されるとしてもその時期等は不明確なので、その間は、そのリクエストした機能に ついては、何かしらの代替手段で工夫していくことになります(もちろん、自ら実装して pull request を送ってしまうのもアリだと思います!)。

この代替手段については、お問い合わせをいただいた際にはできる範囲でご紹介させていただいております。

今回、その一例が ansible.builtin.uri モジュールになります。 REST API を用いて管理されるノードやサービスで、現行の Ansible モジュールが利用したい機能を提供していない場合はこのモジュールを活用する事が考えられる手段の一つとなります。

ここからは、実際の利用例の紹介となります。また今回は controller.group モジュールを例にしてみました。 本記事の作成時点では、controller.group モジュールでインベントリのグループからホストの関連付け を解除するためには、関連づけておきたい全てのホストを記述する必要があります。 console.redhat.com

例えば以下の様なプレイブックになります。ここでは、Ansible Automation Controller(※以降コントローラ)に存在するインベントリ「test inventory 」に存在するインベントリ グループ「test group」にホスト「test1」「test2」が存在する状態から、test2 のみの関連付けを解除するタスクになります。

※コントローラに必要な接続情報は controller_info.ymlファイルに変数として全て定義し、インポートしています。

---
- hosts: localhost
  gather_facts: no

  tasks:
    - name: Include vars
      ansible.builtin.include_vars:
        file: controller_info.yml

    - name: Disassociate "test2" from "test group" of "test inventory"
      ansible.controller.group:
        controller_host: "{{ CONTROLLER_URL }}"
        controller_username: "{{ USERNAME }}"
        controller_password: "{{ PASSWORD }}"
        controller_oauthtoken: "{{ TOKEN }}"
        inventory: "inventory test"
        name: "test group"
        hosts:
          - test1
        state: present 
        validate_certs: no
        preserve_existing_hosts: no

上記の例では、test group に存在していてほしいホストが test1 のみのため、特に不便はありませんが、これが多数ある場合はその全てを記載する必要があります。 例えばクラウド環境等をダイナミックインベントリを使って管理していた場合は、都度リストを用意するのが手間になる事が考えられます。 しかしながら本記事作成時点で、グループに存在しているホストのリストを取得する機能が controller.group モジュールにはありません。

そこで、ansible.builtin.uri module を使って関連付けの解除を行う前のホストのリストを一度取得し、そこから削除するホストのみを選択すれば済むタスクを用意しました。 ※community.general コレクションが必要となります

---
- hosts: localhost
  gather_facts: no

  tasks:
    - name: Include vars
      ansible.builtin.include_vars:
        file: controller_info.yml
      no_log: true

    - name: Gathering a host list   # ターゲットとなるグループのホストの情報を取得する
      ansible.builtin.uri:
        url: "{{ CONTROLLER_HOST + '/api/v2/groups/' + GROUP_ID  + '/all_hosts/' }}"
        method: GET
        url_username: "{{ CONTROLLER_USERNAME }}"
        url_password: "{{ CONTROLLER_PASSWORD }}"
        force_basic_auth: yes
        headers:
          Content-Type: "application/json"
        validate_certs: false
      register: result

    - name: Define a list of all hosts   # ホストのリストのみを取り出す
      ansible.builtin.set_fact:
        host_list: "{{ result | community.general.json_query('json.results[*].name') | list }}"

    - name: Make a host list that should exist only.  # 関連付けを解除したいホストのみを除外したリストを作成する
      ansible.builtin.set_fact:
        host_list: "{{ host_list | reject('search', REMOVED_HOSTNAME) }}"

    - name: Dissociate ec2 host from the "{{ GROUP_NAME }}"   # 最後に、関連付けを解除したいホストが含まれないリストを渡す
      ansible.controller.group:
        controller_host: "{{ CONTROLLER_HOST }}"
        controller_username: "{{ CONTROLLER_USERNAME }}"
        controller_password: "{{ CONTROLLER_PASSWORD }}"
        controller_oauthtoken: "{{ CONTROLLER_OUTHTOKEN }}"
        inventory: "{{ INVENTORY_NAME }}"
        name: "{{ GROUP_NAME }}"
        hosts: "{{ host_list }}"
        state: present
        validate_certs: no
        preserve_existing_hosts: no

もっと適切な書き方があるかもしれませんが、上記のタスクがサンプルになります。

まとめ

今回は、利用したい機能が Ansible モジュールに無い場合に工夫する方法の一例を紹介させていただきました。 少々複雑なプレイブックを書く必要も場合によっては出てきてしまうかもしれませんが、「適切なモジュールが無さそう...でもなんとかしなければ!」 という場合に、今回ご紹介した ansible.builtin.uri のような、汎用性の高いモジュールを活用すれば意外と何とかなるケースが多いかもしれません。

少しでもご参考になる情報になれていれば幸いです。

* 各記事は著者の見解によるものでありその所属組織を代表する公式なものではありません。その内容については非公式見解を含みます。