mirror of
https://github.com/kasmtech/kasm-install-wizard.git
synced 2026-07-17 16:35:08 +00:00
KASM-8264 Registry based wizard installer
This commit is contained in:
parent
502bc2f530
commit
d4b7db69f4
3 changed files with 98 additions and 5 deletions
94
index.js
94
index.js
|
|
@ -24,15 +24,100 @@ const { spawn } = require('node:child_process');
|
|||
var EULA;
|
||||
var images;
|
||||
var currentVersion;
|
||||
var sourceLocal = false;
|
||||
var gpuInfo;
|
||||
var installSettings = {};
|
||||
var upgradeSettings = {};
|
||||
|
||||
// Find the best matching compatibility entry for the current version.
|
||||
// Exact version match takes precedence over wildcard (e.g. "1.18.x").
|
||||
function matchVersion(currentVer, compatibilityList) {
|
||||
if (!compatibilityList || compatibilityList.length === 0) return null;
|
||||
const parts = currentVer.split('.');
|
||||
const major = parts[0];
|
||||
const minor = parts[1] !== undefined ? parts[1] : '0';
|
||||
|
||||
// Exact match (most precise)
|
||||
let match = compatibilityList.find(c => c.version === currentVer);
|
||||
if (match) return match;
|
||||
|
||||
// Major.minor wildcard, e.g. "1.18.x"
|
||||
match = compatibilityList.find(c => c.version === `${major}.${minor}.x`);
|
||||
if (match) return match;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Fetch workspace list from registry and convert to the images YAML structure.
|
||||
// Falls back to local list.json if the remote is unavailable.
|
||||
async function fetchWorkspaceList(currentVer, archName) {
|
||||
let listData;
|
||||
try {
|
||||
const response = await fetch('https://registry.kasmweb.com/1.1/list.json');
|
||||
if (!response.ok) throw new Error(`HTTP ${response.status}`);
|
||||
listData = await response.json();
|
||||
} catch (err) {
|
||||
console.error('Failed to fetch workspace list, falling back to local list.json:', err.message);
|
||||
let localList = await fsw.readFile('/wizard/list.json', 'utf8');
|
||||
listData = JSON.parse(localList);
|
||||
sourceLocal = true;
|
||||
}
|
||||
|
||||
const defaultChannel = listData.default_channel;
|
||||
const filtered = (listData.workspaces || []).filter(
|
||||
ws => ws.architecture && ws.architecture.includes(archName)
|
||||
);
|
||||
|
||||
let imageIdx = 1;
|
||||
const imagesList = [];
|
||||
for (const ws of filtered) {
|
||||
const compat = matchVersion(currentVer, ws.compatibility || []);
|
||||
if (!compat) continue;
|
||||
|
||||
// Use default_channel tag if it exists in available_tags, otherwise keep compat image tag
|
||||
let imageName = compat.image;
|
||||
const imageBase = imageName.split(':')[0];
|
||||
if (defaultChannel && compat.available_tags && compat.available_tags.includes(defaultChannel)) {
|
||||
imageName = imageBase + ':' + defaultChannel;
|
||||
}
|
||||
|
||||
imagesList.push({
|
||||
categories: ws.categories,
|
||||
cores: 2.0,
|
||||
cpu_allocation_method: 'Inherit',
|
||||
description: ws.description,
|
||||
docker_registry: ws.docker_registry,
|
||||
enabled: true,
|
||||
exec_config: {},
|
||||
friendly_name: ws.friendly_name,
|
||||
gpu_count: 0,
|
||||
hidden: false,
|
||||
image_id: '${uuid:image_id:' + imageIdx + '}',
|
||||
image_src: 'https://registry.kasmweb.com/1.1/icons/' + ws.image_src,
|
||||
image_type: 'Container',
|
||||
launch_config: {},
|
||||
memory: 2768000000,
|
||||
name: imageName,
|
||||
notes: ws.notes || null,
|
||||
run_config: {},
|
||||
uncompressed_size_mb: compat.uncompressed_size_mb,
|
||||
zone_id: null
|
||||
});
|
||||
imageIdx++;
|
||||
}
|
||||
|
||||
return { alembic_version: 'e3900d8a4fee', images: imagesList };
|
||||
}
|
||||
|
||||
// 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,'');
|
||||
try {
|
||||
currentVersion = fs.readFileSync('/version.txt', 'utf8').replace(/(\r\n|\n|\r)/gm,'');
|
||||
} catch (err) {
|
||||
currentVersion = '1.18.1!';
|
||||
}
|
||||
images = await fetchWorkspaceList(currentVersion, arch);
|
||||
let gpuData = [];
|
||||
let gpuCmd = spawn('/gpuinfo.sh');
|
||||
gpuCmd.stdout.on('data', function(data) {
|
||||
|
|
@ -192,6 +277,7 @@ io.on('connection', async function (socket) {
|
|||
dashinfo['localVersion'] = 'Unknown';
|
||||
}
|
||||
dashinfo['currentVersion'] = currentVersion;
|
||||
dashinfo['sourceLocal'] = sourceLocal;
|
||||
dashinfo['gpuInfo'] = gpuInfo;
|
||||
dashinfo['containers'] = containers;
|
||||
dashinfo['cpu'] = await si.cpu();
|
||||
|
|
@ -201,7 +287,7 @@ io.on('connection', async function (socket) {
|
|||
socket.emit('renderdash', [dashinfo, images]);
|
||||
// Render installer
|
||||
} else {
|
||||
socket.emit('renderinstall', [EULA, images, gpuInfo]);
|
||||
socket.emit('renderinstall', [EULA, images, gpuInfo, currentVersion, sourceLocal]);
|
||||
}
|
||||
}
|
||||
// Disable wizard
|
||||
|
|
|
|||
1
list.json
Normal file
1
list.json
Normal file
File diff suppressed because one or more lines are too long
|
|
@ -88,6 +88,10 @@ function titleChange(value) {
|
|||
$('#title').text(value);
|
||||
}
|
||||
|
||||
function versionChange(ver, local) {
|
||||
document.title = 'Kasm Wizard ' + ver + (local ? ' (local)' : '');
|
||||
}
|
||||
|
||||
// Render landing as installer page
|
||||
function renderInstall(data) {
|
||||
showContainer();
|
||||
|
|
@ -95,6 +99,7 @@ function renderInstall(data) {
|
|||
EULA = data[0];
|
||||
images = data[1];
|
||||
gpus = data[2];
|
||||
versionChange(data[3], data[4]);
|
||||
let EULADiv = $('<div>', {id: 'EULA'}).text(EULA);
|
||||
$('#container').append(EULADiv);
|
||||
let EULAButton = $('<button>', {id: 'EULAButton', onclick: 'pickSettings()', class: 'btn btn-default btn-ghost'}).text('Accept and continue');
|
||||
|
|
@ -107,6 +112,7 @@ async function renderDash(data) {
|
|||
titleChange('Dashboard');
|
||||
let info = data[0];
|
||||
images = data[1];
|
||||
versionChange(info.currentVersion, info.sourceLocal);
|
||||
// Store GPU info
|
||||
$('body').data('gpuInfo', info.gpuInfo);
|
||||
// Upgrade button if needed
|
||||
|
|
@ -319,7 +325,7 @@ async function pickImages(upgrade) {
|
|||
title: image.description,
|
||||
onclick: 'selectImage(\'' + image.friendly_name.replace(new RegExp(' ', 'g'), '_').replace('.', '-') + '\')'
|
||||
}).append(imageName).css('filter', 'grayscale(100%)')
|
||||
let thumb = $('<img>', {class: 'thumb', src: 'public/' + image.image_src});
|
||||
let thumb = $('<img>', {class: 'thumb', src: image.image_src, loading: 'lazy'});
|
||||
imageDiv.append(thumb);
|
||||
$('#images').append(imageDiv);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue