Skip to content

CML でノードの起動時間を取得する

Cisco CML で「一定時間以上、起動しているラボは停止する」という処理を実装しようと思ったのですが、ラボには「作成時間」や「起動時間」というプロパティが存在しないようです。 代替手段として「機器へ TELNET / SSH して uptime を取得する」という方法もあるかもしれませんが、イマイチです。 ラボそのものには「起動時間」のプロパティが無いものの、ノードには「起動時間を示すプロパティ」があるようです。 今回はその値を取得する Python のサンプルプログラムをメモしておきます。

検証環境

対象 バージョン
CML 2.6.1
macOS 14.4
Python 3.12.2

ノードの起動時間は BOOTED プロパティで取得出来る

結論から述べると「ノードの起動時間」は Labs にある /labs/{lab_id}/simulation_stats API の結果に含まれる BOOTED という値として取得出来ました。 「ノードの起動時間」ということで Nodes の API で取得出来そうな気がするのですが、こちらでは取得出来ませんでした。

file

実際に /labs/{lab_id}/simulation_stats API を実行した結果例は以下の通りです。 テストした対象ラボは 2 ノード存在する為、「2 ノード分の実行結果」を取得しています。

 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
{
  "links": {},
  "nodes": {
    "18c1ac79-64f7-4cc4-b55f-fd07c4d31f3e": {
      "block0_rd_bytes": 1571173888,
      "block0_wr_bytes": 608583680,
      "cpu_usage": 45.81,
      "times": {
        "BOOTED": 614,
        "QUEUED": 11,
        "STARTED": 730
      }
    },
    "d5cb4984-d086-441f-981c-da0fd7bbbef5": {
      "block0_rd_bytes": 1569957376,
      "block0_wr_bytes": 339341312,
      "cpu_usage": 46.77,
      "times": {
        "BOOTED": 620,
        "QUEUED": 4,
        "STARTED": 737
      }
    }
  }
}

BOOTEDSTARTED の値がありますが、これらはおそらく以下の意味だと思われます。

項目 意味
STARTED ノードが開始されてから経過した秒数
BOOTED ノードが「起動した」と認識されてから経過した秒数

ノードを「起動した」と判定するロジックは CML の Node Definition 中で定義されています。

サンプルプログラム

BOOTED の値に加え、STARTED も取得しています。 BOOTED の値を取得するだけであれば不要ですが、ソート等が楽なので pandas を利用しています。

 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
#!/usr/bin/env python3

import http.client
import json
import ssl

import pandas

address = "10.0.0.1"
username = "admin"
password = "password"


def authenticate(conn, username, password):
    payload = json.dumps({"username": username, "password": password})
    headers = {"Content-Type": "application/json"}
    conn.request("POST", "/api/v0/authenticate", payload, headers)
    res = conn.getresponse()
    data = res.read()
    return data.decode("utf-8").replace('"', "")


def get_json(conn: http.client.HTTPSConnection, token: str, url: str):
    payload = ""
    headers = {"Authorization": "Bearer " + token}
    conn.request("GET", url, payload, headers)
    return json.loads(conn.getresponse().read().decode("utf-8"))


def get_lab(conn: http.client.HTTPSConnection, token: str, lab_id: str):
    return get_json(conn, token, f"/api/v0/labs/{lab_id}")


def get_labs(conn: http.client.HTTPSConnection, token: str):
    return get_json(conn, token, "/api/v0/labs")


def get_node(conn: http.client.HTTPSConnection, token: str, lab_id: str, node_id: str):
    return get_json(conn, token, f"/api/v0/labs/{lab_id}/nodes/{node_id}")


def get_stats(conn: http.client.HTTPSConnection, token: str, lab_id: str):
    return get_json(conn, token, f"/api/v0/labs/{lab_id}/simulation_stats")


def main():
    conn = http.client.HTTPSConnection(
        address, context=ssl._create_unverified_context()
    )
    token = authenticate(conn, username, password)
    labs = get_labs(conn, token)
    values = []
    for lab in labs:
        lab_title = get_lab(conn, token, lab)["lab_title"]
        stats = get_stats(conn, token, lab)
        for node in stats["nodes"]:
            n = get_node(conn, token, lab, node)
            booted = stats["nodes"][node]["times"]["BOOTED"]
            started = stats["nodes"][node]["times"]["STARTED"]
            values.append([lab_title, n["label"], booted, started])
    df = pandas.DataFrame(
        columns=["lab_title", "label", "BOOTED", "STARTED"], data=values
    )
    print(df.sort_values(["lab_title", "label"]).to_string(index=False))


if __name__ == "__main__":
    main()

実行結果

実行例は以下の通りです。

1
2
3
lab_title      label  BOOTED  STARTED
  Sample1 cat8000v-0     635      751
  Sample1 cat8000v-1     628      744