Skip to content

Commit a115b4d

Browse files
kaelemcFloSch62
authored andcommitted
migrate containerlab calls to custom bin path
1 parent bd73581 commit a115b4d

File tree

8 files changed

+25
-40
lines changed

8 files changed

+25
-40
lines changed

src/commands/clabCommand.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as vscode from "vscode";
22
import * as cmd from './command';
33
import { ClabLabTreeNode } from "../treeView/common";
4+
import { containerlabBinaryPath } from "../extension";
45
/**
56
* A helper class to build a 'containerlab' command (with optional sudo, etc.)
67
* and run it either in the Output channel or in a Terminal.
@@ -22,13 +23,13 @@ export class ClabCommand extends cmd.Command {
2223
let options: cmd.CmdOptions;
2324
if (useTerminal) {
2425
options = {
25-
command: "containerlab",
26+
command: containerlabBinaryPath,
2627
useSpinner: false,
2728
terminalName: terminalName || "Containerlab",
2829
};
2930
} else {
3031
options = {
31-
command: "containerlab",
32+
command: containerlabBinaryPath,
3233
useSpinner: true,
3334
spinnerMsg: spinnerMsg || {
3435
progressMsg: `Running ${action}...`,

src/commands/gottyShare.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as vscode from "vscode";
22
import { ClabLabTreeNode } from "../treeView/common";
3-
import { outputChannel, gottySessions, runningLabsProvider, refreshGottySessions } from "../extension";
3+
import { outputChannel, gottySessions, runningLabsProvider, refreshGottySessions, containerlabBinaryPath } from "../extension";
44
import { getHostname } from "./capture";
55
import { runWithSudo } from "../helpers/utils";
66

@@ -56,7 +56,7 @@ async function gottyStart(action: "attach" | "reattach", node: ClabLabTreeNode)
5656
}
5757
try {
5858
const port = vscode.workspace.getConfiguration('containerlab').get<number>('gotty.port', 8080);
59-
const out = await runWithSudo(`containerlab tools gotty ${action} -l ${node.name} --port ${port}`, `GoTTY ${action}`, outputChannel, 'containerlab', true, true) as string;
59+
const out = await runWithSudo(`${containerlabBinaryPath} tools gotty ${action} -l ${node.name} --port ${port}`, `GoTTY ${action}`, outputChannel, 'containerlab', true, true) as string;
6060
const link = await parseGottyLink(out || '');
6161
if (link) {
6262
gottySessions.set(node.name, link);
@@ -90,7 +90,7 @@ export async function gottyDetach(node: ClabLabTreeNode) {
9090
return;
9191
}
9292
try {
93-
await runWithSudo(`containerlab tools gotty detach -l ${node.name}`, 'GoTTY detach', outputChannel, 'containerlab');
93+
await runWithSudo(`${containerlabBinaryPath} tools gotty detach -l ${node.name}`, 'GoTTY detach', outputChannel, 'containerlab');
9494
gottySessions.delete(node.name);
9595
vscode.window.showInformationMessage('GoTTY session detached');
9696
} catch (err: any) {

src/commands/impairments.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import * as vscode from "vscode";
33
import * as utils from "../helpers/utils";
44
import { ClabInterfaceTreeNode } from "../treeView/common";
55
import { execCommandInOutput } from "./command";
6+
import { containerlabBinaryPath } from "../extension";
67

78
// Common validation messages and patterns
89
const ERR_EMPTY = 'Input should not be empty';
@@ -23,7 +24,7 @@ async function setImpairment(node: ClabInterfaceTreeNode, impairment?: string, v
2324
}
2425
const impairmentFlag = impairment ? `--${impairment}` : undefined;
2526
if (impairment && !value) { return; }
26-
const cmd = `${utils.getSudo()}containerlab tools netem set --node ${node.parentName} --interface ${node.name} ${impairmentFlag} ${value}`;
27+
const cmd = `${utils.getSudo()}${containerlabBinaryPath} tools netem set --node ${node.parentName} --interface ${node.name} ${impairmentFlag} ${value}`;
2728
const msg = `set ${impairment} to ${value} for ${node.name} on ${node.parentName}.`;
2829
vscode.window.showInformationMessage(`Attempting to ${msg}`);
2930
execCommandInOutput(cmd, false,

src/commands/nodeImpairments.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import * as vscode from "vscode";
22
import { ClabContainerTreeNode } from "../treeView/common";
33
import { getNodeImpairmentsHtml } from "../webview/nodeImpairmentsHtml";
44
import { runWithSudo } from "../helpers/utils";
5-
import { outputChannel } from "../extension";
5+
import { outputChannel, containerlabBinaryPath } from "../extension";
66

77
type NetemFields = {
88
delay: string;
@@ -74,7 +74,7 @@ function ensureDefaults(map: Record<string, NetemFields>, node: ClabContainerTre
7474
async function refreshNetemSettings(node: ClabContainerTreeNode): Promise<Record<string, NetemFields>> {
7575
const config = vscode.workspace.getConfiguration("containerlab");
7676
const runtime = config.get<string>("runtime", "docker");
77-
const showCmd = `containerlab tools -r ${runtime} netem show -n ${node.name} --format json`;
77+
const showCmd = `${containerlabBinaryPath} tools -r ${runtime} netem show -n ${node.name} --format json`;
7878
let netemMap: Record<string, NetemFields> = {};
7979

8080
try {
@@ -143,7 +143,7 @@ async function applyNetem(
143143
for (const [intfName, fields] of Object.entries(netemData)) {
144144
const netemArgs = buildNetemArgs(fields as Record<string, string>);
145145
if (netemArgs.length > 0) {
146-
const cmd = `containerlab tools netem set -n ${node.name} -i ${intfName} ${netemArgs.join(" ")} > /dev/null 2>&1`;
146+
const cmd = `${containerlabBinaryPath} tools netem set -n ${node.name} -i ${intfName} ${netemArgs.join(" ")} > /dev/null 2>&1`;
147147
ops.push(
148148
runWithSudo(
149149
cmd,
@@ -179,7 +179,7 @@ async function clearNetem(
179179
continue;
180180
}
181181
const cmd =
182-
`containerlab tools netem set -n ${node.name} -i ${norm} --delay 0s --jitter 0s --loss 0 --rate 0 --corruption 0.0000000000000001 > /dev/null 2>&1`;
182+
`${containerlabBinaryPath} tools netem set -n ${node.name} -i ${norm} --delay 0s --jitter 0s --loss 0 --rate 0 --corruption 0.0000000000000001 > /dev/null 2>&1`;
183183
ops.push(
184184
runWithSudo(
185185
cmd,

src/commands/sshxShare.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as vscode from "vscode";
22
import { ClabLabTreeNode } from "../treeView/common";
3-
import { outputChannel, sshxSessions, runningLabsProvider, refreshSshxSessions } from "../extension";
3+
import { outputChannel, sshxSessions, runningLabsProvider, refreshSshxSessions, containerlabBinaryPath } from "../extension";
44
import { runWithSudo } from "../helpers/utils";
55

66
function parseLink(output: string): string | undefined {
@@ -15,7 +15,7 @@ async function sshxStart(action: "attach" | "reattach", node: ClabLabTreeNode) {
1515
return;
1616
}
1717
try {
18-
const out = await runWithSudo(`containerlab tools sshx ${action} -l ${node.name}`, `SSHX ${action}`, outputChannel, 'containerlab', true, true) as string;
18+
const out = await runWithSudo(`${containerlabBinaryPath} tools sshx ${action} -l ${node.name}`, `SSHX ${action}`, outputChannel, 'containerlab', true, true) as string;
1919
const link = parseLink(out || '');
2020
if (link) {
2121
sshxSessions.set(node.name, link);
@@ -49,7 +49,7 @@ export async function sshxDetach(node: ClabLabTreeNode) {
4949
return;
5050
}
5151
try {
52-
await runWithSudo(`containerlab tools sshx detach -l ${node.name}`, 'SSHX detach', outputChannel);
52+
await runWithSudo(`${containerlabBinaryPath} tools sshx detach -l ${node.name}`, 'SSHX detach', outputChannel);
5353
sshxSessions.delete(node.name);
5454
vscode.window.showInformationMessage('SSHX session detached');
5555
} catch (err: any) {

src/extension.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,7 @@ function setClabBinPath(): boolean {
392392
// if empty fall back to resolving from PATH
393393
if (!configPath || configPath.trim() === '') {
394394
try {
395+
// eslint-disable-next-line sonarjs/no-os-command-from-path
395396
const stdout = execSync('which containerlab', { encoding: 'utf-8' });
396397
const resolvedPath = stdout.trim();
397398
if (resolvedPath) {
@@ -400,7 +401,7 @@ function setClabBinPath(): boolean {
400401
return true;
401402
}
402403
} catch (err) {
403-
outputChannel.warn('Could not resolve containerlab bin path from sys PATH');
404+
outputChannel.warn(`Could not resolve containerlab bin path from sys PATH: ${err}`);
404405
}
405406
containerlabBinaryPath = 'containerlab';
406407
return true;
@@ -414,7 +415,7 @@ function setClabBinPath(): boolean {
414415
return true;
415416
} catch (err) {
416417
// Path is invalid or not executable - try to resolve from PATH as fallback
417-
outputChannel.error(`Invalid containerlab.binaryPath setting: "${configPath}" is not a valid executable.`);
418+
outputChannel.error(`Invalid containerlab.binaryPath "${configPath}": ${err}`);
418419
vscode.window.showErrorMessage(
419420
`Configured containerlab binary path "${configPath}" is invalid or not executable.`
420421
);

src/helpers/utils.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { exec } from "child_process";
66
import * as net from "net";
77
import { promisify } from "util";
88
import { ClabLabTreeNode } from "../treeView/common";
9+
import { containerlabBinaryPath } from "../extension";
910

1011
const execAsync = promisify(exec);
1112

@@ -207,7 +208,7 @@ async function tryRunAsGroupMember(
207208
async function hasPasswordlessSudo(checkType: 'generic' | 'containerlab' | 'docker'): Promise<boolean> {
208209
let checkCommand: string;
209210
if (checkType === 'containerlab') {
210-
checkCommand = "sudo -n containerlab version >/dev/null 2>&1 && echo true || echo false";
211+
checkCommand = `sudo -n ${containerlabBinaryPath} version >/dev/null 2>&1 && echo true || echo false`;
211212
} else if (checkType === 'docker') {
212213
checkCommand = "sudo -n docker ps >/dev/null 2>&1 && echo true || echo false";
213214
} else {
@@ -410,10 +411,10 @@ export async function checkAndUpdateClabIfNeeded(
410411
context: vscode.ExtensionContext
411412
): Promise<void> {
412413
try {
413-
log('Running "containerlab version check".', outputChannel);
414+
log(`Running "${containerlabBinaryPath} version check".`, outputChannel);
414415
// Run the version check via runWithSudo and capture output.
415416
const versionOutputRaw = await runWithSudo(
416-
'containerlab version check',
417+
`${containerlabBinaryPath} version check`,
417418
'containerlab version check',
418419
outputChannel,
419420
'containerlab',
@@ -436,7 +437,7 @@ export async function checkAndUpdateClabIfNeeded(
436437
context.subscriptions.push(
437438
vscode.commands.registerCommand(updateCommandId, async () => {
438439
try {
439-
await runWithSudo('containerlab version upgrade', 'Upgrading containerlab', outputChannel, 'generic');
440+
await runWithSudo(`${containerlabBinaryPath} version upgrade`, 'Upgrading containerlab', outputChannel, 'generic');
440441
vscode.window.showInformationMessage('Containerlab updated successfully!');
441442
log('Containerlab updated successfully.', outputChannel);
442443
} catch (err: any) {

src/services/containerlabEvents.ts

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { spawn, ChildProcess } from "child_process";
2-
import * as fs from "fs";
32
import * as readline from "readline";
43
import * as utils from "../helpers/utils";
54
import type { ClabDetailedJSON } from "../treeView/common";
65
import type { ClabInterfaceSnapshot, ClabInterfaceSnapshotEntry } from "../types/containerlab";
6+
import { containerlabBinaryPath } from "../extension";
77

88
interface ContainerlabEvent {
99
timestamp?: string;
@@ -249,25 +249,6 @@ function scheduleDataChanged(): void {
249249
}, DATA_NOTIFY_DELAY_MS);
250250
}
251251

252-
function findContainerlabBinary(): string {
253-
const candidateBins = [
254-
"/usr/bin/containerlab",
255-
"/usr/local/bin/containerlab",
256-
"/bin/containerlab",
257-
];
258-
259-
for (const candidate of candidateBins) {
260-
try {
261-
if (fs.existsSync(candidate)) {
262-
return candidate;
263-
}
264-
} catch {
265-
// ignore filesystem errors and continue searching
266-
}
267-
}
268-
return "containerlab";
269-
}
270-
271252
function scheduleInitialResolution(): void {
272253
if (initialLoadComplete) {
273254
return;
@@ -963,7 +944,7 @@ function startProcess(runtime: string): void {
963944
});
964945

965946
const sudo = utils.getSudo().trim();
966-
const containerlabBinary = findContainerlabBinary();
947+
const containerlabBinary = containerlabBinaryPath
967948
const baseArgs = ["events", "--format", "json", "--initial-state"];
968949
if (runtime) {
969950
baseArgs.splice(1, 0, "-r", runtime);

0 commit comments

Comments
 (0)