てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] ハンドラー名はユニークにしておいた方が良い理由と検証

はじめに

Ansible には、タスクのステータスが changed のときだけ実行したい処理を定義するために、ハンドラーという機能があります。

docs.ansible.com

ハンドラーには、通常のタスクと同様に name を指定できます。ハンドラーで指定した name をこの記事ではハンドラー名と呼びます。

タスクとハンドラーを関連付ける方法は複数あります。その一つは、通常のタスクの notify ディレクティブで、呼びたいハンドラー名を指定する方法です。 (実際には一通りタスクの処理が終わってからハンドラーが呼ばれます。ロールを含めた処理順はこちら

そのため、ハンドラー名は重要な識別子の役割を持ちます。もし、同じハンドラー名のハンドラーが複数あると思わぬ結果を招く場合あります。ハンドラー名はユニークにしておくべきと、ドキュメントに記載があります。

Each handler should have a globally unique name.

同じくドキュメントに記載されている、グロバルスコープで扱われるという点も重要です。

Handlers from roles are not just contained in their roles but rather inserted into the global scope with all other handlers from a play.

この記事では、同じ名前のハンドラーがある場合の挙動を、通常の場合と比較して検証します。

  • 検証環境
    • ansible-core 2.15.2

1. 通常の場合(ユニークなハンドラー名の場合)

まずは、比較のためにユニークなハンドラー名で構成された通常の場合の挙動です。

フォルダ・ファイル構成

それぞれハンドラーを持つ 2つのロール role1role2 からなる構成とします。

.
├── playbook.yml
└── roles
    ├── role1
    │   ├── handlers
    │   │   └── main.yml
    │   └── tasks
    │       └── main.yml
    └── role2
        ├── handlers
        │   └── main.yml
        └── tasks
            └── main.yml

role1 ロール

role1/tasks/main.yml:

---
- name: Task with changed
  ansible.builtin.command:    # changed
    cmd: "echo Hello!"
  notify:
    - Test Handler in role1

role1/handlers/main.yml:

---
- name: Test Handler in role1   # ロール固有の名前
  ansible.builtin.debug:
    msg: "handler {{ ansible_role_name }}"

role2 ロール

role1 とすべて同じです)

role2/tasks/main.yml:

---
- name: Task with changed
  ansible.builtin.command:    # changed
    cmd: "echo Hello!"
  notify:
    - Test Handler in role2

role2/handlers/main.yml:

---
- name: Test Handler in role2   # ロール固有の名前
  ansible.builtin.debug:
    msg: "handler {{ ansible_role_name }}"

Playbook

2つのロールを呼び出すPlaybookです。

playbook.yml:

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

  tasks:
    - name: Import role1
      ansible.builtin.import_role:
        name: role1

    - name: Import role2
      ansible.builtin.import_role:
        name: role2

実行結果

以下のような実行順序になります。

  1. role1 のタスク
  2. role2 のタスク
  3. role1 のハンドラー
  4. role2 のハンドラー

コマンド実行ログは以下のとおりです。

$ ansible-playbook -i localhost, playbook.yml

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

TASK [role1 : Task with changed] ************************************************************************************
changed: [localhost]

TASK [role2 : Test Handler in role1] ********************************************************************************
changed: [localhost]

RUNNING HANDLER [role1 : Test Handler in role1] *********************************************************************
ok: [localhost] => {
    "msg": "handler role1"
}

RUNNING HANDLER [role2 : Test Handler in role2] *********************************************************************
ok: [localhost] => {
    "msg": "handler role2"
}

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

2. 同じ名前のハンドラーがある場合

次に、同じ名前のハンドラーが複数に含まれている場合です。

role1 ロール

role1/tasks/main.yml:

---
- name: Task with changed
  ansible.builtin.command:    # changed
    cmd: "echo Hello!"
  notify:
    - Test Handler

role1/handlers/main.yml:

---
- name: Test Handler    # 他のロールにあるハンドラーと同じ名前
  ansible.builtin.debug:
    msg: "handler {{ ansible_role_name }}"

role2 ロール

role1 とすべて同じです)

role2/tasks/main.yml:

---
- name: Task with changed
  ansible.builtin.command:    # changed
    cmd: "echo Hello!"
  notify:
    - Test Handler

role2/handlers/main.yml:

---
- name: Test Handler    # 他のロールにあるハンドラーと同じ名前
  ansible.builtin.debug:
    msg: "handler {{ ansible_role_name }}"

Playbook

2つのロールを呼び出すPlaybookです。

playbook.yml:

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

  tasks:
    - name: Import role1
      ansible.builtin.import_role:
        name: role1

    - name: Import role2
      ansible.builtin.import_role:
        name: role2

実行結果

以下のような実行順序になります。

  1. role1 のタスク
  2. role2 のタスク
  3. role2 のハンドラー

role1 のハンドラーが呼ばれていないところがポイントです。

コマンド実行ログは以下のとおりです。

$ ansible-playbook -i localhost, playbook.yml

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

TASK [role1 : Task with changed] ************************************************************************************
changed: [localhost]

TASK [role2 : Task with changed] ************************************************************************************
changed: [localhost]

RUNNING HANDLER [role2 : Test Handler] ******************************************************************************
ok: [localhost] => {
    "msg": "handler role2"
}

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

この、role1 のハンドラーが呼ばれなかったところが、ドキュメントの言葉でいう

shadowing all of the previous handlers with the same name.

かなと思います。

なお、ansible.builtin.import_role でインポートするロールを逆( role2role1 の順)にしたら、role1 のハンドラーのみが呼ばれました。

おまけ

ハンドラーはグローバルで有効という性質上、以下のようなこともできます。

特定のロールのハンドラーを指定

notify で ロール名 : ハンドラー名 を指定すると、ロールを明示的に指定できます。ドキュメントにも方法が載っています(最近知りました)。

たとえば、role1/tasks/main.yml で、以下のように role2 内の ハンドラーを Test Handler 呼ぶとします。

---
- name: Task with changed
  ansible.builtin.command:
    cmd: "echo Hello!"
  notify:
    - "role2 : Test Handler"

これで、role2/handlers/main.yml の以下のハンドラーが呼ばれます。

---
- name: Test Handler
  ansible.builtin.debug:
    msg: "handler {{ ansible_role_name }}"

ただし、role2 も Playbook 側で読み込んでおく必要があります。

ハンドラーのみのロールでハンドラーを共通化

ハンドラーのみのロールを用意して、他のロールからハンドラーを呼ぶようにして、ハンドラーを共通化するような方法です。

.
├── playbook.yml
└── roles
    ├── role1
    │   └── tasks
    │       └── main.yml
    └── role_handler_only
        └── handlers
            └── main.yml

role_handler_only/handlers/main.yml:

---
- name: Test Handler      # role_handler_only ロールはこれのみ
  ansible.builtin.debug:
    msg: "handler {{ ansible_role_name }}"

role1/tasks/main.yml:

---
- name: Task with changed # role1 ロールはこれのみ
  ansible.builtin.command:
    cmd: "echo Hello!"
  notify:
    - Test Handler

playbook.yml:

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

  tasks:
    - name: Import role1
      ansible.builtin.import_role:
        name: role1

    - name: Import role_handler_only
      ansible.builtin.import_role:
        name: role_handler_only  # ハンドラーのみのロール

実行ログ:

ansible-playbook -i localhost, playbook.yml

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

TASK [role1 : Task with changed] *********************************************************************************************
changed: [localhost]

RUNNING HANDLER [role_handler_only : Test Handler] ***************************************************************************
ok: [localhost] => {
    "msg": "handler role_handler_only"
}

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

ハンドラーのみのロールの実装のヒントは、以下の記事から得ました。ありがとうございます。

qiita.com

おわりに

同じ名前のハンドラーがあることで、起こる現象を検証しました。

ざっくり、ハンドラー名は Play 内でグローバルなスコープで処理される、というイメージでとらえておけばよいかなと思いました。

[Ansible/AAP] AAP のドキュメントから Ansible 2.9 の記載がなくなってきている

いよいよという感じですが、AAP (Ansible Automation Platform)のドキュメントから Ansible 2.9 の記載がなくなってきています。

たまたま、Before / After のキャプチャーが撮れたので載せておきます。

たとえば、システム要件のページ。

Before (Ansible 2.9)

After (2.15)

関連PR

github.com

なお、ライフサイクルについては以下のページを参照してください。

access.redhat.com

[Ansible/AAP] Automation Controller へのマニフェストファイル適用時にエラー「Request failed with status code 413」になる現象と対処

はじめに

Automation Controller にライセンスを適用する方法には以下の2つがあります。

  1. 予め作成したマニフェストファイル(zip)をライセンス適用画面でアップロード
  2. ライセンス適用画面でユーザー名 / パスワードを入力してライセンスを選択

このうち、1 のマニフェストファイルをアップロードした時に Request failed with status code 413 というになる現象に出会いました。

本記事では原因と対策を記載します。簡単にまとめると、アップロードするマニフェストファイルのサイズが大きくて nginx の制限に引っかかってしまったので制限を変更しました。

なお、本事象の調査の一通りし終えた後に、レッドハット社の以下の関連ナレッジを見つけました。閲覧できる方は、あわせてご参照ください。

環境

  • Automation Controller 4.1.2 (AAP 2.1 に含まれる)
    • すでに EOL を迎えていますが、アップグレードの準備や機能差分の調査などで利用する機会はなくもないと思います
    • Automation Controller 4.2 以降はいくつか事情が異なるのでご注意ください(詳細は「補足」にて)

現象

ライセンス未適用 の Automation Controller にログインすると以下の画面になります(適用済み Automation Controller の [設定] > [サブスクリプション設定] > [編集] でも類似の画面になります)。

サブスクリプション適用画面

ここで、予め Red Hat Customer Portal で有効なサブスクリプションから作成したマニフェストファイルの zip をアップロードして、「使用許諾契約書」まで進めて [送信] をクリックします。すると、Request failed with status code 413 というエラーが表示されました。

