てくなべ (tekunabe)

ansible / network / automation

[Ansible] 「つまずき Ansible 【Part5】Arista EOS に何かしてみる」ふりかえり

はじめに

2020/06/13 に、YouTube Live で「つまずき Ansible 【Part5】Arista EOS に何かしてみる」という配信をしました。 実際に作業しながらエラーと戦って進めるシリーズです。

tekunabe.connpass.com

今回は、Arista EOS の機器(cEOS-lab) への接続確認、show コマンド実行、スタティックルート設定する Playbook を作りました。

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

動画

www.youtube.com


■ 疎通確認

接続できないエラーが発生

以下のエラー。

(ansible) [vagrant@stumble stumble]$ ansible -i inventory.ini eos -m eos_facts
eos1 | FAILED! => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "msg": "[Errno None] Unable to connect to port 22 on 192.168.1.133"
}

原因

コンテナで立てた cEOS-lab へは、-p 5022:22 でポートフォワーディングしているの対して、Ansible 側でポート指定していなかった。

対処

以下の変数で、ポートを指定。

ansible_port: 5022


■ スタティックルートの追加

mask オプションがない旨エラーが発生

以下のエラー。

fatal: [eos1]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "msg": "Unsupported parameters for (eos_static_route) module: mask Supported parameters include: address, admin_distance, aggregate, auth_pass, authorize, host, next_hop, password, port, provider, ssh_keyfile, state, timeout, transport, use_ssl, username, validate_certs, vrf"}

原因

ios_static_route モジュールと同じ用に prefixmask オプションで指定したが、 eos_static_route モジュールには mask オプションがない。

対処

address オプションプレフィックス表記で指定する。

    - name: set route
      eos_static_route:
        address: 0.0.0.0/0
        next_hop: 192.168.1.1


■ eAPI 経由で show コマンド実行

接続不可のエラーが発生

以下のエラー。

 Could not connect to http://192.168.1.133:80/command-api: [Errno 111] Connection refused\

原因

ansible_connection: httpapi

を指定していたため、デフォルトでは80/TCPで接続しようとするが、環境の都合上別のポート 5080 を指定する必要があった。

さらに、httpapi の場合は、ポートの指定は ansible_port 変数ではなく、ansible_httpapi_port 変数 である。

対処

以下の変数定義を追加。

ansible_httpapi_port: 5080


おまけ

閲覧したサイト

各種ファイル

インベントリ: inventory.ini

[ios]
rt01 ansible_host=192.168.1.11
rt02 ansible_host=192.168.1.12

[eos]
eos1 ansible_host=192.168.1.133

変数定義ファイル: group_vars/eos.yml

---
ansible_network_os: eos

ansible_connection: network_cli
ansible_port: 5022
# ansible_connection: httpapi    # eAPI 利用時はこちら
# ansible_httpapi_port: 5080     # eAPI 利用時はこちら

ansible_user: ansible
ansible_password: p@ssword

# 以下、一般権限を利用する場合は以下の特権設定も必要
ansible_become: true 
ansible_become_method: enable
ansible_become_password: secret 

Playbook: eos_show.yml

---
- hosts: eos
  gather_facts: false
  
  tasks:
    - name: show version
      eos_command: 
        commands:
          - show ver
      register: result
    
    - name: debug
      debug:
        msg: "{{ result }}"

Playbook: eos_set.yml

---
- hosts: eos
  gather_facts: false

  tasks:
    - name: set route
      eos_static_route:
        address: 0.0.0.0/0
        next_hop: 192.168.1.1

    - name: save
      eos_config:
        save_when: modified

全実行ログ

クリックして開く

