Ansible cli_commandモジュールのprompt/answerオプション動作確認
Ansibleのcli_command
モジュールは、ネットワーク機器でshowコマンド等を実行できるマルチOS対応のモジュールです。
本モジュールは、Cisco IOS、NX-OS、Juniper等、OSの違いを意識せずに使えるのが最大のメリットですが、他にも、コマンド実行後に "複数の" 確認メッセージが出る場合に、あらかじめ指定した回答を返すことが出来ます。
後者については、Red HatのAnsibleブログでも、Ciscoルータの再起動(reload)の例が紹介されています。
今回は、Ansibleブログと同じくCisco IOSで、様々な確認メッセージ(promptオプション)と回答(answerオプション)のパターンで動作確認してみました。
Ansibleは2.8.4、NW機器はCatalyst3560、12.2台を使用しました。
CLIで再起動した時の確認メッセージ
①Cisco IOSの場合、前回の設定保存以降に一度でもグローバルコンフィグレーションモードに移行した場合、設定変更していなくても保存するか聞かれます。
Router#reload System configuration has been modified. Save? [yes/no]:
②その後、本当に再起動して問題ないか聞かれます。
Proceed with reload? [confirm]
OKパターン1:prompt
オプションを①Save?
、②confirm
の順番で定義
Playbook
prompt
オプションに、メッセージの表示順通り、リスト形式で①Save\?
、②confirm
を定義しました。(①は?
が正規表現として扱われないよう、\
でエスケープ処理しています。)
各メッセージに対する回答は、いずれもy
にしています。
check_all
オプションはデフォルトでFalse
が採用され、①②いずれかに回答したタイミングでそれ以降のメッセージ確認/回答は行いません。そのため今回はTrue
を指定し、①②両方に回答するようにしています。True
の場合、設定保存済みで①が表示されないケースでは、①のプロンプトを待ち続け、コマンドタイムアウトでエラー終了となってしまうので注意が必要です。
--- - hosts: cisco gather_facts: no connection: network_cli tasks: - name: reboot ios device cli_command: command: reload check_all: True prompt: - 'Save\?' - 'confirm' answer: - 'y' - 'y'
実行結果
問題なく再起動できました。
$ ansible-playbook -i inventory_3560 playbook_cli_command1.yml PLAY [cisco] ******************************************************************************* TASK [reboot ios device] ******************************************************************* ok: [Router] PLAY RECAP ********************************************************************************* Router : ok=1 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
OKパターン2:prompt
オプションを②confirm
、①Save?
の順番で定義
Playbook
OKパターン1のprompt
オプションのリストデータを逆にした場合に、再起動できるか確認してみました。
--- - hosts: cisco gather_facts: no connection: network_cli tasks: - name: reboot ios device cli_command: command: reload check_all: True prompt: - 'confirm' - 'Save\?' answer: - 'y' - 'y'
実行結果
出力内容は割愛しますが、問題なく再起動できました。定義の順番は関係なさそうです。
NGパターン1:Save?
に対しシングルクォーテーションなしのyes
で回答
Playbook
設定保存するかSave? [yes/no]:
で聞かれた時、シングルクォーテーションなしのyes
で回答してみました。yes
かno
で答えてくれと言われているので、このパターンは一見問題なさそうです。
--- - hosts: cisco gather_facts: no connection: network_cli tasks: - name: reboot ios device cli_command: command: reload check_all: True prompt: - 'Save\?' - 'confirm' answer: - yes # yからyesに変更。かつシングルクォーテーションを外す。 - 'y'
実行結果
コマンドタイムアウトでエラー終了してしまいました。デバッグモードの途中結果を見ると、yes
がtrue
に変換されています。別の方法でも確認したところ、どうやらyes
の代わりにTrue
で回答し、そこで止まってしまったようです。
$ ansible-playbook -i inventory_3560 playbook_cli_command1.yml -vvv (省略) fatal: [Router]: FAILED! => { "changed": false, "invocation": { "module_args": { "answer": [ true, "y" ], "check_all": true, "command": "reload", "prompt": [ "Save\\?", "confirm" ], "sendonly": false } }, "msg": "command timeout triggered, timeout value is 30 secs.\nSee the timeout setting options in the Network Debug and Troubleshooting Guide." } PLAY RECAP ********************************************************************************* Router : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
NGパターン2:Save?
をダブルクォーテーションで定義
Playbook
これまでのPlaybookはすべての値をシングルクォーテーションで囲っていましたが、代わりにSave?
をダブルクォーテーションで囲ってみます。多くのケースでは、どちらで囲っても問題なく、何となく選んでいるケースが多いと思います。
--- - hosts: cisco gather_facts: no connection: network_cli tasks: - name: reboot ios device cli_command: command: reload check_all: True prompt: - "Save\?" # シングルクォーテーションからダブルクォーテーションに変更 - 'confirm' answer: - 'y' - 'y'
実行結果
シンタックスエラーとなってしまいました。ダブルクォーテーション内でエスケープ処理する場合、"Save\\?"
とすれば問題なさそうです。(使い分けがややこしいですね!)
$ ansible-playbook -i inventory_3560 playbook_cli_command1.yml -vvv (省略) ERROR! Syntax Error while loading YAML. found unknown escape character '?' The error appears to be in '/home/centos/venv/ansible/playbook_cli_command1.yml': line 13, column 19, but may be elsewhere in the file depending on the exact syntax problem. The offending line appears to be: prompt: - "Save\?" ^ here
そもそもの話になってしまいますが、再起動は、直前に設定保存すればプロンプト処理は1回で済むため、わざわざcli_command
モジュールを使う必要はないかもしれません。
他の応用例として、拡張Tracerouteの実行例もメモしておきます。
おまけ:拡張Tracerouteの実行例
CLIで実行した時のメッセージ
Router#traceroute Protocol [ip]: ip Target IP address: 192.168.100.1 Source address: 192.168.100.24 Numeric display [n]: n Timeout in seconds [3]: 3 Probe count [3]: 3 Minimum Time to Live [1]: 1 Maximum Time to Live [30]: 10 Port Number [33434]: 33434 Loose, Strict, Record, Timestamp, Verbose[none]: Type escape sequence to abort. Tracing the route to 192.168.100.1 1 192.168.100.1 0 msec 0 msec 0 msec
Playbook
--- - hosts: cisco gather_facts: no connection: network_cli tasks: - name: issue extended traceroute command cli_command: command: traceroute check_all: True prompt: - 'Protocol' - 'Target' - 'Source' - 'Numeric' - 'Timeout' - 'Probe' - 'Minimum' - 'Maximum' - 'Port' - 'Loose' answer: - 'ip' - '192.168.100.1' - '192.168.100.24' - 'n' - '3' - '3' - '1' - '10' - '33434' - '' register: result - name: debug debug: msg: "{{ result }}"
実行結果
$ ansible-playbook -i inventory_3560 playbook_cli_traceroute.yml PLAY [cisco] ******************************************************************************* TASK [issue extended traceroute command] ******************************************************************* ok: [Router] TASK [debug] ******************************************************************************* ok: [Router] => { "msg": { "changed": false, "failed": false, "stdout": "Protocol [ip]: ip\nTarget IP address: 192.168.100.1\nSource address: 192.168.100.24\nNumeric display [n]: n\nTimeout in seconds [3]: 3\nProbe count [3]: 3\nMinimum Time to Live [1]: 1\nMaximum Time to Live [30]: 10\nPort Number [33434]: 33434\nLoose, Strict, Record, Timestamp, Verbose[none]: \nType escape sequence to abort.\nTracing the route to 192.168.100.1\n\n 1 192.168.100.1 0 msec 0 msec 0 msec", "stdout_lines": [ "Protocol [ip]: ip", "Target IP address: 192.168.100.1", "Source address: 192.168.100.24", "Numeric display [n]: n", "Timeout in seconds [3]: 3", "Probe count [3]: 3", "Minimum Time to Live [1]: 1", "Maximum Time to Live [30]: 10", "Port Number [33434]: 33434", "Loose, Strict, Record, Timestamp, Verbose[none]: ", "Type escape sequence to abort.", "Tracing the route to 192.168.100.1", "", " 1 192.168.100.1 0 msec 0 msec 0 msec" ] } } PLAY RECAP ********************************************************************************* Router : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0