てくなべ (tekunabe)

ansible / network automation / 学習メモ

Ansible ネットワークモジュールにおける facts の扱い

■ はじめに

Ansible のネットワークモジュールは、通常のモジュールとは facts の扱いが異なります。 この記事では、ネットワークモジュール固有の facts の扱い方についてご紹介します。 想定バージョンは Ansible 2.5.2 です。


■ 通常の facts は ネットワーク機器側ではなく Ansible ホスト側

ios_commandjunos_config などのネットワークモジュールは、Ansible ホスト側で Python スクリプトが実行されます。 そのため、 gather_facts: yes (デフォルト) で取得される facts は、操作対象のネットワーク機器側ではなく、Ansible ホスト側の facts になります。


■ ネットワーク機器側の facts は専用モジュールで取得

ネットワーク機器側のホスト名や、インターフェース情報などの facts を取得するにためには、 ios_facts や junos_facts など、ネットワークプラットフォームごとに用意された専用の *_facts モジュールを利用します。

サンプルPlaybook

Junosの facts を取得するjunos_facts モジュールを利用するサンプルです。

gather_subset オプションを省略した場合は、コンフィグ以外の facts を取得します。

- hosts: junos
  connection: netconf
  gather_facts: no

  tasks:
    - name: facts
      junos_facts:

    - name: debug
      debug:
        msg: "{{ ansible_facts }}"

ここでは、Ansible ホスト側の facts は必要ないとしているので、 gather_facts: no にしています。 また、msg: "{{ ansible_facts }}" と指定しているように、Ansible 2.5 から facts は ansible_facts.* という名前空間配下でも参照可能です

実行結果

(ansible25) [vagrant@centos7 vagrant]$ ansible-playbook -i inventory junos_test.yml --tag=d

PLAY [junos] *************************************************************************************************

TASK [facts] *************************************************************************************************
ok: [172.16.0.1]

TASK [debug] *************************************************************************************************
ok: [172.16.0.1] => {
    "msg": {
        "net_filesystems": [
            "/dev/ad0s1a",
            "devfs",
            "/dev/md0",
            "/cf",
            "devfs",
            "procfs",
            "/dev/bo0s1e",
            "/dev/md1",
            "/cf/var/jail",
            "/cf/var/log",
            "devfs",
            "/dev/md2"
        ],
        "net_gather_subset": [
            "hardware",
            "default",
            "interfaces"
        ],
        "net_has_2RE": false,
        "net_hostname": "vsrx1",
        "net_interfaces": {
            ".local.": {
                "admin-status": "up",
                "macaddress": "Unspecified",
                "mtu": "Unlimited",
                "oper-status": "up",
                "speed": "Unlimited",
                "type": "Loopback"
            },
            "dsc": {
                "admin-status": "up",
                "macaddress": "Unspecified",
                "mtu": "Unlimited",
                "oper-status": "up",
                "speed": "Unspecified",
                "type": "Software-Pseudo"
            },
            "ge-0/0/0": {
                "admin-status": "up",
                "macaddress": "08:00:27:ae:**:**",
                "mtu": "1514",
                "oper-status": "up",
                "speed": "1000mbps",
                "type": null
            },
            "ge-0/0/1": {
                "admin-status": "up",
                "macaddress": "08:00:27:af:**:**",
                "mtu": "1514",
                "oper-status": "up",
                "speed": "1000mbps",
                "type": null
            },
            (略)
            }
        },
        "net_memfree_mb": 76448,
        "net_memtotal_mb": 1031572,
        "net_model": "firefly-perimeter",
        "net_modules": [
            {
                "name": "Midplane"
            },
            {
                "name": "System IO"
            },
            {
                "description": "FIREFLY-PERIMETER RE",
                "name": "Routing Engine"
            },
            {
                "description": "Virtual FPC",
                "name": "FPC 0"
            },
            {
                "name": "Power Supply 0"
            }
        ],
        "net_routing_engines": {
            "null": {
                "cpu_background": "0",
                "cpu_idle": "100",
                "cpu_interrupt": "0",
                "cpu_system": "0",
                "cpu_user": "0",
                "last_reboot_reason": "Router rebooted after a normal shutdown.",
                "load_average_fifteen": "0.00",
                "load_average_five": "0.02",
                "load_average_one": "0.00",
                "memory_control_plane": "594",
                "memory_control_plane_used": "321",
                "memory_control_plane_util": "54",
                "memory_data_plane": "430",
                "memory_data_plane_used": "211",
                "memory_data_plane_util": "49",
                "memory_system_total": "1024",
                "memory_system_total_used": "532",
                "memory_system_total_util": "52",
                "model": "FIREFLY-PERIMETER RE",
                "slot": null,
                "start_time": "2018-04-11 13:23:07 UTC",
                "status": "Testing",
                "up_time": "1 day, 17 hours, 40 minutes, 58 seconds"
            }
        },
        "net_serialnum": "a9039f******",
        "net_version": null
    }
}

PLAY RECAP ***************************************************************************************************
172.16.0.1                 : ok=2    changed=0    unreachable=0    failed=0

(ansible25) [vagrant@centos7 vagrant]$

ホスト名 vsrx1 や、インターフェースの情報などが facts として取得できたことが分かります。


■ 補足

https://www.ansible.com/blog/coming-soon-networking-features-in-ansible-2.5 上記の Ansible 2.5 正式リリース前の公式ブログに、

Fact gathering for network_cli and netconf connection methods are not turned on by default.

という記述がありますが、実際は異なるようです。ネットワークモジュールのベストプラクティスはあくまでも、必要でない限りは、gather_facts: no を指定しておくことのようです。

Ansible 2.5 から facts は ansible_facts.* という名前空間配下でも参照可能

はじめに

Ansible 2.5 から facts は ansible_facts.* という名前空間配下でも参照可能になりました。

  • ansilbe_distribution であれば
    • ansible_facts.distribution でも参照可能
  • ansilbe_nodename であれば
    • ansible_facts.nodename でも参照可能

そのため、ansible_facts を参照すると、配下の facts の一覧を取得できます。

サンプル Playbook

- hosts: webservers
  gather_facts: yes
  
  tasks:
    - name: facts
      debug:      
        msg: "{{ ansible_facts }}"   

実行結果

$ ansible-playbook -i inventory junos_test.yml --tag=d

PLAY [webservers] ***************************************************

TASK [Gathering Facts] *******************************************************
ok: [172.16.0.1]

TASK [facts list] ************************************************************
ok: [172.16.0.1] => {
    "msg": {
        "all_ipv4_addresses": [
            "172.17.0.1",
            "172.16.0.9",
            "10.0.2.15"
        ],
        "all_ipv6_addresses": [
            "fe80::42:75ff:fe85:****",
            "fe80::a00:27ff:fe74:****",
            "fe80::5054:ff:feda:****"
        ],
        "ansible_local": {},
        "apparmor": {
            "status": "disabled"
        },
        "architecture": "x86_64",
        "bios_date": "12/01/2006",
        "bios_version": "VirtualBox",
    
(略)
        "userspace_bits": "64",
        "virtualization_role": "guest",
        "virtualization_type": "virtualbox"
    }
}

PLAY RECAP *****************************************************************
172.16.0.1                 : ok=2    changed=0    unreachable=0    failed=0

まとめ

既存の ansible_ というプレフィックよりも ansible_facts という名前空間で整理されているほうが、まとめて処理がしやすいので使いやすいと感じました。

  • 参考リンク

www.ansible.com

Ansible Network Team によってメンテナンスされているネットワークモジュール一覧

Ansible Network Team によってメンテナンスされているネットワークモジュール一覧は以下のページにまとめられています。

Modules Maintained by the Ansible Network Team — Ansible Documentation

(参考リンク)

なお、サポートされないものも含めたネットワークモジュールは以下のページにまとめられています。

Network modules — Ansible Documentation

Ansible ネットワークモジュールの aggregate オプションによる繰り返し処理の特徴

■ はじめに

Ansible 2.4 から、ネットワークモジュールの一部で、繰り返しを伴う設定を効率的に投入できる aggregate というオプションが利用できるようになりました。 この記事では、既存の with_items による繰り返しとの比較を通じて、動作の紹介をします。 検証環境は Ansible 2.5.2 です。


■ aggregate オプションの利用例

aggregate オプションは以下のような利用の仕方になります。(junos_static_route モジュールでの例)

サンプル

- name: set static route
  junos_static_route:
    aggregate:
      - { address: 172.16.1.0/24, next_hop: 10.0.0.1 }
      - { address: 172.16.2.0/24, next_hop: 10.0.0.2 }
      - { address: 172.16.3.0/24, next_hop: 10.0.0.3 }

雰囲気である程度予想できるかもしれませんが、上記の場合3つのスタティックルートが追加されます。

junos_static_routeモジュールにはもともと、 addressnext_hop などのオプションがあり、それらを繰り返し指定するために、 aggregate オプション配下に指定する形になります。

実行結果

(ansible25) [vagrant@centos7 vagrant]$ ansible-playbook -i inventory junos_test.yml

PLAY [junos] ****************************************************************************

TASK [set static route (aggregate)] *****************************************************
changed: [172.16.0.1]

PLAY RECAP ******************************************************************************
172.16.0.1                 : ok=1    changed=1    unreachable=0    failed=0

(ansible25) [vagrant@centos7 vagrant]$

ポイントは、スタティックルートを追加する処理を3回繰り返すのではなく、1回の処理で完了 している点です。 これは、繰り返し分のコンフィグを生成してから、1つのタスクとしていっぺんにコンフィグ投入するためです。 仮に、特定の1つのスタティックルートにパラメータエラーがあった場合は、3つのスタティックルートとも設定が入りません。

ネットワーク機器側の確認

念のため確認します。

root@vsrx1# show routing-options static | display set
set routing-options static route 172.16.1.0/24 next-hop 10.0.0.1
set routing-options static route 172.16.2.0/24 next-hop 10.0.0.2
set routing-options static route 172.16.3.0/24 next-hop 10.0.0.3

無事に追加されました。


■ aggregate オプションが利用できるモジュール例

一例ですが、以下のようなモジュールで aggregate オプションが利用できます。 公式ドキュメント内に一覧は見当たりませんでしたが、*_config*_commmand のように、コンフィグをそのまま指定するタイプのモジュールではなく、コンフィグのオプションがオプションとして抽象化されたモジュールが対象のようです。


■ ちなみに・・with_items の場合

繰り返し処理というと with_itemsloop(Asnible2.5から利用可)を思い浮かべると思います。先程のサンプルを with_itmes で記載すると以下のようになります。

サンプル

- name: set static route (with_items)
  junos_static_route:
    address: "{{item.address}}"
    next_hop: "{{item.next_hop}}"
  with_items:
    - { address: 172.16.1.0/24, next_hop: 10.0.0.1 }
    - { address: 172.16.2.0/24, next_hop: 10.0.0.2 }
    - { address: 172.16.3.0/24, next_hop: 10.0.0.3 }

実行結果

(ansible25) [vagrant@centos7 vagrant]$ ansible-playbook -i inventory junos_test.yml

PLAY [junos] ****************************************************************************

TASK with_items) ***********************************************************************
changed: [172.16.0.1] => (item={u'next_hop': u'10.0.0.1', u'address': u'172.16.1.0/24'})
changed: [172.16.0.1] => (item={u'next_hop': u'10.0.0.2', u'address': u'172.16.2.0/24'})
changed: [172.16.0.1] => (item={u'next_hop': u'10.0.0.3', u'address': u'172.16.3.0/24'})

PLAY RECAP ******************************************************************************
172.16.0.1                 : ok=1    changed=1    unreachable=0    failed=0

(ansible25) [vagrant@centos7 vagrant]$

おなじみの with_items らしいログとなりました。 仮に、特定の1つのスタティックルートにパラメータエラーがあった場合は、そのスタティックルート以外は設定されます。


■ aggregate と with_items の比較

まとめると以下のようになります。

比較項目 aggregate with_items
利用可能バージョン 2.4以上
利用可能モジュール 一部 すべて
処理速度 早い 遅い
パラメータエラー時 (junos_static_route で確認) 1つも設定されない エラー分のみスキップ


■ まとめ

個人的には aggregate オプションのほうが早いですし、よりフェールファーストらしい挙動になるので、利用できるモジュールの場合は特徴を理解した上で、 aggregate オプションを利用したほうが良いと思いました。


参考資料(公式ブログ)

www.ansible.com

Ansible Night in Tokyo 2018.04 で「Junosモジュールのコネクションタイプの使い分け」という発表をしてきました

■ はじめに

2018/04/26 に開催された Ansible Night in Tokyo 2018.04 で「Junosモジュールのコネクションタイプの使い分け」という発表をさせていただきました。

ansible-users.connpass.com

Ansible 2.5 で、ネットワークモジュール向けに network_clinetconf という2つのコネクションタイプが追加され、Junos モジュールではどちらも使用できます。 今回の発表ではこれらのコネクションタイプの使い分け方をご紹介しました。

この記事では私の発表資料の共有や、他の方の発表資料、ブロガー枠の方の記事の紹介などをまとめます。


■ 資料

私が発表に使用した資料はこちらです。

www.slideshare.net


■ 他の方の資料まとめ

他の方の資料は以下のページにアップされています。

ansible-users.connpass.com

www.slideshare.net

speakerdeck.com

speakerdeck.com

speakerdeck.com

www.slideshare.net


■ ブロガー枠の方のレポート記事

ブロガー枠(一般参加枠より倍率が低く参加しやすい)で参加された方のレポート記事です。 smallpalace.hatenablog.com

heroween.hateblo.jp

tips-reports.blogspot.jp


■ 感想など

来日されていた Red Hat の Sean Cavanaugh さんによる通常セッション「Ansible 2.5 のアップデートとネットワーク自動化」の内容と一部被ってしまうではないかと、内心ハラハラしていたのですが、 結果的には Sean さんの発表の一部を深掘りして日本語でお届けでできた、とかたちになったのでホッとしました。

そしてコメント頂き嬉しかったです。

JANOG41.5 で「もっと気軽に始めるAnsible」という発表をしてきました

■ はじめに

2018/04/20 に開催された JANOG41.5 Interim Meeting で「もっと気軽に始めるAnsible」という発表をさせていただきました。

janog.connpass.com

Ansible はネットワーク機器にも対応しています。YAML形式の定義ファイル(Playbook)を書かずに、もっと気軽に始められる Ad-Hoc な Ansible の使い方をご紹介します。

今回は、Playbook もインベントリファイルも、設定ファイルも作らず、意地でもコマンドで済ませるというポリシーです。

この記事では、発表資料の共有とサンプルコマンドの再掲、感想をまとめます。


■ 資料

発表に使用した資料はこちらです。

speakerdeck.com

■ 動画

Jストリーム様のご協力により発表の動画も公開されました。私の発表は 1:23:20 頃からです。

api01-platform.stream.co.jp

他の方の発表の分も JANOG41.5 connpass イベントページ に掲載されています。

コマンドサンプル

資料中に掲載されているサンプルコマンドをコピペしやすいように、以下に再掲します。

環境準備 (資料P22)

# Ansible のインストール
pip install ansible
# Junosモジュールで必要なpythonモジュールのインストール
pip install ncclient jxmlease

利用例1: コンフィグの取得

  • 準備 (資料P12)
# 実行結果を json にする
export ANSIBLE_STDOUT_CALLBACK=json
# ansible コマンドでも前述の設定を有効にする
export ANSIBLE_LOAD_CALLBACK_PLUGINS=True
# (オプション)接続対象ホストキーがAnsibleホストに未登録の場合は、ホストキーチェックを無効化
export ANSIBLE_HOST_KEY_CHECKING=False
  • 実行 (資料P13)
ansible -i 172.16.0.1, all \
   -m junos_command \
   -a "commands='show configuration'" \
   -c netconf -u root -k \
   -e ansible_network_os=junos \
   | jq -r ".plays[0].tasks[0].hosts[].stdout[0]" > config.txt

利用例2: 参照NTPサーバーの追加

  • 準備
# (オプション)接続対象ホストキーがAnsibleホストに未登録の場合は、ホストキーチェックを無効化
export ANSIBLE_HOST_KEY_CHECKING=False
  • 実行 (資料P16)
ansible -i 172.16.0.1,172.16.0.2 all \
   -m junos_config \
   -a "lines='set system ntp server 172.16.0.123'" \
   -c netconf -u user1 -k \
   -e ansible_network_os=junos

参考資料

資料中に掲載されているリンクをジャンプしやすいように、以下に再掲します。

  • 公式ドキュメント
    • ansible コマンドでネットワークモジュール を使う (Run Your First Network Ansible Command)

Run Your First Command and Playbook — Ansible Documentation


■ togetter まとめ

私の発表時のツイートは P13 の 18:23 あたりからです。

togetter.com


■ 感想など

発表の反応を拝見すると「ワンライナー的な使い方もアリだな」ですとか「Cisco IOSで試してみた」という方々がいらっしゃって嬉しかったです。

ネットワークエンジニアが Ansible を触ってみる入り口の一つとして、今回の発表が参考になったら幸いです。

さて、JANOG は前回のJANOG 41が初参加でした。ネットワーク運用自動化BoF内で発表もさせ頂いたので、2回連続で機会をいただきました。ありがとうございました。

次回 JANOG 42 は、2018/07/11-13 に三重で開催されます。次回も参加する予定です。

www.janog.gr.jp

「Safety‐1 & Safety‐2―安全マネジメントの過去と未来」という本を読みました

書籍「Safety‐1 & Safety‐2―安全マネジメントの過去と未来」

Safety‐1 & Safety‐2―安全マネジメントの過去と未来

Safety‐1 & Safety‐2―安全マネジメントの過去と未来

  • 作者: エリックホルナゲル,Eric Hollnagel,北村正晴,小松原明哲
  • 出版社/メーカー: 海文堂出版
  • 発売日: 2015/11/01
  • メディア: 単行本
  • この商品を含むブログを見る


Safety‐1 、Safety‐2 という考え方について

Safety-1 は、うまくいかない要因を排除しようという考え方の安全マネジメント。 Safety-2 は、うまくいく理由を理解して、うまくいくようにしようという考え方の安全マネジメント。Safety-2 の考え方に興味を持ったので読みました。

たとえば、インシデントのなぜなぜ分析は良くすると思いますが「うまくいったことのなぜなぜ分析」はしたことありますでしょうか?読みながらそんな問いかけを思い浮かべました。

うまくいったことは認識しずらく、測定もしずらい。けれど、そこと向き合うのが Safety-2。


個人的な気付きと解釈

  • Safety-1 は、プレッシャーを受けやすい。
  • Safety-2 は、モチベーションを保てる。
  • これら2つは排他関係ではなく、Safety-2 は Safety-1 を補完するような関係。
  • うまくいかないことの原因は、そもそも線形でたどれるほど単純ではない。要因特性図を思い浮かべればは分かる。
  • なのでうまくいかない原因らしきものを捉えても同じようなことは起こる。
  • それをよりもうまくいくことに真面目に向き合うべき。

難しく、飲み込みきれない部分も多いですが、考え方の枠が広がった気がします。 ほかの分野にも応用できる部分もありそうです。