diff --git a/test/modelgrid-config_test.ts b/test/modelgrid-config_test.ts index 75eecca..c727137 100644 --- a/test/modelgrid-config_test.ts +++ b/test/modelgrid-config_test.ts @@ -1,6 +1,7 @@ import { assertEquals } from 'jsr:@std/assert@^1.0.0'; import { ConfigManager } from '../ts/config/config-manager.ts'; import type { IModelGridConfig } from '../ts/interfaces/config.ts'; +import { logger } from '../ts/logger.ts'; Deno.test('ConfigManager normalizes current config defaults', () => { const configManager = new ConfigManager(); @@ -46,3 +47,73 @@ Deno.test('ConfigManager normalizes current config defaults', () => { assertEquals(normalized.ui.port, 8081); assertEquals(normalized.ui.assetSource, 'bundle'); }); + +Deno.test('ConfigManager warns when config contains ignored keys', () => { + const configManager = new ConfigManager(); + const warnings: string[] = []; + const originalWarn = logger.warn; + logger.warn = (message: string) => { + warnings.push(message); + }; + + try { + configManager.normalizeConfig({ + version: '1.0.0', + api: { + port: 8080, + host: '127.0.0.1', + apiKeys: [], + }, + docker: { + networkName: 'modelgrid', + runtime: 'docker', + }, + gpus: { + autoDetect: true, + assignments: {}, + }, + containers: [ + { id: 'legacy', type: 'ollama' } as never, + ], + models: { + registryUrl: 'https://example.com/catalog.json', + autoDeploy: true, + defaultEngine: 'vllm', + autoLoad: [], + greenlistUrl: 'https://legacy.example.com/catalog.json', + autoPull: true, + defaultContainer: 'legacy-container', + } as IModelGridConfig['models'] & { + greenlistUrl: string; + autoPull: boolean; + defaultContainer: string; + }, + cluster: { + enabled: false, + nodeName: 'modelgrid-local', + role: 'standalone', + bindHost: '0.0.0.0', + gossipPort: 7946, + heartbeatIntervalMs: 5000, + seedNodes: [], + }, + checkInterval: 30000, + legacySection: true, + } as Partial & { + legacySection: boolean; + models: IModelGridConfig['models'] & { + greenlistUrl: string; + autoPull: boolean; + defaultContainer: string; + }; + }); + } finally { + logger.warn = originalWarn; + } + + assertEquals(warnings.includes('Ignoring unknown config key: legacySection'), true); + assertEquals(warnings.includes('Ignoring removed config key: models.greenlistUrl'), true); + assertEquals(warnings.includes('Ignoring removed config key: models.autoPull'), true); + assertEquals(warnings.includes('Ignoring removed config key: models.defaultContainer'), true); + assertEquals(warnings.includes('Ignoring unsupported container type: ollama'), true); +}); diff --git a/ts/config/config-manager.ts b/ts/config/config-manager.ts index 07facf2..a1c004f 100644 --- a/ts/config/config-manager.ts +++ b/ts/config/config-manager.ts @@ -1,6 +1,7 @@ import * as fs from 'node:fs/promises'; import { PATHS, VERSION } from '../constants.ts'; import type { IModelGridConfig } from '../interfaces/config.ts'; +import { logger } from '../logger.ts'; export class ConfigManager { public async loadConfig(): Promise { @@ -21,6 +22,8 @@ export class ConfigManager { } public normalizeConfig(config: Partial): IModelGridConfig { + this.logIgnoredConfigKeys(config); + const filteredContainers = (config.containers || []).filter( (container) => (container as { type?: string }).type !== 'ollama', ); @@ -72,4 +75,38 @@ export class ConfigManager { checkInterval: config.checkInterval || 30000, }; } + + private logIgnoredConfigKeys(config: Partial): void { + const unknownTopLevelKeys = Object.keys(config).filter((key) => + !['version', 'api', 'ui', 'docker', 'gpus', 'containers', 'models', 'cluster', 'checkInterval'] + .includes(key) + ); + + for (const key of unknownTopLevelKeys) { + logger.warn(`Ignoring unknown config key: ${key}`); + } + + const legacyModelConfig = config.models as { + greenlistUrl?: string; + autoPull?: boolean; + defaultContainer?: string; + } | undefined; + + if (legacyModelConfig?.greenlistUrl) { + logger.warn('Ignoring removed config key: models.greenlistUrl'); + } + if (legacyModelConfig?.autoPull !== undefined) { + logger.warn('Ignoring removed config key: models.autoPull'); + } + if (legacyModelConfig?.defaultContainer) { + logger.warn('Ignoring removed config key: models.defaultContainer'); + } + + for (const container of config.containers || []) { + const containerType = (container as { type?: string }).type; + if (containerType === 'ollama') { + logger.warn('Ignoring unsupported container type: ollama'); + } + } + } }