てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] 特定バージョンの collection をインストールするには

基本コマンド

collection をインストールするコマンドは ansible-galaxy collection install です。

たとえば、cisco.ios であれば以下のとおりです。

ansible-galaxy collection install cisco.ios

この場合、最新の安定版リリースがインストールされます。

古いバージョンや、バージョン番号に dev がつくような開発版をインストールするにはバージョン指定が必要です。

cisco.ios を例にして、2つの方法をご紹介します。


■ 方法1: コマンドラインで バージョン指定する

手軽な方法です。

バージョン 0.0.1 をインストールする場合

ansible-galaxy collection install cisco.ios:0.0.1

開発バージョン 0.0.3-dev78 をインストールする場合

ansible-galaxy collection install cisco.ios:==0.0.3-dev78 


■ 方法2: requirements.yml でバージョン指定する

requirements.yml という定義ファイルに collection 名やバージョンを指定して読み込む方法です。

開発バージョン 0.0.3-dev78 をインストールする場合

  • requirements.yml
collections:
  - name: cisco.ios
    version: 0.0.3-dev78

コマンド

ansible-galaxy collection install -r requirements.yml


余談

雰囲気で pip コマンドのように cisco.ios==0.0.1 と指定してうまく行かず、調べました。 : が必要なのですね。

参考

docs.ansible.com

AWS 上の Cisco CSR1000V インスタンスにユーザーデータを指定する

はじめに

AWS で EC2 インスタンス起動時にスクリプト実行させるユーザーデータという機能があります。

サーバーが対象であれば、普通にスクリプトを書くようにコマンドを羅列すればよいわけですが、仮想ルーターなどの仮想アプライアンスの場合は、個別の指定方法があるようです。

ここでは、Cisco CSR1000V のインスタンス作成時にユーザーデータを指定する方法を試します。

インスタンス作成

Maketplace で Cisco CSR1000V を選択、インスタンスタイプを選択後「インスタンスの詳細の設定」をクリックします(確認と作成ではなく)。

f:id:akira6592:20200519172936p:plain
インスタンスタイプの選択

続いて「インスタンスの詳細の設定」画面の下の方のユーザーデータ欄にユーザーデータを入力します。

f:id:akira6592:20200519172958p:plain
ユーザーデータ入力欄

今回は、Cisco 公式ドキュメントの書き方に従って以下を入力します。

hostname="sakana"
ios-config-1="username operator privilege 1 password testpass99"
ios-config-2="username admin privilege 15 password testpass99"

ホスト名の設定と、コンフィグを2行指定しています。 デフォルトでは、ec2-user というユーザーのみなので、もう2つユーザーを追加します。

その後、通常通りインスタンス作成を進めます。

確認

とりえず、デフォルトの ec2-user でログインします。

$ ssh ec2-user@IPアドレス -i hogehoge.pem

sakana#

ユーザーデータで指定したとおり、ホスト名が sakana になりました。

一旦ログアウトして、追加したユーザーでもログインできるか確認します。

  • ユーザー: admin
$ ssh admin@IPアドレス
Password:   # 指定したパスワードを入力


sakana#
sakana#
sakana#exit
  • ユーザー: operator
$ ssh operator@IPアドレス
Password:   # 指定したパスワードを入力


sakana>
sakana>

無事にログインできました。

おわりに

この手の仮想アプライアンスはユーザーデータを指定できないと思っていたのですが、ちゃんと調べたやり方がありました。 調べてみるものですね。

www.cisco.com

[Ansible] 変数優先順位の「20. role (and include_role) params」とは何なのか

はじめに

Ansible は、様々な場所に変数を定義できます。便利な半面、優先順位がどうだったか混乱してしまうこともあります。 調べたいときに確認するのが、以下の公式ドキュメントのページです。

docs.ansible.com

この中で、20. role (and include_role) params という、割と強めな定義方法が何なのか分かりませんでした。

以下のブログにもあるように、同じように感じてるかがいらっしゃるようです。

zaki-hmkc.hatenablog.com

ちゃんと調べてみると、以下の記事が参考になりました。 qiita.com

---
- name: "test ansible var precedence"
  hosts: all
# ...(略)..
  roles:
    - role: test_role
      var_test20: "This is 'role (and include_role) params'"

このように、roles ディレクティブを利用した際に、role と同じレベル定義した変数のことのようです。

この記事では、一応自分でも検証してみます。


検証

優先順位をあらためて確認すると、20. role (and include_role) params19. set_facts / registered vars より強いようです。

19. set_facts / registered vars
20. role (and include_role) params
21. include params
22. extra vars (always win precedence)

なので、set_fact より優先されることをもって確認したいと思います。

ファイル構成

test.yml から testrole ロールを呼び出す構成です。

.
├── roles
│   └── testrole
│       └── tasks
│           └── main.yml
└── test.yml
  • test.yml
---
- hosts: localhost
  gather_facts: false

  roles:
    - role: testrole
      vars:
        msg: I'm in roles vars  # 似て非なる定義(どれだろう・・優先度は低め)
      msg: I'm in roles param   # これが 20. role (and include_role) params のはず
  • roles/testrole/tasks/main.yml
---
- name: set_fact
  set_fact: 
    msg: "I'm in tasks/main set_fact" # 19. set_facts / registered vars
    
- name: debug
  debug:
    msg: "{{ msg }}"

実行

Playbook を実行します。

$ ansible-playbook -i localhost, test.yml 

PLAY [localhost] *************************************************************************************************

TASK [testrole : set_fact] ***************************************************************************************
ok: [localhost]

TASK [testrole : debug] ******************************************************************************************
ok: [localhost] => {
    "msg": "I'm in roles param"
}

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

I'm in roles param が表示されました。set_fact より優先されたことが分かりました。

補足

さすがに 22. extra vars (always win precedence) には負けます。

$ ansible-playbook -i localhost, test.yml -e msg="extra_vars"

PLAY [localhost] *****************************************************************************************************

TASK [testrole : set_fact] *******************************************************************************************
ok: [localhost]

TASK [testrole : debug] **********************************************************************************************
ok: [localhost] => {
    "msg": "extra_vars"
}

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


おわりに

混乱のもとになるので、ある程度定義場所は制限したほうが良いと思います。

[Ansible/AWX] AWX コマンドで git プロジェクトを更新する

はじめに

先日以下のツイートを拝見しました。煩わしさ同感です。

その後、以下の記事が公開され、GitLab 側から AWX の API を叩く方法が紹介されていました。

https://nnstt1.hatenablog.com/entry/2020/05/17/224049

GitLab に Playbook を push すると、自動で AWS 側のプロジェクトが更新されるので、実施漏れもなく良いと思いました。

一方で「そこまで仕込む程でもないけど、とにかく画面上で操作するのが手間」というレベル感の場合のあるかと思います。

この記事では、awx コマンドでプロジェクトを更新する方法(awx project update プロジェクト名)を紹介します。


awx コマンドのインストールと設定

インストールや認証情報の設定などは以下の記事を参照してください。

tekunabe.hatenablog.jp


動作検証

実際に試してみます。

Playbook の追加

まずリポジトリ上(今回は GitHub)に新しく Playbook を追加します。

ここでは show2.yml とします。

f:id:akira6592:20200518082122p:plain
show2.yml の追加

この時点では、該当プロジェクトを使用するジョブテンプレートでは、show2.yml は選択できません。

f:id:akira6592:20200518082245p:plain
更新前なのでまだ show2.yml を選択できない

awx コマンドでプロジェクト更新

ここで、awx コマンドでプロジェクト更新します。

書式は、awx project update プロジェクト名 です。

今回の該当のプロジェクト名は pj_tower-sample-nw です。

$ awx project update pj_tower-sample-nw
{
     "project_update": 1239,
     "id": 1239,
     "type": "project_update",
     "url": "/api/v2/project_updates/1239/",
     "summary_fields": {
          "organization": {
               "id": 2,
               "name": "test_org",
               "description": "test organization"
          },
          "project": {
               "id": 13,
               "name": "pj_tower-sample-nw",
               "description": "tower-sample-nw",
               "status": "pending",
               "scm_type": "git"
          },
          "unified_job_template": {
               "id": 13,
               "name": "pj_tower-sample-nw",
               "description": "tower-sample-nw",
               "unified_job_type": "project_update"
          },
          "created_by": {
               "id": 1,
               "username": "admin",
               "first_name": "",
               "last_name": ""
          },
          "modified_by": {
               "id": 1,
               "username": "admin",
               "first_name": "",
               "last_name": ""
          },
          "user_capabilities": {
               "delete": true,
               "start": true
          }
     },
     "created": "2020-05-17T23:23:07.364032Z",
     "modified": "2020-05-17T23:23:07.400366Z",
     "name": "pj_tower-sample-nw",
     "description": "tower-sample-nw",
     "local_path": "_13__pj_tower_sample_nw",
     "scm_type": "git",
     "scm_url": "https://github.com/akira6592/tower-sample-nw.git",
     "scm_branch": "master",
     "scm_refspec": "",
     "scm_clean": true,
     "scm_delete_on_update": true,
     "credential": null,
     "timeout": 0,
     "scm_revision": "",
     "unified_job_template": 13,
     "launch_type": "manual",
     "status": "pending",
     "failed": false,
     "started": null,
     "finished": null,
     "canceled_on": null,
     "elapsed": 0.0,
     "job_args": "",
     "job_cwd": "",
     "job_env": {},
     "job_explanation": "",
     "execution_node": "",
     "result_traceback": "",
     "event_processing_finished": false,
     "project": 13,
     "job_type": "check",
     "job_tags": "update_git,delete"
}

なお、 -f human` オプションを追加すると、出力がすっきりします。

$ awx project update pj_tower-sample-nw -f human
id   name               
==== ================== 
1240 pj_tower-sample-nw 

確認

もう一度、該当プロジェクトを使用するジョブテンプレートを確認すると、show2.yml が選択できるようになりました。

f:id:akira6592:20200518082437p:plain
show2.yml が選択できるようになった


おわりに

Playbook の開発段階などでは、繰り返し発生する作業は、GUI よりコマンドのほうが便利かと思います。

curlAPI 叩くのでもよいかもしれませんが、API だと対象オブジェクト(プロジェクトなど)を內部で管理している id で指定する必要があります。awx コマンドでは名前で指定できるので便利です。

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

各社実装