Add --config CLI argument and fix cluster nodes driver selection

- Add --config <file> argument to load config from custom path
- Modify config loader to use custom config file if specified
- Fix cluster nodes interface to only show available GPU backends for workers
- Differentiate between local and remote node driver selection
parent 63965769
......@@ -226,40 +226,94 @@ function openDriverModal(hostname, token, hostnameValue) {
const container = document.getElementById('workerDriverSelections');
container.innerHTML = '';
// 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);
}
});
}
// Handle local vs remote nodes differently
if (node.is_local) {
// For local node, use single driver selection for all workers
const availableGpuBackends = node.available_backends.filter(b => b !== 'cpu');
if (availableGpuBackends.length === 0) {
container.innerHTML = '<p>No GPU backends available for local workers.</p>';
return;
}
if (gpuWorkers.length === 0) {
container.innerHTML = '<p>No GPU-requiring workers found on this node.</p>';
return;
}
let optionsHtml = '';
availableGpuBackends.forEach(backend => {
optionsHtml += `<option value="${backend}">${backend.toUpperCase()}</option>`;
});
// Create form fields for each GPU worker
gpuWorkers.forEach(worker => {
const workerDiv = document.createElement('div');
workerDiv.className = 'form-group';
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">
<option value="cuda">CUDA</option>
<option value="rocm">ROCm</option>
<option value="cpu">CPU</option>
</select>
container.innerHTML = `
<div class="form-group">
<label for="driver">Driver for all local workers:</label>
<select id="driver" name="driver">
${optionsHtml}
</select>
</div>
`;
container.appendChild(workerDiv);
// Set current preference or default
const select = workerDiv.querySelector('select');
// For now, default to the worker's current backend
select.value = worker.backend;
});
// Set current preference or default to first available
const select = document.getElementById('driver');
// For local, default to the first GPU backend available
select.value = availableGpuBackends[0];
} else {
// For remote nodes, show worker-specific selections
// 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';
}
......
......@@ -112,6 +112,11 @@ Examples:
help=f'Default model type for auto-detection (default: {default_model_type})'
)
parser.add_argument(
'--config',
help='Path to configuration file (overrides default locations)'
)
parser.add_argument(
'--dir',
default=get_config('allowed_dir', ''),
......
......@@ -102,10 +102,21 @@ def load_initial_config(cli_args=None) -> dict:
args = cli_args or _cli_args
# 1. Load from config files (lower precedence than env, but higher than defaults)
config_files = [
Path.home() / '.config' / 'vidai' / 'vidai.conf',
Path('/etc/vidai.conf')
]
config_files = []
# Check for custom config file from CLI
if args and hasattr(args, 'config') and args.config:
custom_config = Path(args.config)
if custom_config.exists():
config_files.append(custom_config)
else:
print(f"Warning: Specified config file '{args.config}' does not exist. Falling back to default locations.")
else:
# Default locations
config_files = [
Path.home() / '.config' / 'vidai' / 'vidai.conf',
Path('/etc/vidai.conf')
]
for config_file in config_files:
if config_file.exists():
......
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