From 64f37687481ca0272875655466e15c25f6ce0944 Mon Sep 17 00:00:00 2001 From: Richard Koliser Date: Wed, 17 Jun 2026 13:42:15 -0400 Subject: [PATCH 1/5] KASM-1190 Update wizard for Kasm Workspaces 1.19.0 rolling changes Rolling is now the default in 1.19.0's install.sh, so the wizard no longer needs to patch service image tags manually. Remove appendRollingToServiceImages() and both call sites (install and upgrade paths). Update the version fallback from 1.18.1 to 1.19.0. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- index.js | 32 +++----------------------------- 1 file changed, 3 insertions(+), 29 deletions(-) diff --git a/index.js b/index.js index 19f84c2..c2b65d6 100644 --- a/index.js +++ b/index.js @@ -48,7 +48,7 @@ function matchVersion(currentVer, compatibilityList) { } // Build the image tag for a given compat entry. -// Returns e.g. "1.18.1-rolling-weekly", falling back to "develop". +// Returns e.g. "1.19.0-rolling-weekly", falling back to "develop". function buildImageTag(compat) { const compatTag = compat.image.split(':')[1] || ''; const versionPrefix = compatTag.replace(/-[^-]+-[^-]+$/, ''); // strip last two dash-segments @@ -70,7 +70,7 @@ async function fetchListData() { } // Return the rolling-weekly tag string for the current version by finding -// the first compatible workspace in the registry (e.g. "1.18.1-rolling-weekly"). +// the first compatible workspace in the registry (e.g. "1.19.0-rolling-weekly"). async function getRollingWeeklyTag(currentVer, archName) { const listData = await fetchListData(); const ws = (listData.workspaces || []).find( @@ -142,7 +142,7 @@ async function installerBlobs() { try { currentVersion = fs.readFileSync('/version.txt', 'utf8').replace(/(\r\n|\n|\r)/gm,''); } catch (err) { - currentVersion = '1.18.1'; + currentVersion = '1.19.0'; } images = await fetchWorkspaceList(currentVersion, arch); gpuInfo = {}; @@ -210,28 +210,6 @@ async function setGpu(imagesI) { return imagesI; } -// For rolling-weekly installs, append -rolling to service image tags in docker conf yamls. -// Prevents -rolling-rolling by only modifying tags that don't already end with -rolling. -async function appendRollingToServiceImages() { - const confDir = '/kasm_release/docker'; - let entries; - try { - entries = await fsw.readdir(confDir); - } catch (err) { - return; - } - for (const file of entries.filter(f => f.endsWith('.yaml'))) { - const filePath = confDir + '/' + file; - const content = await fsw.readFile(filePath, 'utf8'); - const updated = content.split('\n').map(line => { - if (/ image:/.test(line) && /"$/.test(line) && !/-rolling"$/.test(line) && !/develop"$/.test(line)) { - return line.replace(/"$/, '-rolling"'); - } - return line; - }).join('\n'); - await fsw.writeFile(filePath, updated); - } -} //// Http server //// baserouter.use('/public', express.static(__dirname + '/public')); @@ -268,7 +246,6 @@ io.on('connection', async function (socket) { installFlags = installFlags.filter(function(e) { return e !== '-W' }); } else { await fsw.writeFile('/kasm_release/conf/database/seed_data/default_images_' + arch + '.yaml', yamlStr); - await appendRollingToServiceImages(); } // Copy over version @@ -290,9 +267,6 @@ io.on('connection', async function (socket) { async function upgrade(data) { let upgradeFlags = ['/kasm_release/upgrade.sh', '-L', port]; - // Patch service image tags for rolling builds - await appendRollingToServiceImages(); - // Run upgrade let cmd = pty.spawn('/bin/bash', upgradeFlags); cmd.on('data', function(data) { From 0774b59deb6d02f681c635c19a9aea193826de09 Mon Sep 17 00:00:00 2001 From: Richard Koliser Date: Wed, 17 Jun 2026 14:16:12 -0400 Subject: [PATCH 2/5] KASM-1190 Remove legacy GPU seeding in favour of 1.19.0 agent management In 1.19.0, the provision agent dynamically assigns GPUs to containers using capability probing (EGL, DRI3, VAAPI, NVENC, VULKAN) and load-balancing across devices. Pre-seeding GPU run_config/exec_config into workspace images at install time conflicts with this system and uses removed env var names (HW3D/DRINODE replaced by KVNC_DESKTOP_GPU_HW3D/KVNC_DESKTOP_GPU_DRINODE). Remove setGpu(), the gpuinfo.sh detection block, the GPU yaml-merge call in install(), and the "Use GPU on all images" install UI option. Replace the UI option with a notice directing admins to configure GPU acceleration in the admin panel post-install. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- index.js | 71 +--------------------------------------------- public/js/index.js | 14 ++------- 2 files changed, 3 insertions(+), 82 deletions(-) diff --git a/index.js b/index.js index c2b65d6..0b4ad82 100644 --- a/index.js +++ b/index.js @@ -19,12 +19,11 @@ const docker = new Docker({socketPath: '/var/run/docker.sock'}); const arch = os.arch().replace('x64', 'amd64'); const baseUrl = process.env.SUBFOLDER || '/'; const port = process.env.KASM_PORT || '443'; -const { spawn } = require('node:child_process'); let EULA; let images; let currentVersion; let sourceLocal = false; -let gpuInfo; +let gpuInfo = {}; let installSettings = {}; let upgradeSettings = {}; @@ -145,72 +144,9 @@ async function installerBlobs() { currentVersion = '1.19.0'; } images = await fetchWorkspaceList(currentVersion, arch); - gpuInfo = {}; - await new Promise((resolve) => { - 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"; - } - } - } - resolve(); - }); - }); } installerBlobs(); -// GPU image yaml merging -async function setGpu(imagesI) { - if (upgradeSettings['forceGpu'] !== undefined) { - installSettings = upgradeSettings; - } - const forceGpu = installSettings.forceGpu; - if (!forceGpu || forceGpu === 'disabled' || !forceGpu.includes('|')) { - console.error('setGpu: invalid or missing forceGpu value:', forceGpu); - return imagesI; - } - const [gpu, gpuName] = forceGpu.split('|'); - if (!gpu || !gpuName) { - console.error('setGpu: could not parse GPU path or name from forceGpu:', forceGpu); - return imagesI; - } - const card = gpu.slice(-1); - const render = (Number(card) + 128).toString(); - // Handle NVIDIA Gpus - let baseRun; - if (gpuName.includes('NVIDIA')) { - 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 (let i=0; i', {id: 'EULA'}).text(EULA); $('#container').append(EULADiv); @@ -230,14 +228,7 @@ async function pickSettings() { $('