てくなべ (tekunabe)

ansible / network automation / 学習メモ

VS Code でうっかり作業中のターミナルを終了しないための設定("terminal.integrated.confirmOnExit": "always")

はじめに

VS Code には統合ターミナルという機能があり、一画面の中で何かを書いたりターミナル作業したりできて便利です。私もかなりの頻度で利用します。

ただ、ワークスペースの切り替えたりするときに、うっかり作業中のターミナルを終了されてしまい「あれ、さっき実行中だったやつどうなったんだろう・・」となったり、やらかしてしまうことがありました。

先日たまたま、うっかり終了しないために、確認をとる設定("terminal.integrated.confirmOnExit": true)が分かったのでまとめます。

2022/02/26 追記

どのバージョンからかはわかりませんが(1.59?)、この設定項目が取りうる値の選択肢が変わったようです。

おそらく"terminal.integrated.confirmOnExit": "always" が狙った動作なので "always" にしています。

公式ドキュメントの Default settings から、説明文含めて引用します。

  // Controls whether to confirm when the window closes if there are active terminal sessions.
  //  - never: Never confirm.
  //  - always: Always confirm if there are terminals.
  //  - hasChildProcesses: Confirm if there are any terminals that have child processes.
  "terminal.integrated.confirmOnExit": "never",

  // Controls whether to confirm killing terminals when they have child processes. When set to editor, terminals in the editor area will be marked as changed when they have child processes. Note that child process detection may not work well for shells like Git Bash which don't run their processes as child processes of the shell.
  //  - never: Never confirm.
  //  - editor: Confirm if the terminal is in the editor.
  //  - panel: Confirm if the terminal is in the panel.
  //  - always: Confirm if the terminal is either in the editor or panel.
  "terminal.integrated.confirmOnKill": "editor",

設定

設定画面を開きます。

f:id:akira6592:20200517105001p:plain
設定画面を開く

設定を有効にしたい範囲(ユーザー/ワークスペース)を選択します。

設定項目 terminal.integrated.confirmOnExit を探してチェックを入れて有効にします。

f:id:akira6592:20200517105447p:plain
terminal.integrated.confirmOnExit を有効にする

setting,json に書く場合は、以下のようにします。(2022/02/26 true から "always" に修正)

    "terminal.integrated.confirmOnExit": "always",

以上で設定が有効になりました。VS Code の再起動は不要です。

設定確認

どのようになるか確認します。

以下のようにターミナルを開いている状態でで、ウィンドウを閉じます。

f:id:akira6592:20200517110013p:plain
ウィンドウを閉じる

すると、以下のように、確認ダイアログが表示されます。ここでキャンセルするとうっかりターミナルを終了せずにすみます。デフォルトではこの確認ダイアログが表示されずに終了します。

f:id:akira6592:20200517110137p:plain
確認ダイアログ

地味に便利なのが、閉じたけど生きてるターミナルがあるときも確認してくれる点です。

f:id:akira6592:20200517111152p:plain
助かる

おわりに

個人的にはデフォルトで有効でも良いのでは、という感覚の設定です。 もしうっかり終了してお困りの経験がある方お試しください。

[Ansible] つまずきながら進める Ansible 【Part1】ふりかえり

はじめに

2020/05/16 に、YouTube Live でつまずいきながら進める Ansible 【Part1】という配信をしました。 実際に作業しながらエラーと戦ってすすめるものです。

とりあえず目指したのは以下のアンケートで一番多かった、show コマンドの結果をファイルで保存する Playbook です。

Part 1 では、Ansible のインストールからはじめました。 環境は、CentOS 8.0 を利用しました。

つまずいたエラーと原因、対処をふりかえります。

動画

www.youtube.com


■ 検証環境 VM への SSH 接続 (Ansible 以前の以前の問題・・)

VS Code Remote - SSH で接続で fingerprint のエラーになる

原因

VM ごとを消して再作成したら fingerprint が変更されて、known_hosts に記録されていたものと不一致になっていたため。

対処

known_hosts を削除した(乱暴)。

■ venv の作成 と ansible のインストール

python -m venv ansiblepython コマンドがないというエラーになる

原因

RHEL8/CentOS 8 でシステムに組み込まれてるのは /usr/libexec/platform-python であって、python コマンドは利用できないため

対策

dnf install python3 で別途インストール。(一応、システムに組み込みのものとは別にする)

■ Playbook 実行

paramiko is not installed: No module named 'paramiko' というエラーになる

原因

ネットワーク機器に SSH 接続するときに必要なライブラリ paramiko がインストールされていないなめ

詳細: [Ansible] エラー「paramiko is not installed: No module named 'paramiko'」の原因と対策 - てくなべ (tekunabe)

対処

pip install paramiko でインストール

fingerprint エラーになる

原因

初回接続の相手であり、known_hosts に載っていないため

対処

ansible.cfg に以下のように設定する。(検証環境のため、簡易的な対処)

[defaults]
host_key_checking=False

設定が意図通り変更されたかどうかは ansible-config dump --only-changed で確認する。

詳細: [Ansible] デフォルトから変更されている設定項目を確認する方法(ansible-config dump --only-changed) - てくなべ (tekunabe)

ios_command モジュール実行時に unsupported parameters というエラーになる

    - name: test
      ios_command:
        command:
          - show ip route

というタスクに対して以下のエラー。

"Unsupported parameters for (ios_command) module: command Supported parameters include: auth_pass, authorize, commands, host, interval, match, password, port, provider, retries, ssh_keyfile, timeout, username, wait_for"

原因

オプション名は command ではなく、commands が正しい

対処

以下に修正

    - name: test
      ios_command:
        commands:
          - show ip route


Part 2にむけて

いきなり VM への接続で予想外につまずいてあせりました・・。

show ip route コマンドの実行結果を、ファイルに保存しましたが、以下のように、改行もされず、余計なものが入っている状態でした。これをもう少し欲しい状態にします。

{"changed": false, "stdout": ["Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP\n       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area \n       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2\n       E1 - OSPF external type 1, E2 - OSPF external type 2\n       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2\n       ia - IS-IS inter area, * - candidate default, U - per-user static route\n       o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP\n       a - application route\n       + - replicated route, % - next hop override, p - overrides from PfR\n\nGateway of last resort is 192.168.1.1 to network 0.0.0.0\n\nS*    0.0.0.0/0 [1/0] via 192.168.1.1\n      10.0.0.0/8 is variably subnetted, 4 subnets, 2 masks\nC        10.0.0.0/24 is directly connected, GigabitEthernet0/3\nL        10.0.0.1/32 is directly connected, GigabitEthernet0/3\nC        10.255.255.1/32 is directly connected, Loopback0\nO        10.255.255.2/32 [110/2] via 10.0.0.2, 05:24:25, GigabitEthernet0/3\n      172.16.0.0/16 is variably subnetted, 2 subnets, 2 masks\nC        172.16.1.0/24 is directly connected, GigabitEthernet0/1\nL        172.16.1.253/32 is directly connected, GigabitEthernet0/1\n      192.168.1.0/24 is variably subnetted, 2 subnets, 2 masks\nC        192.168.1.0/24 is directly connected, GigabitEthernet0/0\nL        192.168.1.11/32 is directly connected, GigabitEthernet0/0"], "stdout_lines": [["Codes: L - local, C - connected, S - static, R - RIP, M - mobile, B - BGP", "       D - EIGRP, EX - EIGRP external, O - OSPF, IA - OSPF inter area ", "       N1 - OSPF NSSA external type 1, N2 - OSPF NSSA external type 2", "       E1 - OSPF external type 1, E2 - OSPF external type 2", "       i - IS-IS, su - IS-IS summary, L1 - IS-IS level-1, L2 - IS-IS level-2", "       ia - IS-IS inter area, * - candidate default, U - per-user static route", "       o - ODR, P - periodic downloaded static route, H - NHRP, l - LISP", "       a - application route", "       + - replicated route, % - next hop override, p - overrides from PfR", "", "Gateway of last resort is 192.168.1.1 to network 0.0.0.0", "", "S*    0.0.0.0/0 [1/0] via 192.168.1.1", "      10.0.0.0/8 is variably subnetted, 4 subnets, 2 masks", "C        10.0.0.0/24 is directly connected, GigabitEthernet0/3", "L        10.0.0.1/32 is directly connected, GigabitEthernet0/3", "C        10.255.255.1/32 is directly connected, Loopback0", "O        10.255.255.2/32 [110/2] via 10.0.0.2, 05:24:25, GigabitEthernet0/3", "      172.16.0.0/16 is variably subnetted, 2 subnets, 2 masks", "C        172.16.1.0/24 is directly connected, GigabitEthernet0/1", "L        172.16.1.253/32 is directly connected, GigabitEthernet0/1", "      192.168.1.0/24 is variably subnetted, 2 subnets, 2 masks", "C        192.168.1.0/24 is directly connected, GigabitEthernet0/0", "L        192.168.1.11/32 is directly connected, GigabitEthernet0/0"]], "failed": false}

BGP Unnumbered で遊んでみた

はじめに

2020/05/09 に、YouTube Live で「BGP Unnumbered で遊んでみた」というお話させていただきました。

BGP Unnumbered は インターフェースや BGP ネイバーの IPアドレス設定が不要な BGP の設定方法です。 IPv6RFC 5549 の仕組みが活用されています。

初めて知ったのは、JANOG43 の「LINEのネットワークをゼロから再設計した話」を聞いたときでした。その後、Cloud Native Data Center Networking という書籍(ここから無料ダウンロードも可能)で Cumulus Linux での実装が掲載されるのを見て、おもしろそうだったので、ためしたうえで、紹介させていただきました。

こちらのブログにも各種リソースを掲載します。

動画

www.youtube.com

補足

UPDATE メッセージで、 IPv6ネクストホップとした、IPv4 経路が広報されてきたときのパケットです。

f:id:akira6592:20200516102025p:plain
UPDATE メッセージ

資料

www.slideshare.net

デモ環境構築 Vagrantfile

github.com

f:id:akira6592:20200516092545p:plain:w300
構成

質疑応答

後日、社内でも同じ発表をしたところいくつか質問をもらいました。それに対する回答です。

Q1. (ネイバー間は IPv6 のみだが) IPv6 のトンネルで IPv4 パケットを運ぶ?

トンネルは利用しません。エンドツーエンドの IPv4 パケットは、ネイバー間も普通の IPv4 パケットです。

IPv6 アドレスは、インターフェースへの自動割当、BGP ネイバーの確立、ネクストホップのMACアドレス導出あたりまでしか利用されません。 ネクストホップの MAC アドレスまで分かれば、あとは普通に(もとの IPv4 ヘッダのアドレスのまま)ネクストホップに転送するだけで、トンネリングしません。

以下は、エンドツーエンド(sv02 > sv01 )で ping を実行した際の、途中の leaf01 で取得したパケットキャプチャです。普通の IPv4 のパケットであることが分かります。

f:id:akira6592:20200516091932p:plain
普通の IPv4 パケット

Q2. show ip bgp summary でネイバー名(spine01 など)が見えたがどういう仕組みで取得しているのか、LLDPか何か?

以下は、leaf01 での show ip bgp summary の結果の抜粋です。

Neighbor        V         AS MsgRcvd MsgSent   TblVer  InQ OutQ  Up/Down State/PfxRcd
spine01(swp1)   4      65000     453     455        0    0    0 00:22:22            3
spine02(swp2)   4      65000     453     455        0    0    0 00:22:21            3

ネイバーのホスト名 spine01 が、spine02 が見えてみます。

BGP の OPEN メッセージを調べたところ、Capability として FQDN Capability というものがあり、ここでホスト名が通知されていました。おそらくこちらの値が利用されているのだと思います。

f:id:akira6592:20200516092059p:plain
FQDN Capability

Q3. エンドツーエンドで traceroute したときに途中のホップの ループバックアドレスが見えたが、どういうこと?

こちらの記事の traceroute の項で解説されています。

参考資料

参考資料の最後に掲載した参考資料を再掲します。

本・サイト

RFC

各社実装

CML-P (VIRL2) のインストールと基本機能

はじめに

2020/05/13 に、CML-Personal (VIRL2) のインストールと基本機能について、YouTube Live でお話させていただきました。

CML-Personal は、Cisco 公式のバーチャルラボ環境のソフトウェアで、仮想アプライアンス(.ova)として提供されます。IOSIOS XR、NX-OSなどの各種イメージもセットなので、「中古で買った機器のイメージを吸い上げて・・」といった作業も不要です。

前バージョンの VIRL 1.x よりもだいぶ使い勝手が良くなった感じだったので紹介させていただきました。

こちらのブログにも各種リソースを掲載します。

動画

www.youtube.com

  • 0:00 概要説明
  • 6:10 インストール
  • 8:43 セットアップ
  • 11:25 ラボ設定
  • 17:44 その他機能
    • パケットキャプチャ
    • ラボのダウンロード、インポート、
    • API
    • コンソールサーバー
    • Breakout tool

(音声がいまいちですみません・・。試行錯誤中です)

資料

www.slideshare.net

参考資料

参考資料の最後に掲載した参考資料を再掲します。

公式ドキュメント

説明動画

日本語ブログ

[Ansible] エスケープされた JSON を正しくディクショナリにする from_json フィルター

はじめに

Ansible では、結果が JSON になるタスクを実行すると、(少なくとも表示上は)エスケープされた JSON が返ってくることがあります。

この場合、構造化データのように見えて文字列なので、ディクショナリ(構造化データ)として正しく扱えません。

from_json フィルターをかけると、うまくいきます。

この記事では簡単なサンプルをもとに説明します。

  • 動作確認環境
    • Ansible 2.9.7


エスケープされた JSON とは?

以下は、nclu モジュールを利用して、Cumulus Linux に対して、show bgp summary json コマンドを実行した結果を、debug モジュールで表示した結果です。

msg 内に \ によるエスケープが入っています。JSON のように見えてただの文字列です。

TASK [debug show bgp summary] *************************************************************************
ok: [leaf01] => {
    "msg": {
        "changed": false,
        "failed": false,
        "msg": "{\n    \"ipv4 unicast\": {\n        \"as\": 65011, \n        \"bestPath\": {\n            \"multiPathRelax\": \"true\"\n        }, \n        \"dynamicPeers\": 0, \n        \"peerCount\": 2, \n        \"peerGroupCount\": 1, \n        \"peerGroupMemory\": 64, \n        \"peerMemory\": 42352, 
        ...(略)...
    }
}

このままでは、result.msg['ipv4 unicast'] のように、内部のキーを指定しても、'dict object' has no attribute 'ipv4 unicast' のような、キーの参照エラーになってしまいます。

ちょっとハマりやすいのは、上記例でいうと result.msg を参照したときは、以下のように、いかにも正しい JSON っぽく表示される点です。

