てくなべ (tekunabe)

ansible / network automation / 学習メモ

[Ansible] 「つまずき Ansible 【Part32】凡ミスTOP5」ふりかえり

はじめに

2021/02/27 に、YouTube Live で「つまずき Ansible 【Part32】凡ミスTOP5」という配信をしました。

実際に作業しながら(ときには)エラーと戦って進めるシリーズです。

tekunabe.connpass.com

今回は、私がよくやりがちな Playbook 上のミスを6個ほど紹介しました。

TOP5というタイトルですが、厳密につまずき回数をカウントしているわけではなく、なんとなくです。


動画

www.youtube.com

  • 0:00 オープニング
  • 1:30 気になり Ansible
  • 3:15 1.Python キーワードの利用
  • 9:38 2.モジュール名間違い
  • 13:32 3.パラメーター名間違い
  • 17:52 4.)閉じ忘れ
  • 22:46 5.インデント間違い
  • 26:40 6.変数のみ定義
  • 28:42 おわりに

(冒頭のおまけコーナー) 気になり Ansible 👀

ここ一週間くらいで気になった issue や PR、リリースを紹介するコーナーです。

今回は以下を取り上げました。

気になり リリース


以下、本編。

1. Python 的なキーワードを変数のキーとして使ってしまう

問題のある Playbook

- hosts: ios
  gather_facts: false

  vars:
    targets:
      items:
        - dest: 192.168.1.1
          count: 4
        - dest: 192.168.1.2
          count: 4

  tasks:
    - name: ping
      cisco.ios.ios_ping:
        dest: "{{ item.dest }}"
        count: "{{ item.count }}"
      loop: "{{ targets.items }}"

エラー

loop では リストの指定が期待されているが、リストでない。

TASK [ping] *************************************************************************************************************************************************************************************
fatal: [ios01]: FAILED! => {"msg": "Invalid data passed to 'loop', it requires a list, got this instead: <built-in method items of dict object at 0x7f1e6c33ba68>. Hint: If you passed a list/dict of just one element, try adding wantlist=True to your lookup invocation or use q/query instead of lookup."}

items

https://docs.ansible.com/ansible/latest/user_guide/playbooks_variables.html#referencing-key-value-dictionary-variables

に掲載されているように、ドットのキーの指定はできない。

--syntax-check では検出できない。

対処

自分で変数の構造を変えられる場合は、問題ないキーに変更する。

APIからの応答などにより、自分で構造を変えられない場合は、targets.itemstargets['items'] のように指定する。


2. モジュール名のスペルミス

問題のある Playbook

- hosts: ios
  gather_facts: false

  tasks:
    - name: configure lldp
      cisco.ios.ios_lldp_interface:
        config:
          - name: GigabitEthernet0/1
            receive: true
            transmit: true
            state: merge

エラー

ios_lldp_interface ではなく、ios_lldp_interfacesが正しい。

(a210) [admin@gitlab stumble]$ ansible-playbook -i inventory.ini bonmiss02.yml
ERROR! couldn't resolve module/action 'cisco.ios.ios_lldp_interface'. This often indicates a misspelling, missing collection, or incorrect module path.

The error appears to be in '/home/admin/general/vagrant/nwlab/stumble/bonmiss02.yml': line 5, column 7, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

  tasks:
    - name: configure lldp
      ^ here

--syntax-check でも検出できる。

対処

正しいモジュール名、ios_lldp_interfacesに修正する。


3. オプション名のミス

問題のある Playbook

- hosts: ios
  gather_facts: false

  tasks:
    - name: configure interface
      cisco.ios.ios_interfaces:
        config:
          - name: GigabitEthernet0/1
            description: pukupuku
            state: merge

エラー

cisco.ios.ios_interfaces モジュールの config 内で、state が指定されたがサポートされていない。

TASK [configure interface] **********************************************************************************************************************************************************************
fatal: [ios01]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "msg": "Unsupported parameters for (cisco.ios.ios_interfaces) module: state found in config. Supported parameters include: description, duplex, enabled, mtu, name, speed"}

--syntax-check では検出できない。

state オプションは、config と同じならびが正しいので一旦修正。

    - name: configure interface
      cisco.ios.ios_interfaces:
        config:
          - name: GigabitEthernet0/1
            description: pukupuku
        state: merge

ただし、これでもまだ以下のエラー。

TASK [configure interface] **********************************************************************************************************************************************************************
fatal: [ios01]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "msg": "value of state must be one of: merged, replaced, overridden, deleted, rendered, parsed, gathered, got: merge"}

やはり、--syntax-check では検出できない。

state オプションが取りうる値は、

  • merged
  • replaced
  • overridden
  • deleted
  • rendered
  • parsed
  • gathered

であるのに対して、merge が指定された。

対処

正しいオプションの位置、正しい値に修正。

- hosts: ios
  gather_facts: false

  tasks:
    - name: configure interface
      cisco.ios.ios_interfaces:
        config:
          - name: GigabitEthernet0/1
            description: pukupuku
        state: merged


4. ) の閉じ忘れ

問題のある Playbook

- hosts: ios
  gather_facts: false

  vars:
    default:
      a:
        x: default_x
        y: default_x
      b: default_b
      c: default_c
    patch:
      a:
        y: patch_y
        z: patch_x
      b: patch_b

  tasks:
    - name: debug
      ansible.builtin.debug:
        msg: "{{ default | combine(patch, recursive=True }}"

エラー

) を期待している箇所に } がある。

TASK [debug] ************************************************************************************************************************************************************************************
fatal: [ios01]: FAILED! => {"msg": "template error while templating string: unexpected '}', expected ')'. String: {{ default | combine(patch, recursive=True }}"}

--syntax-check では検出できない。(おそらく文字列として扱われている中のため)

対処

以下のように修正。

        msg: "{{ default | combine(patch, recursive=True) }}"

ちなみに、以下の結果になる。

TASK [debug] ***************************************************
ok: [ios01] => {
    "msg": {
        "a": {
            "x": "default_x",
            "y": "patch_y",
            "z": "patch_x"
        },
        "b": "patch_b",
        "c": "default_c"
    }
}

5. インデント間違い

問題のある Playbook

- hosts: ios
  gather_facts: false

  tasks:
    - name: debug
      debug:
        msg: "hello {{ item }}"
     loop:
        - 1
        - 2
        - 3

エラー

loop のインデント位置がおかしい。

(a210) [admin@gitlab stumble]$ ansible-playbook -i inventory.ini bonmiss05.yml 
ERROR! We were unable to read either as JSON nor YAML, these are the errors we got from each:
JSON: Expecting value: line 1 column 1 (char 0)

Syntax Error while loading YAML.
  did not find expected '-' indicator

The error appears to be in '/home/admin/general/vagrant/nwlab/stumble/bonmiss05.yml': line 8, column 6, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

        msg: "hello {{ item }}"
     loop:
     ^ here

--syntax-check でも検出できる。

対処

インデントを正しく修正する。

- hosts: ios
  gather_facts: false

  tasks:
    - name: debug
      debug:
        msg: "hello {{ item }}"
      loop:
          - 1
          - 2
          - 3

6. 変数のみ定義

問題のある Playbook

- hosts: ios
  gather_facts: false

  vars:
    msg: pukupuku

  tasks:
    - name: debug
      debug:
        msg: "hello {{ mgs }}"

エラー

msg 変数を定義したのに対して、誤って mgs を参照しようとしている。

TASK [debug] ************************************************************************************************************************************************************************************
fatal: [ios01]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'mgs' is undefined\n\nThe error appears to be in '/home/admin/general/vagrant/nwlab/stumble/bonmiss06.yml': line 8, column 7, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n  tasks:\n    - name: debug\n      ^ here\n"}

--syntax-check では検出できない。

対処

変数名を正しく修正。

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


Part33にむけて

以下のネタを検討中です。気が向いたものをやります。 connpass申込時のアンケートでいただいたものも含めています。

  • connection: local ななにか
  • Windows
  • cli_parse モジュール(Part15 の続き)
  • Ansible 2.10 関連
  • Ansible 3.0.0 関連
  • モジュールのテスト
  • Tower / AWX
  • role と Playbook のリポジトリ分割と読み込み
  • AWXとの共存を念頭に入れたDirectory構成

[Ansible] 「つまずき Ansible 【Part31】Katacoda Ansible 101 をやってみる」ふりかえり

はじめに

2021/02/13 に、YouTube Live で「つまずき Ansible 【Part31】Katacoda Ansible 101 をやってみる」という配信をしました。

実際に作業しながら(ときには)エラーと戦って進めるシリーズです。

tekunabe.connpass.com

今回は、先日の Ansible Night Online 2021.02のクロージングでも案内があった、Katacoda Ansible のコースをやってみました。

このコースは、@irix_jpさん作成のコースで、ブラウザのみでAnsibleを体験しながら学習できる、初心者向けのものです。

実際にやったのは Ansible 101 というコースです。

www.katacoda.com


動画

youtu.be

  • 0:00 イントロダクション
  • 1:40 今週の気になりAnsible
  • 7:00 Ansible 101 Step 1
  • 10:56 Ansible 101 Step 2
  • 23:50 Ansible 101 Step 3
  • 28:13 Ansible 101 Step 4
  • 40:10 おわりに

■ (おまけコーナー) 気になり Ansible 👀

せっかくだいたい毎週配信できてるので、もっとタイムリーな情報があってもいいかなと思いました。 そこで、気になりAnsibleというかたちで、ここ一週間くらいで気になった issue や PR、リリースを紹介する時間を設けました。

今回は以下を取り上げました。

気になり リリース

気になり PR

■ やったこと

(ログを消失してしまったため、コース紹介兼ねて項目だけ・・)

対象コース

www.katacoda.com

Step 1

  • 準備作業

Step 2

  • Ansible の基礎、インベントリー、認証情報
  • 演習環境での Ansible の実行
  • ansible.cfg の確認
  • インベントリーの確認
  • 認証情報の確認
    • 【補足】 21:28あたりで、ansible コマンドの -u オプションで指定したユーザー名より、インベントリファイルで指定した ansible_user 変数が優先されたのは、正しい挙動です。公式ドキュメントに記載があります。

Step 3

  • Ad-Hocコマンドとモジュール
  • モジュールとは
  • モジュールの一覧 (andible-doc)
  • Ad-hoc コマンド
  • ping モジュールの実行
  • shell モジュールの実行
  • yum モジュールの実行
  • setup モジュールの実行

Step 4

  • Playbookの記述と実行
  • Playbook の基礎
  • playbook の作成
    • yum モジュールと、service モジュール
  • play パート
  • task パート
  • playbook の実行
  • タスクの追加
    • copy モジュール
  • 冪等性(べきとうせい)


おわりに

ブラウザだけでお手軽に Ansible を体験できてとても便利です。

参考

rheb.hatenablog.com


Part32にむけて

以下のネタを検討中です。気が向いたものをやります。 connpass申込時のアンケートでいただいたものも含めています。

  • 凡ミスTOP3(変数名間違いなど)
  • connection: local ななにか
  • Windows
  • cli_parse モジュール(Part15 の続き)
  • Ansible 2.10 関連
  • Ansible 3.0.0 関連
  • モジュールのテスト
  • AWXとの共存を念頭に入れたDirectory構成

[Ansible] 「つまずき Ansible 【Part30】Ansible 3.0.0b1 を少し探る」ふりかえり

はじめに

2021/02/07 に、YouTube Live で「つまずき Ansible 【Part30】Ansible 3.0.0b1 を少し探る」という配信をしました。

実際に作業しながら(ときには)エラーと戦って進めるシリーズです。

今回は、まだベータですが先日リリースされた Ansible 3.0.0b1 を少し探ります。

connpass.com

  • 環境
    • Ansible 3.0.0b1