[vagrant@stumble stumble]$ source ~/envs/ansible/bin/activate
(ansible) [vagrant@stumble stumble]$ 
(ansible) [vagrant@stumble stumble]$ 
(ansible) [vagrant@stumble stumble]$ 
(ansible) [vagrant@stumble stumble]$ ansible -i inventory.ini eos -m eos_facts
eos1 | FAILED! => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false,
    "msg": "[Errno None] Unable to connect to port 22 on 192.168.1.133"
}
(ansible) [vagrant@stumble stumble]$ ansible -i inventory.ini eos -m eos_facts
[WARNING]: default value for `gather_subset` will be changed to `min` from `!config` v2.11 onwards
eos1 | SUCCESS => {
    "ansible_facts": {
        "ansible_net_all_ipv4_addresses": [
            "0.0.0.0"
        ],
        "ansible_net_all_ipv6_addresses": [],
        "ansible_net_api": "cliconf",
        "ansible_net_filesystems": [
            "file:",
            "flash:",
            "system:"
        ],
        "ansible_net_fqdn": "ceos1",
        "ansible_net_gather_network_resources": [],
        "ansible_net_gather_subset": [
            "hardware",
            "default",
            "interfaces"
        ],
        "ansible_net_hostname": "ceos1",
        "ansible_net_interfaces": {
            "Ethernet1": {
                "bandwidth": 0,
                "description": "",
                "duplex": "duplexFull",
                "ipv4": {},
                "lineprotocol": "up",
                "macaddress": "02:42:ac:15:00:02",
                "mtu": 9214,
                "operstatus": "connected",
                "type": "bridged"
            },
            "Ethernet2": {
                "bandwidth": 0,
                "description": "",
                "duplex": "duplexFull",
                "ipv4": {
                    "address": "0.0.0.0",
                    "masklen": 0
                },
                "lineprotocol": "up",
                "macaddress": "02:42:ac:2a:8f:7d",
                "mtu": 1500,
                "operstatus": "connected",
                "type": "routed"
            },
            "Ethernet3": {
                "bandwidth": 0,
                "description": "",
                "duplex": "duplexFull",
                "ipv4": {},
                "lineprotocol": "up",
                "macaddress": "02:42:ac:17:00:02",
                "mtu": 9214,
                "operstatus": "connected",
                "type": "bridged"
            },
            "Ethernet4": {
                "bandwidth": 0,
                "description": "",
                "duplex": "duplexFull",
                "ipv4": {},
                "lineprotocol": "up",
                "macaddress": "02:42:ac:18:00:02",
                "mtu": 9214,
                "operstatus": "connected",
                "type": "bridged"
            }
        },
        "ansible_net_memfree_mb": 1234.15625,
        "ansible_net_memtotal_mb": 1991.46875,
        "ansible_net_model": "cEOSLab",
        "ansible_net_neighbors": {},
        "ansible_net_python_version": "2.7.5",
        "ansible_net_serialnum": "",
        "ansible_net_system": "eos",
        "ansible_net_version": "4.21.10M",
        "ansible_network_resources": {},
        "discovered_interpreter_python": "/usr/bin/python"
    },
    "changed": false
}
(ansible) [vagrant@stumble stumble]$ 
(ansible) [vagrant@stumble stumble]$ 
(ansible) [vagrant@stumble stumble]$ 
(ansible) [vagrant@stumble stumble]$ 
(ansible) [vagrant@stumble stumble]$ ansible-playbook -i inventory.ini eos_show.yml 

PLAY [eos] *****************************************************************************************

TASK [show version] ********************************************************************************
ok: [eos1]

TASK [debug] ***************************************************************************************
ok: [eos1] => {
    "msg": {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        },
        "changed": false,
        "failed": false,
        "stdout": [
            "cEOSLab\nHardware version:    \nSerial number:       \nSystem MAC address:  0242.ac2a.8f7d\n\nSoftware image version: 4.21.10M\nArchitecture:           i386\nInternal build version: 4.21.10M-15347597.42110M\nInternal build ID:      9d960dea-a6da-424b-b373-2958c07c48c3\n\ncEOS tools version: 1.1\n\nUptime:                 0 weeks, 0 days, 3 hours and 40 minutes\nTotal memory:           2039264 kB\nFree memory:            1264168 kB"
        ],
        "stdout_lines": [
            [
                "cEOSLab",
                "Hardware version:    ",
                "Serial number:       ",
                "System MAC address:  0242.ac2a.8f7d",
                "",
                "Software image version: 4.21.10M",
                "Architecture:           i386",
                "Internal build version: 4.21.10M-15347597.42110M",
                "Internal build ID:      9d960dea-a6da-424b-b373-2958c07c48c3",
                "",
                "cEOS tools version: 1.1",
                "",
                "Uptime:                 0 weeks, 0 days, 3 hours and 40 minutes",
                "Total memory:           2039264 kB",
                "Free memory:            1264168 kB"
            ]
        ]
    }
}

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

(ansible) [vagrant@stumble stumble]$ 
(ansible) [vagrant@stumble stumble]$ ansible-playbook -i inventory.ini eos_set.yml 

PLAY [eos] ***************************************************************************************************

TASK [set route] *********************************************************************************************
fatal: [eos1]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "msg": "Unsupported parameters for (eos_static_route) module: mask Supported parameters include: address, admin_distance, aggregate, auth_pass, authorize, host, next_hop, password, port, provider, ssh_keyfile, state, timeout, transport, use_ssl, username, validate_certs, vrf"}

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

(ansible) [vagrant@stumble stumble]$ ansible-playbook -i inventory.ini eos_set.yml 

PLAY [eos] **********************************************************************************

TASK [set route] ****************************************************************************
changed: [eos1]

TASK [save] *********************************************************************************
changed: [eos1]

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

(ansible) [vagrant@stumble stumble]$ ansible -i inventory.ini eos -m eos_eapi -a http=true
eos1 | CHANGED => {
    "ansible_facts": {
        "discovered_interpreter_python": "/usr/bin/python",
        "eos_eapi_urls": {}
    },
    "changed": true,
    "commands": [
        "management api http-commands",
        "protocol http port 80",
        "no shutdown"
    ],
    "session_name": "ansible_1592047615"
}
(ansible) [vagrant@stumble stumble]$ ansible-playbook -i inventory.ini eos_show.yml 

PLAY [eos] **************************************************************************************************

TASK [show version] *****************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ansible.module_utils.connection.ConnectionError: Could not connect to http://192.168.1.133:80/command-api: [Errno 111] Connection refused
fatal: [eos1]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "module_stderr": "Traceback (most recent call last):\n  File \"/home/vagrant/.ansible/tmp/ansible-local-401092_8yu3k/ansible-tmp-1592047746.7101004-4016-36587511630429/AnsiballZ_eos_command.py\", line 102, in <module>\n    _ansiballz_main()\n  File \"/home/vagrant/.ansible/tmp/ansible-local-401092_8yu3k/ansible-tmp-1592047746.7101004-4016-36587511630429/AnsiballZ_eos_command.py\", line 94, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/vagrant/.ansible/tmp/ansible-local-401092_8yu3k/ansible-tmp-1592047746.7101004-4016-36587511630429/AnsiballZ_eos_command.py\", line 40, in invoke_module\n    runpy.run_module(mod_name='ansible.modules.network.eos.eos_command', init_globals=None, run_name='__main__', alter_sys=True)\n  File \"/usr/lib64/python2.7/runpy.py\", line 176, in run_module\n    fname, loader, pkg_name)\n  File \"/usr/lib64/python2.7/runpy.py\", line 82, in _run_module_code\n    mod_name, mod_fname, mod_loader, pkg_name)\n  File \"/usr/lib64/python2.7/runpy.py\", line 72, in _run_code\n    exec code in run_globals\n  File \"/tmp/ansible_eos_command_payload_DavWF4/ansible_eos_command_payload.zip/ansible/modules/network/eos/eos_command.py\", line 248, in <module>\n  File \"/tmp/ansible_eos_command_payload_DavWF4/ansible_eos_command_payload.zip/ansible/modules/network/eos/eos_command.py\", line 219, in main\n  File \"/tmp/ansible_eos_command_payload_DavWF4/ansible_eos_command_payload.zip/ansible/module_utils/network/eos/eos.py\", line 637, in run_commands\n  File \"/tmp/ansible_eos_command_payload_DavWF4/ansible_eos_command_payload.zip/ansible/module_utils/network/eos/eos.py\", line 107, in get_connection\n  File \"/tmp/ansible_eos_command_payload_DavWF4/ansible_eos_command_payload.zip/ansible/module_utils/connection.py\", line 185, in __rpc__\nansible.module_utils.connection.ConnectionError: Could not connect to http://192.168.1.133:80/command-api: [Errno 111] Connection refused\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

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

(ansible) [vagrant@stumble stumble]$ 
(ansible) [vagrant@stumble stumble]$ 
(ansible) [vagrant@stumble stumble]$ ansible-playbook -i inventory.ini eos_show.yml 

PLAY [eos] **************************************************************************************************

TASK [show version] *****************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ansible.module_utils.connection.ConnectionError: Could not connect to http://192.168.1.133:80/command-api: [Errno 111] Connection refused
fatal: [eos1]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "module_stderr": "Traceback (most recent call last):\n  File \"/home/vagrant/.ansible/tmp/ansible-local-40497utj2p8g/ansible-tmp-1592047800.735867-4055-74241524366622/AnsiballZ_eos_command.py\", line 102, in <module>\n    _ansiballz_main()\n  File \"/home/vagrant/.ansible/tmp/ansible-local-40497utj2p8g/ansible-tmp-1592047800.735867-4055-74241524366622/AnsiballZ_eos_command.py\", line 94, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/vagrant/.ansible/tmp/ansible-local-40497utj2p8g/ansible-tmp-1592047800.735867-4055-74241524366622/AnsiballZ_eos_command.py\", line 40, in invoke_module\n    runpy.run_module(mod_name='ansible.modules.network.eos.eos_command', init_globals=None, run_name='__main__', alter_sys=True)\n  File \"/usr/lib64/python2.7/runpy.py\", line 176, in run_module\n    fname, loader, pkg_name)\n  File \"/usr/lib64/python2.7/runpy.py\", line 82, in _run_module_code\n    mod_name, mod_fname, mod_loader, pkg_name)\n  File \"/usr/lib64/python2.7/runpy.py\", line 72, in _run_code\n    exec code in run_globals\n  File \"/tmp/ansible_eos_command_payload_EHXx7W/ansible_eos_command_payload.zip/ansible/modules/network/eos/eos_command.py\", line 248, in <module>\n  File \"/tmp/ansible_eos_command_payload_EHXx7W/ansible_eos_command_payload.zip/ansible/modules/network/eos/eos_command.py\", line 219, in main\n  File \"/tmp/ansible_eos_command_payload_EHXx7W/ansible_eos_command_payload.zip/ansible/module_utils/network/eos/eos.py\", line 637, in run_commands\n  File \"/tmp/ansible_eos_command_payload_EHXx7W/ansible_eos_command_payload.zip/ansible/module_utils/network/eos/eos.py\", line 107, in get_connection\n  File \"/tmp/ansible_eos_command_payload_EHXx7W/ansible_eos_command_payload.zip/ansible/module_utils/connection.py\", line 185, in __rpc__\nansible.module_utils.connection.ConnectionError: Could not connect to http://192.168.1.133:80/command-api: [Errno 111] Connection refused\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

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

(ansible) [vagrant@stumble stumble]$ ansible-playbook -i inventory.ini eos_show.yml 

PLAY [eos] **************************************************************************************************

TASK [show version] *****************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ansible.module_utils.connection.ConnectionError: Could not connect to http://192.168.1.133:80/command-api: [Errno 111] Connection refused
fatal: [eos1]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "module_stderr": "Traceback (most recent call last):\n  File \"/home/vagrant/.ansible/tmp/ansible-local-4088qmoqg6k4/ansible-tmp-1592047844.611491-4094-263218421081738/AnsiballZ_eos_command.py\", line 102, in <module>\n    _ansiballz_main()\n  File \"/home/vagrant/.ansible/tmp/ansible-local-4088qmoqg6k4/ansible-tmp-1592047844.611491-4094-263218421081738/AnsiballZ_eos_command.py\", line 94, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/vagrant/.ansible/tmp/ansible-local-4088qmoqg6k4/an
(ansible) [vagrant@stumble stumble]$ ansible-playbook -i inventory.ini eos_show.yml 

PLAY [eos] **************************************************************************************************

TASK [show version] *****************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ansible.module_utils.connection.ConnectionError: Could not connect to http://192.168.1.133:80/command-api: [Errno 111] Connection refused
fatal: [eos1]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "module_stderr": "Traceback (most recent call last):\n  File \"/home/vagrant/.ansible/tmp/ansible-local-41274_remwl3/ansible-tmp-1592047863.403169-4133-45467802027754/AnsiballZ_eos_command.py\", line 102, in <module>\n    _ansiballz_main()\n  File \"/home/vagrant/.ansible/tmp/ansible-local-41274_remwl3/ansible-tmp-1592047863.403169-4133-45467802027754/AnsiballZ_eos_command.py\", line 94, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/vagrant/.ansible/tmp/ansible-local-41274_remwl3/ansi
(ansible) [vagrant@stumble stumble]$ ansible-playbook -i inventory.ini eos_show.yml 

PLAY [eos] **************************************************************************************************

TASK [show version] *****************************************************************************************
ok: [eos1]

