はじめに
こちらは Cisco の有志による Cisco Systems Japan Advent Calendar 2025 の記事の1つとして投稿しています。
こちらの記事では、CML 上で virl2_client を使用したノードのデプロイの自動化について説明します。
公式ドキュメント( https://developer.cisco.com/docs/virl2-client/ )が用意されているのですが、実装例やドキュメントが見つけられず、苦労したのでメモを残します。
用語集
本記事で使用する用語について定義しておきます。
- ノード : CML 上で動作する Router や Switch 等のシミュレータのこと
- イメージ : CML 上で動作する Router や Switch 等の OS ファイルのこと
- デプロイ : CML 上にノードを配置、起動させること
- ラボ : CML 内で Router 等を配置している1つのシミュレート環境のこと
環境について
私が今回実施した環境は以下になります。
Python 3.13.7
virl2_client 2.9.1
CML 2.9
上記の環境で実現できましたが、必要に応じてバージョン等は調整いただければと思います。
やりたいこと
私は個人的に CML でネットワークの検証をする環境を自動で作りたい、と思っていました。
今回は、複数の IOS-XE ルータに、基本的な config が入っている状態で起動してきてくれる、まで実施しました。
具体的な手順としては以下のとおりです。
- Router の Image Definition, Node Definition を用意する
- Router を実際に配置する
- Router に設定を投入する
Image Definition, Node Definition を用意する
CML でノードを配置するにはイメージとノードの定義を用意しておく必要があります。
実際には、以下のような画面で確認できるのですが、おそらく基本的な router や switch はデフォルトで用意されているはずです。
image
今回は、C8000v という IOS-XE の仮想ルータ、を使用します。
元々用意されていたので、そちらを使用します。
もし、自分が使いたいノードやイメージがない、という場合には自分でアップロードすることもできます。
アップロードの方法には 2 種類あります。
- GUI からアップロードする
- python を利用してアップロードする
個人的には、1つのCML 環境につき1度実施すれば良い作業ですので、GUI で実施するのがオススメです。
参考までに python でのやり方を載せておきます。
ノードやイメージの項目を定義した yaml ファイルを予め用意しておきます。
そのうえで、以下のようなコードでアップロードができます。
import yaml
from virl2_client import ClientLibrary
client = ClientLibrary("CML URL", "username", "password", ssl_verify=False)
filename = "******.qcow2"
client.definitions.upload_image_file(filename)
file_path = "****.yaml"
with open(file_path, 'r') as file:
yaml_content = yaml.safe_load(file)
client.definitions.upload_node_definition(yaml_content, False, False)
まず、virl2_client ライブラリを使用して CML 環境のインスタンスを用意します。
この時、CML URL , username , password はご利用の環境の情報を指定してください。
このインスタンスを指定することで自分の環境にファイルのアップロードやノードの配置等が行えます。
実際に image ファイル、ノード定義を記述した yaml ファイルのアップロードを実施しています。
image_file_path = "****.yaml"
with open(image_file_path, 'r') as image_file:
image_yaml_content = yaml.safe_load(image_file)
client.definitions.upload_image_definition(image_yaml_content, False, False)
そして、イメージ定義を記述した yaml ファイルをアップロードすることで、CML 上に反映されているはずです。
Router を実際に配置する
Router を配置し、起動するだけなら、以下のようなコードで実現可能です。
from virl2_client import ClientLibrary
client = ClientLibrary("CML URL", "username", "password", ssl_verify=False)
lab = client.create_lab()
c8kv_1 = lab.create_node("c8kv-1", "cat8000v", 0, 0)
c8kv_2 = lab.create_node("c8kv-2", "cat8000v", 0, 200)
# alternatively, use this convenience function:
lab.connect_two_nodes(c8kv_1, c8kv_2)
# start the lab
lab.start()
# print nodes and interfaces states:
for node in lab.nodes():
print(node, node.state, node.cpu_usage)
for interface in node.interfaces():
print(interface, interface.readpackets, interface.writepackets)
こちらのコードでは、以下のようなことを実現しています。
- ノードの配置
- インタフェースの用意
- ノード同士の接続
- ラボの開始
最後の for 文について
ラボの開始後、起動しているかを確認するため、node の状態、 interface の状態を表示しています
実行後には CML 上にラボが作成され、以下のようになっているはずです。
コンソールにも以下のような出力がされているはずです。
~ python3.13 arrange_router.py
SSL Verification disabled
Node: c8kv-1 BOOTED 52.82
Interface: Loopback0 0 0
Interface: GigabitEthernet1 0 0
Node: c8kv-2 BOOTED 100
Interface: Loopback0 0 0
Interface: GigabitEthernet1 0 0
Router に設定を投入する
さて、今までの手順で Router の起動までは行えるようになりました。
設定を入れた状態で上がってくるようにするには以下のようなコードを追加します。
c8kv_1 = lab.create_node("c8kv-1", "cat8000v", 0, 0)
c8kv_2 = lab.create_node("c8kv-2", "cat8000v", 0, 200)
# ファイルを開いて内容を読み込み、変数に代入する例
file_path = "./c8kv1-test.cfg" # 読み込みたいファイルのパス
with open(file_path, "r", encoding="utf-8") as file:
c8kv1_cfg = file.read() # ファイルの全内容を文字列として読み込む
file_path = "./c8kv2-test.cfg" # 読み込みたいファイルのパス
with open(file_path, "r", encoding="utf-8") as file:
c8kv2_cfg = file.read() # ファイルの全内容を文字列として読み込む
c8kv_1.config = c8kv1_cfg
c8kv_2.config = c8kv2_cfg
こちらのコードでは、設定ファイルを読み込んで機器に投入しています。
こちらの設定ファイルには実際にルータから抜き出した running-config 等を利用できます。
完成版は以下になっています。
完成版 python コード
from virl2_client import ClientLibrary
client = ClientLibrary("CML URL", "username", "password", ssl_verify=False)
lab = client.create_lab()
c8kv_1 = lab.create_node("c8kv-1", "cat8000v", 0, 0)
c8kv_2 = lab.create_node("c8kv-2", "cat8000v", 0, 200)
# ファイルを開いて内容を読み込み、変数に代入する例
file_path = "./c8kv1-test.cfg" # 読み込みたいファイルのパス
with open(file_path, "r", encoding="utf-8") as file:
c8kv1_cfg = file.read() # ファイルの全内容を文字列として読み込む
file_path = "./c8kv2-test.cfg" # 読み込みたいファイルのパス
with open(file_path, "r", encoding="utf-8") as file:
c8kv2_cfg = file.read() # ファイルの全内容を文字列として読み込む
c8kv_1.config = c8kv1_cfg
c8kv_2.config = c8kv2_cfg
# create a link between r1 and r2
c8kv1_i1 = c8kv_1.create_interface()
c8kv2_i1 = c8kv_2.create_interface()
# alternatively, use this convenience function:
lab.connect_two_nodes(c8kv_1, c8kv_2)
# start the lab
lab.start()
# print nodes and interfaces states:
for node in lab.nodes():
print(node, node.state, node.cpu_usage)
for interface in node.interfaces():
print(interface, interface.readpackets, interface.writepackets)
こちらのコードを実行すると設定が入った状態で機器が起動してくるはずです。
最後に
今回は、virl2_client を使用して、CML 上に設定が入った状態で機器が起動してくるようなコードを実装しました。
こちらを利用して、複数台の構成をコマンド1つで起動させることができるようになりました。
みなさんも是非こちらを参考に環境の構築を自動化してみてください。
参考URL
