feat(docker): add Docker context detection, rootless support, and context-aware buildx registry handling
This commit is contained in:
69
ts/classes.dockercontext.ts
Normal file
69
ts/classes.dockercontext.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import * as plugins from './tsdocker.plugins.js';
|
||||
import { logger } from './tsdocker.logging.js';
|
||||
import type { IDockerContextInfo } from './interfaces/index.js';
|
||||
|
||||
const smartshellInstance = new plugins.smartshell.Smartshell({ executor: 'bash' });
|
||||
|
||||
export class DockerContext {
|
||||
public contextInfo: IDockerContextInfo | null = null;
|
||||
|
||||
/** Sets DOCKER_CONTEXT env var for explicit context selection. */
|
||||
public setContext(contextName: string): void {
|
||||
process.env.DOCKER_CONTEXT = contextName;
|
||||
logger.log('info', `Docker context explicitly set to: ${contextName}`);
|
||||
}
|
||||
|
||||
/** Detects current Docker context via `docker context inspect` and rootless via `docker info`. */
|
||||
public async detect(): Promise<IDockerContextInfo> {
|
||||
let name = 'default';
|
||||
let endpoint = 'unknown';
|
||||
|
||||
const contextResult = await smartshellInstance.execSilent(
|
||||
`docker context inspect --format '{{json .}}'`
|
||||
);
|
||||
if (contextResult.exitCode === 0 && contextResult.stdout) {
|
||||
try {
|
||||
const parsed = JSON.parse(contextResult.stdout.trim());
|
||||
const data = Array.isArray(parsed) ? parsed[0] : parsed;
|
||||
name = data.Name || 'default';
|
||||
endpoint = data.Endpoints?.docker?.Host || 'unknown';
|
||||
} catch { /* fallback to defaults */ }
|
||||
}
|
||||
|
||||
let isRootless = false;
|
||||
const infoResult = await smartshellInstance.execSilent(
|
||||
`docker info --format '{{json .SecurityOptions}}'`
|
||||
);
|
||||
if (infoResult.exitCode === 0 && infoResult.stdout) {
|
||||
isRootless = infoResult.stdout.includes('name=rootless');
|
||||
}
|
||||
|
||||
this.contextInfo = { name, endpoint, isRootless, dockerHost: process.env.DOCKER_HOST };
|
||||
return this.contextInfo;
|
||||
}
|
||||
|
||||
/** Logs context info prominently. */
|
||||
public logContextInfo(): void {
|
||||
if (!this.contextInfo) return;
|
||||
const { name, endpoint, isRootless, dockerHost } = this.contextInfo;
|
||||
logger.log('info', '=== DOCKER CONTEXT ===');
|
||||
logger.log('info', `Context: ${name}`);
|
||||
logger.log('info', `Endpoint: ${endpoint}`);
|
||||
if (dockerHost) logger.log('info', `DOCKER_HOST: ${dockerHost}`);
|
||||
logger.log('info', `Rootless: ${isRootless ? 'yes' : 'no'}`);
|
||||
}
|
||||
|
||||
/** Emits rootless-specific warnings. */
|
||||
public logRootlessWarnings(): void {
|
||||
if (!this.contextInfo?.isRootless) return;
|
||||
logger.log('warn', '[rootless] network=host in buildx is namespaced by rootlesskit');
|
||||
logger.log('warn', '[rootless] Local registry may have localhost vs 127.0.0.1 resolution quirks');
|
||||
}
|
||||
|
||||
/** Returns context-aware builder name: tsdocker-builder-<context> */
|
||||
public getBuilderName(): string {
|
||||
const contextName = this.contextInfo?.name || 'default';
|
||||
const sanitized = contextName.replace(/[^a-zA-Z0-9_-]/g, '-');
|
||||
return `tsdocker-builder-${sanitized}`;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user