227 lines
5.6 KiB
TypeScript
227 lines
5.6 KiB
TypeScript
import * as plugins from './mod.plugins.js';
|
|
import * as helpers from './helpers.js';
|
|
import { logger } from '../gitzone.logging.js';
|
|
|
|
export type ContainerStatus = 'running' | 'stopped' | 'not_exists';
|
|
|
|
export interface IDockerRunOptions {
|
|
name: string;
|
|
image: string;
|
|
ports?: { [key: string]: string };
|
|
volumes?: { [key: string]: string };
|
|
environment?: { [key: string]: string };
|
|
restart?: string;
|
|
command?: string;
|
|
}
|
|
|
|
export class DockerContainer {
|
|
private smartshell: plugins.smartshell.Smartshell;
|
|
|
|
constructor() {
|
|
this.smartshell = new plugins.smartshell.Smartshell({
|
|
executor: 'bash',
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Check if Docker is installed and available
|
|
*/
|
|
public async checkDocker(): Promise<boolean> {
|
|
try {
|
|
const result = await this.smartshell.exec('docker --version');
|
|
return result.exitCode === 0;
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get container status
|
|
*/
|
|
public async getStatus(containerName: string): Promise<ContainerStatus> {
|
|
try {
|
|
// Check if running
|
|
const runningResult = await this.smartshell.exec(
|
|
`docker ps --format '{{.Names}}' | grep -q "^${containerName}$"`
|
|
);
|
|
|
|
if (runningResult.exitCode === 0) {
|
|
return 'running';
|
|
}
|
|
|
|
// Check if exists but stopped
|
|
const existsResult = await this.smartshell.exec(
|
|
`docker ps -a --format '{{.Names}}' | grep -q "^${containerName}$"`
|
|
);
|
|
|
|
if (existsResult.exitCode === 0) {
|
|
return 'stopped';
|
|
}
|
|
|
|
return 'not_exists';
|
|
} catch (error) {
|
|
return 'not_exists';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Start a container
|
|
*/
|
|
public async start(containerName: string): Promise<boolean> {
|
|
try {
|
|
const result = await this.smartshell.exec(`docker start ${containerName}`);
|
|
return result.exitCode === 0;
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stop a container
|
|
*/
|
|
public async stop(containerName: string): Promise<boolean> {
|
|
try {
|
|
const result = await this.smartshell.exec(`docker stop ${containerName}`);
|
|
return result.exitCode === 0;
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove a container
|
|
*/
|
|
public async remove(containerName: string, force: boolean = false): Promise<boolean> {
|
|
try {
|
|
const forceFlag = force ? '-f' : '';
|
|
const result = await this.smartshell.exec(`docker rm ${forceFlag} ${containerName}`);
|
|
return result.exitCode === 0;
|
|
} catch (error) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Run a new container
|
|
*/
|
|
public async run(options: IDockerRunOptions): Promise<boolean> {
|
|
let command = 'docker run -d';
|
|
|
|
// Add name
|
|
command += ` --name ${options.name}`;
|
|
|
|
// Add ports
|
|
if (options.ports) {
|
|
for (const [hostPort, containerPort] of Object.entries(options.ports)) {
|
|
command += ` -p ${hostPort}:${containerPort}`;
|
|
}
|
|
}
|
|
|
|
// Add volumes
|
|
if (options.volumes) {
|
|
for (const [hostPath, containerPath] of Object.entries(options.volumes)) {
|
|
command += ` -v "${hostPath}:${containerPath}"`;
|
|
}
|
|
}
|
|
|
|
// Add environment variables
|
|
if (options.environment) {
|
|
for (const [key, value] of Object.entries(options.environment)) {
|
|
command += ` -e ${key}="${value}"`;
|
|
}
|
|
}
|
|
|
|
// Add restart policy
|
|
if (options.restart) {
|
|
command += ` --restart ${options.restart}`;
|
|
}
|
|
|
|
// Add image
|
|
command += ` ${options.image}`;
|
|
|
|
// Add command if provided
|
|
if (options.command) {
|
|
command += ` ${options.command}`;
|
|
}
|
|
|
|
try {
|
|
const result = await this.smartshell.exec(command);
|
|
return result.exitCode === 0;
|
|
} catch (error) {
|
|
logger.log('error', `Failed to run container: ${error.message}`);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Execute a command in a running container
|
|
*/
|
|
public async exec(containerName: string, command: string): Promise<string> {
|
|
try {
|
|
const result = await this.smartshell.exec(`docker exec ${containerName} ${command}`);
|
|
if (result.exitCode === 0) {
|
|
return result.stdout;
|
|
}
|
|
return '';
|
|
} catch (error) {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get container logs
|
|
*/
|
|
public async logs(containerName: string, lines?: number): Promise<string> {
|
|
try {
|
|
const tailFlag = lines ? `--tail ${lines}` : '';
|
|
const result = await this.smartshell.exec(`docker logs ${tailFlag} ${containerName}`);
|
|
return result.stdout;
|
|
} catch (error) {
|
|
return `Error getting logs: ${error.message}`;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if a container exists
|
|
*/
|
|
public async exists(containerName: string): Promise<boolean> {
|
|
const status = await this.getStatus(containerName);
|
|
return status !== 'not_exists';
|
|
}
|
|
|
|
/**
|
|
* Check if a container is running
|
|
*/
|
|
public async isRunning(containerName: string): Promise<boolean> {
|
|
const status = await this.getStatus(containerName);
|
|
return status === 'running';
|
|
}
|
|
|
|
/**
|
|
* Wait for a container to be ready
|
|
*/
|
|
public async waitForReady(containerName: string, maxAttempts: number = 30): Promise<boolean> {
|
|
for (let i = 0; i < maxAttempts; i++) {
|
|
if (await this.isRunning(containerName)) {
|
|
return true;
|
|
}
|
|
await plugins.smartdelay.delayFor(1000);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Get container information
|
|
*/
|
|
public async inspect(containerName: string): Promise<any> {
|
|
try {
|
|
const result = await this.smartshell.exec(`docker inspect ${containerName}`);
|
|
if (result.exitCode === 0) {
|
|
return JSON.parse(result.stdout);
|
|
}
|
|
return null;
|
|
} catch (error) {
|
|
return null;
|
|
}
|
|
}
|
|
} |