Fix cluster nodes modal to show per-worker driver selects

- Show individual select forms for every worker in the driver modal
- Update API to handle per-worker driver selection for local nodes
- Maintain compatibility with existing backend switching logic
parent a7d2d90e
...@@ -226,94 +226,62 @@ function openDriverModal(hostname, token, hostnameValue) { ...@@ -226,94 +226,62 @@ function openDriverModal(hostname, token, hostnameValue) {
const container = document.getElementById('workerDriverSelections'); const container = document.getElementById('workerDriverSelections');
container.innerHTML = ''; container.innerHTML = '';
// Handle local vs remote nodes differently // Get GPU-requiring workers (analysis_cuda, training_cuda, analysis_rocm, training_rocm)
if (node.is_local) { const gpuWorkers = [];
// For local node, use single driver selection for all workers if (node.workers && node.workers.length > 0) {
node.workers.forEach(worker => {
if (worker.backend !== 'cpu') {
gpuWorkers.push(worker);
}
});
}
if (gpuWorkers.length === 0) {
container.innerHTML = '<p>No GPU-requiring workers found on this node.</p>';
return;
}
// Create form fields for each GPU worker
gpuWorkers.forEach(worker => {
const workerDiv = document.createElement('div');
workerDiv.className = 'form-group';
// Get available GPU backends for this node (exclude CPU for GPU workers)
const availableGpuBackends = node.available_backends.filter(b => b !== 'cpu'); const availableGpuBackends = node.available_backends.filter(b => b !== 'cpu');
// If no GPU backends available, skip this worker or show warning
if (availableGpuBackends.length === 0) { if (availableGpuBackends.length === 0) {
container.innerHTML = '<p>No GPU backends available for local workers.</p>'; workerDiv.innerHTML = `
<label>${worker.type} (${worker.backend.toUpperCase()}) Worker:</label>
<p style="color: #dc2626;">No GPU backends available for this worker</p>
`;
container.appendChild(workerDiv);
return; return;
} }
// Create select with only available GPU backends
let optionsHtml = ''; let optionsHtml = '';
availableGpuBackends.forEach(backend => { availableGpuBackends.forEach(backend => {
optionsHtml += `<option value="${backend}">${backend.toUpperCase()}</option>`; optionsHtml += `<option value="${backend}">${backend.toUpperCase()}</option>`;
}); });
container.innerHTML = ` workerDiv.innerHTML = `
<div class="form-group"> <label for="worker_${worker.type}_${worker.backend}_driver">${worker.type} (${worker.backend.toUpperCase()}) Worker:</label>
<label for="driver">Driver for all local workers:</label> <select id="worker_${worker.type}_${worker.backend}_driver" name="worker_${worker.type}_${worker.backend}_driver">
<select id="driver" name="driver"> ${optionsHtml}
${optionsHtml} </select>
</select>
</div>
`; `;
container.appendChild(workerDiv);
// Set current preference or default to first available // Set current preference or default to first available
const select = document.getElementById('driver'); const select = workerDiv.querySelector('select');
// For local, default to the first GPU backend available if (availableGpuBackends.includes(worker.backend)) {
select.value = availableGpuBackends[0]; select.value = worker.backend;
} else {
} else { // Default to first available GPU backend
// For remote nodes, show worker-specific selections select.value = availableGpuBackends[0];
// Get GPU-requiring workers (analysis_cuda, training_cuda, analysis_rocm, training_rocm)
const gpuWorkers = [];
if (node.workers && node.workers.length > 0) {
node.workers.forEach(worker => {
if (worker.backend !== 'cpu') {
gpuWorkers.push(worker);
}
});
}
if (gpuWorkers.length === 0) {
container.innerHTML = '<p>No GPU-requiring workers found on this node.</p>';
return;
} }
});
// Create form fields for each GPU worker
gpuWorkers.forEach(worker => {
const workerDiv = document.createElement('div');
workerDiv.className = 'form-group';
// Get available GPU backends for this node (exclude CPU for GPU workers)
const availableGpuBackends = node.available_backends.filter(b => b !== 'cpu');
// If no GPU backends available, skip this worker or show warning
if (availableGpuBackends.length === 0) {
workerDiv.innerHTML = `
<label>${worker.type} (${worker.backend.toUpperCase()}) Worker:</label>
<p style="color: #dc2626;">No GPU backends available for this worker</p>
`;
container.appendChild(workerDiv);
return;
}
// Create select with only available GPU backends
let optionsHtml = '';
availableGpuBackends.forEach(backend => {
optionsHtml += `<option value="${backend}">${backend.toUpperCase()}</option>`;
});
workerDiv.innerHTML = `
<label for="worker_${worker.type}_${worker.backend}_driver">${worker.type} (${worker.backend.toUpperCase()}) Worker:</label>
<select id="worker_${worker.type}_${worker.backend}_driver" name="worker_${worker.type}_${worker.backend}_driver">
${optionsHtml}
</select>
`;
container.appendChild(workerDiv);
// Set current preference or default to first available
const select = workerDiv.querySelector('select');
if (availableGpuBackends.includes(worker.backend)) {
select.value = worker.backend;
} else {
// Default to first available GPU backend
select.value = availableGpuBackends[0];
}
});
}
document.getElementById('driverModal').style.display = 'block'; document.getElementById('driverModal').style.display = 'block';
} }
......
...@@ -730,10 +730,15 @@ def api_set_client_driver(): ...@@ -730,10 +730,15 @@ def api_set_client_driver():
# Handle local workers # Handle local workers
if token == 'local': if token == 'local':
# For local workers, expect a single driver for all workers # For local workers, parse worker-specific drivers but use the same backend for all
driver = request.form.get('driver') driver = None
if not driver or driver not in ['cuda', 'rocm', 'cpu']: for key, value in request.form.items():
return {'success': False, 'error': 'Invalid driver - only CUDA, ROCm, and CPU are supported'}, 400 if key.startswith('worker_') and key.endswith('_driver'):
if value in ['cuda', 'rocm', 'cpu']:
driver = value
break # Use the first valid driver found
if not driver:
return {'success': False, 'error': 'No valid driver found for local workers'}, 400
success = switch_local_worker_backends(driver) success = switch_local_worker_backends(driver)
return {'success': success} return {'success': success}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment