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