Skip to content

Commit e5fca86

Browse files
authored
Merge pull request #68 from netreplica/node-labels
Aligned node labels between NetBox and Containerlab
2 parents ed2f761 + 372d152 commit e5fca86

5 files changed

Lines changed: 143 additions & 57 deletions

File tree

app/js/clab.js

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,22 +116,31 @@ function convert_clab_topology_data_to_cmt(c){
116116
cmt_node["name"] = node;
117117
cmt_node["icon"] = "router";
118118

119+
// node labels mapping to CMT fields
120+
node_labels_map = {
121+
"graph-icon": "icon",
122+
"graph-level": "layerSortPreference",
123+
"group": "group",
124+
"role": "role",
125+
"vendor": "vendor",
126+
"model": "model",
127+
"platform": "platform",
128+
};
129+
119130
if (n.hasOwnProperty("labels")) {
120131
if (n.labels.hasOwnProperty("graph-hide") && equals_true(n.labels["graph-hide"])) {
121132
continue; // do not visualize this node
122133
}
123-
if (n.labels.hasOwnProperty("graph-icon")) {
124-
cmt_node["icon"] = n.labels["graph-icon"];
125-
}
126-
if (n.labels.hasOwnProperty("graph-level")) {
127-
cmt_node["layerSortPreference"] = n.labels["graph-level"];
134+
for (const [label, field] of Object.entries(node_labels_map)) {
135+
if (n.labels.hasOwnProperty(label)) {
136+
cmt_node[field] = n.labels[label];
137+
}
128138
}
129139
}
130140

131141
cmt_node["fullname"] = n.longname;
132142
cmt_node["kind"] = n.kind;
133143
cmt_node["image"] = n.image;
134-
cmt_node["group"] = n.group;
135144

136145
if (n.hasOwnProperty("mgmt-ipv4-address")) {
137146
cmt_node["mgmtIPv4"] = n["mgmt-ipv4-address"];

app/js/nextui.js

Lines changed: 45 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -324,7 +324,7 @@
324324
tag: 'span',
325325
content: '{#node.model.image}',
326326
}]
327-
}, {
327+
}, {
328328
tag: 'div',
329329
props: {
330330
"style": "font-size:80%;"
@@ -334,12 +334,12 @@
334334
props: {
335335
"style": "padding-right: 5px"
336336
},
337-
content: 'Vendor:',
337+
content: 'Group:',
338338
}, {
339339
tag: 'span',
340-
content: '{#node.model.vendor}',
340+
content: '{#node.model.group}',
341341
}]
342-
}, {
342+
}, {
343343
tag: 'div',
344344
props: {
345345
"style": "font-size:80%;"
@@ -349,10 +349,25 @@
349349
props: {
350350
"style": "padding-right: 5px"
351351
},
352-
content: 'Model:',
352+
content: 'Role:',
353353
}, {
354354
tag: 'span',
355-
content: '{#node.model.model}',
355+
content: '{#node.model.role}',
356+
}]
357+
}, {
358+
tag: 'div',
359+
props: {
360+
"style": "font-size:80%;"
361+
},
362+
content: [{
363+
tag: 'label',
364+
props: {
365+
"style": "padding-right: 5px"
366+
},
367+
content: 'Vendor:',
368+
}, {
369+
tag: 'span',
370+
content: '{#node.model.vendor}',
356371
}]
357372
}, {
358373
tag: 'div',
@@ -364,12 +379,12 @@
364379
props: {
365380
"style": "padding-right: 5px"
366381
},
367-
content: 'Version:',
382+
content: 'Model:',
368383
}, {
369384
tag: 'span',
370-
content: '{#node.model.os_version}',
385+
content: '{#node.model.model}',
371386
}]
372-
}, {
387+
}, {
373388
tag: 'div',
374389
props: {
375390
"style": "font-size:80%;"
@@ -379,11 +394,26 @@
379394
props: {
380395
"style": "padding-right: 5px"
381396
},
382-
content: 'Group:',
397+
content: 'Platform:',
383398
}, {
384399
tag: 'span',
385-
content: '{#node.model.group}',
400+
content: '{#node.model.platform}',
386401
}]
402+
}, {
403+
tag: 'div',
404+
props: {
405+
"style": "font-size:80%;"
406+
},
407+
content: [{
408+
tag: 'label',
409+
props: {
410+
"style": "padding-right: 5px"
411+
},
412+
content: 'Version:',
413+
}, {
414+
tag: 'span',
415+
content: '{#node.model.os_version}',
416+
}]
387417
}, {
388418
tag: 'div',
389419
props: {
@@ -1337,12 +1367,14 @@
13371367
if (node_data.hasOwnProperty("hostname")) {
13381368
node.model().set('hostname', node_data["hostname"]);
13391369
}
1370+
var platform = "";
13401371
if (node_data.hasOwnProperty("vendor")) {
1341-
node.model().set('vendor', node_data["vendor"]);
1372+
platform = node_data["vendor"];
13421373
}
13431374
if (node_data.hasOwnProperty("model")) {
1344-
node.model().set('model', node_data["model"]);
1375+
platform += " " + node_data["model"];
13451376
}
1377+
node.model().set('platform', platform);
13461378
if (node_data.hasOwnProperty("os_version")) {
13471379
node.model().set('os_version', node_data["os_version"]);
13481380
}

docs/CONTAINERLAB.md

Lines changed: 2 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
5454
## Improve visualization via custom labels in a ContainerLab YAML file
5555
56-
The visualization we got on the previous step lacks hierarchy. Let's fix that by assigning nodes in the ContainerLab topology YAML file to different levels, using custom labels that Graphite understands.
56+
The visualization we got on the previous step lacks hierarchy. Let's fix that by assigning nodes in the ContainerLab topology YAML file to different levels, using custom labels that Graphite understands. Read [LABELS.md](LABELS.md) for a full list of labels supported by Graphite.
5757

5858
1. Open the topology YAML file in the text editor and append the following lines to each `node1-*` definition.
5959

@@ -101,7 +101,7 @@ The visualization we got on the previous step lacks hierarchy. Let's fix that by
101101

102102
## Changing visualization icons
103103

104-
All the nodes in our visualization so far represented by the same "router" icon. Let's assume that nodes at tier-1 in our Clos topology can act as L2 switches, and we want to reflect that in the visualization. To achieve that, we can use custom label again, with a name `graph-icon`.
104+
All the nodes in our visualization so far represented by the same "router" icon. Let's assume that nodes at tier-1 in our Clos topology can act as L2 switches, and we want to reflect that in the visualization. To achieve that, we can use custom label again, with a name `graph-icon`. See possible `graph-icon` values [here](LABELS.md#node-icons).
105105
106106
107107
1. Open the topology YAML file in the text editor and append the following line to each `node1-*` definition.
@@ -124,16 +124,6 @@ All the nodes in our visualization so far represented by the same "router" icon.
124124
graph-icon: switch
125125
```
126126
127-
Possible graph-icon types are (from [Cisco DevNet NeXT UI API doc](https://developer.cisco.com/site/neXt/document/api-reference-manual/files/src_js_graphic_svg_Icons.js/#l11)):
128-
129-
| graph-icon | graph-icon | graph-icon |
130-
|---|---|---|
131-
|switch|router|wlc|
132-
|server|phone|nexus5000|
133-
|ipphone|host|camera|
134-
|accesspoint|cloud|unlinked|
135-
|firewall|hostgroup|wirelesshost|
136-
137127
4. Redeploy the topology
138128
139129
```Shell
@@ -143,29 +133,3 @@ All the nodes in our visualization so far represented by the same "router" icon.
143133
3. Now refresh the web page in the browser, and click "Horizontal Layout". Now the bottom row of nodes uses "switch" icons.
144134
145135
![clos-3tier Graphite Topology Visualization with switch icons](../images/clos-3tier.clab.icons.png)
146-
147-
## Using `port` visualization mode
148-
149-
Some nodes that can be used within ContainerLab topology may not act as regular network devices. Examples of such nodes could be
150-
151-
* Linux hosts with disabled IP forwarding,
152-
* Traffic Generators.
153-
154-
If such node has multiple interfaces connected to the emulated topology, its visualization might not represent their role well. To address this, there is a special `port` visuzalization mode available in Graphite. With such mode enabled for a node, each its interface would be displayed as a separate icon with a name "interface-name@node-name". Below is an example of using `port` mode for `ixia-c-one` traffic generator, together with a "cloud" icon:
155-
156-
```Yaml
157-
ixia:
158-
kind: keysight_ixia-c-one
159-
image: ghcr.io/open-traffic-generator/ixia-c-one:0.0.1-2770
160-
labels:
161-
graph-icon: cloud
162-
graph-mode: port
163-
links:
164-
- endpoints: ["pe-router:eth1","ce-router:eth1"]
165-
- endpoints: ["pe-router:eth2","ixia:eth1"]
166-
- endpoints: ["ce-router:eth2","ixia:eth2"]
167-
```
168-
169-
The `ixia` node will be visualized as two icons `eth1@ixia` and `eth2@ixia`:
170-
171-
![Ixia-c-one node visualized in port mode](/images/clab-graphite-ixia-ports-cloud.png)

docs/LABELS.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# Labels
2+
3+
## Node labels
4+
5+
When you click on a node in the topology diagram, a view pops up with node details:
6+
7+
![Node details](../images/labels.clab.png)
8+
9+
The table belows shows where the values of each field in the popup come from, depending on the type of the topology.
10+
11+
| Label | NetBox | Containerlab | Live Data
12+
| ----- | ------------------- | ------------------- | --------
13+
| Name | `nodes: {name}` | `nodes: {name}` | N/A
14+
| Full name | N/A | `longname` | Ansible inventory
15+
| Hostname | N/A | N/A | `hostname`
16+
| Kind | N/A | `kind` | N/A
17+
| Image | N/A | `image` | N/A
18+
| Group | `labels: group` | `labels: group` | N/A
19+
| Role | `labels: role` | `labels: role` | N/A
20+
| Vendor | `labels: vendor` | `labels: vendor` | N/A
21+
| Model | `labels: model` | `labels: model` | N/A
22+
| Platform | `labels: platform` | `labels: platform` | `vendor model`
23+
| Version | N/A | N/A | `os_version`
24+
| IPv4 | `mgmt-ipv4-address` | `mgmt-ipv4-address` | N/A
25+
| IPv6 | `mgmt-ipv4-address` | `mgmt-ipv6-address` | N/A
26+
27+
Special labels
28+
29+
| Label | NetBox | Containerlab | Live Data
30+
| ----- | ------------------- | ------------------- | --------
31+
| Node icon | `labels: graph-icon` | `labels: graph-icon` | N/A
32+
| Node level | `labels: graph-level` | `labels: graph-level` | N/A
33+
| Node display mode | `labels: graph-mode` | `labels: graph-mode` | N/A
34+
35+
## Node icons
36+
37+
Possible graph-icon values, based on [Cisco DevNet NeXT UI API doc](https://developer.cisco.com/site/neXt/document/api-reference-manual/files/src_js_graphic_svg_Icons.js/#l11):
38+
39+
| `label: graph-icon` |
40+
| ------------ |
41+
| `switch` |
42+
| `router` |
43+
| `wlc` |
44+
| `server` |
45+
| `phone` |
46+
| `nexus5000` |
47+
| `ipphone` |
48+
| `host` |
49+
| `camera` |
50+
| `access` |
51+
| `cloud` |
52+
| `unlinked` |
53+
| `firewall` |
54+
| `hostgroup` |
55+
| `wirelesshost` |
56+
57+
## `port` visualization mode
58+
59+
Some nodes that can be used within the topology may not act as regular network devices. Examples of such nodes could be
60+
61+
* Linux hosts with disabled IP forwarding,
62+
* Traffic Generators.
63+
64+
If such node has multiple interfaces connected to the emulated topology, its visualization might not represent their role well. To address this, there is a special `port` visuzalization mode available in Graphite. With such mode enabled for a node, each its interface would be displayed as a separate icon with a name "interface-name@node-name". Below is an example of using `port` mode for `ixia-c-one` traffic generator, together with a "cloud" icon:
65+
66+
```Yaml
67+
ixia:
68+
kind: keysight_ixia-c-one
69+
image: ghcr.io/open-traffic-generator/ixia-c-one:0.0.1-2770
70+
labels:
71+
graph-icon: cloud
72+
graph-mode: port
73+
links:
74+
- endpoints: ["pe-router:eth1","ce-router:eth1"]
75+
- endpoints: ["pe-router:eth2","ixia:eth1"]
76+
- endpoints: ["ce-router:eth2","ixia:eth2"]
77+
```
78+
79+
The `ixia` node will be visualized as two icons `eth1@ixia` and `eth2@ixia`:
80+
81+
![Ixia-c-one node visualized in port mode](/images/clab-graphite-ixia-ports-cloud.png)

images/labels.clab.png

127 KB
Loading

0 commit comments

Comments
 (0)