■ はじめに
Ansible 2.8 では、RESTCONF でネットワーク機器の情報を取得したり、設定を変更したりできる RESTCONF モジュールが導入されます。(本記事執筆時現在 RC段階)
この記事では restconf_get
モジュールを利用して、IOS-XE へ RESTCONF でアクセスしてインターフェース情報の取得を試してみます。(後述しますが、そのままではうまくいかなかったので、暫定対処として一部コードの修正をして試しました → Ansible 2.8.2 でバグ解消済み)
■ 環境
- Cisco IOS-XE (16.8)
- Cisco DevNet SandBox
- NETCONF-YANG and RESTCONF Always-On
netconf-yang
、restconf
コマンド有効
- Cisco DevNet SandBox
- Ansible 2.8.0rc1
- 本記事執筆時現在 RC段階のため、
pip install ansible==2.8.0rc1
でインストール
- 本記事執筆時現在 RC段階のため、
■ 準備
Playook 実行に必要なファイルや Playbook を作成していきます。
インベントリファイル
ホスト情報を示すインベントリファイルを作成します。
- inventory
[ios] iosao1 ansible_host=ios-xe-mgmt.cisco.com
変数定義ファイル
インベントリファイルで定義したグループ ios
が利用する変数を定義するファイルを作成します。
- group_vars/ios.yml
ansible_connection: httpapi ansible_httpapi_port: 9443 ansible_network_os: restconf ansible_user: root ansible_password: p@ss9999 ansible_httpapi_use_ssl: yes ansible_httpapi_validate_certs: no
変数の説明
変数が多数登場しますのでそれぞれ説明します。
- ansible_connection
- 利用するコネクションプラグインを指定します。
- restconf では
httpapi
コネクションプラグインを利用します。ネットワークモジュールでは、他にもnetwork_cli
やnetconf
も利用されます。
- ansible_httpapi_port
- 利用するポートを指定します。SSH 接続では
ansible_port
やansible_ssh_port
変数でポート番号を指定しますが、ansible_httpapi_port
であることにご注意ください。 - デフォルトは、変数
ansible_httpapi_use_ssl
の値によって変わります。yes
の場合は443
、no
の場合は80
です。 - ここでは、環境の都合により
9443
を指定しています。
- 利用するポートを指定します。SSH 接続では
- ansible_network_os
- ネットワークOSを指定します。
ios_config
やjunos_config
モジュールなどのベンダー個別モジュールを利用する場合はこの変数はios
やjunos
といった値を指定しますが、RESTCONF モジュールを利用する場合は、このようにrestconf
を利用します。こうすることで、restconf
という httpapi プラグインが利用されます。- もし、例えば
ios
を指定した場合はunable to load API plugin for network_os ios
というエラーが表示されます。
- ansible_user
- ユーザー名を指定します。
- ansible_password
- パスワードを指定します。ここではダミーの値を記載しています。必要に応じて
ansible-vault
で暗号化します。
- パスワードを指定します。ここではダミーの値を記載しています。必要に応じて
- ansible_httpapi_use_ssl
- ansible_httpapi_validate_certs
- SSL/TLS 接続する場合に証明書をかどうかを指定します。デフォルトは
yes
です。 - ここでは、環境の都合により
no
を指定しています。
- SSL/TLS 接続する場合に証明書をかどうかを指定します。デフォルトは
Playbook
処理内容を記載する Playbook を作成します。
- restconf.yml
- hosts: ios gather_facts: no tasks: - name: restconf test restconf_get: path: /data/ietf-interfaces:interfaces register: result - name: debug result debug: msg: "{{ result }}"
path は Cisco DevNet Learning Labs の「Exploring IOS XE YANG Data Models with RESTCONF」や、こちらのサンプルに出てきたものを利用します。
restconf モジュールでは、root_path
としてデフォルトで /restconf
が定義されているため、実際には、/restconf
以降を path
に指定します。
■ 実行(失敗)
それでは、Playbook を実行します。が、エラーになってしまいます。
$ ansible-playbook -i inventory restconf.yml (...略...) fatal: [iosao1]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": false, "code": 406, "msg": "HTTP Error 406: Not Acceptable"} (...略...)
HTTP Error 406: Not Acceptable
とのことなので、HTTP の Acceppt フィールドまわりを調査しました。
原因調査と暫定対処
Ansible ではなく Postman で同様の GET を試すと以下の結果になりました。
Accept: application/yang-data+json
では正常に json で情報が取得できたAccept:
では406: Not Acceptable
になった- Accept フィールド自体を指定しない場合は、XML で情報が取得できた
また、lib/ansible/module_utils/network/restconf/restconf.py を見ると、以下のようになっていました。
accept = None if output == 'xml': accept = 'application/yang.data+xml' connection = Connection(module._socket_path) return connection.send_request(None, path=path, method='GET', accept=accept)
どうやら、Accept フィールドが空になってしまっていたようです。
暫定対処として、
accept = None
の箇所を
accept = 'application/yang-data+json'
に修正しました。
■ 再実行(成功)
暫定対処したところで、再度同じ Playbook を実行します。
$ ansible-playbook -i inventory restconf.yml PLAY [ios] *********************************************************************************************************************** TASK [restconf test] ************************************************************************************************************* [WARNING]: Platform darwin on host iosao1 is using the discovered Python interpreter at /usr/bin/python, but future installation of another Python interpreter could change this. See https://docs.ansible.com/ansible/2.8/reference_appendices/interpreter_discovery.html for more information. ok: [iosao1] TASK [debug result] ************************************************************************************************************** ok: [iosao1] => { "msg": { "ansible_facts": { "discovered_interpreter_python": "/usr/bin/python" }, "changed": false, "failed": false, "response": { "ietf-interfaces:interfaces": { "interface": [ { "description": "DON'T TOUCH ME", "enabled": true, "ietf-ip:ipv4": { "address": [ { "ip": "10.10.20.48", "netmask": "255.255.255.0" } ] }, "ietf-ip:ipv6": {}, "name": "GigabitEthernet1", "type": "iana-if-type:ethernetCsmacd" }, { "enabled": true, "ietf-ip:ipv4": {}, "ietf-ip:ipv6": {}, "name": "GigabitEthernet2", "type": "iana-if-type:ethernetCsmacd" }, { "enabled": false, "ietf-ip:ipv4": {}, "ietf-ip:ipv6": {}, "name": "GigabitEthernet3", "type": "iana-if-type:ethernetCsmacd" } ] } }, "warnings": [ "Platform darwin on host iosao1 is using the discovered Python interpreter at /usr/bin/python, but future installation of another Python interpreter could change this. See https://docs.ansible.com/ansible/2.8/reference_appendices/interpreter_discovery.html for more information." ] } } PLAY RECAP *********************************************************************************************************************** iosao1 : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
こんどは正常にインターフェース情報を取得できました。
※ちらっと表示されている Python interpreter についての WARNING の詳細は こちらをご参照ください。
■ まとめ
Ansible 2.8 で導入される restconf_get
モジュールで、Cisco IOS-XE のインターフェース情報を取得してみました。
(一部コード修正が必要だった点は、他の対応方法があるのかなどの点は現時点では不明です。)
RESTCONF が有効であれば、他のベンダーの機器にも使える雰囲気がします。ベンダーごとにモジュールを使い分けなくて良い点は便利そうだと感じました。
また、Cisco IOS-XE では、RESTCONF が使えるようになってきているようなので、今後 RESTCONF は自動化の手段の選択肢になり得るのではないかと思います。
[2019/05/27 追記] 少しに気なる issue を見つけました。
restconf httpapi plugin Media Type · Issue #56680 · ansible/ansible · GitHub
[2019/09/06 追記] Ansible 2.8.2 で修正されていることを確認しました。 ansible/CHANGELOG-v2.8.rst at stable-2.8 · ansible/ansible · GitHub
Fix media type of RESTCONF requests.
[2019/09/09 追記] 設定変更編を投稿しました。