TASK [debug show bgp summary] *************************************************************************
ok: [leaf01] => {
    "msg": {
        "ipv4 unicast": {
            "as": 65011,
            "bestPath": {
                "multiPathRelax": "true"
            },
            "dynamicPeers": 0,
            "peerCount": 2,
            ...(略)...

どう見てもディクショナリとして扱えそうですが、{{ result.msg | type_debug }} の結果は AnsibleUnsafeText です。どうして・・。


from_json フィルターでディクショナリに変換

正しくディクショナリとして扱うために、from_json フィルターをかけます。

"{{ result_bgp_summary_raw | from_json }}"

こでれで、JSON、ディクショナリになります。

TASK [debug show bgp summary] *************************************************************************
ok: [leaf01] => {
    "msg": {
        "ipv4 unicast": {
            "as": 65011,
            "bestPath": {
                "multiPathRelax": "true"
            },
            "dynamicPeers": 0,
            "peerCount": 2,
            ...(略)...

"{{ result_bgp_summary_raw.msg | from_json | type_debug }}" の結果は dict です。

ここまでくれば、通常のディクショナリと同じく、特定のキーを参照したりするだけです。

タスク例

    - name: debug show bgp summary
      debug:
        msg: "{{ bgp_summary['ipv4 unicast']['peerCount'] }}"
      vars:
        bgp_summary: "{{ result_bgp_summary_raw.msg | from_json }}"

(キーの指定を .ipv4 unicast ではなく ['ipv4 unicast'] としているのは、今回対象のデータに、たまたまスペース入りのキー名があったためです)

実行例

TASK [debug show bgp summary] *************************************************************************
ok: [leaf01] => {
    "msg": "2"
}


■ おわりに

エスケープされた JSON に、from_json フィルターをかけて、ディクショナリにする方法をご紹介しました。

私だけかもしれませんが、Ansible で構造化データの扱いで悩むことが結構あります。

あるはずのキーが has no attribute となってハマったときは、エスケープされてないか、type_debugの結果はどうなるか、などを確認するのがよさそうです。

[Ansible] nclu モジュールでエラー「Error in pending config. You may want to view `net pending` on this target.」発生時はbecomeを確認

はじめに

Ansible には Cumulus Linux のネットワーク管理コマンドツール nclu を扱う nclu モジュールがあります。

先日、試しに使ってみたところ以下のエラーになりました。

Error in pending config. You may want to view `net pending` on this target.

ピンとこなかったのですが、結果的には become: true のつけ忘れでした。

この記事では、発生したときのPlaybook、実行例、その対策を紹介します。

  • 動作確認環境
    • Ansible 2.9.7

発生の経緯

以下のような Playbook を利用しました。Plyabook 中には登場しませんが、利用するユーザーは vagrant という一般ユーザーです。

この記事ベースで環境を作成

---
- hosts: leaf01
  gather_facts: false

  tasks:
    - name: show bgp summary json
      nclu:
        commands:
          - show bgp summary json
      register: result_bgp_summary_raw

実行結果はこちら。

$ ansible-playbook -i intentory.ini assert_bgp.yml 

PLAY [leaf01] *************************************************************************************************************************

TASK [show bgp summary json] **********************************************************************************************************
fatal: [leaf01]: FAILED! => {"changed": false, "msg": "Error in pending config. You may want to view `net pending` on this target."}

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

対策(become: true 追加)

一般ユーザーで net show コマンドを実行すると

vagrant@leaf01:mgmt:~$ net show interface
ERROR: You do not have permission to execute that command.

のようなエラーになることを思い出したので、権限周りが原因だと思いました。

そこで以下のように become: true を追加したらうまくいきました、

---
- hosts: leaf01
  gather_facts: false
  become: true    # 追加

  tasks:
    - name: show bgp summary json
      nclu:
        commands:
          - show bgp summary json
      register: result_bgp_summary_raw

参考

[2020/05/03 追記]

Cumulus 側で、ユーザーをグループに追加する方法もあるようです。

[Ansible/AWX] 起動したジョブをあとあから awx コマンドでモニターする(monitor サブコマンド)

はじめに

以前の記事で、awx コマンドでジョブの実行を終了までリアルタイムに見届ける --monitor オプションをご紹介しました。

tekunabe.hatenablog.jp

この --monitor オプションは、launch サブコマンドのオプションなので、起動とセットでした。

AWX 11.2.0 では、あらかめ GUIawx コマンドなどで起動したジョブを、あとからモニターできる monitor サブコマンドが追加されました。

この記事では、ジョブテンプレートとワークフロージョブテンプレートの monitor オプションを利用する例をご紹介します。

  • 動作検証環境
    • AWX 11.2.0

■ ジョブテンプレートの monitor

コマンド書式

ジョブテンプレートの実行ジョブのモニターは、以下のコマンド書式です。

awx jobs monitor [ジョブID]

実行例

まず、awx job_templates launch でジョブテンプレートを起動し(--monitor オプションなし)、あとから awx jobs monitor [ジョブID] でモニターします。

ログです。

$awx job_templates launch jt_01_show -f human     # 起動のみ(--monitor なし)
id   name       
==== ========== 
1220 jt_01_show           # ID が表示される
$
$ awx jobs monitor 1220   # 先程起動したワークフロージョブIDを指定してモニター
------Starting Standard Out Stream------  # ここから処理ををって徐々に表示される
SSH password: 

PLAY [ios] *********************************************************************

TASK [show ip route] ***********************************************************
ok: [ios1]

ASK [show ip route] ***********************************************************

...(略)....

ASK [debug ios_facts] *********************************************************
ok: [ios1] => {
    "ansible_facts.net_version": "16.11.01a"
}


LAY RECAP *********************************************************************
ios1                       : ok=4    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

------End of Standard Out Stream--------  # 終了

$
$ awx jobs monitor 1220         # 終了したジョブなので、その旨のメッセージのみ表示
Unable to monitor finished job

(ところどころ、TASKASK のように 1文字目が欠けてるので微妙に気になります)


■ ワークフロージョブテンプレートの monitor

コマンド書式

ワークフロージョブテンプレートの実行ジョブのモニターは、以下のコマンド書式です。

awx workflow_jobs monitor [ジョブID]

実行例

まず、awx workflow_job_templates launch でワークフロージョブテンプレートを起動し(--monitor オプションなし)、あとから awx workflow_jobs monitor [ジョブID] でモニターします。

ログです。

$ awx workflow_job_templates launch  wf_01 -f human   # 起動のみ(--monitor なし)
id   name  
==== ===== 
1208 wf_01    # ID が表示される

$ awx workflow_jobs monitor 1208            # 先程起動したワークフロージョブIDを指定してモニター
------Starting Standard Out Stream------    # ここから処理ををって徐々に表示される
Launching wf_01...
 ↳ 1209 - jt_02_debug successful
 ↳ 1211 - jt_03_debug successful
------End of Standard Out Stream--------    # 終了
$
$ awx workflow_jobs monitor 1208            # 終了したジョブなので、その旨のメッセージのみ表示
Unable to monitor finished job  


おわりに

awx コマンドで、ジョブをあとからモニターできる monitor サブコマンドをご紹介しました。

今回は、awx コマンドで起動して awx コマンドでモニターする例でしたが、GUI で起動して awx コマンドでモニターするおような組み合わせもできます。 シチュエーションに応じて、使い分けできるようになって便利だと感じました。

参考