(この記事はネットワーク自動化 Advent Calendar 2019 15日目として書いています)
今回は pyATS/Genie の Genie API を紹介します。後半では Robot Framework と組み合わせた使い方を紹介しています。
目次
Genie API とは?
pyATS/Genie を少しでも試したことのなる人には、pyATS/Genie では主に python コードを書いてネットワークの自動化をするというのは理解いただいているかと思います。
そのコーディングを手助けするために用意されているのが Genie API 、要はコーディングが楽になるライブラリです。
まずはどんなものがあるか見てみましょう。
上の画面の左側のボタンにある APIS をクリックします。
すると既に用意されている API が一覧で表示され、OS 毎にフィルターしたり、キーワードを検索ボックスに入れて、例えば bgp とか ospf とかのキーワードで探すことができます。
Genie API の名前をクリックすると、API に渡すパラメータや戻り値などが確認できます。下記は get_ospf_neighbors という API で OSPFネイバーのリストが取得できるということが情報から分かります。
現時点(2019年12月)で 500 近くの API が既に存在します。また、Genie ライブラリの抽象化は API にも引き継がれており、同じ API で異なるプラットフォームを同じように設定したり、情報を取得することができます。
ネットワーク構成と testbed.yaml
それでは今回 Genie API を試すネットワーク構成です。 IOSXE(R1_xe)、IOS-XR(R2_xr)、NX-OS(R3_nx)を VIRL 上で起動して使います。
全ルータで OSPF が Area0 で設定されており、接続インタフェースとループバック(10.1.1.1/32, 10.2.2.2/32, 10.3.3.3/32)が OSPF 経路として見える状況です。
testbed.yaml は下記になります。
devices:
R1_xe:
alias: uut
connections:
defaults:
via: ssh
ssh:
ip: 172.16.1.228
protocol: ssh
proxy: jump_host
credentials:
default:
password: Cisc0123
username: cisco
enable:
password: Cisc0123
os: iosxe
platform: iosxe
type: CSR1000v
R2_xr:
alias: R2_xr
connections:
defaults:
via: ssh
ssh:
ip: 172.16.1.229
protocol: ssh
proxy: jump_host
credentials:
default:
password: Cisc0123
username: admin
enable:
password: Cisc0123
os: iosxr
platform: iosxrv9k
type: IOS XRv 9000
R3_nx:
alias: R3_nx
connections:
defaults:
via: ssh
ssh:
ip: 172.16.1.230
protocol: ssh
proxy: jump_host
credentials:
default:
password: Cisc0123
username: admin
enable:
password: Cisc0123
os: nxos
platform: n9kv
type: NX-OSv 9000
jump_host:
connections:
cli:
ip: 172.25.192.134
port: 22
protocol: ssh
credentials:
default:
password: VIRL
username: virl
os: linux
type: linux
Genie Shell から Genie API を使ってみる
それではお手軽に python コードが試せる Genie Shell から Genie API を試してみます。
※既に python virtualenv の作成、pyATS/Genie はインストール済みと想定しています。
genie shell コマンドに –testbed-file オプションで testbed.yaml を渡すだけで、testbed.yaml を読み込んだ testbed オブジェクトが用意されて python interpreter が起動されます。
(genie)$ genie shell --testbed-file testbed.yaml
Welcome to Genie Interactive Shell
==================================
Python 3.7.3 (default, Jun 5 2019, 11:26:12)
[Clang 10.0.1 (clang-1001.0.46.4)]
>>> from genie.testbed import load
>>> testbed = load('testbed.yaml')
-------------------------------------------------------------------------------
>>>
機器への接続 <device>.connect()
それではデバイス R1_xe
を xe として testbed オブジェクトからセットします。
>>> testbed
<Testbed object 'testbed' at 0x10dc1e0f0>
>>> xe = testbed.devices['R1_xe']
>>> xe
<Device R1_xe at 0x10dc0d470>
xe
がデバイスオブジェクトになります。このデバイスへの接続には connect()
を下記のように実行します。
>>> xe.connect()
[2019-12-13 20:52:14,493] +++ R1_xe logfile /tmp/R1_xe-cli-20191213T205214492.log +++
[2019-12-13 20:52:14,494] +++ Unicon plugin iosxe +++
[2019-12-13 20:52:14,498] connection via proxy jump_host
[2019-12-13 20:52:14,502] +++ connection to spawn: ssh -l virl 172.25.192.134 -p 22, id: 4526263432 +++
[2019-12-13 20:52:14,503] connection to jump_host
virl@172.25.192.134's password:
Welcome to Ubuntu 16.04.4 LTS (GNU/Linux 4.4.0-116-generic x86_64)
System information as of Sat Dec 14 01:52:15 GMT 2019
System load: 21.22 IP address for eth0: 172.25.192.134
Usage of /: 33.6% of 191.02GB IP address for br3: 172.16.3.250
Memory usage: 51% IP address for br1: 172.16.1.250
Swap usage: 2% IP address for br2: 172.16.2.250
Processes: 1013 IP address for br4: 172.16.10.250
Users logged in: 0 IP address for docker0: 172.17.0.1
Graph this data and manage this system at:
https://landscape.canonical.com/
New release '18.04.3 LTS' available.
Run 'do-release-upgrade' to upgrade to it.
Last login: Sat Dec 14 01:41:43 2019 from 10.24.58.107
virl@asg-ucs4-virl:~$
[2019-12-13 20:52:16,869] +++ initializing handle +++
[2019-12-13 20:52:17,011] connection to R1_xe
ssh -l cisco 172.16.1.228
Password:
R1_xe>
[2019-12-13 20:52:17,816] +++ initializing handle +++
enable
Password:
R1_xe#
[2019-12-13 20:52:18,102] +++ R1_xe: executing command 'term length 0' +++
term length 0
R1_xe#
[2019-12-13 20:52:18,364] +++ R1_xe: executing command 'term width 0' +++
term width 0
R1_xe#
[2019-12-13 20:52:18,621] +++ R1_xe: executing command 'show version' +++
show version
Cisco IOS XE Software, Version 16.09.01
Cisco IOS Software [Fuji], Virtual XE Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), Version 16.9.1, RELEASE SOFTWARE (fc2)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2018 by Cisco Systems, Inc.
Compiled Tue 17-Jul-18 16:57 by mcpre
Cisco IOS-XE software, Copyright (c) 2005-2018 by cisco Systems, Inc.
All rights reserved. Certain components of Cisco IOS-XE software are
licensed under the GNU General Public License ("GPL") Version 2.0. The
software code licensed under GPL Version 2.0 is free software that comes
with ABSOLUTELY NO WARRANTY. You can redistribute and/or modify such
GPL code under the terms of GPL Version 2.0. For more details, see the
documentation or "License Notice" file accompanying the IOS-XE software,
or the applicable URL provided on the flyer accompanying the IOS-XE
software.
ROM: IOS-XE ROMMON
R1_xe uptime is 6 days, 11 hours, 25 minutes
Uptime for this control processor is 6 days, 11 hours, 26 minutes
System returned to ROM by reload
System image file is "bootflash:packages.conf"
Last reload reason: Reload Command
This product contains cryptographic features and is subject to United
States and local country laws governing import, export, transfer and
use. Delivery of Cisco cryptographic products does not imply
third-party authority to import, export, distribute or use encryption.
Importers, exporters, distributors and users are responsible for
compliance with U.S. and local country laws. By using this product you
agree to comply with applicable laws and regulations. If you are unable
to comply with U.S. and local laws, return this product immediately.
A summary of U.S. laws governing Cisco cryptographic products may be found at:
If you require further assistance please contact us by sending email to
export@cisco.com.
License Level: ax
License Type: Default. No valid license found.
Next reload license Level: ax
cisco CSR1000V (VXE) processor (revision VXE) with 1217428K/3075K bytes of memory.
Processor board ID 9ZFZVAFKW4L
2 Gigabit Ethernet interfaces
32768K bytes of non-volatile configuration memory.
3018864K bytes of physical memory.
7774207K bytes of virtual hard disk at bootflash:.
0K bytes of WebUI ODM Files at webui:.
Configuration register is 0x2102
R1_xe#
[2019-12-13 20:52:18,896] +++ R1_xe: config +++
config term
Enter configuration commands, one per line. End with CNTL/Z.
R1_xe(config)#no logging console
R1_xe(config)#line console 0
R1_xe(config-line)#exec-timeout 0
R1_xe(config-line)#end
R1_xe#
>>>
ここまでで、機器への接続ができましたので、Genie API を実行する準備ができました。
Genie API の実行 <device>.api.<api_name>()
Genie API はネットワークエンジニアに直感的に分かりやすく使えるようにデバイス中心に実行することができます。例えば、上記で見た get_ospf_neighbors
はデバイスオブジェクトに対して xe.api.
とした後に続けて下記のように実行できます。
>>> xe.api.get_ospf_neighbors()
Getting all ospf neighbors
[2019-12-13 20:55:55,018] +++ R1_xe: executing command 'show ip ospf neighbor' +++
show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
172.16.12.2 1 FULL/DR 00:00:36 172.16.12.2 GigabitEthernet2
R1_xe#
['172.16.12.2']
最後の行に API の戻り値としてリストで OSPFネイバー が取得できていることが分かります。お気づきになったでしょうか? Genie Parser では OSPF Neighbor の State や Address など全ての情報を構造化データと返すので、OSPFネイバーのみのリストが欲しいという場合にはその構造化データから取得するコードを書く必要がありますが、API を使うとその部分が省略できます。
実際に API がどのような事を知りたければ、オープンソースなのでコードを見ることができまし、何か追加したいものがあれば開発してコントリビュートすることも可能です。
実際にネイバーを取得しているコードが下記のようになっています。
try:
out = device.parse("show ip ospf neighbor")
except SchemaEmptyParserError:
return neighbor_addresses
if out and "interfaces" in out and interface in out["interfaces"]:
for neighbor in out["interfaces"][interface].get("neighbors", {}):
neighbor_addresses.append(neighbor)
return neighbor_addresses
見てみると、show ip ospf neighbor
をパースして、内容が空でないかをチェックし、また構造化データに沿って for 文でループしたりしていることが分かります。
そういうコードを書く手間がなくなるだけでも、かなり楽にコーディングができるようになります。
get_ API は情報取得に使う
もう一つ get_ospf_neighbor_address_in_state
を試して見ます。引数として state
を渡すことで条件に合致した OSPFネイバーのみを取得することができます。
>>> xe.api.get_ospf_neighbor_address_in_state(state='FULL/DR')
[2019-12-13 21:18:15,955] +++ R1_xe: executing command 'show ip ospf neighbor' +++
show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
172.16.12.2 1 FULL/DR 00:00:33 172.16.12.2 GigabitEthernet2
R1_xe#
['172.16.12.2']
>>>
試しに違う state
で試してみると、条件に合致しないのでネイバーが取得できません。
>>> xe.api.get_ospf_neighbor_address_in_state(state='FULL/BDR')
[2019-12-13 21:20:12,544] +++ R1_xe: executing command 'show ip ospf neighbor' +++
show ip ospf neighbor
Neighbor ID Pri State Dead Time Address Interface
172.16.12.2 1 FULL/DR 00:00:39 172.16.12.2 GigabitEthernet2
R1_xe#
[]
configure_ API で設定もできる
次は configure_
で始まる Genie API を試してみます。これは名前から分かるように設定を行うことができます。引数に OSPFプロセスID と対象のインタフェースを渡して passive
を投入する API です。
>>> xe.api.configure_ospf_passive_interface(ospf_process_id='1', interface=['GigabitEthernet2'])
[2019-12-13 21:24:40,290] +++ R1_xe: config +++
config term
Enter configuration commands, one per line. End with CNTL/Z.
R1_xe(config)#router ospf 1
R1_xe(config-router)#passive-interface GigabitEthernet2
R1_xe(config-router)#end
R1_xe#
>>>
verify_ API は確認に使う
verify_
で始まる Genie API は get_
に似ていますが、大きな相違点は確認用としてリトライを行います。下記のように APIガイド に沿って引数を渡すと、指定した最大時間とインターバルの範囲で繰り返し確認を行います。
>>> xe.api.verify_ospf_neighbor_address_in_state(addresses=['172.16.12.2'], state='FULL/DR', max_time=60, check_interval=30)
Starting a timeout with maximum time of 60 seconds with interval of 30 seconds, Test case will fail after the maximum time set
[2019-12-13 21:30:36,747] +++ R1_xe: executing command 'show ip ospf neighbor' +++
show ip ospf neighbor
R1_xe#
The following addresses are not in state FULL/DR: {'172.16.12.2'}
59.71 seconds remaining; Sleeping for 30.00 seconds. '1' attempt(s) have been performed
[2019-12-13 21:31:07,041] +++ R1_xe: executing command 'show ip ospf neighbor' +++
show ip ospf neighbor
R1_xe#
The following addresses are not in state FULL/DR: {'172.16.12.2'}
29.41 seconds remaining; Sleeping for 29.41 seconds. '2' attempt(s) have been performed
Performing the last attempt
[2019-12-13 21:31:36,751] +++ R1_xe: executing command 'show ip ospf neighbor' +++
show ip ospf neighbor
R1_xe#
The following addresses are not in state FULL/DR: {'172.16.12.2'}
0 second remaining; Will not sleep
Ran out of time for this timeout
False
>>>
例えば、インタフェースの shutdown
/ no shutdown
の後でネイバーがアップになるまで時間がかかる場合などに verify_ でリトライでネイバーアップになるまで確認を繰り返すことができます。
Genie API を使ってコーディングが簡単になるだろうことは分かりましたが、まだコーディング必要です。次はさらに簡単になる方法を紹介します。
Genie API を Robot Framework で使う
前述までの説明で Genie API を使うことでコーディング楽になることが分かりましたが、実は Robot Framework と組み合わせることでキーワードベースで分かり易い記述でネットワークの自動化を実現することが可能です。
Genie API は開発されると同時に Robot キーワードが自動的に追加されるという仕組みになっています。その為、Genie API で存在するものと同様の Robot キーワードは基本的に別途開発する必要はありません。
本記事ではどういう感じで使えるかというのをお伝えするのを目的としている為、Robot Framework の記述についての詳細は割愛します。
Genie API を使った Robot ファイルのサンプル
前の項目で使った Genie API を利用して Robot Framework で使う robot ファイルを作成してみました。ファイルの拡張子は .robot
になります。
# Genie API example with Robot
*** Settings ***
Library Collections
Library ats.robot.pyATSRobot
Library genie.libs.robot.GenieRobot
Library genie.libs.robot.GenieRobotApis
*** Variables ***
${testbed} testbed.yaml
*** Test Cases ***
Connect to Devices
use genie testbed "${testbed}"
connect to all devices
Check Ospf and Shut/Noshut Interface
@{ospf_neighbors} = Get Ospf Neighbors device=R1_xe
:For ${ospf_neighbor} IN @{ospf_neighbors}
\ @{neighbors} = Create List ${ospf_neighbor}
\ Verify Ospf Neighbor Address In State addresses=@{neighbors} state=FULL/DR device=R1_xe
\ Shut Interface interface=GigabitEthernet2 device=R1_xe
\ Unshut Interface interface=GigabitEthernet2 device=R1_xe
\ ${result} = Verify Ospf Neighbor Address In State addresses=@{neighbors} state=FULL/DR device=R1_xe
\ Should Be True ${result}
Settings
には pyATS/Genie のライブラリを指定する必要があることに注意してください。
実際の自動化テストの内容は Test Cases
に記載していきます。上記のファイルのテスト内容をざっくり書くとこんな感じです。
- 機器へ接続
- インターフェースの shut/no shut 及び OSPF ネイバー確認
- OSPFネイバーの一覧取得
- 取得ネイバーで下記を繰り返し
- OSPFネイバーの状態チェック ‘FULL/DR’ か
- インタフェースの shutdown
- インタフェースの no shutdown
- OSPFネイバーの状態チェック ‘FULL/DR’ か
- 4 の結果判定
実際には各キーワードの成否判定などを充実させるべきですが、サンプルとして見ていただければと思います。
Robot キーワードと Genie API の比較
下記の部分が Genie API を Robot キーワードとして書いている部分になります。
\ Verify Ospf Neighbor Address In State addresses=@{neighbors} state=FULL/DR device=R1_xe
\ Shut Interface interface=GigabitEthernet2 device=R1_xe
これは python
で書く場合の下記と同意となります。
xe.api.verify_ospf_neighbor_address_in_state(addresses=['<address>'], state='FULL/DR')
xe.api.shut_interface(interface='GigabitEthernet2')
比べると分かるかと思いますが、API の名前がそのまま Robot キーワード(_ を space に変換) に対応し、引数も同じようにキーワードに続けて書くだけです。Robot
で書く場合は device
は追加で指定する必要があります。
Robot ファイルの実行
それでは上記の robot
ファイルを実行してみます。robot
コマンドに続けてファイルを指定するだけです。
(genie)$ robot genie_api.robot
==============================================================================
Genie Api
==============================================================================
Connect to Devices | PASS |
------------------------------------------------------------------------------
Check Ospf and Shut/Noshut Interface | PASS |
------------------------------------------------------------------------------
Genie Api | PASS |
2 critical tests, 2 passed, 0 failed
2 tests total, 2 passed, 0 failed
==============================================================================
Output: /Users/ccieojisan/.pyenv/versions/3.7.3/envs/genie_pkg/output.xml
Log: /Users/ccieojisan/.pyenv/versions/3.7.3/envs/genie_pkg/log.html
Report: /Users/ccieojisan/.pyenv/versions/3.7.3/envs/genie_pkg/report.html
実際のコンソールでは下記のように PASS
や結果にはカラー付けがされる為、非常に結果が見易くなっています。
上記 Log
の項目にある log.html
は HTML ファイルになっており、ブラウザで開くと結果とログの詳細を確認することができます。
機器の接続からインタフェースの shut/no shut、OSPF ネイバーの確認部分はこんな感じです。
各項目を展開して詳細を開くと、実際のコンソールが画面が確認できます。具体的にどのような確認を行なっているか、設定を行なったが確認できます。
Genie API を Robot Framework の組み合わせも非常に強力なことが分かるかと思います。Genie API が豊富なネットワーク機器の設定、確認を提供し、Robot Framework の記述でキーワード対話形式で自動化テストを記述することが可能になります。
まとめ
- Genie API は python コーディングの手助けをしてくれる
- Genie API は オープンソースなので、問題があればソースを確認できるし、GitHub 上でコントリビュートすることも可能
https://github.com/CiscoTestAutomation/genielibs/tree/master/pkgs/sdk-pkg/src/genie/libs/sdk/apis - Genie API は既に 500 近く開発されており、随時追加されている
https://pubhub.devnetcloud.com/media/genie-feature-browser/docs/#/apis - Genie API には get_/verify_/configure_ と機能別に API が付けられている
- Genie API の追加と同時に Robot キーワードが自動的に追加される
https://developer.cisco.com/docs/genie-docs/ - Genie API と Robot Framework と組み合わせることでキーワード対話形式での自動化テストを作る事が可能になる
今回は Genie API を紹介しました。Python コーディングを手助けするものとして有益なこと、Robot Framework と組み合わせることで、コーディング無しでテスト自動化ができることも紹介しました。ネットワーク自動化の選択肢としては有力な組み合わせではないかと思います。