てくなべ

ansible / network automation / 学習メモ / 思考メモ

[Ansible] ansible-core 2.21.0 がリリース。便利そうな点と注意点。注目は Register Projections

はじめに

2026/05/18 に ansible-core 2.21.0 がリリースされました。

コードネームは「The Rain Song」です。

www.youtube.com

CHANGELOG などでぱっと見で気になった「便利そうなポイント」と「ちょっと注意ポイント」を簡単ですがまとめます。

先に、リリース時によくチェックするドキュメントをまとめておきます。詳細や正確な情報は、以下の一次情報をご参照ください。

ちなみに、よくあるサポートする最低 Python バージョンの引き上げは今回はありません(参考)。

便利そうなポイント

とても便利そう、地味に便利そうな機能追加や変更点についてです。

レジスタ変数の取り回しがしやすくなる Register Projections

個人的には一番の目玉だと思っています。

1つのタスクで、レジスタ(register)変数を複数定義できる機能です。

ちょっと個別に扱いたかったので、別の記事にしました。

tekunabe.hatenablog.jp

暗黙的なタスクオブジェクト _task による register の省略

同じくレジスタ変数回りの機能追加です。

register を定義しなくても、タスク内であれば _task.result で参照できるようになったりします。

これも個別に扱いたかったので、先述の Register Projections の件と合わせて別の記事にしました。

tekunabe.hatenablog.jp

  • 関連PR: Register projections and action plugin dynamic host/group/var API by nitzmahone · Pull Request #86241 · ansible/ansible · GitHub
  • changelog:

    task implicit object - A new task implicit object is available for use in register and task conditional expressions (e.g., failed_when). The result of the current task can be accessed via the task.result property, without the use of register. Under a loop, task.result is the most recently completed result and task.loop_result provides access to accumulated loop results. The _task.polymorphic_result property provides compatibility with classic name-only register in loops. The value is the result of the most recent loop iteration, then becomes the final list loop result once the loop is complete.

include_* 系の動的読み込みのログの出力有無を切り替え可能に

include_* 系の ansible.builtin.include_tasks モジュールや、ansible.builtin.include_role モジュールで、タスクやロールを動的に読み込む際、今までは Playbook 実行ログに included ~ というログが表示されていました(関連 Issue)。

たとえば、ansible.builtin.include_tasksloop でループさせると、ループごとに included ~ が表示されノイジーになってしまうことがあります。 こんな課題を解決できるように、このログの表示、非表示を切り替えられるようになりました。

設定項目は、ansible.builtin.default コールバックプラグインの display_included_hosts です。デフォルトは true なので、つまり今までと同じ挙動です。

例えば ansible.cfgfalse を設定したい場合は以下のように指定します。

[defaults]
display_included_hosts = false

以下のようなタスクを用意します。ansible.builtin.include_tasksloop で回します。

(ちなみにループは ansible.builtin.import_tasks ではできません)

    - name: Test include_tasks
      ansible.builtin.include_tasks:
        file: "{{ item }}"
      loop:
        - tasks1.yml
        - tasks2.yml
        - tasks3.yml

以下のような実行ログになります。included: ~ のログが表示されないことが分かります。

% ansible-playbook -i localhost, include.yml

PLAY [Test Play] ***************************************************************************************************

TASK [Test include_tasks] ******************************************************************************************

TASK [Test debug] **************************************************************************************************
ok: [localhost] => {
    "msg": "in tasks1.yml"
}

TASK [Test debug] **************************************************************************************************
ok: [localhost] => {
    "msg": "in tasks2.yml"
}

