UNPKG

docker-pilot

Version:

A powerful, scalable Docker CLI library for managing containerized applications of any size

139 lines (138 loc) 6.57 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ScaleCommand = void 0; const BaseCommand_1 = require("./BaseCommand"); const child_process_1 = require("child_process"); const util_1 = require("util"); const execAsync = (0, util_1.promisify)(child_process_1.exec); class ScaleCommand extends BaseCommand_1.BaseCommand { constructor(context) { super('scale', 'Set number of containers to run for a service', 'docker-pilot scale <service>=<replicas> [service2=replicas2...] [options]', context); } async execute(args, _options) { const { args: parsedArgs, options: parsedOptions } = this.parseOptions(args); try { const startTime = Date.now(); if (parsedArgs.length === 0) { return this.createErrorResult(this.i18n.t('cmd.args_required', { type: 'service=replicas pair' })); } if (!(await this.checkDockerAvailable())) { return this.createErrorResult(this.i18n.t('cmd.docker_not_available')); } // Parse service=replicas pairs const scaleTargets = []; for (const arg of parsedArgs) { const [service, replicasStr] = arg.split('='); if (!service || !replicasStr) { return this.createErrorResult(this.i18n.t('cmd.invalid_format', { format: arg }) + '. ' + this.i18n.t('cmd.scale.format_help')); } const replicas = parseInt(replicasStr, 10); if (isNaN(replicas) || replicas < 0) { return this.createErrorResult(this.i18n.t('cmd.scale.invalid_replicas', { replicas: replicasStr })); } scaleTargets.push({ service, replicas }); } this.logger.loading(this.i18n.t('cmd.scaling')); // Debug: Log the context compose file // Build Docker command const composeFile = this.context.composeFile; const scaleArgs = ['compose']; // Add compose file if available (always should be from context) if (composeFile) { scaleArgs.push('-f', composeFile); } else { this.logger.warn('ScaleCommand: No compose file in context, command may fail'); } scaleArgs.push('up', '--detach', '--scale'); // Add scale targets for (const { service, replicas } of scaleTargets) { scaleArgs.push(`${service}=${replicas}`); } // Add no-recreate flag to avoid recreating existing containers if (!parsedOptions['recreate']) { scaleArgs.push('--no-recreate'); } // Add timeout if specified if (parsedOptions['timeout']) { scaleArgs.push('--timeout', parsedOptions['timeout']); } const command = 'docker ' + scaleArgs.join(' '); this.logger.debug(`Executing: ${command}`); // Execute the real Docker command const result = await this.execDockerCommand(command); // Display scaling results this.showScalingResults(scaleTargets, result.stdout); const executionTime = Date.now() - startTime; // Show current status this.showScalingResults(scaleTargets); const plural = scaleTargets.length === 1 ? '' : 's'; this.logger.success(this.i18n.t('cmd.scaled_success', { count: scaleTargets.length, plural })); return this.createSuccessResult(this.i18n.t('cmd.scaled_success', { count: scaleTargets.length, plural }), executionTime); } catch (error) { const errorMessage = error instanceof Error ? error.message : 'Unknown error'; this.logger.error(this.i18n.t('cmd.scale.failed', { error: errorMessage })); return this.createErrorResult(errorMessage); } } async execDockerCommand(command) { try { const result = await execAsync(command, { cwd: this.context.workingDirectory, maxBuffer: 1024 * 1024 * 5 // 5MB buffer }); return result; } catch (error) { // Some docker commands return non-zero exit codes but still have useful output if (error.stdout) { return { stdout: error.stdout, stderr: error.stderr || '' }; } throw error; } } showScalingResults(scaleTargets, output) { if (output && output.trim() !== '') { this.logger.newLine(); this.logger.info('📋 Scaling details:'); this.logger.separator('-', 30); // Display the output const lines = output.split('\n').filter(line => line.trim() !== ''); lines.forEach(line => { if (line.includes('ERROR') || line.includes('error')) { this.logger.error(` ${line}`); } else if (line.includes('WARN') || line.includes('warn')) { this.logger.warn(` ${line}`); } else if (line.includes('Creating') || line.includes('Starting') || line.includes('Stopping')) { this.logger.success(` ${line}`); } else { this.logger.info(` ${line}`); } }); this.logger.newLine(); } this.logger.info('📊 Current scaling status:'); for (const { service, replicas } of scaleTargets) { const status = replicas === 0 ? 'stopped' : 'running'; const color = replicas === 0 ? '🔴' : '🟢'; this.logger.info(` ${color} ${service}: ${replicas} replica${replicas === 1 ? '' : 's'} (${status})`); } } showExamples() { this.logger.info(` Examples: docker-pilot scale web=3 # Scale web service to 3 replicas docker-pilot scale web=3 worker=2 # Scale multiple services docker-pilot scale web=0 # Stop all containers for web service docker-pilot scale web=1 --recreate # Scale and recreate containers docker-pilot scale api=5 --timeout 30 # Scale with custom timeout Scale Patterns: service=0 # Stop all containers for service service=1 # Run single instance (default) service=N # Run N instances (horizontal scaling) `); } } exports.ScaleCommand = ScaleCommand; //# sourceMappingURL=ScaleCommand.js.map