参考: [Ansible] Ansible 2.10 の次は 3.0.0 - てくなべ (tekunabe)


動画

youtu.be

  • 0:00 イントロダクション
  • 1:40 概要の概要
  • 4:50 ポーティングガイド
  • 8:55 インストール・バージョン確認
  • 13:45 collection の確認
  • 18:30 Playbook の実行
  • 27:15 おわりに

■ やったこと

資料

インストール

まだベータバージョンなので、バージョン指定が必要。

(a300) [admin@gitlab stumble]$ pip install ansible==3.0.0b1
Collecting ansible==3.0.0b1
  Using cached https://files.pythonhosted.org/packages/3e/0e/de3d605e101d7220807fa7c3234aada8b99c1277ec1a68a95b355f726b74/ansible-3.0.0b1.tar.gz
...(略)...

バージョンの確認

ansible --version では、ansible-base としてのバージョン 2.10.5 が表示される。

(a300) [admin@gitlab meta]$ ansible --version
ansible 2.10.5
  config file = None
  configured module search path = ['/home/admin/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/admin/envs/a300/lib64/python3.6/site-packages/ansible
  executable location = /home/admin/envs/a300/bin/ansible
  python version = 3.6.8 (default, Nov 16 2020, 16:55:22) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]

pip freeze では、ansibleansible-base の両方が表示される。

(a300) [admin@gitlab stumble]$ pip freeze
ansible==3.0.0b1
ansible-base==2.10.5
cffi==1.14.4
cryptography==3.3.1
Jinja2==2.11.3
MarkupSafe==1.1.1
packaging==20.9
pycparser==2.20
pyparsing==2.4.7
PyYAML==5.4.1
six==1.15.0

同梱コレクションの確認

ansible-galaxy collection list

# /home/admin/envs/a300/lib/python3.6/site-packages/ansible_collections
Collection                    Version
----------------------------- -------
amazon.aws                    1.3.0  
ansible.netcommon             1.5.0  
ansible.posix                 1.1.1  
ansible.utils                 2.0.0  
ansible.windows               1.3.0  
arista.eos                    1.3.0  
awx.awx                       17.0.1 
azure.azcollection            1.4.0  
check_point.mgmt              2.0.0  
chocolatey.chocolatey         1.0.2  
cisco.aci                     2.0.0  
cisco.asa                     1.0.4  
cisco.intersight              1.0.10 
cisco.ios                     1.3.0  
cisco.iosxr                   1.2.1  
cisco.meraki                  2.2.0  
cisco.mso                     1.1.0  
cisco.nso                     1.0.3  
cisco.nxos                    1.4.0  
cisco.ucs                     1.6.0  
cloudscale_ch.cloud           2.0.0  
community.aws                 1.3.0  
community.azure               1.0.0  
community.crypto              1.4.0  
community.digitalocean        1.0.0  
community.docker              1.2.1  
community.fortios             1.0.0  
community.general             2.0.0  
community.google              1.0.0  
community.grafana             1.1.0  
community.hashi_vault         1.0.0  
community.hrobot              1.1.0  
community.kubernetes          1.1.1  
community.kubevirt            1.0.0  
community.libvirt             1.0.0  
community.mongodb             1.2.0  
community.mysql               1.2.0  
community.network             2.0.0  
community.okd                 1.0.1  
community.postgresql          1.1.0  
community.proxysql            1.0.0  
community.rabbitmq            1.0.1  
community.routeros            1.1.0  
community.skydive             1.0.0  
community.sops                1.0.3  
community.vmware              1.7.0  
community.windows             1.2.0  
community.zabbix              1.2.0  
containers.podman             1.4.1  
cyberark.conjur               1.1.0  
cyberark.pas                  1.0.5  
dellemc.openmanage            3.0.0  
dellemc.os10                  1.1.1  
dellemc.os6                   1.0.6  
dellemc.os9                   1.0.3  
f5networks.f5_modules         1.7.1  
fortinet.fortimanager         2.0.1  
fortinet.fortios              1.1.8  
frr.frr                       1.0.3  
gluster.gluster               1.0.1  
google.cloud                  1.0.1  
hetzner.hcloud                1.2.1  
ibm.qradar                    1.0.3  
infinidat.infinibox           1.2.4  
inspur.sm                     1.1.2  
junipernetworks.junos         1.3.0  
kubernetes.core               1.1.1  
mellanox.onyx                 1.0.0  
netapp.aws                    20.9.0 
netapp.elementsw              20.11.0
netapp.ontap                  21.1.1 
netapp_eseries.santricity     1.1.0  
netbox.netbox                 2.0.0  
ngine_io.cloudstack           2.0.0  
ngine_io.exoscale             1.0.0  
ngine_io.vultr                1.1.0  
openstack.cloud               1.2.1  
openvswitch.openvswitch       1.1.0  
ovirt.ovirt                   1.3.0  
purestorage.flasharray        1.5.1  
purestorage.flashblade        1.4.0  
sensu.sensu_go                1.8.0  
servicenow.servicenow         1.0.3  
splunk.es                     1.0.2  
t_systems_mms.icinga_director 1.13.0 
theforeman.foreman            1.5.1  
vyos.vyos                     1.1.1  
wti.remote                    1.0.1  

# /home/admin/envs/a300/lib64/python3.6/site-packages/ansible_collections
Collection                    Version
----------------------------- -------
amazon.aws                    1.3.0  
ansible.netcommon             1.5.0  
ansible.posix                 1.1.1  
ansible.utils                 2.0.0  
ansible.windows               1.3.0  
arista.eos                    1.3.0  
awx.awx                       17.0.1 
azure.azcollection            1.4.0  
check_point.mgmt              2.0.0  
chocolatey.chocolatey         1.0.2  
cisco.aci                     2.0.0  
cisco.asa                     1.0.4  
cisco.intersight              1.0.10 
cisco.ios                     1.3.0  
cisco.iosxr                   1.2.1  
cisco.meraki                  2.2.0  
cisco.mso                     1.1.0  
cisco.nso                     1.0.3  
cisco.nxos                    1.4.0  
cisco.ucs                     1.6.0  
cloudscale_ch.cloud           2.0.0  
community.aws                 1.3.0  
community.azure               1.0.0  
community.crypto              1.4.0  
community.digitalocean        1.0.0  
community.docker              1.2.1  
community.fortios             1.0.0  
community.general             2.0.0  
community.google              1.0.0  
community.grafana             1.1.0  
community.hashi_vault         1.0.0  
community.hrobot              1.1.0  
community.kubernetes          1.1.1  
community.kubevirt            1.0.0  
community.libvirt             1.0.0  
community.mongodb             1.2.0  
community.mysql               1.2.0  
community.network             2.0.0  
community.okd                 1.0.1  
community.postgresql          1.1.0  
community.proxysql            1.0.0  
community.rabbitmq            1.0.1  
community.routeros            1.1.0  
community.skydive             1.0.0  
community.sops                1.0.3  
community.vmware              1.7.0  
community.windows             1.2.0  
community.zabbix              1.2.0  
containers.podman             1.4.1  
cyberark.conjur               1.1.0  
cyberark.pas                  1.0.5  
dellemc.openmanage            3.0.0  
dellemc.os10                  1.1.1  
dellemc.os6                   1.0.6  
dellemc.os9                   1.0.3  
f5networks.f5_modules         1.7.1  
fortinet.fortimanager         2.0.1  
fortinet.fortios              1.1.8  
frr.frr                       1.0.3  
gluster.gluster               1.0.1  
google.cloud                  1.0.1  
hetzner.hcloud                1.2.1  
ibm.qradar                    1.0.3  
infinidat.infinibox           1.2.4  
inspur.sm                     1.1.2  
junipernetworks.junos         1.3.0  
kubernetes.core               1.1.1  
mellanox.onyx                 1.0.0  
netapp.aws                    20.9.0 
netapp.elementsw              20.11.0
netapp.ontap                  21.1.1 
netapp_eseries.santricity     1.1.0  
netbox.netbox                 2.0.0  
ngine_io.cloudstack           2.0.0  
ngine_io.exoscale             1.0.0  
ngine_io.vultr                1.1.0  
openstack.cloud               1.2.1  
openvswitch.openvswitch       1.1.0  
ovirt.ovirt                   1.3.0  
purestorage.flasharray        1.5.1  
purestorage.flashblade        1.4.0  
sensu.sensu_go                1.8.0  
servicenow.servicenow         1.0.3  
splunk.es                     1.0.2  
t_systems_mms.icinga_director 1.13.0 
theforeman.foreman            1.5.1  
vyos.vyos                     1.1.1  
wti.remote                    1.0.1  

Playbook の実行

以下の Playbook を利用。

---
- hosts: ios
  gather_facts: false

  tasks:
    - name: show
      ios_command:
      # cisco.ios.ios_command:   # もちろん FQCN でも可
        commands:
          - show interfaces
      register: res_show
    
    - name: debug
      debug:
        msg: "{{ res_show.stdout_lines[0] }}"

paramiko のインストール。

pip install paramiko

実行結果

(a300) [admin@gitlab stumble]$ ansible-playbook -i inventory.ini test.yml 

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

TASK [show] ********************************************************************
ok: [ios01]

TASK [debug] *******************************************************************
ok: [ios01] => {
    "msg": [
        "GigabitEthernet0/0 is up, line protocol is up ",
        "  Hardware is iGbE, address is 5254.0001.xxxx (bia 5254.0001.xxx)",
        "  Internet address is 192.168.1.11/24",
        "  MTU 1500 bytes, BW 1000000 Kbit/sec, DLY 10 usec, ",
        "     reliability 255/255, txload 1/255, rxload 1/255",
        "  Encapsulation ARPA, loopback not set",
        "  Keepalive set (10 sec)",
        "  Auto Duplex, Auto Speed, link type is auto, media type is RJ45",
        "  output flow-control is unsupported, input flow-control is unsupported",
        "  ARP type: ARPA, ARP Timeout 04:00:00",
        "  Last input 00:00:00, output 
...(略)...


Part31にむけて

以下のネタを検討中です。気が向いたものをやります。 connpass申込時のアンケートでいただいたものも含めています。

  • Katakoda Ansible 101
  • connection: local ななにか
  • Windows
  • cli_parse モジュール(Part15 の続き)
  • Ansible 2.10 関連
  • Ansible 3.0.0 関連
  • モジュールのテスト
  • AWXとの共存を念頭に入れたDirectory構成

[Ansible] 「つまずき Ansible 【Part29】フィルター」ふりかえり

はじめに

2021/02/06 に、YouTube Live で「つまずき Ansible 【Part29】フィルター」という配信をしました。

実際に作業しながら(ときには)エラーと戦って進めるシリーズです。

今回は、値を変換したり抽出したりするフィルターをいくつか試しました。

参考 https://docs.ansible.com/ansible/latest/user_guide/playbooks_filters.html

tekunabe.connpass.com

  • 環境
    • Ansible 2.9.16


動画

youtu.be

  • 0:00 イントロダクション
  • 4:11 抽出系
    • gt のとこを「以上」と説明してしまいましたが、正しくは「より大きい」です。失礼しました。
  • 13:11 変換系
  • 13:53 結合系
  • 15:05 正規表現
  • 16:29 パス操作系
  • 17:57 ネットワーク系
  • 22:22 その他
  • 23:30 試行錯誤1 ansible-console
  • 25:32 試行錯誤2 debugger
  • 29:37 おわりに

■ やったこと

抽出系

selectattr フィルター

条件にあったものを抽出。

---
- hosts: localhost
  gather_facts: no
  connection: local
  debugger: always

  vars:
    users:
      - name: yamada
        age: 42
      - name: tanaka
        age: 26
      - name: suzuki
        age: 32
      - name: sato
        age: 27

  tasks:
    - name: debug 1
      debug: #  select * from users where age > 30 のようなイメージ
        msg: "{{ users | selectattr('age', 'gt', 30) | list }}" # gt は > でも可

実行結果

ok: [localhost] => {
    "msg": [
        {
            "age": 42,
            "name": "yamada"
        },
        {
            "age": 32,
            "name": "suzuki"
        }
    ]
}

map フィルター

様々な機能がある。今回は SQL でいうカラムの選択。

    - name: debug 2
      debug:  # select name from users where age >= 30  のようなイメージ
        msg: "{{ users | selectattr('age', 'gt', 30) | map(attribute='name') | list }}"

実行結果

ok: [localhost] => {
    "msg": [
        "yamada",
        "suzuki"
    ]
}

以下は説明のみ

  • json_query: jmethpath を利用した複雑なクエリー

変換系

説明のみ

結合系

説明のみ

正規表現

regex_replace フィルター

正規表現を使用した置換。後方参照利用できる。

    - name: regex
      debug:
        msg:  "{{ 'foobar' | regex_replace('^f.*o(.*)$', '\\1') }}"

実行結果

ok: [localhost] => {
    "msg": "bar"
}

パス操作系

説明のみ


ネットワーク系

parse_cli_textfsm フィルター

TextFSM テンプレートを利用して、ネットワーク機器の show コマンドの実行結果を構造化データにパースする。

---
- hosts: ios
  gather_facts: false

  tasks:
    - name: show
      ios_command:
        commands:
          - show interfaces
      register: res

    - name: debug
      debug:
        msg: "{{ res.stdout[0] | parse_cli_textfsm(path_template) }}"
      vars:
        path_template: "/home/admin/envs/a29/lib/python3.6/site-packages/ntc_templates/templates/cisco_ios_show_interfaces.textfsm"

実行結果

ok: [ios01] => {
    "msg": [
        {
            "ABORT": "",
            "ADDRESS": "5254.00xx.xxxx",
            "BANDWIDTH": "1000000 Kbit",
            "BIA": "5254.00xx.xxxx",
            "CRC": "0",
            "DELAY": "10 usec",
            "DESCRIPTION": "",
            "DUPLEX": "Auto Duplex",
            "ENCAPSULATION": "ARPA",
            "HARDWARE_TYPE": "iGbE",
            "INPUT_ERRORS": "0",
            "INPUT_PACKETS": "854394",
            "INPUT_RATE": "0",
            "INTERFACE": "GigabitEthernet0/0",
            "IP_ADDRESS": "192.168.1.11/24",
            "LAST_INPUT": "00:00:00",
            "LAST_OUTPUT": "00:00:00",
            "LAST_OUTPUT_HANG": "never",
            "LINK_STATUS": "up",
            "MEDIA_TYPE": "RJ45",
            "MTU": "1500",
            "OUTPUT_ERRORS": "0",
            "OUTPUT_PACKETS": "127122",
            "OUTPUT_RATE": "0",
            "PROTOCOL_STATUS": "up",
            "QUEUE_STRATEGY": "fifo",
            "SPEED": "Auto Speed"
        },
// ....(略)...

参考: show コマンド結果をパースする方法あれこれ(TextFSM / Genie Parser と Netmiko / Ansible の組み合わせ) - てくなべ (tekunabe)

その他

説明のみ

試行錯誤に便利

フィルターを色々試したい時に便利な方法。

ansible-console

ansible-console コマンド

対話的な操作。

(a29) [admin@gitlab stumble]$ ansible-console -i localhost, 
Welcome to the ansible console.
Type help or ? to list commands.

admin@all (1)[f:5]$ debug msg="{{ [1,2,3] | max  }} "
localhost | SUCCESS => {
    "msg": "3 "
}
admin@all (1)[f:5]$ debug msg="{{ [1,2,3] | min  }} "
localhost | SUCCESS => {
    "msg": "1 "
}

参考: [Ansible] フィルターを手軽に試行錯誤したいときの ansible-console コマンドの使い方 - てくなべ (tekunabe)

Playbook Debugger

Playbook Debugger

たとえば、Play に debugger: always を指定すると、各タスク実行後にデバッガーが起動する。

---
- hosts: localhost
  gather_facts: no
  connection: local
  debugger: always    # ここ

以下が、デバッガーが起動した状態。

[localhost] TASK: debug 1 (debug)>

task.args で、タスクのオプションの書き換えができる。そのが r で再実行できる。

[localhost] TASK: debug 1 (debug)> task.args['msg'] = "{{ users | selectattr('age', 'gt', 40) | list }}"
[localhost] TASK: debug 1 (debug)> r
ok: [localhost] => {
    "msg": [
        {
            "age": 42,
            "name": "yamada"
        }
    ]
}


おわりに

フィルターは数も多く、奥が深いです。

全ては覚えられないので、フィルター的なことをしたい場合は、Ansible や Jinja2 の公式ドキュメントを眺めて探しています。

Filters — Ansible Documentation

Jinja — Jinja Documentation (2.11.x)


Part30にむけて

ベータですが、Ansible 3.0.0b1 がリリースされたので、こちらを扱ってみます。

tekunabe.connpass.com

他、以下のネタを検討中です。気が向いたものをやります。 connpass申込時のアンケートでいただいたものも含めています。

  • Katakoda Ansible 101
  • connection: local ななにか
  • Windows
  • cli_parse モジュール(Part15 の続き)
  • Ansible 2.10 関連
  • Ansible 3.0.0 関連
  • モジュールのテスト
  • AWXとの共存を念頭に入れたDirectory構成

[Ansible] cisco.ios.ios_ping モジュールに size と df_bit オプションを追加しました

はじめに

Cisco IOS のネットワーク機器 から 指定の宛先に ICMP による Ping を実行する cisco.ios.ios_ping というモジュールがあります。

指定した宛先などのオプションに基づいて ping コマンドを生成し、IOS の機器上で実行して結果を表示します。

[Ansible] -----> [IOS] -- ICMP Ping -->[dest指定先]

この cisco.ios.ios_ping モジュールに、ping コマンドの df-bitsize オプションに相当するオプションを追加しました。cisco.ios collection 1.3.0 としてリリースされました。

この2つのオプションの使い方をご紹介します。

  • 動作確認環境
    • Ansible 2.10.6 / 2.9.17
    • cisco.ios collection 1.3.0

オプションの説明

オプション名 デフォルト 説明
df_bit bool false DF bit を立てるかどうかの指定 。ping コマンドの df-bit オプションに相当
size int モジュールとしてはデフォルトなし サイズの指定。ping コマンドの size オプションに相当

使用例

size のみ指定

サイズを指定する例です。

- hosts: ios
  gather_facts: false

  tasks:
    - name: size
      cisco.ios.ios_ping:
        dest: 192.168.1.1
        size: 1400

ping 192.168.1.1 size 1400 コマンドが実行されます。

df-bit のみ指定

DF bit を指定する例です。

- hosts: ios
  gather_facts: false

  tasks:
    - name: df_bit
      cisco.ios.ios_ping:
        dest: 192.168.1.1
        df_bit: true

ping 192.168.1.1 df-bit コマンドが実行されます。

df_bitsize の指定

併用もできます。

- hosts: ios
  gather_facts: false

  tasks:
    - name: size and df_bit
      cisco.ios.ios_ping:
        dest: 192.168.1.1
        size: 1400
        df_bit: true

ping 192.168.1.1 size 1400 df-bit コマンドが実行されます。

トラブルシューティング

もし、Playbook 実行時に、以下のように指定されたオプションはサポートされない旨のエラーが出た場合は、cisco.ios collection 1.3.0 以上ががインストールされているかどうか、それを Playbook が参照しているかをご確認ください。モジュール名を ios_ping と指定してだめでしたら cisco.ios.ios_ping のような FQCN 表記を試してみてください。

"msg": "Unsupported parameters for (ios_ping) module: df_bit Supported parameters include: auth_pass, authorize, count, dest, host, password, port, provider, source, ssh_keyfile, state, timeout, username, vrf"

おわりに(おまけ)

今回、はじめて機能追加をしてみました。追加したい処理そのものより、ansible-test によるテストの実行方法を調べるほうが時間がかかってしまいました。

参考: Testing Ansible — Ansible Documentation

試行錯誤記録(スレッド続きます)

[2022/08/02 追記]

cisco.ios コレクション 3.2.0 の v6 対応時に size オプションが無くなってしまったようです。

IOS Ping module (#595) · ansible-collections/cisco.ios@1af932e · GitHub

cisco.ios/CHANGELOG.rst at main · ansible-collections/cisco.ios · GitHub

[Ansible] 「つまずき Ansible 【Part28】ping 系モジュールを試す」ふりかえり

はじめに

2021/01/30 に、YouTube Live で「つまずき Ansible 【Part28】ping 系モジュールを試す」という配信をしました。

実際に作業しながら(ときには)エラーと戦って進めるシリーズです。

今回は、pingios_ping や win_ping などの ping 系モジュールの違いを確認しながら、試しました。

tekunabe.connpass.com

  • 環境
    • Ansible 2.10.6

参考: 【Ansible】ping 系モジュールまとめ(ping/win_ping/ios_ping/nxos_ping/net_ping) - てくなべ (tekunabe)


動画

youtu.be

■ やったこと

ping モジュール

pingモジュールは、ターゲットノードへのAnsible的な接続や認証の正常性を確認する。

ICMP ではなく、通常は SSH を利用する。

[A] --- SSH ---> [linux]
  • 実行ログ
$  ansible -i inventory.ini linux  -m ping
linux01 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
  • Playbook の場合
---
- hosts: linux
  gather_facts: false

  tasks:
    - ping:

win_ping モジュール

win_ping モジュールは、Windows ターゲットのターゲットノードへのAnsible的な接続や認証の正常性を確認する。

通常は、WinRM を利用する。

[A] -- WinRM --> [Windows]
  • 実行ログ
$ ansible -i inventory.ini win -m win_ping
win01 | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

おまけ: うっかり Windows 相手に ping モジュールを使った場合のエラー

$ ansible -i inventory.ini win -m ping
[WARNING]: No python interpreters found for host win01 (tried ['/usr/bin/python', 'python3.7', 'python3.6', 'python3.5',
'python2.7', 'python2.6', '/usr/libexec/platform-python', '/usr/bin/python3', 'python'])
win01 | FAILED! => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "module_stderr": "Exception calling \"Create\" with \"1\" argument(s): \"At line:4 char:21\r\n+ def _ansiballz_main():\r\n+                     ~\r\nAn expression was expected after '('.\r\nAt line:13 char:27\r\n+     except (AttributeError, OSError):\r\n+                           ~\r\nMissing argument in parameter list.\r\nAt line:15 char:29\r\n+     excludes = set(('', '.', scriptdir))\r\n+                             ~\r\nMissing expression after ','.\r\nAt line:15 char:30\r\n+     excludes = set(('', '.', scriptdir))\r\n+                              ~~~~~~~~~\r\nUnexpected token 'scriptdir' in expression or statement.\r\nAt line:15 char:29\r\n+     excludes = set(('', '.', scriptdir))\r\n+                             ~\r\nMissing closing ')' in expression.\r\nAt line:15 char:39\r\n+     excludes = set(('', '.', scriptdir))\r\n+                                       ~\r\nUnexpected token ')' in expression or statement.\r\nAt line:15 char:40\r\n+     excludes =

ios_ping モジュール

ios_ping モジュールは、Cisco IOS 機器から指定した宛先への疎通確認をする。

ターゲットノード「へ」ではなく「から」。

[A] ------------ [ios]--- ICMP ---> [dest先]
  • 実行ログ
$ ansible -i inventory.ini ios -m ios_ping -a "dest=192.168.1.1"
ios01 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "commands": [
        "ping 192.168.1.1"
    ],
    "packet_loss": "0%",
    "packets_rx": 5,
    "packets_tx": 5,
    "rtt": {
        "avg": 1,
        "max": 2,
        "min": 1
    }
}
  • Playbook の場合
---
# ios
- hosts: ios
  gather_facts: no

  tasks:
    # ansible -i inventory.ini ios -m ios_ping -a "dest=192.168.1.1"
    - name: ping for ios
      ios_ping:
        dest: 192.168.1.1

net_ping モジュール

ios_ping モジュールは、ios_pingjunos_ping モジュールなどを抽象化したもの。

  • Playbook
---
# ios
- hosts: ios
  gather_facts: no

  tasks:
    - name: ping for ios
      net_ping:
        dest: 192.168.1.1

番外編1: ネットワーク機器に ping モジュールを使ったら?

配信後にご質問をいただきました。

はい、SUCCESS になってしまいます。(たしか Ansible 2.9 頃からの仕様)

  • 認証情報が誤っていてもSUCCESS
$ ansible -i inventory.ini ios -m ping -e ansible_user=tekitoutekiyou
ios01 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}
  • 接続先が誤っていても SUCCESS
$ ansible -i inventory.ini ios -m ping -e ansible_host=tekitoudesuuuuuuu
ios01 | SUCCESS => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "ping": "pong"
}

番外編2:ICMP による ping

[A] ---- ICMP ---> [dest先]

command モジュール使うくらいしか思い浮かばす・・。

$ ansible -i inventory.ini linux -m command -a "ping {{ ansible_host }} -c 4" -c local
linux01 | CHANGED | rc=0 >>
PING 192.168.1.145 (192.168.1.145) 56(84) bytes of data.
64 bytes from 192.168.1.145: icmp_seq=1 ttl=64 time=0.176 ms
64 bytes from 192.168.1.145: icmp_seq=2 ttl=64 time=0.212 ms
64 bytes from 192.168.1.145: icmp_seq=3 ttl=64 time=0.198 ms
64 bytes from 192.168.1.145: icmp_seq=4 ttl=64 time=0.264 ms

--- 192.168.1.145 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 2999ms
rtt min/avg/max/mdev = 0.176/0.212/0.264/0.035 ms

回数を指定する -c を忘れると無限 ping になって、応答が返ってこない。

ありがとうございます!

参考: [Ansible] コントロールノードから ICMP ping を実行する(ただしcommandモジュール) - てくなべ (tekunabe)


おわりに

名前がよく似てても性質が結構違ったりするので、少し注意が必要でした。 公式ドキュメントに必要な情報は掲載されているので、やっぱりよく確認すべきですね。


Part29 にむけて

以下のネタを検討中です。気が向いたものをやります。 connpass申込時のアンケートでいただいたものも含めています。

  • Ansible 2.10 関連
  • connection: local ななにか
  • Jinja2、フィルター
  • Windows
  • ESXi で VM作成
  • モジュールのテスト
  • AWXとの共存を念頭に入れたDirectory構成

[Ansible] 「つまずき Ansible 【Part27】ネットワーク機器の状態確認をしたい」ふりかえり

はじめに

2021/01/23 に、YouTube Live で「つまずき Ansible 【Part27】ネットワーク機器の状態確認をしたい」という配信をしました。

実際に作業しながら(ときには)エラーと戦って進めるシリーズです。

今回は、以下の記事を参照しながら、ネットワーク機器の状態確認する処理を試しました。

www.ansible.com

tekunabe.connpass.com

  • 環境
    • Ansible 2.10.5
      • (配信中、記事の前提のバージョンが不明と言ってしまいましたが、実際は 2.9.15 と記載がありました。失礼しました。)


動画

youtu.be

  • 00:00 イントロダクション
  • 05:56 情報の取得とパース結果の表示
  • 21:55 インターフェース状態のバリデーション
  • 30:26 復旧
  • 32:46 BGP状態のバリデーション
  • 44:49 おわりに

■ やったこと

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

まず、環境の準備として、新しい venv に ansible をインストール。

[admin@gitlab ~]$ python3 -m venv envs/a210
[admin@gitlab ~]$ source envs/a210/bin/activate
(a210) [admin@gitlab ~]$ pip install ansible
(略)
(a210) [admin@gitlab ~]$ ansible --version
ansible 2.10.5
(略)

表示用Playbook の実行

Playbook (公式ブログからの引用)を実行

---
- hosts: nxos
  connection: ansible.netcommon.network_cli
  gather_facts: false
  vars:
    ansible_network_os: cisco.nxos.nxos
    ansible_user: "changeme"
    ansible_password: "changeme"

  tasks:
  - name: "Fetch interface state and parse with pyats"
    ansible.utils.cli_parse:
      command: show interface
      parser:
        name: ansible.netcommon.pyats
    register: nxos_pyats_show_interface

  - name: print structured interface state data
    ansible.builtin.debug:
      msg: "{{ nxos_pyats_show_interface['parsed'] }}"

ansible.utils.cli_parse モジュール関連のエラー

ansible.utils.cli_parse モジュールが見つからないエラー。

ERROR! couldn't resolve module/action 'ansible.utils.cli_parse'. This often indicates a misspelling, missing collection, or incorrect module path.

上記エラーの対策として、ansible.utils collection をインストール。

(a210) [admin@gitlab stumble]$ ansible-galaxy collection install ansible.utils
Starting galaxy collection install process
Process install dependency map
Starting collection install process
Installing 'ansible.utils:1.0.1' to '/home/admin/.ansible/collections/ansible_collections/ansible/utils'
Downloading https://galaxy.ansible.com/download/ansible-utils-1.0.1.tar.gz to /home/admin/.ansible/tmp/ansible-local-23876jjourm5u/tmppi521mhv
ansible.utils (1.0.1) was installed successfully

paramiko 関連のエラー

再度 Playbook 実行で、paramiko が見つからないエラー。

TASK [Fetch interface state and parse with pyats] *****************************************************************************
fatal: [nxos01]: FAILED! => {"changed": false, "msg": ["paramiko is not installed: No module named 'paramiko'"]}

上記エラーの対策として、paramiko をインストール。

pip install paramiko

pyats 関連のエラー

再度 Playbook 実行で、pyats が見つからないエラー。

TASK [Fetch interface state and parse with pyats] *****************************************************************************
fatal: [nxos01]: FAILED! => {"changed": false, "msg": "Failed to import the required Python library (genie) on gitlab's Python /home/admin/envs/a210/bin/python3. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter Failed to import the required Python library (pyats) on gitlab's Python /home/admin/envs/a210/bin/python3. Please read the module documentation and install it in the appropriate location. If the required library is installed, but Ansible is using the wrong Python interpreter, please consult the documentation on ansible_python_interpreter"}

上記エラーの対策として、pyats をインストール。

pip install pyats

gccのエラー

    gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/admin/envs/a210/include -I/usr/include/python3.6m -c multidict/_multidict.c -o build/temp.linux-x86_64-3.6/multidict/_multidict.o -O2 -std=c99 -Wall -Wsign-compare -Wconversion -fno-strict-aliasing -pedantic
    unable to execute 'gcc': No such file or directory
    error: command 'gcc' failed with exit status 1
    
    ----------------------------------------
Command "/home/admin/envs/a210/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-ptsvl0o2/multidict/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-eplnwr3p-record/install-record.txt --single-version-externally-managed --compile --install-headers /home/admin/envs/a210/include/site/python3.6/multidict" failed with error code 1 in /tmp/pip-build-ptsvl0o2/multidict/
You are using pip version 9.0.3, however version 20.3.3 is available.

上記の対策として、yum でインストール。(実際はもっと最小限にできたと思います)

yum groupinstall "Development Tools"
sudo yum install python3-* -y

その後 pip install "pyats[full]" 実行で無事インストール。

再度 Playbook 実行。無事に show interface 実行結果がパースされて表示される。

(a210) [admin@gitlab stumble]$ ansible-playbook -i inventory.ini debug.yml 

PLAY [nxos] *******************************************************************************************************************

TASK [Fetch interface state and parse with pyats] *****************************************************************************
ok: [nxos01]

TASK [print structured interface state data] **********************************************************************************
ok: [nxos01] => {
    "msg": {
        "Ethernet2/1": {
            "admin_state": "up",
            "auto_mdix": "off",
            "auto_negotiate": false,
            "bandwidth": 1000000,
            "beacon": "off",
            "counters": {
                "in_bad_etype_drop": 0,
                "in_broadcast_pkts": 0,
                "in_crc_errors": 0,
                "in_discard": 0,
                "in_errors": 0,
                "in_if_down_drop": 0,
                "in_ignored": 0,
                "in_jumbo_packets": 0,
                "in_mac_pause_frames": 0,
                "in_multicast_pkts": 0,
                "in_no_buffer": 0,
                "in_octets": 0,
                "in_overrun": 0,
                "in_oversize_frame": 0,
                "in_pkts": 0,
                "in_runts": 0,
                "in_short_frame": 0,
                "in_storm_suppression_packets": 0,
                "in_underrun": 0,
                "in_unicast_pkts": 0,
                "in_unknown_protos": 0,
                "in_watchdog": 0,
                "in_with_dribble": 0,
                "last_clear": "never",
                "out_babble": 0,
                "out_broadcast_pkts": 0,
                "out_collision": 0,
                "out_deferred": 0,
                "out_discard": 0,
                "out_errors": 0,
                "out_jumbo_packets": 0,
                "out_late_collision": 0,
                "out_lost_carrier": 0,
                "out_mac_pause_frames": 0,
                "out_multicast_pkts": 0,
                "out_no_carrier": 0,
                "out_octets": 0,
                "out_pkts": 0,
                "out_unicast_pkts": 0,
                "rate": {
                    "in_rate": 0,
                    "in_rate_bps": 0,
                    "in_rate_pkts": 0,
                    "in_rate_pps": 0,
                    "load_interval": 0,
                    "out_rate": 0,
                    "out_rate_bps": 0,
                    "out_rate_pkts": 0,
                    "out_rate_pps": 0
                },
                "rx": true,
                "tx": true
            },
            "dedicated_interface": true,
            "delay": 10,
            "duplex_mode": "full",
            "efficient_ethernet": "n/a",
            "enabled": true,
            "encapsulations": {
                "encapsulation": "arpa"
            },
            "ethertype": "0x8100",
            "flow_control": {
                "receive": false,
                "send": false
            },
            "interface_reset": 1,
            "last_link_flapped": "02:25:36",
            "link_state": "up",
            "mac_address": "0000.0000.002f",
            "medium": "broadcast",
            "mtu": 1500,
            "oper_status": "up",
            "phys_address": "5254.0003.xxxx",
            "port_channel": {
                "port_channel_member": false
            },
            "port_mode": "routed",
            "port_speed": "1000",
            "reliability": "255/255",
            "rxload": "1/255",
            "switchport_monitor": "off",
            "txload": "1/255",
            "types": "Ethernet"
        },
        "Ethernet2/10": {
            "admin_state": "down",
...(略)...

バリデーション用Playbook の実行以降

Validation 以降 については動画をご参照下さい。

(チャプター再掲)

  • 00:00 イントロダクション
  • 05:56 情報の取得とパース結果の表示
  • 21:55 インターフェース状態のバリデーション
  • 30:26 復旧
  • 32:46 BGP状態のバリデーション
  • 44:49 おわりに


おわりに

配信中はかなり雰囲気で試しましたが、使いこなすには、JSON Schema の書き方や、データの構造をよく理解したほうが良いと思いました。


Part28 にむけて

以下のネタを検討中です。気が向いたものをやります。

  • Ansible 2.10 関連
  • connection: local ななにか
  • Jinja2、フィルター
  • Windows
  • ESXi で VM作成