Skip to content

Commit 215fc63

Browse files
authored
Merge pull request #160 from asadarafat/topoviewer-edgeshark-with-empty-prefix
update environment.json to get the data from live cy instance
2 parents f6158c2 + 9d39f4b commit 215fc63

File tree

6 files changed

+141
-30
lines changed

6 files changed

+141
-30
lines changed

src/topoViewer/backend/topoViewerAdaptorClab.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,10 @@ export class TopoViewerAdaptorClab {
9494

9595

9696
var clabName = parsed.name
97-
97+
var clabPrefix = parsed.prefix;
98+
// if (clabPrefix == "") {
99+
// clabPrefix = ""
100+
// }
98101

99102

100103
// Define the EnvironmentJson object
@@ -104,6 +107,7 @@ export class TopoViewerAdaptorClab {
104107

105108
const environmentJson: EnvironmentJson = {
106109
workingDirectory: ".",
110+
clabPrefix: `${clabPrefix}`,
107111
clabName: `${clabName}`,
108112
clabServerAddress: "",
109113
clabAllowedHostname: hostname,
@@ -112,8 +116,7 @@ export class TopoViewerAdaptorClab {
112116
deploymentType: "vs-code",
113117
topoviewerVersion: `${topoViewerVersion}`,
114118
topviewerPresetLayout: `${this.currentIsPresetLayout.toString()}`,
115-
envCyTopoJsonBytes: cytoTopology,
116-
envCyTopoJsonBytesAddon: cytoTopology
119+
envCyTopoJsonBytes: cytoTopology
117120
};
118121

119122
// Serialize EnvironmentJson with hyphenated keys
@@ -175,9 +178,9 @@ export class TopoViewerAdaptorClab {
175178
* @returns An array of Cytoscape elements (`CyElement[]`) representing nodes and edges.
176179
*/
177180
public clabYamlToCytoscapeElements(yamlContent: string, clabTreeDataToTopoviewer: Record<string, ClabLabTreeNode> | undefined): CyElement[] {
178-
const parsed = yaml.load(yamlContent) as ClabTopology;
179-
return this.buildCytoscapeElements(parsed, { includeContainerData: true, clabTreeData: clabTreeDataToTopoviewer });
180-
}
181+
const parsed = yaml.load(yamlContent) as ClabTopology;
182+
return this.buildCytoscapeElements(parsed, { includeContainerData: true, clabTreeData: clabTreeDataToTopoviewer });
183+
}
181184

182185

183186
/**
@@ -193,9 +196,9 @@ export class TopoViewerAdaptorClab {
193196
* @returns An array of Cytoscape elements (`CyElement[]`) representing nodes and edges.
194197
*/
195198
public clabYamlToCytoscapeElementsEditor(yamlContent: string): CyElement[] {
196-
const parsed = yaml.load(yamlContent) as ClabTopology;
197-
return this.buildCytoscapeElements(parsed, { includeContainerData: false });
198-
}
199+
const parsed = yaml.load(yamlContent) as ClabTopology;
200+
return this.buildCytoscapeElements(parsed, { includeContainerData: false });
201+
}
199202

200203

201204
/**
@@ -248,6 +251,7 @@ export class TopoViewerAdaptorClab {
248251
private mapEnvironmentJsonToHyphenated(envJson: EnvironmentJson): string {
249252
const hyphenatedJson = {
250253
"working-directory": envJson.workingDirectory,
254+
"clab-prefix": envJson.clabPrefix,
251255
"clab-name": envJson.clabName,
252256
"clab-server-address": envJson.clabServerAddress,
253257
"clab-allowed-hostname": envJson.clabAllowedHostname,
@@ -256,8 +260,7 @@ export class TopoViewerAdaptorClab {
256260
"deployment-type": envJson.deploymentType,
257261
"topoviewer-version": envJson.topoviewerVersion,
258262
"topoviewer-layout-preset": envJson.topviewerPresetLayout,
259-
"EnvCyTopoJsonBytes": envJson.envCyTopoJsonBytes,
260-
"EnvCyTopoJsonBytesAddon": envJson.envCyTopoJsonBytesAddon
263+
"EnvCyTopoJsonBytes": envJson.envCyTopoJsonBytes
261264
};
262265

263266
return JSON.stringify(hyphenatedJson, null, 2);
@@ -284,6 +287,8 @@ export class TopoViewerAdaptorClab {
284287
log.info(`######### status preset layout: ${this.currentIsPresetLayout}`);
285288

286289
const clabName = parsed.name;
290+
291+
287292
const parentMap = new Map<string, string | undefined>();
288293
let nodeIndex = 0;
289294

src/topoViewer/backend/topoViewerWebUiFacade.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,35 @@ export class TopoViewer {
642642
}
643643
break;
644644
}
645+
646+
case 'save-environment-json-to-disk': {
647+
try {
648+
const environmentData = JSON.parse(payload as string);
649+
650+
if (!this.lastFolderName) {
651+
throw new Error('No folderName available (this.lastFolderName is undefined).');
652+
}
653+
654+
// Construct full path under `topoViewerData/<folder>/environment.json`
655+
const environmentJsonPath = vscode.Uri.joinPath(
656+
this.context.extensionUri,
657+
'topoViewerData',
658+
this.lastFolderName,
659+
'environment.json'
660+
);
661+
662+
// Write to disk
663+
await fs.promises.writeFile(environmentJsonPath.fsPath, JSON.stringify(environmentData, null, 2), 'utf8');
664+
665+
result = `Environment JSON successfully saved to disk at ${environmentJsonPath.fsPath}`;
666+
log.info(result);
667+
} catch (innerError) {
668+
result = `Error saving environment JSON to disk.`;
669+
log.error(`Error in 'save-environment-json-to-disk': ${JSON.stringify(innerError, null, 2)}`);
670+
}
671+
break;
672+
}
673+
645674
default: {
646675
error = `Unknown endpoint "${endpointName}".`;
647676
log.error(error);

src/topoViewer/backend/types/topoViewerType.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ export type CytoTopology = CyElement[];
5656
*/
5757
export interface EnvironmentJson {
5858
workingDirectory: string;
59+
clabPrefix: string;
5960
clabName: string;
6061
clabServerAddress: string;
6162
clabAllowedHostname: string;
@@ -65,7 +66,6 @@ export interface EnvironmentJson {
6566
topoviewerVersion: string;
6667
topviewerPresetLayout: string
6768
envCyTopoJsonBytes: CytoTopology | '';
68-
envCyTopoJsonBytesAddon: CytoTopology | '';
6969
}
7070

7171

src/topoViewer/webview-ui/html-static/js/common.js

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ var globalNodeContainerStatusVisibility = false;
1313
var globalShellUrl = "/js/cloudshell";
1414
let deploymentType;
1515
var globalLabName;
16+
var globalPrefixName
1617
var multiLayerViewPortState = false;
1718

1819
// Cytoscape-Leaflet variables
@@ -69,6 +70,7 @@ async function initEnv() {
6970

7071
// Assign to global variables
7172
globalLabName = environments["clab-name"];
73+
globalPrefixName = environments["clab-prefix"];
7274
deploymentType = environments["deployment-type"];
7375
globalIsPresetLayout = environments["topoviewer-layout-preset"] === "true";
7476
globalAllowedhostname = environments["clab-allowed-hostname"];
@@ -90,36 +92,67 @@ async function initEnv() {
9092
// -----------------------------------------------------------
9193

9294
/**
93-
* Fetches environment configurations.
95+
* Fetches environment configuration JSON and updates its topology data
96+
* with the current live Cytoscape graph. Persists the updated JSON to disk
97+
* using VS Code's postMessage API.
98+
*
99+
* @returns {Promise<object|null>} Updated environment object or null on failure.
94100
*/
95101
async function getEnvironments() {
96102
try {
97103
let environments;
104+
98105
if (isVscodeDeployment) {
99-
// Using a JSON file in the VS Code deployment scenario
100106
const response = await fetch(window.jsonFileUrlDataEnvironment);
101107
if (!response.ok) {
102-
throw new Error(`Network response not ok: ${response.status}`);
108+
throw new Error(`Failed to fetch environment JSON: ${response.statusText}`);
103109
}
110+
104111
environments = await response.json();
112+
113+
if (typeof cy !== 'undefined' && typeof cy.elements === 'function') {
114+
const liveCyData = cy.elements().jsons();
115+
environments.EnvCyTopoJsonBytes = liveCyData;
116+
117+
console.log("Updated environments with live Cytoscape data:", environments)
118+
console.debug("Replaced EnvCyTopoJsonBytes with live Cytoscape data.");
119+
120+
if (typeof vsCode !== 'undefined' && typeof vsCode.postMessage === 'function') {
121+
vsCode.postMessage({
122+
type: "POST",
123+
requestId: `save-${Date.now()}`,
124+
endpointName: "save-environment-json-to-disk",
125+
payload: JSON.stringify(environments)
126+
});
127+
console.log("[VS Code] saveEnvJsonToDisk message sent to extension host.");
128+
} else {
129+
console.warn("VS Code postMessage API not available — skipping save.");
130+
}
131+
} else {
132+
console.warn("Cytoscape instance is not available. EnvCyTopoJsonBytes not updated.");
133+
}
105134
} else {
106-
// Using a dedicated GET endpoint in other scenarios
107135
environments = await sendRequestToEndpointGetV2("/get-environments");
108136
}
109137

110-
if (environments && typeof environments === 'object' && Object.keys(environments).length > 0) {
111-
console.log("Fetched Environments:", environments);
138+
if (
139+
environments &&
140+
typeof environments === "object" &&
141+
Object.keys(environments).length > 0
142+
) {
143+
console.debug("Final environments object:", environments);
112144
return environments;
113145
} else {
114-
console.log("Empty or invalid JSON response for environments");
146+
console.warn("Fetched environment object is empty or invalid.");
115147
return null;
116148
}
117149
} catch (error) {
118-
console.error("Error fetching environments:", error);
150+
console.error("Error while fetching environments:", error);
119151
return null;
120152
}
121153
}
122154

155+
123156
/**
124157
* Helper function to send a GET request to an endpoint.
125158
*/
@@ -357,7 +390,7 @@ function updateSocketBinding() {
357390
function updateMessageStreamBinding() {
358391
// Create the event handler once and store it as a property if it doesn't exist.
359392
if (!updateMessageStreamBinding.handler) {
360-
updateMessageStreamBinding.handler = function(event) {
393+
updateMessageStreamBinding.handler = function (event) {
361394
try {
362395
const message = event.data;
363396
if (message && message.type === 'clab-tree-provider-data-native-vscode-message-stream') {

src/topoViewer/webview-ui/html-static/js/dev.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2374,8 +2374,9 @@ async function linkWireshark(event, option, endpoint, referenceElementAfterId) {
23742374
netNsResponse = await sendRequestToEndpointGetV3("/clab-node-network-namespace", [clabSourceLongName]);
23752375
netNsId = extractNamespaceId(netNsResponse.namespace_id);
23762376
console.info("linkWireshark - netNsSource: ", netNsId);
2377-
23782377
urlParams = `container={"netns":${netNsId},"network-interfaces":["${clabSourcePort}"],"name":"${clabSourceLongName.toLowerCase()}","type":"docker","prefix":""}&nif=${clabSourcePort}`;
2378+
const edgeSharkHref = baseUrl + urlParams;
2379+
console.info("linkWireshark - edgeSharkHref: ", edgeSharkHref);
23792380
}
23802381
} else if (endpoint === "target") {
23812382
if (isVscodeDeployment) {
@@ -2393,10 +2394,11 @@ async function linkWireshark(event, option, endpoint, referenceElementAfterId) {
23932394
netNsId = extractNamespaceId(netNsResponse.namespace_id);
23942395
console.info("linkWireshark - netNsTarget: ", netNsId);
23952396
urlParams = `container={"netns":${netNsId},"network-interfaces":["${clabTargetPort}"],"name":"${clabTargetLongName.toLowerCase()}","type":"docker","prefix":""}&nif=${clabTargetPort}`;
2397+
const edgeSharkHref = baseUrl + urlParams;
2398+
console.info("linkWireshark - edgeSharkHref: ", edgeSharkHref);
23962399
}
23972400
}
2398-
const edgeSharkHref = baseUrl + urlParams;
2399-
console.info("linkWireshark - edgeSharkHref: ", edgeSharkHref);
2401+
24002402

24012403
// window.open(edgeSharkHref);
24022404

src/topoViewer/webview-ui/html-static/js/managerSocketDataEnrichment.js

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,35 +48,77 @@
4848
function socketDataEncrichmentLink(labData) {
4949
const linkMap = new Map();
5050

51-
// Iterate through all lab entries and gather interface data from matching lab
51+
console.log(`debug labData:`, labData);
52+
console.log(`debug labData.name`, labData.name);
53+
console.log(`debug globalLabName`, globalLabName);
54+
55+
// Build interface key mapping for the current lab
5256
Object.values(labData).forEach(lab => {
5357
if (lab.name !== globalLabName || !Array.isArray(lab.containers)) return;
5458

5559
lab.containers.forEach(container => {
5660
if (typeof container.label !== 'string' || !Array.isArray(container.interfaces)) return;
5761

58-
// Derive short node name by stripping lab prefix from the container label
5962
const nodeName = container.label.split(lab.name)[1]?.replace(/^-/, '') || container.label;
60-
61-
// Build key per interface and store MAC/MTU/type
63+
6264
container.interfaces.forEach(iface => {
6365
const key = `${lab.name}::${nodeName}::${iface.label}`;
6466
linkMap.set(key, { mac: iface.mac, mtu: iface.mtu, type: iface.type });
6567
});
68+
69+
console.log(`Enriched link data for node: ${nodeName} with interfaces:`, container.interfaces);
70+
console.log(`Enriched link map data:`, linkMap);
6671
});
6772
});
6873

69-
// Match the key parts with Cytoscape edge's source/target endpoint data
74+
// Compute prefix safely
75+
let assignedPrefixLabName;
76+
77+
switch (true) {
78+
case typeof globalPrefixName === "string" && globalPrefixName.trim() === "undefined":
79+
assignedPrefixLabName = `clab-${globalLabName}-`;
80+
break;
81+
82+
case typeof globalPrefixName === "string" && globalPrefixName.trim() !== "":
83+
assignedPrefixLabName = `${globalPrefixName.trim()}-${globalLabName}-`;
84+
break;
85+
86+
default:
87+
assignedPrefixLabName = null;
88+
break;
89+
}
90+
91+
// Enrich edges
7092
linkMap.forEach((iface, key) => {
7193
const [, nodeName, endpoint] = key.split('::');
7294
cy.edges().forEach(edge => {
7395
const data = edge.data();
96+
97+
// Safely build clabSourceLongName and clabTargetLongName
98+
const clabSourceLongName = assignedPrefixLabName
99+
? `${assignedPrefixLabName}${data.source}`
100+
: data.source;
101+
102+
const clabTargetLongName = assignedPrefixLabName
103+
? `${assignedPrefixLabName}${data.target}`
104+
: data.target;
105+
106+
const updatedExtraData = {
107+
...edge.data('extraData'),
108+
clabSourceLongName,
109+
clabTargetLongName
110+
};
111+
edge.data('extraData', updatedExtraData);
112+
113+
// Enrich with interface details if matched
74114
if (data.source === nodeName && data.sourceEndpoint === endpoint) {
75115
edge.data({ sourceMac: iface.mac, sourceMtu: iface.mtu, sourceType: iface.type });
76116
}
77117
if (data.target === nodeName && data.targetEndpoint === endpoint) {
78118
edge.data({ targetMac: iface.mac, targetMtu: iface.mtu, targetType: iface.type });
79119
}
120+
121+
console.log(`Edge data after enrichment:`, edge.data());
80122
});
81123
});
82124
}
@@ -101,7 +143,7 @@ function socketDataEncrichmentLink(labData) {
101143
*/
102144
function socketDataEncrichmentNode(labData) {
103145
const nodeMap = new Map();
104-
146+
105147
// Build node mapping from container longname -> metadata
106148
Object.values(labData).forEach(lab => {
107149
if (lab.name !== globalLabName || !Array.isArray(lab.containers)) return;

0 commit comments

Comments
 (0)