エラー Request failed with status code 413`

初見では、レッドハット社側のサイトからのエラーが表示されているように思いましたが、通信状況を確認すると、レッドハット社のサイトへの通信は発生していませんでした。そのため、Automation Controller 自身が 413、つまり Content Too Large を返していると判断しました。

原因

Automation Controller で利用されている nginx の client_max_body_size がデフォルトの 1m のままだったため、これを超えるサイズのマニフェストファイル(今回は1069KB)をアップロードできないのが原因でした。

これまで利用していたマニフェストファイルは 500KB 程度だったのでこの制限に引っかかりませでした。今回は作成する元のサブスクリプションが変わった影響かマニフェストファイルのサイズが大きくなって制限に引っかかってしまったようです。

対策

今回の環境ではなく次のバージョンの Automation Controller 4.3 からは client_max_body_size が デフォルトで 5m に設定されるようになっています。

そのため、今回の環境も 5m に設定することにしました。

/etc/nginx/nginx.confhttp > server 配下に client_max_body_size 5m; を追加します。

# ...(略)...
http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    server_tokens off;

    # ...(略)...
    server {
        listen 443 default_server ssl;
        listen 127.0.0.1:80 default_server;

        client_max_body_size 5m;        # 追加

        # If you have a domain name, this is where to add it
        server_name _;
        keepalive_timeout 65;
        # ...(略)...

nginx 単体の再起動でもよいかもしれませんが、念のため automation-controller-service コマンドで再起動します。

$ sudo automation-controller-service restart

これで正常にマニフェストファイルをアップロード、ライセンス適用できました。

補足

今回は Automation Controller 4.1 での事象と対策でした。

他のバージョンの事情も少し調べたのでまとめておきます。ただし、AAP のインストーラーの処理を机上で追っただけです。

Automation Controller バージョン nginx 設定ファイル client_max_body_size 設定
4.1.2 (AAP 2.1) /etc/nginx/nginx.conf 指定なし(デフォルトの 1m
4.2.2 (AAP 2.2) /etc/nginx/nginx.conf 1m (変数 automationcontroller_client_max_body_size で変更可)
4.3.19 (AAP 2.3) /etc/nginx/conf.d/automation-controller.nginx.conf 5m (変数 automationcontroller_client_max_body_size で変更可)
4.5.5 (AAP 2.4) /etc/nginx/conf.d/automation-controller.nginx.conf 5m (変数 automationcontroller_client_max_body_size で変更可)

また、Automation Controller 4.3.7 のリリースノート

Made client_max_body_size for controller nginx configurable at install time for the VM installer,

とあります。変数化されているという意味であれば、私が調べた限りは、 4.2.2 でも変数化されていました。

おわりに

Automation Controller とエラー「Request failed with status code 413」を頼りに調べていた時は、なかなか解決の糸口が見つからなかったのですが、ファイルサイズに着目してナレッジを検索していれば、もう少し早く解決したかなと思いました。

[Ansible] IOS-XR 向けのタスクがエラー「No existing session」になる原因のひとつ

はじめに

Ansible のネットワークモジュールでたまに見かけるエラー

"msg": "No existing session"

は、個人的に切り分けが難しいエラーの一つだと思っています。

先日は IOS-XR に対する Playbook で、認証系の誤りによってこのエラーが表示されたことがあります。

再現方法と対処をまとめます。

このエラーが必ずしもこの対処で解消されるとは限りませんので、一つの例として捉えていただければと思います。

環境

  • ansible-core 2.16.0
  • paramiko ( ansible-pylibssh は未インストール)
  • cisco.iosxr コレクション 6.1.0
  • ansible.netcommon コレクション5.3.0

Playbook 類

適用させるインベントリ変数ファイルは以下のとおりです。

---
ansible_network_os: cisco.iosxr.iosxr
ansible_connection: ansible.netcommon.network_cli
ansible_user: admin
ansible_password: xxxxx

show コマンドを実行するかんたんな Playbook は以下のとおりです。

---
- hosts: iosxr_sandbox
  gather_facts: false

  tasks:
    - name: Test show command
      cisco.iosxr.iosxr_command:
        commands:
          - show version

実行とエラー

Playbook を実行すると・・・

 % ansible-playbook -i inventory.ini iosxr.yml

PLAY [iosxr_sandbox] *****************************************************************************************************************

TASK [Test show command] *************************************************************************************************************
[WARNING]: ansible-pylibssh not installed, falling back to paramiko
fatal: [iosxr_sandbox01]: FAILED! => {"changed": false, "msg": "No existing session"}

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

例のエラーが表示されます。

"msg": "No existing session"

ぱっと見ではわかりませんよね・・

対処

もともとは Ansible Forum のトピック で、このエラーが出てる現象を見かけました。なんだろうなと思ったんですが、ふと思い出したのが以前の記事でも触れた、パスワードを指定していても paramiko がデフォルトの秘密鍵を探す件です。

このときの対処と同じく、鍵を探さないように look_for_keys の値を変更したら正常に実行できました。

ansible.cfg :

[paramiko_connection]
look_for_keys = False

おわりに

エラーの切り分けが難しいときは、認証周りも含めて確認しようと思いました。

3級 テクニカルライティング試験[TW]を受けてきました

はじめに

以前から文章に対する苦手意識がありました。

分かりやすく誤解されにくい文章を書くには?レビューで指摘したあの件、合っていたのかな?などなど・・。

何かのタイミングで体系的にテクニカルライティングを学んで見たいと思っていて、気になっていた「3級 テクニカルライティング試験[TW]」を本日受験してきました。

jtca.org

この記事では、やってきたことや、当日の感想などをまとめます。

(結果発表はまだです)

試験を知る

まずは、試験の説明ページをよく見て、試験の範囲や形式を確認しました。

例題でレベル感を確認して、いけなくもないかな・・・と思って受験することにしました。

想定する受験対象者として「製品の設計に関わるエンジニア」もあるので、親和性は高いと思います。

他にも、受験された方の記事を拝見しました。大変参考になりました。

勉強方法

書籍

現状は「日本語スタイルガイド(第3版)」がバイブル(試験対策としてはこの本の主張が正解)とのことなので、これを読み込みました。

jtca.org

練習問題もあるので何回かやりました。回答に解説が書いてあると助かるのですが、載っていません・・。

こちらの書籍、試験対策としてだけでなく、とても役立つ内容でした。「よくやってしまうやつだ」「そう言われてみればそうだな」「なるほど、よく迷うけどそういう使い分けすればいいのか」といった発見がたくさんありました。

例:

  • 動詞に「こと」、「方法」などを付けに安易に名詞化しない(P104)

    • ✗ マウスを使用するという方法もあります。
    • ◯ マウスも使用できます。
  • 複数の修飾語がある場合は、長い修飾語・修飾部から順に記載する(P75)

    • ✗ コンパクトな多くの編集機能を搭載した複合機
    • ◯ 多くの編集機能を搭載したコンパクトな複合機
  • 「に」と「へ」を区別して使う(P78)
    • 「〜に」は、動作目標や到達点
    • 「〜へ」は、方向

P289 には、各分野のウェイトがA〜Dで示されているので、どこに注力すると良さそうかが分かります。優先して身につけたい分野と同じだったので良かったです。

ちなみに第4版は制作中のようです。

ウェビナー

一般財団法人テクニカルコミュニケーター協会が主催している、試験対策ウェビナーも参加しました。

日本語スタイルガイドをベースにしたポイントのおさらいや、練習問題の提供などがありました。

受験日当日

試験の形式は、選択問題が50分、休憩を挟んで記述問題が50分です。

総じて「時間がない」という印象でした。途中で何度か、これはだめかも知れないと思いました。

選択問題は以下の順番で解いていきました。

  1. すぐ解ける問題
  2. 少し考えれば解ける問題
  3. ほぼ当てずっぽうになりそうな問題

記述問題は、問題を解く前にペース配分(この問題を何時何分に始めれば順調か)を書いてから始めました。

こちらもやはり、特に時間がかかる問題は一旦とばしました。

結果としてはかなりギリギリでした。解答欄はすべて埋めましたが、もう15分くらい確認に時間が欲しかったです。

ひとことでいうと舐めていました。レベル感だけで判断してはいけませんね。慣れていないと問題をペースよくさばけていけません。。

(完全に余談ですが、お昼に入ったラーメン屋さんでASIAN KUNG-FU GENERATION の「リライト」が流れたのが面白かったです。リライト作業が求められるので)

感想

当日は思いの外あせって、疲れてしまいました。

ですが、勉強の段階で得られたものは大きかったです。

迷っていた書き方の判断ができるようになったり、なんとなく書き分けていた根拠が得られたり、自分の癖がわかったり。

合否はまだわかりませんが、良いきっかけになりました。

JANOG53 Meeting アーカイブ視聴レポート

はじめに

2024/01/17-19 に福岡県福岡市の博多国際展示場&カンファレンスセンターで JANOG53 Meeting が開催されました。

現地は私のチームの他の人に行ってもらいました。また、ストリーミングもなしということでしたので、アーカイブが公開(ありがとうざいます!)されてから視聴しました。

現地参加者は3000人を超えて、大盛りあがりだったようですね。すごい!

本記事では、アンケート締め切り前に視聴したいくつかのプログラムや、全体的な所感についてまとめます。

なお、各プログラムの詳細ページから資料や、アーカイブ動画が見れます(一部アーカイブなし)。アーカイブ動画は 2024/02/29 13:00 まで の公開です。

www.janog.gr.jp

Day1

海外で日本のやり方が通用しないの、なぁぜなぁぜ? 〜東南アジアでのインターネットインフラを構築の実例から、グローバルでのオペレータ交流を考える〜

www.janog.gr.jp

www.youtube.com

立松さんパート

BBIX のフィリピン展開にあたって、実際の経験からくるリアルなお話がたくさん聞けました。大きく分けると、文化の違いと物理的な事情からるくるように感じました。

いわゆる「日本品質」という考えに縛られずに、国によって求められる QCD のバランスをしっかり考える必要があるようでした。

物理的な事情でいうと、フィリピンでは、車両ナンバーの末尾によって走行できる日が規制されているそうです。交通という物理インフラの固有の事情は様々な場面に影響しそうですね。基本的に渋滞対策だそうです。他にも、現地での作業で機材が予定通りに届かないというトラブルなどでも苦労されたそうです。

これらの違いは一見、海外が変わってるようにも見えますが、逆に海外からると日本が変わっているという見方もあるように思います。立松さんパートにあった、なぜそうなってるのかを考えて、よく理解することが大切だという点が印象的でした。

私の場合、つい言語の壁がまっさきに思い浮かびましたが、それだけではないのですね。

また、SNS投稿禁止のパートなので内容の言及は避けますが、発表冒頭のアイスブレイクパートが大変興味深かったです。

冨樫さんパート

ジャカルタの JKT-IX の成長過程のお話でした。こちらのパートは、対人、コミュニケーション、周りの経験談がメインでした。

印象的だったのが、めぐりめぐって分かるJANOGの良さの話でした。

なんとなくの言葉の定義でコミュニケーションを取って問題になることがあるため、その話をIDNOGで問題定義しようと思っても、スポンサー枠もあってか、枠が空いてないという事情で発表できなかったそうです。一方で、JANOGは、自由公募で審査通過のみオペレーターが発表でき、この制度は素晴らしいというお話でした。こういうのも地域によって違うものですね。

お二方のパートを通じて新鮮なお話が聞け、品質や価値の捉え方について考えるきっかけになりました。

Day3

BIGLOBE AS2518をまるごと仮想環境へ”コピー”してみた

www.janog.gr.jp

www.youtube.com

自動化の文脈でも、検証環境がなかったり環境差分がったりというのは課題になりがちなので、以前から興味があるトピックでした。また、習熟が難しい構成ほど、習熟するための環境を用意することも難しい、というジレンマがあるようにも思います。タイトルに有るように、確かに ”コピー” ができたらよいなと思いました。

思うところまでは簡単にできますが、実際にやってみた、というところが今回のプログラムの貴重なところでした。一定の効果が見られた一方で、他ベンダー対応、インターフェース名の差分などの課題も出てきたようです。

どこまで頑張るか、どこまで例外を認めるかという話も難しいですね・・

NETCON Wrap-up

www.janog.gr.jp

www.youtube.com

定番化してきている、ネットワークエンジニアのためのコンテスト NETCON。ふりかえりと表彰式的なプログラムです。

参加者の 45.3% が 8時間以上 NETCON に取り組んだというアンケート結果があって驚きました。ものすごい熱意です・・。

優勝された方!

NETCONは環境に結構なお金(100万円くらい)がお金がかかっているという話もあって、資金的な課題があるようです。スポンサーなどの形式で資金的な援助があるとよいのでしょうか。

JANOG update

www.janog.gr.jp

www.youtube.com

本会議参加登録者数 3,028名。オンラインなしでもこの人数、いやぁすごいですね・・。

また、JANOG 45 から会長を努められていた吉野さんが会長を辞め、運営員会からも引退されるそうです。JANOG 45 というと 2020年1月開催。コロナ禍に突入する時期から今までということで、とても大変な時期だったと思います。お疲れ様でした。

最後のごあいさつのところで、ご自身のリーダーシップのスタイルを語られているところが印象的でした。自分は前に出るタイプではないが、そういうのでも良いというのが不思議で、すごく幸せな環境、と。

新しい会長は宮坂さん。よろしくおねがします!

他のアーカイブ視聴予定

本記事では、アンケートの締め切り(2024/02/04 23:59 まで)までに、アーカイブ視聴したプログラムのみ取り上げました。

他にも興味深いプログラムがあるため、アーカイブが公開されているうち(2024/02/29 13:00まで)に視聴しようと思います。主に以下のプログラムを中心に視聴予定です。

以下、アーカイブはありませんが、資料は拝見したいと思います。

プログラム以外

今回の JANOG 自体で感じたことなどです。

Slack のプログラムごとのチャンネル

これまでは会場の部屋ごとにチャンネルが用意されていました。

今回は、#janog53-インフラ運用ツール開発組織を1から組織した話 のようにプログラムごとにチャンネルが用意されていました。

私のようにアーカイブで見る場合、Slackを見返しやすくて便利に感じました。

インターネット体験会

すごい良い企画だなーとおもいました。物理の作業を体験できるのも貴重な機会だと思います。

www.janog.gr.jp

オンラインの扱いの変化

前回はストリーミングはあっても音声による質疑はできない仕組みでした(Slackは可)。今回はストリーミング自体がありませんでした。

申込時画面にもオンライン参加の選択肢はありませんでした。そのため、広島の JANOG 41での参加以降、初めて申し込みをしないで当日を迎えました。

ここ数年はコロナ禍の影響で、例外的にオンラインで参加しやすい体制を作っていただいていたという認識です。実際に少し前は、オンラインで質問やコメントをさせていただきました。

あまり詳細な経緯は追えていませんが、状況に合わせて変化していくものだと思っています。ハイブリッドも大変のようですからね。運営の方の判断を尊重したいと思います。

おわりに

今回は参加できず、アーカイブ視聴のみとなりましたが、現地が盛り上がっていたようで嬉しく感じました。登壇者、スタッフ、スポンサーのみなさまありがとうございました!

次回 JANOG54 Meeting は 2024年7月に奈良県奈良市で開催予定とのことです。その次が京都なので近畿が続きますね。

参考

show int さんの関連動画

www.youtube.com

www.youtube.com

togetter

私と JANOG のこれまで

[Ansible] 「つまずき Ansible 【Part38】ネットワークモジュールを VS Code でデバッグしたい」ふりかえり

はじめに

2024/02/04 に、「つまずき Ansible【Part38】ネットワークモジュールを VS Codeデバッグしたい」という配信をしました。

tekunabe.connpass.com

cisco.ios コレクションのモジュールのような、ネットワーク機器に接続して操作するとき、Playbook で指定したオプションがどのように処理されるのか、を知りたいときがあって、VS Code でステップ実行とかできたらいいなーと思っていました。

あくまでも Playbook を起点にデバッグしたかったです。

いろいろ試行錯誤した結果できるようになり、ブログよりもデモ中心にお見せしたほうが伝わりやすいと思い、久々に配信をしました。


動画

youtu.be

前提条件

今回の方法が通用するのは、わかっている範囲でいくつか条件があります。

  • ネットワークモジュールであること
    • つまり、コントロールノードでモジュールのコードが動作する
  • Direct Execution (import_modules) が有効であること
    • ansible.netcommon コレクション 3.0.0 からデフォルトで有効
    • つまり、コントロールノードで「圧縮→コピー→解凍」というフェーズを介さずにモジュールのコードが動作する

また、私の環境ではまだ macOS でしかできていません。Remote SSH で接続した先の Linux ではうまくブレークポイントを有効にできませんでした(類似事象 issue)。

([2024/02/27 追記] issue がクローズされ、参考ドキュメトがアップされていました)

仕込み

デバッガの定義ファイルである .vscode/launch.json には以下の定義をしてあります。

今回は、ansible もコレクションも ${workspaceFolder}/.venv にインストールしています。

programで、そのなかの ansible-playbook を指定しているのが一番のポイントです。

{
  // IntelliSense を使用して利用可能な属性を学べます。
  // 既存の属性の説明をホバーして表示します。
  // 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
  "version": "0.2.0",
  "configurations": [
    {
      "name": "ansible-playbook: 現在のファイル",
      "type": "debugpy",
      "request": "launch",
      "console": "integratedTerminal",
      "program": "${workspaceFolder}/.venv/bin/ansible-playbook",   // ポイント
      "args": [
        "${file}",   // 開いているファイル
        "-i",
        "${workspaceFolder}/inventory.yml",    // イベントリファイル
        "-vvvvv"   // お好み
      ],
      "env": {
        // "PYTHONPATH": "${workspaceFolder}/.venv/lib/python3.11/site-packages/", // 試行錯誤の残骸
        // "ANSIBLE_COLLECTIONS_PATHS": "hogehoge",  // 必要に応じて
        "ANSIBLE_PERSISTENT_CONNECT_TIMEOUT": "0" // 必要に応じて(デバッグ中に接続断しないように)
      },
      "justMyCode": false, // モジュールのコードにブレークポイントを張るため
      // "subProcess": false, // 試行錯誤の残骸
    }
  ]
}

cisco.ios.ios_command モジュールのデバッグ

以下のような、show コマンドを実行する Playbook をデバッグします。

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

  tasks:
    - name: Test ios
      cisco.ios.ios_command:
        commands:
          - show interfaces

動かしたいファイルを開いている状態で、統合ターミナルではなく 「実行とデバッグ」経由で、launch.json で定義した ansible-playbook: 現在のファイル" を選択します。

デバッガの起動

すると、あらかじめ設定したブレークポイントのところで止まってくれます。

モジュール内部のブレークポイントで止まっている

少し進めると、Playbook で指定した show コマンドが入っていることがわかります。

show interfaces

変数の値は参照だけでなく変更もできます。この状態で show ip route にコマンドを書き換えて処理を実行すると、show ip route が実行されます。

show ip route に変更

cisco.ios.ios_interfaces モジュールのデバッグ

続いて、インターフェースの基本設定をする cisco.ios.ios_interfaces モジュールのデバッグを試します。

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

  tasks:
    - name: Configure interface
      cisco.ios.ios_interfaces:
        config:
          - name: GigabitEthernet0/0
            description: sakana

今回は、モジュール本体から呼ばれている別のファイルのところにブレークポイントを設定しました。wantd という変数に、Playbook で指定した、こうなってほしいという設定値が入っているのがわかります。

ステップ実行中

一方 haved の中には、機器から取得したインターフェースの今の設定が入っているのがわかります。

haved の中身

今度はちょっと変わった例として、以下のような変なインターフェースの名前を Playbookで指定してデバッグします。

          - name: Giggegegegeggegerrjii0/0

処理を追っていくと、normalize_interface で、インターフェースの名前のノーマライズをしていることがわかります。ここでは、小文字に変換したうえで gi から始まれば、GigabitEthernet として扱う、ということがわかります。

github.com

ノーマライズ判定

おわりに

コードを読む力があれば、デバッグしなくても処理が理解できると思うのですが、私はこのようにステップ実行して見れると非常にありがたいです。

配信方法を急遽 YouTube Live から Zoom に切り替えたため、参加者の皆様にはお手数おかけしました・・。 それでもご視聴いただいた皆さん、ありがとうございました!

参考

VS Code の基本やデバッグについては、最近発売された「改訂新版 Visual Studio Code実践ガイド」がおすすめです。いろいろと新しい機能についても説明されています。