refactor(config): extract config loading from modelgrid
This commit is contained in:
@@ -1,14 +1,11 @@
|
|||||||
import { assertEquals } from 'jsr:@std/assert@^1.0.0';
|
import { assertEquals } from 'jsr:@std/assert@^1.0.0';
|
||||||
import { ModelGrid } from '../ts/modelgrid.ts';
|
import { ConfigManager } from '../ts/config/config-manager.ts';
|
||||||
import type { IModelGridConfig } from '../ts/interfaces/config.ts';
|
import type { IModelGridConfig } from '../ts/interfaces/config.ts';
|
||||||
|
|
||||||
Deno.test('ModelGrid normalizes current config defaults', () => {
|
Deno.test('ConfigManager normalizes current config defaults', () => {
|
||||||
const modelgrid = new ModelGrid();
|
const configManager = new ConfigManager();
|
||||||
const normalizeConfig = (modelgrid as unknown as {
|
|
||||||
normalizeConfig: (config: Partial<IModelGridConfig>) => IModelGridConfig;
|
|
||||||
}).normalizeConfig.bind(modelgrid);
|
|
||||||
|
|
||||||
const normalized = normalizeConfig({
|
const normalized = configManager.normalizeConfig({
|
||||||
version: '1.0.0',
|
version: '1.0.0',
|
||||||
api: {
|
api: {
|
||||||
port: 9000,
|
port: 9000,
|
||||||
|
|||||||
@@ -0,0 +1,75 @@
|
|||||||
|
import * as fs from 'node:fs/promises';
|
||||||
|
import { PATHS, VERSION } from '../constants.ts';
|
||||||
|
import type { IModelGridConfig } from '../interfaces/config.ts';
|
||||||
|
|
||||||
|
export class ConfigManager {
|
||||||
|
public async loadConfig(): Promise<IModelGridConfig> {
|
||||||
|
try {
|
||||||
|
const configContent = await fs.readFile(PATHS.CONFIG_FILE, 'utf-8');
|
||||||
|
return this.normalizeConfig(JSON.parse(configContent) as Partial<IModelGridConfig>);
|
||||||
|
} catch (error) {
|
||||||
|
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
||||||
|
throw new Error(`Configuration file not found: ${PATHS.CONFIG_FILE}`);
|
||||||
|
}
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async saveConfig(config: IModelGridConfig): Promise<void> {
|
||||||
|
await fs.mkdir(PATHS.CONFIG_DIR, { recursive: true });
|
||||||
|
await fs.writeFile(PATHS.CONFIG_FILE, JSON.stringify(config, null, 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
public normalizeConfig(config: Partial<IModelGridConfig>): IModelGridConfig {
|
||||||
|
const filteredContainers = (config.containers || []).filter(
|
||||||
|
(container) => (container as { type?: string }).type !== 'ollama',
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
version: config.version || VERSION,
|
||||||
|
api: {
|
||||||
|
port: config.api?.port || 8080,
|
||||||
|
host: config.api?.host || '0.0.0.0',
|
||||||
|
apiKeys: config.api?.apiKeys || [],
|
||||||
|
rateLimit: config.api?.rateLimit,
|
||||||
|
cors: config.api?.cors ?? true,
|
||||||
|
corsOrigins: config.api?.corsOrigins || ['*'],
|
||||||
|
},
|
||||||
|
ui: {
|
||||||
|
enabled: config.ui?.enabled ?? true,
|
||||||
|
port: config.ui?.port || 8081,
|
||||||
|
host: config.ui?.host || '0.0.0.0',
|
||||||
|
assetSource: config.ui?.assetSource === 'disk' ? 'disk' : 'bundle',
|
||||||
|
},
|
||||||
|
docker: {
|
||||||
|
networkName: config.docker?.networkName || 'modelgrid',
|
||||||
|
runtime: config.docker?.runtime || 'docker',
|
||||||
|
socketPath: config.docker?.socketPath,
|
||||||
|
},
|
||||||
|
gpus: {
|
||||||
|
autoDetect: config.gpus?.autoDetect ?? true,
|
||||||
|
assignments: config.gpus?.assignments || {},
|
||||||
|
},
|
||||||
|
containers: filteredContainers,
|
||||||
|
models: {
|
||||||
|
registryUrl: config.models?.registryUrl || 'https://list.modelgrid.com/catalog/models.json',
|
||||||
|
autoDeploy: config.models?.autoDeploy ?? true,
|
||||||
|
defaultEngine: 'vllm',
|
||||||
|
autoLoad: config.models?.autoLoad || [],
|
||||||
|
},
|
||||||
|
cluster: {
|
||||||
|
enabled: config.cluster?.enabled ?? false,
|
||||||
|
nodeName: config.cluster?.nodeName || 'modelgrid-local',
|
||||||
|
role: config.cluster?.role || 'standalone',
|
||||||
|
bindHost: config.cluster?.bindHost || '0.0.0.0',
|
||||||
|
gossipPort: config.cluster?.gossipPort || 7946,
|
||||||
|
sharedSecret: config.cluster?.sharedSecret,
|
||||||
|
advertiseUrl: config.cluster?.advertiseUrl,
|
||||||
|
controlPlaneUrl: config.cluster?.controlPlaneUrl,
|
||||||
|
heartbeatIntervalMs: config.cluster?.heartbeatIntervalMs || 5000,
|
||||||
|
seedNodes: config.cluster?.seedNodes || [],
|
||||||
|
},
|
||||||
|
checkInterval: config.checkInterval || 30000,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
+6
-76
@@ -24,7 +24,7 @@ import { ClusterHandler } from './cli/cluster-handler.ts';
|
|||||||
import { ModelHandler } from './cli/model-handler.ts';
|
import { ModelHandler } from './cli/model-handler.ts';
|
||||||
import { ConfigHandler } from './cli/config-handler.ts';
|
import { ConfigHandler } from './cli/config-handler.ts';
|
||||||
import { ServiceHandler } from './cli/service-handler.ts';
|
import { ServiceHandler } from './cli/service-handler.ts';
|
||||||
import * as fs from 'node:fs/promises';
|
import { ConfigManager } from './config/config-manager.ts';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ModelGrid - Main application coordinator
|
* ModelGrid - Main application coordinator
|
||||||
@@ -42,6 +42,7 @@ export class ModelGrid {
|
|||||||
private clusterCoordinator?: ClusterCoordinator;
|
private clusterCoordinator?: ClusterCoordinator;
|
||||||
private modelRegistry: ModelRegistry;
|
private modelRegistry: ModelRegistry;
|
||||||
private modelLoader?: ModelLoader;
|
private modelLoader?: ModelLoader;
|
||||||
|
private configManager: ConfigManager;
|
||||||
|
|
||||||
// CLI Handlers
|
// CLI Handlers
|
||||||
private gpuHandler: GpuHandler;
|
private gpuHandler: GpuHandler;
|
||||||
@@ -60,6 +61,7 @@ export class ModelGrid {
|
|||||||
this.containerManager = new ContainerManager();
|
this.containerManager = new ContainerManager();
|
||||||
this.clusterManager = new ClusterManager();
|
this.clusterManager = new ClusterManager();
|
||||||
this.modelRegistry = new ModelRegistry();
|
this.modelRegistry = new ModelRegistry();
|
||||||
|
this.configManager = new ConfigManager();
|
||||||
this.systemd = new Systemd();
|
this.systemd = new Systemd();
|
||||||
this.daemon = new Daemon(this);
|
this.daemon = new Daemon(this);
|
||||||
|
|
||||||
@@ -80,23 +82,8 @@ export class ModelGrid {
|
|||||||
* Load configuration from file
|
* Load configuration from file
|
||||||
*/
|
*/
|
||||||
public async loadConfig(): Promise<void> {
|
public async loadConfig(): Promise<void> {
|
||||||
try {
|
this.config = await this.configManager.loadConfig();
|
||||||
const configContent = await fs.readFile(PATHS.CONFIG_FILE, 'utf-8');
|
logger.dim(`Configuration loaded from ${PATHS.CONFIG_FILE}`);
|
||||||
this.config = this.normalizeConfig(
|
|
||||||
JSON.parse(configContent) as Partial<IModelGridConfig> & {
|
|
||||||
models?: {
|
|
||||||
greenlistUrl?: string;
|
|
||||||
autoPull?: boolean;
|
|
||||||
} & Partial<IModelGridConfig['models']>;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
logger.dim(`Configuration loaded from ${PATHS.CONFIG_FILE}`);
|
|
||||||
} catch (error) {
|
|
||||||
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
||||||
throw new Error(`Configuration file not found: ${PATHS.CONFIG_FILE}`);
|
|
||||||
}
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -107,8 +94,7 @@ export class ModelGrid {
|
|||||||
throw new Error('No configuration to save');
|
throw new Error('No configuration to save');
|
||||||
}
|
}
|
||||||
|
|
||||||
await fs.mkdir(PATHS.CONFIG_DIR, { recursive: true });
|
await this.configManager.saveConfig(this.config);
|
||||||
await fs.writeFile(PATHS.CONFIG_FILE, JSON.stringify(this.config, null, 2));
|
|
||||||
logger.dim(`Configuration saved to ${PATHS.CONFIG_FILE}`);
|
logger.dim(`Configuration saved to ${PATHS.CONFIG_FILE}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,62 +280,6 @@ export class ModelGrid {
|
|||||||
logger.success('ModelGrid initialized');
|
logger.success('ModelGrid initialized');
|
||||||
}
|
}
|
||||||
|
|
||||||
private normalizeConfig(
|
|
||||||
config: Partial<IModelGridConfig>,
|
|
||||||
): IModelGridConfig {
|
|
||||||
const filteredContainers = (config.containers || []).filter(
|
|
||||||
(container) => (container as { type?: string }).type !== 'ollama',
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
version: config.version || VERSION,
|
|
||||||
api: {
|
|
||||||
port: config.api?.port || 8080,
|
|
||||||
host: config.api?.host || '0.0.0.0',
|
|
||||||
apiKeys: config.api?.apiKeys || [],
|
|
||||||
rateLimit: config.api?.rateLimit,
|
|
||||||
cors: config.api?.cors ?? true,
|
|
||||||
corsOrigins: config.api?.corsOrigins || ['*'],
|
|
||||||
},
|
|
||||||
ui: {
|
|
||||||
enabled: config.ui?.enabled ?? true,
|
|
||||||
port: config.ui?.port || 8081,
|
|
||||||
host: config.ui?.host || '0.0.0.0',
|
|
||||||
assetSource: config.ui?.assetSource === 'disk' ? 'disk' : 'bundle',
|
|
||||||
},
|
|
||||||
docker: {
|
|
||||||
networkName: config.docker?.networkName || 'modelgrid',
|
|
||||||
runtime: config.docker?.runtime || 'docker',
|
|
||||||
socketPath: config.docker?.socketPath,
|
|
||||||
},
|
|
||||||
gpus: {
|
|
||||||
autoDetect: config.gpus?.autoDetect ?? true,
|
|
||||||
assignments: config.gpus?.assignments || {},
|
|
||||||
},
|
|
||||||
containers: filteredContainers,
|
|
||||||
models: {
|
|
||||||
registryUrl: config.models?.registryUrl ||
|
|
||||||
'https://list.modelgrid.com/catalog/models.json',
|
|
||||||
autoDeploy: config.models?.autoDeploy ?? true,
|
|
||||||
defaultEngine: 'vllm',
|
|
||||||
autoLoad: config.models?.autoLoad || [],
|
|
||||||
},
|
|
||||||
cluster: {
|
|
||||||
enabled: config.cluster?.enabled ?? false,
|
|
||||||
nodeName: config.cluster?.nodeName || 'modelgrid-local',
|
|
||||||
role: config.cluster?.role || 'standalone',
|
|
||||||
bindHost: config.cluster?.bindHost || '0.0.0.0',
|
|
||||||
gossipPort: config.cluster?.gossipPort || 7946,
|
|
||||||
sharedSecret: config.cluster?.sharedSecret,
|
|
||||||
advertiseUrl: config.cluster?.advertiseUrl,
|
|
||||||
controlPlaneUrl: config.cluster?.controlPlaneUrl,
|
|
||||||
heartbeatIntervalMs: config.cluster?.heartbeatIntervalMs || 5000,
|
|
||||||
seedNodes: config.cluster?.seedNodes || [],
|
|
||||||
},
|
|
||||||
checkInterval: config.checkInterval || 30000,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shutdown the ModelGrid system
|
* Shutdown the ModelGrid system
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user