Skip to content

Python で CML 上のノードの X / Y 座標を変更するサンプル

Cisco CML でラボを作成する際、微妙にノードの位置が揃わない場合があります… GUI 上から揃える方法が分からなかった為、「ノードの X / Y 座標を指定出来る Python スクリプト」を書いたのでメモしておきます。 検証は Ubuntu 22.04LTS 上の Python 3.10.4 で行いました。

venv 環境の作成

venv 環境を作成し、tabulatevirl2-client をインストールしておきます。

1
2
3
4
5
6
7
mkdir links
cd links
python3 -m venv .venv
echo 'source .venv/bin/activate' > .envrc
direnv allow
python3 -m pip install --upgrade pip
python3 -m pip install tabulate virl2_client

サンプルスクリプト

サンプルスクリプトは以下の通りです。 CML のログイン情報は cmlutils と同じく、~/.virlrc を参照するものとしました。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#!/usr/bin/env python3

import argparse
import os

from tabulate import tabulate
from virl2_client import ClientLibrary


def get_property(property: str):
    path = os.path.expanduser("~")
    virlrc = os.path.join(path, ".virlrc")
    if os.path.isfile(virlrc):
        with open(virlrc) as fh:
            config = fh.readlines()

        for line in config:
            if line.startswith(property):
                prop = line.split("=")[1].strip()
                if prop.startswith('"') and prop.endswith('"'):
                    prop = prop[1:-1]
                return prop


def get_nodes(args: argparse.ArgumentParser, cml: ClientLibrary):
    data = []
    index = 0
    for lab in cml.all_labs():
        for node in lab.nodes():
            index += 1
            if args.no == str(index):
                if args.x != None:
                    node.x = int(args.x)
                if args.y != None:
                    node.y = int(args.y)
            data.append(
                [
                    index,
                    lab.title,
                    lab.id,
                    node.label,
                    node.node_definition,
                    node.x,
                    node.y,
                ]
            )
    print(
        tabulate(
            data,
            headers=["No", "Lab", "ID", "Node", "Definition", "X", "Y"],
        )
    )


def main():
    parser = argparse.ArgumentParser(description="Adjust the position of the node.")
    parser.add_argument("-n", "--no", help="Number")
    parser.add_argument("-x", help="X")
    parser.add_argument("-y", help="Y")
    args = parser.parse_args()

    address = get_property("VIRL_HOST")
    username = get_property("VIRL_USERNAME")
    password = get_property("VIRL_PASSWORD")
    verify = True
    if get_property("CML_VERIFY_CERT").lower() == "false":
        verify = False
    cml = ClientLibrary(address, username, password, verify)
    cml.is_system_ready(wait=True)
    get_nodes(args, cml)


if __name__ == "__main__":
    main()

実行例

引数を指定せずに実行すると各ノードの X / Y 座標を表示します。

1
2
3
4
5
6
7
8
9
# ./adjust.py
SSL Verification disabled
  No  Lab    ID                                    Node      Definition            X    Y
----  -----  ------------------------------------  --------  ------------------  ---  ---
   1  Lab1   785c9a1f-4b6e-43cd-a77f-7ef12142620f  external  external_connector  150    0
   2  Lab1   785c9a1f-4b6e-43cd-a77f-7ef12142620f  switch    unmanaged_switch    150   50
   3  Lab1   785c9a1f-4b6e-43cd-a77f-7ef12142620f  ubuntu1   ubuntu22              0  100
   4  Lab1   785c9a1f-4b6e-43cd-a77f-7ef12142620f  ubuntu2   ubuntu22            150  100
   5  Lab1   785c9a1f-4b6e-43cd-a77f-7ef12142620f  ubuntu3   ubuntu22            300  100

「No.5 の Y 座標を 150 へ変更する」場合は以下のように実行します。 「X 座標だけを変更する」「Y 座標だけを変更する」「X / Y 座標両方同時に変更する」などが可能です。

1
2
3
4
5
6
7
8
9
# ./adjust.py --no 5 -y 150
SSL Verification disabled
  No  Lab    ID                                    Node      Definition            X    Y
----  -----  ------------------------------------  --------  ------------------  ---  ---
   1  Lab1   785c9a1f-4b6e-43cd-a77f-7ef12142620f  external  external_connector  150    0
   2  Lab1   785c9a1f-4b6e-43cd-a77f-7ef12142620f  switch    unmanaged_switch    150   50
   3  Lab1   785c9a1f-4b6e-43cd-a77f-7ef12142620f  ubuntu1   ubuntu22              0  100
   4  Lab1   785c9a1f-4b6e-43cd-a77f-7ef12142620f  ubuntu2   ubuntu22            150  100
   5  Lab1   785c9a1f-4b6e-43cd-a77f-7ef12142620f  ubuntu3   ubuntu22            300  150