Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1e57062
KASM-3512 adding select dropdown during installation to force a GPU o…
Nov 1, 2022
64bd739
KASM-3512 use deep merge on the exec and run configs to load the defa…
Nov 5, 2022
37dbb06
KASM-3512 make lossless install default
Nov 17, 2022
0aa9746
KASM-3512 add support for nvidia GPUS
Nov 17, 2022
c51cbe8
KASM-3512 nvidia bugfix
Nov 17, 2022
675ca12
Merge pull request #1 from kasmtech/feature/KASM-3512-gpu-option
j-travis Nov 23, 2022
a5c2f06
KASM-2903 add initial upgrade support
Nov 28, 2022
ee1ea94
KASM-2903 need globals for install and upgrade settings
Nov 28, 2022
bfacaa3
Merge pull request #2 from kasmtech/feature/KASM-2903-upgrade-support
j-travis Nov 30, 2022
a8735cf
KASM-3699 have a fallback mode for gpuinfo script to simply list the …
Dec 5, 2022
3e9264d
Merge pull request #3 from kasmtech/bugfix/KASM-3699-fix-gpu-info-error
j-travis Dec 5, 2022
0c654da
KASM-4200 restructure code to handle new yaml format and update gpu s…
thelamer Mar 28, 2023
e599398
Merge pull request #4 from kasmtech/feature/KASM-4200-113-updates
j-travis Mar 28, 2023
58775a6
fix old bug if no images are selected install and upgrade bombs out
Aug 21, 2023
b5c3569
Merge pull request #5 from kasmtech/114-updates
j-travis Aug 21, 2023
84f2bfd
nvidia runtime updates for 116 release with compatibility
thelamer Jul 8, 2024
0828019
disable lossless
thelamer Jul 10, 2024
8622084
Merge pull request #7 from kasmtech/116-updates
j-travis Jul 15, 2024
cb06a2c
prevent calling setGpu when the image selection is empty
gautamkrishnar Feb 18, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 132 additions & 22 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ var fsw = require('fs').promises;
var fs = require('fs');
var os = require('os');
var yaml = require('js-yaml');
var _ = require('lodash');
var si = require('systeminformation');
var express = require('express');
var app = require('express')();
Expand All @@ -19,16 +20,72 @@ var arch = os.arch().replace('x64', 'amd64');
var baseUrl = process.env.SUBFOLDER || '/';
var version = process.env.VERSION || 'stable';
var port = process.env.KASM_PORT || '443';
const { spawn } = require('node:child_process');
var EULA;
var images;
var currentVersion;
var gpuInfo;
var installSettings = {};
var upgradeSettings = {};
// Grab installer variables
async function installerBlobs() {
EULA = await fsw.readFile('/kasm_release/licenses/LICENSE.txt', 'utf8');
let imagesText = await fsw.readFile('/wizard/default_images_' + arch + '.yaml', 'utf8');
images = yaml.load(imagesText);
currentVersion = fs.readFileSync('/version.txt', 'utf8').replace(/(\r\n|\n|\r)/gm,'');
let gpuData = [];
let gpuCmd = spawn('/gpuinfo.sh');
gpuCmd.stdout.on('data', function(data) {
gpuData.push(data);
});
gpuCmd.on('close', function(code) {
try {
if (code == 0) {
gpuInfo = JSON.parse(gpuData.join(''));
} else {
gpuInfo = {};
}
} catch (err) {
// Manually backfill GPU info if available
gpuInfo = {};
for (let i = 0; i < 10; i++) {
let num = i.toString();
if (fs.existsSync('/dev/dri/card' + num)) {
gpuInfo['/dev/dri/card' + num] = "Unknown GPU";
}
}
}
});
}
installerBlobs();

// GPU image yaml merging
async function setGpu(imagesI) {
if (upgradeSettings['forceGpu'] !== undefined) {
installSettings = upgradeSettings;
}
let gpu = installSettings.forceGpu.split('|')[0];
let gpuName = installSettings.forceGpu.split('|')[1];
let card = gpu.slice(-1);
let render = (Number(card) + 128).toString();
// Handle NVIDIA Gpus
var baseRun;
if (gpuName.indexOf('NVIDIA') !== -1) {
baseRun = JSON.parse('{"runtime":"nvidia","environment":{"NVIDIA_DRIVER_CAPABILITIES":"all","KASM_EGL_CARD":"/dev/dri/card' + card + '","KASM_RENDERD":"/dev/dri/renderD' + render + '"},"device_requests":[{"driver": "","count": -1,"device_ids": null,"capabilities":[["gpu"]],"options":{}}]}');
} else {
baseRun = JSON.parse('{"environment":{"DRINODE":"/dev/dri/renderD' + render + '", "HW3D": true},"devices":["/dev/dri/card' + card + ':/dev/dri/card' + card + ':rwm","/dev/dri/renderD' + render + ':/dev/dri/renderD' + render + ':rwm"]}');
}
let baseExec = JSON.parse('{"first_launch":{"user":"root","cmd": "bash -c \'chown -R kasm-user:kasm-user /dev/dri/*\'"}}');
for (var i=0; i<imagesI.images.length; i++) {
console.log(imagesI.images[i]['run_config']);
finalRun = _.merge(imagesI.images[i]['run_config'], baseRun)
finalExec = _.merge(imagesI.images[i]['exec_config'], baseExec)
imagesI.images[i]['run_config'] = finalRun;
imagesI.images[i]['exec_config'] = finalExec;
}
return imagesI;
}

//// Http server ////
baserouter.use('/public', express.static(__dirname + '/public'));
baserouter.get("/", function (req, res) {
Expand All @@ -45,32 +102,73 @@ io = socketIO(https, {path: baseUrl + 'socket.io'});
io.on('connection', async function (socket) {
// Run bash install with our custom flags
async function install(data) {
// Determine install settings
installSettings = data[0];
let imagesI = data[1];
let imagesD = images;
installFlags = ['/kasm_release/install.sh', '-B' ,'-H', '-e', '-L', port, '-P', installSettings.adminPass, '-U', installSettings.userPass];
if (installSettings.useRolling == true) {
installFlags.push('-O');
var imagesI = data[1];
installFlags = ['/kasm_release/install.sh', '-W', '-B' ,'-H', '-e', '-L', port, '-P', installSettings.adminPass, '-U', installSettings.userPass];
if ((imagesI.hasOwnProperty('images')) && (imagesI.images.length < 10)) {
installFlags.push('-b');
}
if ((installSettings.noDownload == true) || (imagesI == false)) {
installFlags.push('-u');

// GPU yaml merge
if (installSettings.forceGpu !== 'disabled' && imagesI.images) {
imagesI = await setGpu(imagesI);
}
if ((imagesI.hasOwnProperty('images')) && (Object.keys(imagesI.images).length < 10)) {
installFlags.push('-b');

// Write finalized image data
let yamlStr = yaml.dump(imagesI);
if (yamlStr.startsWith("false")) {
installFlags = installFlags.filter(function(e) { return e !== '-W' });
} else {
await fsw.writeFile('/kasm_release/conf/database/seed_data/default_images_' + arch + '.yaml', yamlStr);
}
// Flag the images properly based on selection
for await (let image of Object.keys(images.images)) {
if ((imagesI.hasOwnProperty('images')) && (imagesI.images.hasOwnProperty(image))) {
imagesD.images[image].enabled = true;
imagesD.images[image].hidden = false;
} else {
imagesD.images[image].enabled = false;
imagesD.images[image].hidden = true;

// Copy over version
await fsw.copyFile('/version.txt', '/opt/version.txt');

// Run install
let cmd = pty.spawn('/bin/bash', installFlags);
cmd.on('data', function(data) {
socket.emit('term', data);
});
cmd.on('exit', function(code, signal) {
if (code == 0) {
socket.emit('done', port);
}
});
}

// Run bash upgrade with our custom flags
async function upgrade(data) {
// Determine upgrade settings
upgradeSettings = data[0];
var imagesI = data[1];
upgradeFlags = ['/kasm_release/upgrade.sh', '-L', port];
if (upgradeSettings.keepOldImages == true) {
upgradeFlags.push('-K');
} else {
upgradeFlags.push('-U');
}
let yamlStr = yaml.dump(imagesD);
await fsw.writeFile('/kasm_release/conf/database/seed_data/default_images_' + arch + '.yaml', yamlStr);
let cmd = pty.spawn('/bin/bash', installFlags);

// GPU yaml merge
if (upgradeSettings.forceGpu !== 'disabled' && imagesI.images) {
imagesI = await setGpu(imagesI);
}

// Write finalized image data
let yamlStr = yaml.dump(imagesI);
if (yamlStr.startsWith("false")) {
upgradeFlags = upgradeFlags.filter(function(e) { return e !== '-K' });
upgradeFlags = upgradeFlags.filter(function(e) { return e !== '-U' });
} else {
await fsw.writeFile('/kasm_release/conf/database/seed_data/default_images_' + arch + '.yaml', yamlStr);
}

// Copy over version
await fsw.copyFile('/version.txt', '/opt/version.txt');

// Run upgrade
let cmd = pty.spawn('/bin/bash', upgradeFlags);
cmd.on('data', function(data) {
socket.emit('term', data);
});
Expand All @@ -80,19 +178,30 @@ io.on('connection', async function (socket) {
}
});
}

// Render landing page depending on installed status
async function renderLanding() {
let containers = await docker.listContainers();
// This is a running system
if (containers.length !== 0) {
let dashinfo = {};
// Get version information
if (fs.existsSync('/opt/version.txt')) {
dashinfo['localVersion'] = fs.readFileSync('/opt/version.txt', 'utf8').replace(/(\r\n|\n|\r)/gm,'');
} else {
dashinfo['localVersion'] = 'Unknown';
}
dashinfo['currentVersion'] = currentVersion;
dashinfo['gpuInfo'] = gpuInfo;
dashinfo['containers'] = containers;
dashinfo['cpu'] = await si.cpu();
dashinfo['mem'] = await si.mem();
dashinfo['cpuPercent'] = await si.currentLoad();
dashinfo['port'] = port;
socket.emit('renderdash', dashinfo);
socket.emit('renderdash', [dashinfo, images]);
// Render installer
} else {
socket.emit('renderinstall', [EULA, images]);
socket.emit('renderinstall', [EULA, images, gpuInfo]);
}
}
// Disable wizard
Expand All @@ -104,5 +213,6 @@ io.on('connection', async function (socket) {
//// Incoming requests ////
socket.on('renderlanding', renderLanding);
socket.on('install', install);
socket.on('upgrade', upgrade);
socket.on('nowizard', noWizard);
});
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
"dockerode": "^3.3.2",
"express": "^4.18.1",
"js-yaml": "^4.1.0",
"lodash": "^4.17.21",
"node-pty": "^0.10.1",
"socket.io": "^4.5.1",
"systeminformation": "^5.11.16"
Expand Down
Loading