TASK [debug] ************************************************************************************************
ok: [eos1] => {
    "msg": {
        "ansible_facts": {
            "discovered_interpreter_python": "/usr/bin/python"
        },
        "changed": false,
        "failed": false,
        "stdout": [
            "cEOSLab\nHardware version:    \nSerial number:       \nSystem MAC address:  0242.ac2a.8f7d\n\nSoftware image version: 4.21.10M\nArchitecture:           i386\nInternal build version: 4.21.10M-15347597.42110M\nInternal build ID:      9d960dea-a6da-424b-b373-2958c07c48c3\n\ncEOS tools version: 1.1\n\nUptime:                 0 weeks, 0 days, 3 hours and 56 minutes\nTotal memory:           2039264 kB\nFree memory:            1254684 kB"
        ],
        "stdout_lines": [
            [
                "cEOSLab",
                "Hardware version:    ",
                "Serial number:       ",
                "System MAC address:  0242.ac2a.8f7d",
                "",
                "Software image version: 4.21.10M",
                "Architecture:           i386",
                "Internal build version: 4.21.10M-15347597.42110M",
                "Internal build ID:      9d960dea-a6da-424b-b373-2958c07c48c3",
                "",
                "cEOS tools version: 1.1",
                "",
                "Uptime:                 0 weeks, 0 days, 3 hours and 56 minutes",
                "Total memory:           2039264 kB",
                "Free memory:            1254684 kB"
            ]
        ]
    }
}

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

(ansible) [vagrant@stumble stumble]$ ansible-playbook -i inventory.ini eos_show.yml 

PLAY [eos] **************************************************************************************************

TASK [show version] *****************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: ansible.module_utils.connection.ConnectionError: incomplete token (at token 1: 'ver')
fatal: [eos1]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "module_stderr": "Traceback (most recent call last):\n  File \"/home/vagrant/.ansible/tmp/ansible-local-4211h2y17s33/ansible-tmp-1592047950.0063741-4217-264763540732757/AnsiballZ_eos_command.py\", line 102, in <module>\n    _ansiballz_main()\n  File \"/home/vagrant/.ansible/tmp/ansible-local-4211h2y17s33/ansible-tmp-1592047950.0063741-4217-264763540732757/AnsiballZ_eos_command.py\", line 94, in _ansiballz_main\n    invoke_module(zipped_mod, temp_path, ANSIBALLZ_PARAMS)\n  File \"/home/vagrant/.ansible/tmp/ansible-local-4211h2y17s33/ansible-tmp-1592047950.0063741-4217-264763540732757/AnsiballZ_eos_command.py\", line 40, in invoke_module\n    runpy.run_module(mod_name='ansible.modules.network.eos.eos_command', init_globals=None, run_name='__main__', alter_sys=True)\n  File \"/usr/lib64/python2.7/runpy.py\", line 176, in run_module\n    fname, loader, pkg_name)\n  File \"/usr/lib64/python2.7/runpy.py\", line 82, in _run_module_code\n    mod_name, mod_fname, mod_loader, pkg_name)\n  File \"/usr/lib64/python2.7/runpy.py\", line 72, in _run_code\n    exec code in run_globals\n  File \"/tmp/ansible_eos_command_payload_syvs3j/ansible_eos_command_payload.zip/ansible/modules/network/eos/eos_command.py\", line 248, in <module>\n  File \"/tmp/ansible_eos_command_payload_syvs3j/ansible_eos_command_payload.zip/ansible/modules/network/eos/eos_command.py\", line 219, in main\n  File \"/tmp/ansible_eos_command_payload_syvs3j/ansible_eos_command_payload.zip/ansible/module_utils/network/eos/eos.py\", line 638, in run_commands\n  File \"/tmp/ansible_eos_command_payload_syvs3j/ansible_eos_command_payload.zip/ansible/module_utils/network/eos/eos.py\", line 483, in run_commands\n  File \"/tmp/ansible_eos_command_payload_syvs3j/ansible_eos_command_payload.zip/ansible/module_utils/network/eos/eos.py\", line 451, in run_queue\n  File \"/tmp/ansible_eos_command_payload_syvs3j/ansible_eos_command_payload.zip/ansible/module_utils/connection.py\", line 185, in __rpc__\nansible.module_utils.connection.ConnectionError: incomplete token (at token 1: 'ver')\n", "module_stdout": "", "msg": "MODULE FAILURE\nSee stdout/stderr for the exact error", "rc": 1}

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

(ansible) [vagrant@stumble stumble]$ 

Part6 にむけて

もう少しネットワーク方面をやってみたいと思います。