TASK [Test debug] **************************************************************************************************
ok: [localhost] => {
    "msg": "in tasks3.yml"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=6    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

比較のため display_included_hosts をデフォルト(true)に戻して実行すると、included: のログが表示されます。

% ansible-playbook -i localhost, include.yml

PLAY [Test Play] ***************************************************************************************************

TASK [Test include_tasks] ******************************************************************************************
included: /Users/akira/ansible/ac221/tasks1.yml for localhost => (item=tasks1.yml)
included: /Users/akira/ansible/ac221/tasks2.yml for localhost => (item=tasks2.yml)
included: /Users/akira/ansible/ac221/tasks3.yml for localhost => (item=tasks3.yml)

TASK [Test debug] **************************************************************************************************
ok: [localhost] => {
    "msg": "in tasks1.yml"
}

TASK [Test debug] **************************************************************************************************
ok: [localhost] => {
    "msg": "in tasks2.yml"
}

TASK [Test debug] **************************************************************************************************
ok: [localhost] => {
    "msg": "in tasks3.yml"
}

PLAY RECAP *********************************************************************************************************
localhost                  : ok=6    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

なお、本機能追加は @usagi_automate さんによるものです。リリースおめでとうございます!

関連記事: https://usage-automate.hatenablog.com/entry/2025/12/16/085853

モジュール呼び出し時のパラメーターを register 変数内に仕込めるようになった(INJECT_INVOCATION

Playbook では モジュールに対してパラメーター(オプション)を指定しますが、これらのパラメーターの値(的なもの)をそのタスクの register 変数に仕込めるようになりました。

正確には、モジュールに指定したパラメーターそのものではなく、取り除かれたり内部のパラメーターが追加されたりの加工があるようです。

設定項目は INJECT_INVOCATIONです。デフォルトは False で無効なので、今まで通りです。

例えば以下のような Playbook があるとします。1つ目のタスクの実行結果が入っている register 変数(result_copy)を、2つ目のタスクで表示して中身を確認する Playbook です。

---
- name: Test Play
  hosts: localhost
  connection: local
  gather_facts: false

  vars:
    target_file: output.txt

  tasks:
    - name: Generate a file
      ansible.builtin.copy:
        content: hello
        dest: "{{ target_file }}"
        mode: '0644'
      register: result_copy
      
    - name: Print the registered output
      ansible.builtin.debug:
        msg: "{{ result_copy }}"

上記の Playbook を、環境変数 ANSIBLE_INJECT_INVOCATIONtrue を指定して INJECT_INVOCATION を有効化して実行します。

$ ANSIBLE_INJECT_INVOCATION=true ansible-playbook -i localhost, inject_invocation.yml 

PLAY [Test Play] ******************************************************************************************************

TASK [Generate a file] ************************************************************************************************
ok: [localhost]

TASK [Print the registered output] ************************************************************************************
ok: [localhost] => {
    "msg": {
        "changed": false,
        "checksum": "aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d",
        "dest": "output.txt",
        "diff": [],
        "failed": false,
        "gid": 1000,
        "group": "yokochi",
        "invocation": {
            "module_args": {
                "_diff_peek": null,
                "_original_basename": ".s7ffcq98",
                "access_time": null,
                "access_time_format": "%Y%m%d%H%M.%S",
                "attributes": null,
                "dest": "output.txt",
                "follow": true,
                "force": false,
                "group": null,
                "mode": "0644",
                "modification_time": null,
                "modification_time_format": "%Y%m%d%H%M.%S",
                "owner": null,
                "path": "output.txt",
                "recurse": false,
                "selevel": null,
                "serole": null,
                "setype": null,
                "seuser": null,
                "src": null,
                "state": "file",
                "unsafe_writes": false
            }
        },
        "mode": "0644",
        "owner": "akira",
        "path": "output.txt",
        "size": 5,
        "state": "file",
        "uid": 1000
    }
}

PLAY RECAP ************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

$ 

上記実行結果のうち、2つ目のタスクの ansible.builtin.debug モジュールで表示しているログのうち、invocation 配下が INJECT_INVOCATION を有効化したことによるものです。

先ほど「加工があるようです」と書きましたが、たとえば Playbook 側の content オプションが invocation には含まれませんし、逆に Playbook 側になかった modification_time_formatinvocation に含まれています。

Playbook 上は変数による指定(dest: "{{ target_file }}")でも、ログ上は実際の値("dest": "output.txt")になります。そのため、デバッグしやすい形式になってるとも言えるかなと思います。

補足1: ansible.cfg で設定する場合の注意(ansible-core 2.21.0 時点)

2026/05/20 現在、devel 版ドキュメント上のINJECT_INVOCATIONに掲載されている ini (ansible.cfgのこと)で指定するキーが誤っています。interpreter_python となっていますが、正しくは inject_invocation のようなキーのはずです。

interpreter_pythonINTERPRETER_PYTHON というメジャーな設定項目のキーですでに使われています。ドキュメント上だけの不備ではなく実際の挙動にも影響しています。

すでに 修正PRが出されていますので、おそらく ansible-core 2.21.1 で修正されると思います。

補足2: invocation って前からあったような?

「あれ? そういえば前からログに invocation が含まれてる場合もあったような?」と思って ansible-core 2.20 系で確認しました。すると、ログに invocation が表示されるのは -vv を3つ(-vvv)以上指定して Playbook を実行したときでした。ただ、後続のタスクで register 変数の中身を確認すると invocation が含まれていませんでした。

ansible-core 2.21.0 で INJECT_INVOCATION を有効にすると、ちゃんと register 変数にも invocation が含まれます。

モジュールによって異なるかもしれませんが、今回は ansible.builtin.copy モジュールと ansible.builtin.default コールバックプラグインという組み合わせで確認しました。

template モジュールでエラーの箇所が分かりやすく

Jinja2 テンプレートは便利ではありますが、ときどきエラー時のデバッグがしにくいことがあります。

今回、ansible.builtin.template モジュールを利用したテンプレートに構文エラーがある場合、エラー行にマーカーが引かれて分かりやすくなりました。

例えば、以下のような変数が未定義のテンプレートの場合で説明します。

{% if station_name == "kyoto" %}
京都
{% else if station_name == "demachiyanagi" %}
出町柳
{% else %}
その他の駅
{% endif %}

上記のテンプレートを ansible.builtin.template モジュールで参照すると、以下のようなエラーになります。初見の分かりやすさが向上しました。

TASK [Generate a file] ********************************************************************************************
[ERROR]: Task failed: Syntax error in template: expected token 'end of statement block', got 'if'

Task failed.
Origin: /Users/akira/ansible/ac221/jinja2.yml:11:7

 9
10   tasks:
11     - name: Generate a file
         ^ column 7

<<< caused by >>>

Syntax error in template: expected token 'end of statement block', got 'if'
Origin: /Users/akira/ansible/ac221/test.j2:3

1 {% if station_name == "kyoto" %}
2 京都
3 {% else if station_name == "demachiyanagi" %}
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

fatal: [localhost]: FAILED! => {"changed": false, "msg": "Task failed: Syntax error in template: expected token 'end of statement block', got 'if'"}

PLAY RECAP ********************************************************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

changelog 上は template module の変更点として記載されていますが、試す限り ansible.builtin.template ルックアッププラグイン でも同様でした。

なお、エラーの原因は elif が正しいところ、else if にしているためです。

ちなみに、ansible-core 2.20 までは以下のようなエラーでした。比較のために掲載します。先程と違ってテンプレートファイルのエラーの箇所が表示されていないですね。

TASK [Generate a file] *******************************************************************************************
[ERROR]: Task failed: Syntax error in template: expected token 'end of statement block', got 'if'

Task failed.
Origin: /Users/akira/ansible/ac221/jinja2.yml:11:7

 9
10   tasks:
11     - name: Generate a file
         ^ column 7

<<< caused by >>>

Syntax error in template: expected token 'end of statement block', got 'if'
Origin: /Users/akira/ansible/ac221/test.j2

fatal: [localhost]: FAILED! => {"changed": false, "msg": "Task failed: Syntax error in template: expected token 'end of statement block', got 'if'"}

ちょっと注意ポイント

デグレになるかもしれない少し注意が必要そうな変更点や削除された機能についてです。

Interpreter Discovery の legacy 系モードの削除

ターゲットノードの Python 環境を自動的に検出する Interpreter Discovery という機能があります。

検出モードがいくつかありますが、以下のモードが削除されました。

  • auto_legacy
  • auto_legacy_silent

これまでは Playbook 実行時に以下のような警告が表示されていました。

[DEPRECATION WARNING]: The 'auto_legacy' option for 'INTERPRETER_PYTHON' now has the same effect as 'auto'. This feature will be removed from ansible-core version 2.21.

今回、いよいよ削除されたという形です。

デフォルト値は auto のままです。これまで意図的に legacy 系のモードを指定していた場合は注意が必要です。

なお、試しに ansible-core 2.20.0 で ansible_python_interpreter 変数に auto_legacy を指定した場合は以下のようなエラーが表示されました。auto_legacy が予約されたキーワードではなく、Python インタープリターのパスとして認識された形ですね。

fatal: [localhost]: FAILED! => {"changed": false, "msg": "Task failed: Failed to get information on remote file (test.txt): /bin/sh: auto_legacy: command not found"}

ansible-galaxy でコレクションをインストール時に ansible-core のバージョン互換性をチェックするようになった

コレクションでは、どの ansible-core のバージョンをサポートするかを meta.runtime.yml 内の requires_ansible で定義できます。例えば、ansible.utils コレクション 6.0.0 では requires_ansible: ">=2.16.0" と定義され、ansible-core 2.16.0 以上をサポートしていることを示しています。

ansible-core 2.20 までの場合、デフォルトでは requires_ansible の条件に関わらずインストールする挙動でした。「この ansible-core のバージョンはサポートされてないよ」という旨のメッセージが表示されることはありましたが、それはインストール時ではなく Playbook 実行時でした。

ansible-core 2.21.0 では、デフォルトでは requires_ansible の条件を満たしていればインストールし、満たしていなければインストールしない、という挙動になりました。仕様変更というよりバグ修正の扱いです。個人的にもあるべき姿になったかなと思っています。

requires_ansible の条件を満たしていない場合に、インストールを試みたときのログは以下の通りです。具体的には ansible-core 2.21.0requires_ansible: ">=2.22.0" が指定されたコレクションをインストールしようとしています。

$ ansible-galaxy collection install git+https://github.com/akira6592/ansible.utils.git,devel
Cloning into '/home/yokochi/.ansible/tmp/ansible-local-54954eul3rlht/tmpqo2yc7ps/ansible.utilsfiwl83qa'...
remote: Enumerating objects: 5107, done.
remote: Counting objects: 100% (198/198), done.
remote: Compressing objects: 100% (152/152), done.
remote: Total 5107 (delta 110), reused 44 (delta 44), pack-reused 4909 (from 2)
Receiving objects: 100% (5107/5107), 1.35 MiB | 7.37 MiB/s, done.
Resolving deltas: 100% (3032/3032), done.
branch 'devel' set up to track 'origin/devel'.
Switched to a new branch 'devel'
Starting galaxy collection install process
Process install dependency map
ansible-galaxy is looking at multiple versions of ansible.utils to determine which version is compatible with other requirements. This could take a while.
[ERROR]: Failed to resolve the requested dependencies map. Could not satisfy the following requirements:
* ansible.utils:6.0.2 (dependency of git collection from a Git repo) requires ansible-core >=2.22.0
Hint: To disregard whether the collection supports the current version of ansible-core, configure COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCH as "ignore".
Hint: Pre-releases hosted on Galaxy or Automation Hub are not installed by default unless a specific version is requested. To enable pre-releases globally, use --pre.

以下の行を見れば理由がよくわかるようになっていますね。

* ansible.utils:6.0.2 (dependency of git collection from a Git repo) requires ansible-core >=2.22.0

※ 現状、requires_ansible: ">=2.22.0" が指定されている公開コレクションが思い浮かばなかったので、検証用にフォークして書き換えたコレクションを指定しています。

あまり多くないケースだと思いますが、もし requires_ansible の条件に関わらずコレクションをインストールしたい場合は、COLLECTIONS_ON_ANSIBLE_VERSION_MISMATCHignore を指定します。

おわりに

2つ前の ansible-core 2.19 の時にはテンプレート処理の変更という、影響度高めの変更がありましたが、前回(2.20)と今回(2.21)はそこまで大きいものはなさそうです。

最初に挙げた「Register Projections」は Playbook がすっきり書けるようになって便利そうです。使えるタイミングがあれば使ってみたいと思います。

参考

github.com

tekunabe.hatenablog.jp

[Ansible] レジスター変数を取り回しやすくなる Register Projections (ansible-core 2.21 から)

はじめに

2026/05/18 にリリースされた ansible-core 2.21.0 で、Register Projections という機能が追加されました。

1つのタスクで、レジスター(register)変数を複数定義できたり、タスク内であれば register を定義しなくても _task.result で参照できるようになったりします。

総合的には「レジスター変数が取り回しやすくなり、Playbook をシンプルに書けるようになる」と表現できるかなと思います。

この記事では、 Register Projections そのものと、付随して導入される暗黙的なタスクオブジェクト(task implicit object)の2つに分けてまとめます。

  • 検証環境
    • ansible-core 2.21.0

※ その他の ansible-core 2.21.0 での変更点は [Ansible] ansible-core 2.21.0 がリリース。便利そうな点と注意点。注目は Register Projections - てくなべ を参考にしてください。

1. レジスタ変数の取り回しがしやすくなる Register Projections

タスクの実行結果を register ディレクティブ で指定した変数に格納して、後続のタスクで利用する方法は、よく利用します。

ただ、レジスタ変数の値をそのまま使うことは個人的にはあまりなく、大抵は抽出や変換などの加工が伴います。この加工のために、例えば ansible.builtin.set_fact モジュールのタスクをワンクッション挟んだり、参照するタスク側の vars ディレクティブで加工したりします。

今回追加された、Register Projections という機能によって register ディレクティブを定義する側のタスクで予め加工できるようになります。うまく言えないのですが、私は「レジスタ変数を取り回しやすくなる」と表現しています。

この Register Projections 機能は、fallible による実験的な実装の段階で、@stopendy0122 さんが検証してまとめられていてとても参考になります(はやい!)。

endy-tech.hatenablog.jp

実装のプルリクにもすっきり分かりやすい例が掲載されています。

Register Projections を利用したサンプル Playbook

晴れて ansible-core 側にも実装されたということで、私も以下の Playbook を試してみます。

---
- name: Test Play
  hosts: ios
  gather_facts: false

  tasks:
    - name: Execute show commands
      cisco.ios.ios_command:
        commands:
          - show version
          - show ip route
      register:
        result_show_version: _task.result.stdout_lines[0]   # ポイント
        result_show_ip_route: _task.result.stdout_lines[1]  # ポイント

    - name: Debug result_show_version
      ansible.builtin.debug:
        msg: "{{ result_show_version }}"

    - name: Debug result_show_ip_route
      ansible.builtin.debug:
        msg: "{{ result_show_ip_route }}"

Playbook を見慣れた方ほど違和感があるかもしれません。注目は 1つ目のタスクの register です。ポイントは 2 つあります。

ポイント1: 1つのタスクで複数のレジスタ変数を定義可能に

1つめのポイントは、1つのタスクで複数のレジスタ変数をいっぺんに定義できるようになったことです。

これまでであれば、

      register: result_show_commands

のように、register には変数名を1つ指定する形でした。

今回から、以下のように register をディクショナリで指定することで、複数の変数に入れることができるようになりました。

      register:
        result_show_version: _task.result.stdout[0]
        result_show_ip_route: _task.result.stdout[1]

なお、_task は暗黙的に定義されているタスクオブジェクトです。_task.result でタスクの結果を丸ごと参照できます。なので、

      register: result

      register:
        result: _task.result

は同じです。

_task については別の使い道もあるので、本記事の後で触れます。

ポイント2: 値に Jinja2 書式が利用できる

2つ目のポイントは、Jinja2 書式を指定できることです。

これまでの、

      register: result_show_commands

result_show_commands は、あくまで文字列として変数名を定義しているだけです。そのため、register: result_show_commands.stdout[0] のような書式で抽出や加工の指定はできません。変数名として不正というエラーになってしまいます。

一方、今回から利用できる、

      register:
        result_show_version: _task.result.stdout[0]
        result_show_ip_route: _task.result.stdout[1]

といった書式の _task.result.stdout[0] の箇所は、Jinja2 書式が指定できます。そのため、上記例のように JSON 的な抽出をしたり、他にも各種フィルターも使えます。

なお、ここの Jinja2 書式は "{{ }}" のような囲い方はせずに直接指定します。when ディレクティブなどと同じです。

Register Projections を利用しない場合(比較用)

もし仮に、今まで通り register で丸ごと1つのレジスタ変数に入れる場合は、以下のように変数をばらすためのタスク(以下例では ansible.builtin.set_fact)を挟むことになります。

    - name: Execute show commands
      cisco.ios.ios_command:
        commands:
          - show version
          - show ip route
      register: result_show_commands  # 丸ごと1つのレジスタ変数に入れる場合(ansible-core 2.20 までも可)

    # set_fact で丸ごとのレジスタ変数をばらして仕分ける
    - name: set_fact
      ansible.builtin.set_fact:
        result_show_version: "{{ result_show_commands.stdout_lines[0] }}"
        result_show_ip_route: "{{ result_show_commands.stdout_lines[1] }}"

    - name: Debug result_show_version
      ansible.builtin.debug:
        msg: "{{ result_show_version }}"

    - name: Debug result_show_ip_route
      ansible.builtin.debug:
        msg: "{{ result_show_ip_route }}"

ばらした変数を1回しか参照しないのであれば、参照する側のタスクで抽出する形でもよいでしょう。

もちろん、あえて1つのレジスタ変数に丸ごと入れて、後続のタスクで処理するほうが都合がいいケースもありますが、そこは使い分けですね。

参考

(補足)上記 サンプル Playbook 実行時に [DEPRECATION WARNING] がいくつか表示されました。おそらくは ansible-core 2.21.0 と、今回利用した cisco.ios コレクション 11.4.1 との相性なのかと思います。今後の cisco.ios コレクション側のアップデートで解消されるかもしれません。

2. 暗黙的なタスクオブジェクト _task による register の省略

前述の Register Projections で「_task は暗黙的に定義されているオブジェクトです」と書きましたが、これはこれで1つの機能追加とも言えます。changelog 上は「task implicit object」と表現されています。

これは、register を指定しなくても、そのタスク内であれば _task を通じてタスクの実行結果を参照できる機能です。

例えば、failed_when で、タスクの実行結果を failed として扱うかどうかの条件の指定は、以下のようにシンプルに書けます。

    # ansible-core 2.21 からできる方法
    - name: Test command
      ansible.builtin.command:
        cmd: diff test1.txt test2.txt
      failed_when: _task.result.rc >= 2   # register の代わりに暗黙の _task を利用

failed_when だけでなく、changed_whenuntil などでも _task の参照ができます。when については、タスクの実行前に実行するかどうかを評価するため _task は参照できません(それはそう)。

比較のため、 ansible-core 2.20 まででもできる方法で書くと、以下のように register が必要です。もちろん ansible-core 2.21 でも利用できます。

    # ansible-core 2.20 まででもできる方法(比較用に掲載)
    - name: Test command
      ansible.builtin.command:
        cmd: diff test1.txt test2.txt
      register: my_result             # register を定義
      failed_when: my_result.rc >= 2  # 明示的に定義したレジスタ変数を利用

loop と併用する場合

loop を併用する場合は、少し固有の事情があります。

まず、_task.result は直近のループ 1 回分の結果で毎回上書きされます。

例えば以下のようなタスクの場合、ループの2回目だけ failed になります。

    - name: Test command
      ansible.builtin.command:
        cmd: "echo {{ item }}"
      loop:
        - 1
        - 2
        - 3
      failed_when: _task.result.stdout == "2"

もう一点押さえておきたいのが、ループ全体の結果は _task.loop_results に入るという点です。例えば、1回目のループの結果であれば _task.loop_results[0] に入ります。

ただ、当然ですが、例えば 1回目のループのタイミングでは _task.loop_results[1] は参照できません。正直、現状は使い道が思いつきませんが。

実装PRに掲載されている以下の例は、手元の ansible-core 2.21.0 で試す限り second_echo_stdout の値は 0 になります。意図通りなのかもちょっと判断できていません・・。コメントに書かれてること自体の趣旨は分かるのですが。

- shell: echo {{ item }}
  loop:
    - 1
    - 2
  register:
    second_echo_stdout: _task.loop_results[1].stdout | default(0)  # using default here is necessary as when the loop is on the first item, it will still try and access `loop_results[1]` which doesn't exist yet

参考

  • 関連PR: Register projections and action plugin dynamic host/group/var API by nitzmahone · Pull Request #86241 · ansible/ansible · GitHub
  • changelog:

    task implicit object - A new task implicit object is available for use in register and task conditional expressions (e.g., failed_when). The result of the current task can be accessed via the task.result property, without the use of register. Under a loop, task.result is the most recently completed result and task.loop_result provides access to accumulated loop results. The _task.polymorphic_result property provides compatibility with classic name-only register in loops. The value is the result of the most recent loop iteration, then becomes the final list loop result once the loop is complete.

[2026/05/30 追記]

現状、これに対応したドキュメントは見当たりませんが、未マージのプルリクはありました。

github.com

おわりに

Register Projections という機能についてまとめました。

特に 1つのタスクで、レジスタ変数を複数定義できたり、Jinja2 書式が使えるのは、Playbook がシンプルに書けるようになりそうで、便利だなと思いました。

[Ansible/AAP] 次のバージョンの AAP の情報をリリース前に知る方法

はじめに

Red Hat Ansible Automation Platform (AAP) は、アップグレードのたびに機能追加や古い機能の削除などが行われます。内容は基本的に AAP の公式ドキュメント から該当のバージョンを選択して、「Release notes」などで確認できます。

特に、AAP on AWS のようなマネージド型の場合は、利用者側がアップグレード作業をしなくていい代わりに、決められたアップグレードのタイミング(AAP 2.7の場合のKB)までに事前にアップグレードの変更点は知っておきたいものです。

この記事では、利用者として閲覧できる範囲でなるべく早く次のバージョンの情報を知る方法をまとめます。

補足:

  • 本記事のここでアップグレードとはAAP 2.5 から 2.6 のような単位のことを指します
  • 本記事では「AAP 2.7 の~」といった記述がありますが、本記事執筆時(2026/5/18)では未リリースです。そのためいずれもリリース前の情報です

1. 製品ドキュメントページで「2.next」を選択

最近知ったので最初に紹介します。

「はじめに」で AAP の公式ドキュメント から「該当のバージョンを選択して」と書きましたが、最近「2.next」を選択できることを知りました。

2.next の選択

現状、選択してみるとドキュメント一覧に「Ansible Automation Platform preview release notes」があります。ここに、まだドキュメントのバージョンを明示的に選択できない AAP 2.7 の情報があります。

docs.redhat.com

例えば以下のような内容があります。

なお、2.next の選択肢については、後述の AAP 2.7 のスケジュールに関するKB のコメント欄で知りました。

[2026/05/29 追記] AAP 2.7 については普通にバージョン選択できるようになりました。

Red Hat Ansible Automation Platform | 2.7 | Red Hat Documentation

2. ドキュメント管理リポジトリを見る

AAP のドキュメントの元ネタになっているリポジトリは ansible/aap-docs です。なので、こちらのプルリクをチェックしていると、新しいバージョン含めて更新の動向がうかがえる時があります。

github.com

確認したい AAP のバージョンに合わせて、リポジトリのブランチを選択します。AAP 2.6 であれば 2.6 です。プルリクを眺めている感じですと、プルリクはまず main に対して出されて、そのあと各バージョンのブランチに反映させるためのプルリクが「[2.x backport]~」という形で出されるようです。

ここ最近の状況を眺めていると、バージョンごとのブランチは、リリースの前に新しく作成されてきました。現状 2.7 ブランチがないですが、もうじき作成されるのではないかと思います。

Markdown ではなく AsciiDoc の書式で書かれていて、変数的なものも埋め込まれています。変数的なものはビルドするタイミングで実際の値に書き換わります。ビルド前の生の AsciiDoc のファイル(*.adoc)を見るにはやや慣れが必要かもですが、変数名でだいたい連想できるようになっています。

また、ドキュメントも生き物のようであり、修正頻度がやや多いタイミングもある点は注意が必要です。

3. Red Hat の KB

Red Hat Customer Portal で「AAP 2.7」のようなキーワードで KB を検索すると、リリース前でも次のバージョンの AAP の情報がヒットすることがあります。

access.redhat.com

直近では、マネージド版の AAP 2.7 へのアップグレードのスケジュールに関するKBがとても有用でした。

4. YouTube

Ansible の公式 YouTube チャンネル

直近では、AAP 2.7 の新機能紹介動画がアップされています。

www.youtube.com

他、個人としては @alexdworjan さんの YouTubeでは、新しい機能が紹介されることがあります。

たとえば、 Execution Environment Builder という新しい機能(ansible-builderとは別物)が紹介されていました。

www.youtube.com

5. Red Hat のイベント

年次のグローバルイベントである Red Hat Summit で、新バージョンのAAPの機能について触れられることがあります。先日開催された Red Hat Summit 2026 でも Day 2 キーノートで Automation orchestrator についての発表がありました。

tekunabe.hatenablog.jp

おわりに

新しいバージョンの AAP の情報を早めに知る方法をまとめました。改めて見てみると、文字も動画も結構いろんな方法があってありがたいです。

Red Hat Summit 2026 のキーノートで気になったキーワード(主に自動化方面)

はじめに

2026/05/11-14 (現地時間)、アトランタで Red Hat Summit 2026 が開催されています。例年通りキーノートは YouTube Live で視聴できました。新しいプロダクトや構想の他にも、日産自動車から日本の方が登壇されていたのが印象的でした(参考リンク)。

本記事では、各キーノートから個人的に気になったキーワードを主に自動化方面にフォーカスしてまとめます。

その他、公式情報は Red Hat Summit 関連のプレスリリースまとめ などを追うのがよさそうです。

RHEL 系のアップデートについては、赤帽エンジニアブログの方で詳しくまとまっていて参考になります。

rheb.hatenablog.com

キーノート動画

Day1

www.youtube.com

Day2

www.youtube.com

翻訳字幕付きの動画は https://tv.redhat.com/ で後日(確か 2026/05/22までに)公開されるそうです。

[2026/05/22 追記] 動画自体はアップされていました。

Automation orchestrator

www.redhat.com

これまでの AAP でも、ワークフロージョブテンプレートという形で、「アレしたらコレやって、次に・・」のような、タスクを連ねる形のワークフローを作成できていました。

昨今では、Event-Driven Ansibleや AI 駆動など、自動化を取り巻くプロダクトや概念が増えてきています。おそらく、これらを束ねるものとして Automation orchestrator が登場する、ということのようです。

あまり情報は出ていませんが、以下の画面キャプチャーである程度イメージができます。

インシデント修復ワークフローの例(https://www.redhat.com/en/technologies/management/ansible/automation-orchestrator より引用)

ぱっと見では AAP のワークフロービジュアライザーのように見えます。が、よく見ると、EDA(Event-Driven Ansible)をトリガーにして、AI による調査、人による承認操作、修復タスクなどが含まれています。ワークフロービジュアライザーよりも広い範囲がカバーされているのが見て取れます。

たまたま AAP 2.7 の情報を追っていた時に、Automation orchestrator の存在を知ったのですが、Day2キーノートでも触れられている(14:31頃)ということは目玉の一つという印象でした。

提供形態は「As an add-on capability to an Ansible Automation Platform subscription」という表現がされています。おそらくは画面もインストーラーも別になるのではないかと思います。

リリース時期は technology preview として、2026年3Q または2026年中のようです。(参考記事1参考記事2

他に気になったキーワード

自動化方面以外で気になったキーワードです。前提知識と英語力のなさから、箇条書き+リンク集レベルですが・・・

※前述の赤帽エンジニアブログの記事が参考になります。

おわりに

簡単ですが、Red Hat Summit 2026 のキーノートで気になったキーワードを主に自動化方面にしぼってまとめました。

これまで自動化という切り口にで AAP に注目をしていましたが、 Automation orchestrator が出てくることによって「自動化」が示す範囲が広がるなという印象でした。

余談

去年までは AnsibleFest と同時開催という扱いで、去年時点の来年(2026年)の予告でも「Red Hat Summit and AnsibleFest 2026」という表記でしたが、2026年では「AnsibleFest 2026」という表記は見当たりませんでした。見逃していたらすみません!

参考

[2026/05/21 追記]

qiita.com

tv.redhat.com

タスクの変数を減らす

はじめに

(タイトルがAnsibleの話みたいになってますが別の話です)

先日の記事「自動化の難易度は機能とパラメーターのセットで考える - てくなべ」で、自動化とパラメーターは切っても切り離せない旨を書きました。

このことは「パラメーターが少ない方が自動化しやすいこともある」という側面もあります。

特に目新しい話ではありませんが、最近身近なところで実感した経験がありました。

今から一時間後にアラームを鳴らしたい

毎日行っている1 時間の作業があります。作業の終わりに気付くために、作業開始時に「今から一時間後にアラーム鳴らす設定をする」ということをやっていました。

開始時刻は毎日微妙にぶれていました。そのため「今から~」の「今」の時刻が毎回異なります。

いちいち手動で設定するのは面倒なので、スマホで Gemini「今から1時間後にアラーム」と話しかけて都度設定していました。

だんだんそれさえ面倒に

しばらく、都度 Gemini に声で依頼という運用をしていました。しかし、だんだんとそれさえも面倒になってきてしまいました。もっと効率よく「今から一時間後にアラーム」を設定できないか、と考えました。

が、なかなか妙案は思い浮かびません。もやもやを抱えながらも、ずるずると同じ方法で続けていました。

寝言で「今から一時間後にアラーム」を言ってないか心配です。

前提を変え、設定作業そのものをなくす

ふとある時、「今」が毎回ぶれているからその都度設定する必要があるんだと気が付きました。 そこで、開始時刻を毎日一定にして、その時刻から一時間後に日次アラームを設定しておくことにしました。この設定作業自体は一度キリです。

すると、当たり前ですが毎日設定しなおす手間がなくなりました。

「開始時刻から1時間後の終了時刻」という毎回可変のパラメーターをなくすことで、効率化というか、そもそも毎回のアラーム設定の必要性がなくなりました。

気が付くのが遅かったのですが「これでよかったんだ」と思いました。

おわりに

いわゆる「運用でカバー」のような構図に見えるかもしれませんし、実際そうかもしれません。

ですが、作業を減らす方向に運用の前提を変えると結構よかった、という実体験になりました。

レビュー要・不要の議論の前にレビューの目的を揃えたい

昨今、生成AI によるコードレビューの自動化が発達して「人間のレビューは必要か?不要か?」という論をよく見かけます。

私は流されやすいところももあり、必要論も不要論も「それもそうだな」と、ある種の早合点してしまう傾向があります。

必要か不要かを考える前に。そもそものレビューの目的を捉えなおさないと、軸がなくて判断がぶれてしまうなと思いました。

昔の話ですが、

レビューは、他人のコードを自分のコードにする工程だ

と言われた遠い記憶があります。一言で表すなら、共同所有のため、でしょうか。

品質の観点とはまた別モノです。

もしかしたら、この論を持ち込むのはナンセンスなのかもしれませんし、その役割を人のレビューに求めるのも違うのかもしれません。

ですが、レビューの目的の認識をそろえること自体は今も必要なのかなと思いました。

ファイアウォールのポリシーの設定変更の難しさとその自動化の難しさを考える

はじめに

ネットワークの運用作業で、ファイアウォールのポリシーや ACL の設定追加、変更、削除(以降、ポリシー設定)はよくあるのではないでしょうか。そして、なかなか大変なこと(詳細は後述)も多いです。この大変さを解消する手段の候補として自動化が挙げられます。

ただ、以前の記事「自動化の難易度は機能とパラメーターのセットで考える」でも少し触れたのですが、自動化するのがとても難しい作業だと思っています。

この難しさは、大きく以下の2つに分かれると捉えています。

  1. そもそもの作業の難しさ
  2. それをさらに自動化しようとしたときの難しさ

仮に自動化したとしても、解決したかった課題がおいてけぼりにされて残ったままだと、徒労に終わってしまうかもしれません。

この手の作業ってどんなことが課題になりがちなんだっけ、と自分が立ち止まって考えるために、ポリシー設定作業そのものの難しさと、それを自動化しようとしたときの難しさについてまとめます。

なお、本記事で何か特別な良い方法を示すのではなく、主観的な難しさや大変さを述べるのみですのでご了承ください。

本記事で挙げる難しさを解消する手法やプロダクトがすでにあるかもしれませんが、そのような特別な仕組みがないベーシックな環境を想定しています。

いきなりまとめ

ちょっと長い記事なので先に簡単にまとめます。

  • ポリシー設定作業はそもそも難しい。特に要件から設定を導き出すのが難しい
  • 難しいことを自動化するのは難しい。さらに、手動の効率化の延長に自動化がないこともある

1. 要件から設定を導き出す難しさ

通信要件をもとにして、どの機器にどのような設定を入れればいいか導き出すことの難しさについてです。

これが一番難しいかもしれません。

1.1. そもそもの難しさ

運用体制にもよりますが、どこからか「この通信を通してください」という依頼が来て、それを受けて作業に取り掛かる体制を想定します。

依頼内容は例えば以下のようなものです。

  • 送信元IPアドレス
  • 宛先IPアドレス
  • 宛先ポート番号
  • アクション: 許可/拒否

依頼元はエンドツーエンドの通信要件のみに関心があり、その間にどのようなネットワーク機器があって、どういう設定になっているかは気にしません(というケースを想定)。このこと自体は良しあしではなく、体制上の特性です。

関心の違い(一例)

この場合、依頼を受けた側は実際のどの機器にどういう設定をすればいいか導き出す必要があります。頭の中は以下のような感じです。

  • 「ここからここへの通信だから、FW101とFW801のポリシー、それからL3機器の RT101とRT102のACLが関係しそうだ」
  • 「あれ、、そもそもルーティング的には通ってるかな。どれどれ・・。あぁ大丈夫か」
  • 「それぞれの現状のポリシーをドキュメントで確認しよう」
  • 「FW101とFW801に追加が必要だな。既存のアドレスオブジェクトやサービスオブジェクトで賄えるかな・・?」
  • 「サービスオブジェクトは既にあるな。アドレスオブジェクトだけ作成が必要だ。つまり設定はこんな感じだな」

こういった過程がなかなか大変です。机上でのチェックならなおさらです。レビューする人にとっても。

ちなみに、調べ上げた結果、依頼の通信要件がすでに満たされていることもあり得ます。

1.2. 自動化の難しさ

設定の導出を自動化するには、これまで人がどうやって導き出していたのかをロジック化する必要があります。

与えられたパラメーターを投入すること自体は自動化で担保できたとしても、そもそもパラメーターが誤っていたら「正しく間違える」のようなことになってしまいます。「Garbage In, Garbage Out」にも通じます。

2. 順番を考慮する難しさ

ポリシーの類は上から順に評価されますが、それを考慮することの難しさについてです。

2.1. そもそもの難しさ

ポリシー設定は、ネットワーク機器の設定としてはかなり順序性に気を遣う設定です。

極端な例では、「全ホスト許可」のルールの後に「特定ホストのみ許可」があっても隠れてしまって、意味がありません。隠れたほうのルールを「シャドウルール」と呼ぶこともあります。

機器側の機能としてシャドウルールを検出できる場合もあります。しかし、机上で脳内で判断するのはなかなか難しいものです。

他にも、禁止のポリシーの後に許可をしても意味がないというケースもあります。

ここまでは「そうしないと意図する挙動にならない」という事情でした。

一方で「新規ポリシーを2行目に追加しても3行目に追加してもどっちでもいい」というようなケースもあります。どっちでもいいので制約がなくて楽という反面、制約がないので迷いが生まれるという面もあります。これも何かしらのルールがあるのが理想ですね。

2.2. 自動化の難しさ

先に挙げた「シャドウルール」を避けるような、相応のロジックが必要になります。機器側にシャドウルールを検出してくれる機能があれば、それを自動化の処理の中で応用する方法はあるかもしれません。そうでない場合は、ネットワーク的な計算処理を自前で作成することになり、まるでネットワーク機器側の機能の一部を書くような難しさも垣間見えてきます。

「ある程度どこに追加してもいい」という場合も、人の気分ではなく何かしらのルール化、ロジック化が必要になります。

3. 設定の自由度からくる難しさ

何かと名前付けが必要なポリシー関連の設定の難しさについてです。

3.1. そもそもの難しさ

ポリシー関連の設定は名前付けの嵐です。

  • アドレスオブジェクト名、アドレスグループ名
  • サービス名、サービスグループ名
  • ポリシー名

個人的な感覚ですが、ネットワーク機器の設定として名前を自由に決められる項目は多くないように思います。description くらいでしょうか。ポリシー関連の設定になると自由度が増して、それと同時に「どうしよう・・」という迷いや「適当でもいいかな」という気持ちが芽生えやすい気もします。

あまり適当にしてしまうと、ポリシーの目的が分からずに後で消せなくなったりもします。

名前を自由に決められることは、便利な反面、命名規則などのルールがないと混乱のもとになり得ます。これがある種の難しさの一因かなとも思います。

3.2. 自動化の難しさ

すでに名前付けの難しさを挙げましたが、自動化するには名前付けをルール化する必要があります。

なんとなくで決めていた場合は、いよいよどうするかを決めることを迫られる場面です。

4. グループ化の難しさ

ちょっと細かい話になりますが、アドレスグループのようにオブジェクトをグループ化することは、時々悩ましいことを引き起こすことがあります。

4.1. そもそもの難しさ

たとえば、/32 のアドレスオブジェクトを束ねて、以下のアドレスグループが作成されていたとします。

  • アドレスグループ: WebServers
    • アドレス: 10.0.1.1/32
    • アドレス: 10.0.1.2/32
    • アドレス: 10.0.1.3/32

このようにグループ化しておくと、何かと管理しやすくなり、効率化にもつながりますね。

さらに、上記のアドレスグループが以下のようにポリシーに適用されているとします。

  • 送信元: any
  • 宛先: WebServers
  • サービス: HTTP
  • アクション: 許可

この状態から、以下の通信要件を「削除」する場合についてです。

  • 送信元: any
  • 宛先: 10.0.1.3/32
  • サービス: HTTP
  • アクション: 許可

10.0.1.3/32WebServers のメンバーです。ですが、安直に WebServers から 10.0.1.3/32 を削除すると、WebServers を指定している他のポリシーにも意図せず影響が出てしまいます。

他のポリシーに影響が出ないようにするには、グループ化の仕方を見直すなどの対応が必要になります。

4.2. 自動化の難しさ

影響がない削除の方法をロジック化するのはなかなか難しそうです。

極端かもしれませんが、宛先の指定がアドレスグループではなく 10.0.1.1/3210.0.1.2/3210.0.1.3/32 であれば、このポリシーの宛先から 10.0.1.3/32 を削除すればいいだけなのですが。

この件については「(グループ化のように)手動前提の効率化の延長に自動化があるとは限らない」という点に気付かされます。

5. 作業当日の確認の難しさ

ポリシー変更に限りませんが、作業当日の事後確認の難しさについてです。

5.1. そもそもの難しさ

難しいというよりは、不安という表現の方が適切かもしれません。

必要な設定が揃って手順も完璧!と思って迎える当日も、不安は残ります。そもそも要件から正しい設定を導き出せていたか、それを正しく設定できたかを確認する、事後確認があるためです。

事後確認が必要なこと自体は、ほかの多くの作業に共通することで、たとえばルーティング設定であればL3レベル疎通確認を行います。

ポリシー設定の場合はそれより上のレイヤーを含む確認が必要です。そのため、確認に必要なバリエーションが多かったり、再現が難しい場合もあったりします。この辺りが難しさの要因です。

もちろん、今回の設定に関係ない(はずの)通信に影響がないかも気がかりポイントです。

5.2. 自動化の難しさ

「この通信は通るはず or 通らないはず」というチェックを、エンドツーエンドのエンド側にいる人がやっていた場合、「そこにいる人」からの通信を再現する難しさがあります。

オフィスで利用するような Windows PC から疎通確認を行っていたのを自動化したい場合、ほかの自動化の仕組みとは異なる仕組みが必要かもしれません。例えば他は Python で、エンドだけ PowerShell など。

自動化のために確認方法自体を見直す必要がある場合もあるでしょう。

番外編: ドキュメントの維持の難しさ

これまであげたパラメーターや作業とは少し毛色が異なるので番外編として扱いますが、細かいドキュメントを正しく維持することの難しさについてです。

ドキュメントが正しくメンテナンスされていない場合は、現状のポリシーをドキュメントで確認することができません。この場合は、実機の設定を確認する必要があります。複数の機器の設定を確認するとなると、やはり相応の手間になります。

ドキュメントを正しくメンテナンスしていればいい話、というのはその通りです。ですが、リッチなドキュメントとして管理しようとすると、それだけメンテナンスの負荷も高くなります。

形式 読み手の負荷 メンテナンスの負荷
コンフィグだけ取っておく 高め 低め
ポリシーを表形式にする 低め 高め

表形式の場合、メンテナンスされているのであれば読み手も安心です。そうでなく設定ドリフトがあることが予見される場合、一気に緊張感が高まります。結局、実機を見たほうがいいという心理が働きます。

仮に動的ルーティングの設定であれば、ルーティング情報は機器同士でやりとりがされて、コンフィグに表れるのはルーティングプロトコル自体の設定です。

それに対して、ポリシーの設定の類は機器同士で情報をやり取りすることはなく(そういう高度な仕組みがある場合を除く)、機器ごとのコンフィグにポリシー設定(様々なオブジェクト、ポリシー)が表れます。このような経緯もあり、ポリシー設定は表現するべき情報が多く、リッチなドキュメントにしようとすると負荷がかかりやすくなるのではないか、と思っています。

とにかく「ドキュメントのメンテナンスが大変な割には、役立つ場面がない」というのは避けたいところです。

おわりに

今回はポリシー変更作業とその自動化にフォーカスをあてましたが、総じて以下のようなことが言えるかなと思います。

  • 自動化対象の作業のそもそもの難しさが、自動化の難しさに強く反映されることがある
  • 自動化によって解決したい課題が、その難しさの中にある場合がある
  • 自動化しやすい部分だけに終始すると課題がおいてけぼりになることがあるため、整理整頓と見極めが必要

いわゆる「スモールスタートでやっていきましょう」となった場合でも、難しさや課題を見据えて始めるかどうかは、重要なことだと感じています。