てくなべ

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

[Ansible] Ansible 公式ドキュメントのデータを Markdown 形式で取得する

はじめに

Ansible の公式ドキュメントのページの多くは reStructuredText で書かれていて、Sphinx 経由で出力されています。

人間がブラウザで HTML を表示する分には良いのですが、最近ではより AI に読んでもらいやすいように Markdown でデータを取得したいというニーズもでてきているようです。「人間用ホームページをやめました」という場合もあれば、AWS のドキュメントのようにMarkdown 用のボタンがある場合もありますね。

最近知ったのですが、Ansible のドキュメントのページも Accept: text/markdown を付けてリクエストすると、HTML の代わりに Markdown が返ってくることを知りました。

ちょっと試してみます。

おためし

Reusing Ansible artifacts というページで試します。

curl -H "Accept: text/markdown" https://docs.ansible.com/projects/ansible/latest/playbook_guide/playbooks_reuse.html

以下の Markdown が返ってきました。

クリックしてレスポンスボディ全文を見る <!DOCTYPE html>

* [Blog](https://www.ansible.com/blog)
* [Ansible community forum](https://forum.ansible.com/)
* [Documentation](https://docs.ansible.com/)

[ ![Ansible Logo](https://docs.ansible.com/projects/ansible/latest/_static/images/Ansible-Mark-RGB_White.png) Ansible Community Documentation ](https://docs.ansible.com/) 

* [](https://docs.ansible.com/projects/ansible/latest/index.html)
* [Using Ansible playbooks](https://docs.ansible.com/projects/ansible/latest/playbook%5Fguide/index.html)
* [Working with playbooks](https://docs.ansible.com/projects/ansible/latest/playbook%5Fguide/playbooks.html)
* Reusing Ansible artifacts
* [ Edit on GitHub](https://github.com/ansible/ansible-documentation/edit/devel/docs/docsite/rst/playbook%5Fguide/playbooks%5Freuse.rst?description=%23%23%23%23%23%20SUMMARY%0A%3C!---%20Your%20description%20here%20--%3E%0A%0A%0A%23%23%23%23%23%20ISSUE%20TYPE%0A-%20Docs%20Pull%20Request%0A%0A%2Blabel:%20docsite%5Fpr)

---

# Reusing Ansible artifacts[](#reusing-ansible-artifacts "Link to this heading")

You can write a simple playbook in one very large file, and most users learn the one-file approach first. However, breaking your automation work up into smaller files is an excellent way to organize complex sets of tasks and reuse them. Smaller, more distributed artifacts let you reuse the same variables, tasks, and plays in multiple playbooks to address different use cases. You can use distributed artifacts across multiple parent playbooks or even multiple times within one playbook. For example, you might want to update your customer database as part of several different playbooks. If you put all the tasks related to updating your database in a tasks file or a role, you can reuse them in many playbooks while only maintaining them in one place.

## [Creating reusable files and roles](#id1)[](#creating-reusable-files-and-roles "Link to this heading")

Ansible offers four distributed, reusable artifacts: variables files, task files, playbooks, and roles.

> * A variables file contains only variables.
> * A task file contains only tasks.
> * A playbook contains at least one play, and may contain variables, tasks, and other content. You can reuse tightly focused playbooks, but you can only reuse them statically, not dynamically.
> * A role contains a set of related tasks, variables, defaults, handlers, and even modules or other plugins in a defined file-tree. Unlike variables files, task files, or playbooks, roles can be easily uploaded and shared through Ansible Galaxy. See [Roles](https://docs.ansible.com/projects/ansible/latest/playbook%5Fguide/playbooks%5Freuse%5Froles.html#playbooks-reuse-roles) for details about creating and using roles.

New in version 2.4.

## [Reusing playbooks](#id2)[](#reusing-playbooks "Link to this heading")

You can incorporate multiple playbooks into a main playbook. However, you can only use imports to reuse playbooks. For example:

- import_playbook: webservers.yml
- import_playbook: databases.yml

Importing incorporates playbooks in other playbooks statically. Ansible runs the plays and tasks in each imported playbook in the order they are listed, just as if they had been defined directly in the main playbook.

You can select which playbook you want to import at runtime by defining your imported playbook file name with a variable, then passing the variable with either `--extra-vars` or the `vars` keyword. For example:

- import_playbook: "/path/to/{{ import_from_extra_var }}"
- import_playbook: "{{ import_from_vars }}"
  vars:
    import_from_vars: /path/to/one_playbook.yml

If you run this playbook with `ansible-playbook my_playbook -e import_from_extra_var=other_playbook.yml`, Ansible imports both one\_playbook.yml and other\_playbook.yml.

## [When to turn a playbook into a role](#id3)[](#when-to-turn-a-playbook-into-a-role "Link to this heading")

For some use cases, simple playbooks work well. However, starting at a certain level of complexity, roles work better than playbooks. A role lets you store your defaults, handlers, variables, and tasks in separate directories, instead of in a single long document. Roles are easy to share on Ansible Galaxy. For complex use cases, most users find roles easier to read, understand, and maintain than all-in-one playbooks.

## [Reusing files and roles](#id4)[](#reusing-files-and-roles "Link to this heading")

Ansible offers two ways to reuse files and roles in a playbook: dynamic and static.

> * For dynamic reuse, add an `include_*` task in the tasks section of a play:
> 
>  * [include\_role](https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/include%5Frole%5Fmodule.html#include-role-module)
>  * [include\_tasks](https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/include%5Ftasks%5Fmodule.html#include-tasks-module)
>  * [include\_vars](https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/include%5Fvars%5Fmodule.html#include-vars-module)
> * For static reuse, add an `import_*` task in the tasks section of a play:
> 
>  * [import\_role](https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/import%5Frole%5Fmodule.html#import-role-module)
>  * [import\_tasks](https://docs.ansible.com/projects/ansible/latest/collections/ansible/builtin/import%5Ftasks%5Fmodule.html#import-tasks-module)

Task include and import statements can be used at arbitrary depth.

You can still use the bare [roles](https://docs.ansible.com/projects/ansible/latest/playbook%5Fguide/playbooks%5Freuse%5Froles.html#roles-keyword) keyword at the play level to incorporate a role in a playbook statically. However, the bare [include](https://docs.ansible.com/projects/ansible/2.9/modules/include%5Fmodule.html#include-module "(in Ansible v2.9)") keyword, once used for both task files and playbook-level includes, is now deprecated.

### [Includes: dynamic reuse](#id5)[](#includes-dynamic-reuse "Link to this heading")

Including roles, tasks, or variables adds them to a playbook dynamically. Ansible processes included files and roles as they come up in a playbook, so included tasks can be affected by the results of earlier tasks within the top-level playbook. Included roles and tasks are similar to handlers - they may or may not run, depending on the results of other tasks in the top-level playbook.

The primary advantage of using `include_*` statements is looping. When a loop is used with an include, the included tasks or roles will be executed once for each item in the loop.

The file names for included roles, tasks, and vars are templated before inclusion.

You can pass variables into includes. See [Variable precedence: where should I put a variable?](https://docs.ansible.com/projects/ansible/latest/playbook%5Fguide/playbooks%5Fvariables.html#ansible-variable-precedence) for more details on variable inheritance and precedence.

### [Imports: static reuse](#id6)[](#imports-static-reuse "Link to this heading")

Importing roles, tasks, or playbooks adds them to a playbook statically. Ansible pre-processes imported files and roles before it runs any tasks in a playbook, so imported content is never affected by other tasks within the top-level playbook.

The file names for imported roles and tasks support templating, but the variables must be available when Ansible is pre-processing the imports. This can be done with the `vars` keyword or by using `--extra-vars`.

You can pass variables to imports. You must pass variables if you want to run an imported file more than once in a playbook. For example:

tasks:
- import_tasks: wordpress.yml
  vars:
    wp_user: timmy

- import_tasks: wordpress.yml
  vars:
    wp_user: alice

- import_tasks: wordpress.yml
  vars:
    wp_user: bob

See [Variable precedence: where should I put a variable?](https://docs.ansible.com/projects/ansible/latest/playbook%5Fguide/playbooks%5Fvariables.html#ansible-variable-precedence) for more details on variable inheritance and precedence.

### [Comparing includes and imports: dynamic and static reuse](#id7)[](#comparing-includes-and-imports-dynamic-and-static-reuse "Link to this heading")

Each approach to reusing distributed Ansible artifacts has advantages and limitations. You may choose dynamic reuse for some playbooks and static reuse for others. Although you can use both dynamic and static reuse in a single playbook, it is best to select one approach per playbook. Mixing static and dynamic reuse can introduce difficult-to-diagnose bugs into your playbooks. This table summarizes the main differences so you can choose the best approach for each playbook you create.

|                           | Include\_\*                             | Import\_\*                               |
| ------------------------- | --------------------------------------- | ---------------------------------------- |
| Type of reuse             | Dynamic                                 | Static                                   |
| When processed            | At runtime, when encountered            | Pre-processed during playbook parsing    |
| Task or play              | All includes are tasks                  | import\_playbook cannot be a task        |
| Task options              | Apply only to include task itself       | Apply to all child tasks in import       |
| Calling from loops        | Executed once for each loop item        | Cannot be used in a loop                 |
| Using \--list-tags        | Tags within includes not listed         | All tags appear with \--list-tags        |
| Using \--list-tasks       | Tasks within includes not listed        | All tasks appear with \--list-tasks      |
| Notifying handlers        | Cannot trigger handlers within includes | Can trigger individual imported handlers |
| Using \--start-at-task    | Cannot start at tasks within includes   | Can start at imported tasks              |
| Using inventory variables | Can include\_\*: {{ inventory\_var }}   | Cannot import\_\*: {{ inventory\_var }}  |
| With playbooks            | No include\_playbook                    | Can import full playbooks                |
| With variables files      | Can include variables files             | Use vars\_files: to import variables     |

Note

* There are also big differences in resource consumption and performance, imports are quite lean and fast, while includes require a lot of management and accounting.

## [Reusing tasks as handlers](#id8)[](#reusing-tasks-as-handlers "Link to this heading")

You can also use includes and imports in the [Handlers: running operations on change](https://docs.ansible.com/projects/ansible/latest/playbook%5Fguide/playbooks%5Fhandlers.html#handlers) section of a playbook. For example, if you want to define how to restart Apache, you only have to do that once for all of your playbooks. You might make a `restarts.yml` file that looks like:

# restarts.yml
- name: Restart apache
  ansible.builtin.service:
    name: apache
    state: restarted

- name: Restart mysql
  ansible.builtin.service:
    name: mysql
    state: restarted

You can trigger handlers from either an import or an include, but the procedure is different for each method of reuse. If you include the file, you must notify the include itself, which triggers all the tasks in `restarts.yml`. If you import the file, you must notify the individual task(s) within `restarts.yml`. You can mix direct tasks and handlers with included or imported tasks and handlers.

### [Triggering included (dynamic) handlers](#id9)[](#triggering-included-dynamic-handlers "Link to this heading")

Includes are executed at run-time, so the name of the include exists during play execution, but the included tasks do not exist until the include itself is triggered. To use the `Restart apache` task with dynamic reuse, refer to the name of the include itself. This approach triggers all tasks in the included file as handlers. For example, with the task file shown above:

- name: Trigger an included (dynamic) handler
  hosts: localhost
  handlers:
    - name: Restart services
      include_tasks: restarts.yml
  tasks:
    - command: "true"
      notify: Restart services

### [Triggering imported (static) handlers](#id10)[](#triggering-imported-static-handlers "Link to this heading")

Imports are processed before the play begins, so the name of the import no longer exists during play execution, but the names of the individual imported tasks do exist. To use the `Restart apache` task with static reuse, refer to the name of each task or tasks within the imported file. For example, with the task file shown above:

- name: Trigger an imported (static) handler
  hosts: localhost
  handlers:
    - name: Restart services
      import_tasks: restarts.yml
  tasks:
    - command: "true"
      notify: Restart apache
    - command: "true"
      notify: Restart mysql

See also

[Utilities modules](https://docs.ansible.com/projects/ansible/2.9/modules/list%5Fof%5Futilities%5Fmodules.html#utilities-modules "(in Ansible v2.9)")

Documentation of the `include*` and `import*` modules discussed here.

[Working with playbooks](https://docs.ansible.com/projects/ansible/latest/playbook%5Fguide/playbooks.html#working-with-playbooks)

Review the basic Playbook language features

[Using variables](https://docs.ansible.com/projects/ansible/latest/playbook%5Fguide/playbooks%5Fvariables.html#playbooks-variables)

All about variables in playbooks

[Conditionals](https://docs.ansible.com/projects/ansible/latest/playbook%5Fguide/playbooks%5Fconditionals.html#playbooks-conditionals)

Conditionals in playbooks

[Loops](https://docs.ansible.com/projects/ansible/latest/playbook%5Fguide/playbooks%5Floops.html#playbooks-loops)

Loops in playbooks

[General tips](https://docs.ansible.com/projects/ansible/latest/tips%5Ftricks/ansible%5Ftips%5Ftricks.html#tips-and-tricks)

Tips and tricks for playbooks

[Galaxy User Guide](https://docs.ansible.com/projects/ansible/latest/galaxy/user%5Fguide.html#ansible-galaxy)

How to share roles on galaxy, role management

[Communication](https://docs.ansible.com/projects/ansible/latest/community/communication.html#communication)

Got questions? Need help? Want to share your ideas? Visit the Ansible communication guide

なるほどなるほど。願わくば、コードがコードブロックで囲われてるとうれしい気もします。

仕組み

この挙動はどうやらドキュメントホスティング先の Read the Docs 共通のようです。

docs.readthedocs.com

This feature is powered by Cloudflare.

・・ということで、Cloudflare の Markdown 変換のサービスを利用しているそうです。

blog.cloudflare.com

便利ですねぇ。

Interop Tokyo 2026 参加レポート(主に ShowNet)

はじめに

2026/06/10-12(現地展示期間として)に開催されたInterop Tokyo 2026に参加してきました。

ShowNet の展示やセッションを見てきましたので、いくつかまとめます。

※ 口頭で聞いたあいまいな記憶を思い出しながら書いた記述が含まれます。正確な情報は一次ソースをあたっていただくようお願いします。何かご指摘ありましたら @akira6592 にご連絡いただけるとありがたいです。

1. ShowNet 関連

ShowNet は、多くのベンダーの最新鋭の機器を実際に動作させて相互接続性(Interoperability)を検証する大規模なネットワークです。来場者や展示ブースからのインターネット接続性を提供する役割も持っています。

新しくて分からないものが満載ですが、毎年これを見るのがたのしみにしています。

各ラックで気になった機器についてまとめます。一部、ShowNet ステージなど聞いた話も含みます。

トポロジー図や各ラックに何の機器が設置されているかが分かる「ShowNetの歩き方」などの資料は以下のページにまとめられています。

www.interop.jp

1.1. ShowNet ラック

まず、各ラックで気になった機器についてです。

対外接続回線 / 対外接続ルータ (#N-1 / #N-2 ラック)

ShowNet と外を接続する部分です。ここがあるからこそ ShowNet がインターネットに接続されている、と言える箇所です。

#N-1 ラック

「今年は 4.1T」と書かれていました。どんどん増えていきますね。

今年もBGP ピアリングの認証方式として、MD5 ではなく TCP-AO (Authentication Option)が採用されているようです。

#N-2 ラック

APN は「6wave」。

あと、うっかりすると見過ごしてしまうのですが、いつも足元の対外接続の線もチェックしました。

対外接続の線(足元)

去年は「NTTコミュニケーションズ」だった線は、今年は「NTTドコモビジネス」です。HPE Juniper Networking の件も含め、名称の変化をいくつか感じたのが印象的でした。

コアネットワーク(#N-3 ラック)

対外接続部分から少し内側のコアネットワーク部分です。

#N-3 ラック

SRv6 では、オーバーヘッドが少ないマイクロSIDを使っているそうです。

大容量光トラスポート(#N-4 ラック)

光マトリクススイッチという機器がありました。

Polatis社 光マトリクススイッチ

試験などで光ファイバーのいろいろ接続を切り替えるときに、抜き差ししなくても、内部の組み合わせによって切り替えができるようです。

光マトリクススイッチの説明

高密度パッチパネル / ロボット配線システム(#N-5 ラック)

多くの光ファイバーが集まるラックです。「黄色いラック」と呼ばれることもあるそうです。確かに黄色いですね。

#N-5 ラック

ロボパッチに注目しました。みっちみちにファイバーが集まっています。部分的にしか写せていませんが、赤や緑のランプがある機器です。こちらも光回線をリモートからでも切り替えできる機器です。物理レベルのリモート制御は、あるとないのとでは雲泥の差なのだと思います。

センコーアドアドバンス社 XSOS 576D

参考:

ascii.jp

ユーザ収容ネットワーク(#N-6 ラック)

展示ブースからのトラフィックが集まるネットワークです。

今回で初めて知ったのですが、「ArcOS」というホワイトボックススイッチOSがあって、筐体とセットで設置されていました。

1Finity ArcOS+S9610-36D

ホワイトボックススイッチ説明

また、説明を聞きそびれてしまったのですが、「ShowNet としては初めて上から下(ユーザー)まで IPv6」という説明を伺いました。EVPN VXLAN のアンダーレイの話だったような・・?

・・・と思いながら後日、Internet Week Showcase in 静岡で、「変わり続けるネットワークエンジニアリングを考える ― Interop ShowNetの事例から」を拝聴したら気になっていたことが聞けました。アンダーレイが IPv6 のみになってうれしい点としては、自動生成の IPv6 リンクローカルアドレスだけになり、ある意味でプラグアンドプレイになった点が挙げられました。アドレスの「設計」というプロセスも「設定」という管理対象も不要になることで、シンプルに維持できてよさそうです。

ネットワーク品質検証 / ユーザー体感品質測定(#N-9 ラック)

光配線切替ロボットの小型版である ROME mini。毎年眺めているのですが、今年も実際に切り替えてる瞬間には出会えませんでした。いつか見てみたい・・・。

ROME mini

ラック脇のホワイトボードにはプロンプトインジェクションなどの攻撃を防ぐ製品群のセキュリティ試験について書かれていました。

セキュリティ試験

また、AI 推論パフォーマンス試験のKPI についても書かれていました。初耳でした。

  • TTFT (Time To First Token)
  • TTLT (Time To Last Token)

AI 推論パフォーマンス試験のKPI

背が高いラック(#D-1 ~ D-3)

馴染みがあるのは 42U 高さのラックですが、#D-1 から #D-3 のラックはさらに背が高かったです。52U あるそうです。

背が高いラックたち(#D-4 から右は通常)

水冷(#D-4 ~ D-6)

現地で注目されていた印象が強かったものの一つが「水冷」です。

#D-6ラック全体

#D-6 ラックでは水冷スイッチ QFX5250-64OE-L が動いていました。

水冷スイッチ QFX5250-64OE-L 前面

背面はこんな感じです。少なくともぱっと見でファンは見当たりません。背面の両端に何かが通っていますが、別サイトの写真と合わせて見ると、それがスイッチ内部まで通っているように見えました。

水冷スイッチ QFX5250-64OE-L 背面

見た目のインパクトが大きかったのは #D-4 ラックの裏です。温かい水が赤、冷たい水が青、と演出的に分かりやすくしてました。

#D-4 ラック裏

表はこんな感じです。

#D-4 ラック表

なお、液体を使った冷却を指す言葉がいくつかあるようですが、今回は以下の理由で「水冷」と表現しているそうです。

水冷の表記について(後述のセルフツアー時に閲覧した資料から)

ちなみに、トポロジー図(PDF)で、しずくのアイコンが付いてる機器が水冷とのことです。

しずくアイコン付きの機器例(トポロジー図抜粋)

参考

www.geekpage.jp

ascii.jp

1.2. AI 活用

今年も ShowNet の構築、運用にあたっては AI が活用されたそうです。

大き目トピックで特定のラック固有の話とは限らないので、独立した節でまとめます。

MCP Festa

今回は、各種ログやフロー情報を MCP 経由で自然言語で問い合わせする仕組みを作られていたそうです。たまったログ類自体はデータでしかないので、そこから意味を見出すには相当のスキルが必要そうです。このように自然言語で聞けるのはそのハードルを下げられそうで、有用そうだなと思いました。

MCP FESTA(#S-2 ラック)

少し離れたところで、スライドで紹介されていました。

MCP Festa @FlowInspector

MCP Festa NURO Biz syslog解析AI基盤

また、展示会場内セミナー「ShowNetの安定稼働を支える運用基盤〜モニタリングとAI活用の最前線〜」は、後日アーカイブが公開されました。MCP を含むAI活用の話は 23:00 頃からです。

forest.f2ff.jp

AI Agent 活用

当日は情報を追えなかったのですが、つい先ほどご紹介した「ShowNetの安定稼働を支える運用基盤〜モニタリングとAI活用の最前線〜」のアーカイブの 29:32 ころから「AI Agent の活用デモ」というパートがあったので拝聴しました。

2025年はチャットボットベースのAI活用だったのが、2026年はより自律的な AI エージェントを導入されたそうです。

構成要素は主に以下の通りです。これらによってトラブルシューティングや状況確認ができるそうです。

  • OpenClaw
  • 人間とのUI は Webex
  • AI エージェントへの攻撃に対してはガードレール製品で対策
  • ローカルLLM利用

かなり意外だったのはローカルLLMの置き場所です。去年は Azure 上だったのが、今年は IOWN APN 経由で札幌、三鷹、横浜、福岡に設置された計算資源を利用していたそうです(幕張側にも GPU サーバーあり)。

ガードレールも重要ですね。手堅い手順が求めらえるネットワーク構築、運用の場面において、意図せず機器再起動をされてしまっては困りますし。

このセミナー時点での気づきとしては、AIにどういう情報を与えるか、アクセスさせるか、が重要とのことでした。このように、実際やってみてどうだったかという情報を共有していただけるのは、非常にありがたいです。

1.3. ShowNet セルフツアー

去年に引き続き、タブレット端末を借りてラックに近づくと説明の動画や資料が見れる「ShowNet セルフツアー」があったので参加しました。

セルフツアーなので、自分の時間の都合(受付の開始と終了時刻はある)で見れるのでお手軽です。当日現地での申し込みが必要ですが無料です。

貸し出されるタブレット。ここに行くと見れますよというガイドもある

位置情報を取得している仕組みが面白くて、GPS ではなく Wi-Fi を利用します。

位置情報取得の仕組み

こんな感じで、説明の資料や(写真に撮ってないですが)動画が見れます。それぞれ自分のペースで見れるのがありがたいです。

見れる資料の例

使い勝手的なところは、事後アンケートでフィードバックをいたしました。

2. 展示会場セミナー

参加した展示場内セミナーについてです。

2.1. 「ネットワークと AI の融合」

ネットワークと AI の融合 - 自律型エージェントが拓く運用の未来 をというセミナーを拝聴しました。

ネットワーク運用における AI の活用のこれまでとこれからの流れの解説や、MCP Server を使ったトラシューのデモなどを見れました。

発表されたばかりの Cisco Cloud Control の説明もありました。 局所最適したとしても分断されたプラットフォームは扱いにくいという課題に対して、Cisco Cloud Control はそれらを取りまとめる統合プラットフォームという位置づけのようです。

3. ブース

近年は ShowNet ラック方面を中心に見ていますが、少しだけブースを回れました。

3.1. セイコーソリューションズさん

Best of Show Award で審査員特別賞を受賞された「Netwiser」シリーズが、展示されてました。証明書の自動更新機能が追加されたそうです。

Netwiser SX-41
 

3.2. PagerDuty さん

PagerDuty のサービスの概要や、各種オプションの機能についてご説明いただきました。印象的だったのは、各メンバーの負荷状況が確認できる点です。システムだけでなく、人も見てくれるサービスであるんだなと思いました。

PagerDuty さんブース

おわりに

私が気になったShowNet のラック内の機器の役割や新しい取り組みを中心にまとめました。

2025年の時も、特に AI 活用の結果をあとで共有してくださることがあった(例: JANOG 56 のプログラム)ので、今年の分の情報があればぜひキャッチアップしたいと思いました。

ShowNet の構築、運用に関わった NOC、STM のみなさま、ブースでご対応いただいたみなさま、ありがとうございました!

なお、ShowNet のより詳しい説明がされる shownet.conf_ は、今年は 2026/08/27 - 28 に開催されるそうです。

f2ff.jp

参考

[2026/07/10 追記] ShowNet Stage 2026 動画まとめ www.youtube.com

x.com

note.com

ascii.jp

cloud.watch.impress.co.jp

gorosuke5656.hatenablog.com

[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 で修正されると思います。

[2026/06/19 追記]

上記不具合の修正が含まれる ansible-core 2.21.1 がリリースされました。

config - use correct key value for inject_invocation setting (#86999).

ansible/changelogs/CHANGELOG-v2.21.rst at stable-2.21 · ansible/ansible · GitHub

補足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

[2026/06/11 追記]

www.redhat.com

www.redhat.com

www.youtube.com

タスクの変数を減らす

はじめに

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

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

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

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

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

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

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

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

だんだんそれさえ面倒に

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

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

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

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

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

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

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

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

おわりに

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

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