- Implemented gitzone services command for managing MongoDB and MinIO containers - Added smart port assignment (20000-30000 range) to avoid conflicts - Project-specific container names for complete isolation - Data persistence in .nogit/ directories - MongoDB Compass connection string generation with network IP detection - Auto-configuration via .nogit/env.json with secure defaults - Commands: start, stop, restart, status, config, compass, logs, remove, clean - Interactive confirmations for destructive operations - Comprehensive documentation and Task Venture Capital GmbH legal update
412 lines
14 KiB
TypeScript
412 lines
14 KiB
TypeScript
import * as plugins from './mod.plugins.js';
|
|
import * as helpers from './helpers.js';
|
|
import { ServiceConfiguration } from './classes.serviceconfiguration.js';
|
|
import { DockerContainer } from './classes.dockercontainer.js';
|
|
|
|
export class ServiceManager {
|
|
private config: ServiceConfiguration;
|
|
private docker: DockerContainer;
|
|
|
|
constructor() {
|
|
this.config = new ServiceConfiguration();
|
|
this.docker = new DockerContainer();
|
|
}
|
|
|
|
/**
|
|
* Initialize the service manager
|
|
*/
|
|
public async init(): Promise<void> {
|
|
// Check Docker availability
|
|
if (!(await this.docker.checkDocker())) {
|
|
helpers.printMessage('Error: Docker is not installed. Please install Docker first.', 'red');
|
|
process.exit(1);
|
|
}
|
|
|
|
// Load or create configuration
|
|
await this.config.loadOrCreate();
|
|
helpers.printMessage(`📋 Project: ${this.config.getConfig().PROJECT_NAME}`, 'magenta');
|
|
}
|
|
|
|
/**
|
|
* Start MongoDB service
|
|
*/
|
|
public async startMongoDB(): Promise<void> {
|
|
helpers.printMessage('📦 MongoDB:', 'yellow');
|
|
|
|
const config = this.config.getConfig();
|
|
const containers = this.config.getContainerNames();
|
|
const directories = this.config.getDataDirectories();
|
|
|
|
// Ensure data directory exists
|
|
await plugins.smartfile.fs.ensureDir(directories.mongo);
|
|
|
|
const status = await this.docker.getStatus(containers.mongo);
|
|
|
|
switch (status) {
|
|
case 'running':
|
|
helpers.printMessage(' Already running ✓', 'green');
|
|
break;
|
|
|
|
case 'stopped':
|
|
if (await this.docker.start(containers.mongo)) {
|
|
helpers.printMessage(' Started ✓', 'green');
|
|
} else {
|
|
helpers.printMessage(' Failed to start', 'red');
|
|
}
|
|
break;
|
|
|
|
case 'not_exists':
|
|
helpers.printMessage(' Creating container...', 'yellow');
|
|
|
|
const success = await this.docker.run({
|
|
name: containers.mongo,
|
|
image: 'mongo:7.0',
|
|
ports: {
|
|
[`0.0.0.0:${config.MONGODB_PORT}`]: '27017'
|
|
},
|
|
volumes: {
|
|
[directories.mongo]: '/data/db'
|
|
},
|
|
environment: {
|
|
MONGO_INITDB_ROOT_USERNAME: config.MONGODB_USER,
|
|
MONGO_INITDB_ROOT_PASSWORD: config.MONGODB_PASS,
|
|
MONGO_INITDB_DATABASE: config.MONGODB_NAME
|
|
},
|
|
restart: 'unless-stopped'
|
|
});
|
|
|
|
if (success) {
|
|
helpers.printMessage(' Created and started ✓', 'green');
|
|
} else {
|
|
helpers.printMessage(' Failed to create container', 'red');
|
|
}
|
|
break;
|
|
}
|
|
|
|
helpers.printMessage(` Container: ${containers.mongo}`, 'cyan');
|
|
helpers.printMessage(` Port: ${config.MONGODB_PORT}`, 'cyan');
|
|
helpers.printMessage(` Connection: ${this.config.getMongoConnectionString()}`, 'blue');
|
|
}
|
|
|
|
/**
|
|
* Start MinIO service
|
|
*/
|
|
public async startMinIO(): Promise<void> {
|
|
helpers.printMessage('📦 S3/MinIO:', 'yellow');
|
|
|
|
const config = this.config.getConfig();
|
|
const containers = this.config.getContainerNames();
|
|
const directories = this.config.getDataDirectories();
|
|
|
|
// Ensure data directory exists
|
|
await plugins.smartfile.fs.ensureDir(directories.minio);
|
|
|
|
const status = await this.docker.getStatus(containers.minio);
|
|
|
|
switch (status) {
|
|
case 'running':
|
|
helpers.printMessage(' Already running ✓', 'green');
|
|
break;
|
|
|
|
case 'stopped':
|
|
if (await this.docker.start(containers.minio)) {
|
|
helpers.printMessage(' Started ✓', 'green');
|
|
} else {
|
|
helpers.printMessage(' Failed to start', 'red');
|
|
}
|
|
break;
|
|
|
|
case 'not_exists':
|
|
helpers.printMessage(' Creating container...', 'yellow');
|
|
|
|
const success = await this.docker.run({
|
|
name: containers.minio,
|
|
image: 'minio/minio',
|
|
ports: {
|
|
[config.S3_PORT]: '9000',
|
|
[config.S3_CONSOLE_PORT]: '9001'
|
|
},
|
|
volumes: {
|
|
[directories.minio]: '/data'
|
|
},
|
|
environment: {
|
|
MINIO_ROOT_USER: config.S3_USER,
|
|
MINIO_ROOT_PASSWORD: config.S3_PASS
|
|
},
|
|
restart: 'unless-stopped',
|
|
command: 'server /data --console-address ":9001"'
|
|
});
|
|
|
|
if (success) {
|
|
helpers.printMessage(' Created and started ✓', 'green');
|
|
|
|
// Wait for MinIO to be ready
|
|
await plugins.smartdelay.delayFor(3000);
|
|
|
|
// Create default bucket
|
|
await this.docker.exec(
|
|
containers.minio,
|
|
`mc alias set local http://localhost:9000 ${config.S3_USER} ${config.S3_PASS}`
|
|
);
|
|
|
|
await this.docker.exec(
|
|
containers.minio,
|
|
`mc mb local/${config.S3_BUCKET}`
|
|
);
|
|
|
|
helpers.printMessage(` Bucket '${config.S3_BUCKET}' created ✓`, 'green');
|
|
} else {
|
|
helpers.printMessage(' Failed to create container', 'red');
|
|
}
|
|
break;
|
|
}
|
|
|
|
helpers.printMessage(` Container: ${containers.minio}`, 'cyan');
|
|
helpers.printMessage(` Port: ${config.S3_PORT}`, 'cyan');
|
|
helpers.printMessage(` Bucket: ${config.S3_BUCKET}`, 'cyan');
|
|
helpers.printMessage(` API: http://${config.S3_HOST}:${config.S3_PORT}`, 'blue');
|
|
helpers.printMessage(` Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT} (login: ${config.S3_USER}/***)`, 'blue');
|
|
}
|
|
|
|
/**
|
|
* Stop MongoDB service
|
|
*/
|
|
public async stopMongoDB(): Promise<void> {
|
|
helpers.printMessage('📦 MongoDB:', 'yellow');
|
|
|
|
const containers = this.config.getContainerNames();
|
|
const status = await this.docker.getStatus(containers.mongo);
|
|
|
|
if (status === 'running') {
|
|
if (await this.docker.stop(containers.mongo)) {
|
|
helpers.printMessage(' Stopped ✓', 'green');
|
|
} else {
|
|
helpers.printMessage(' Failed to stop', 'red');
|
|
}
|
|
} else {
|
|
helpers.printMessage(' Not running', 'yellow');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stop MinIO service
|
|
*/
|
|
public async stopMinIO(): Promise<void> {
|
|
helpers.printMessage('📦 S3/MinIO:', 'yellow');
|
|
|
|
const containers = this.config.getContainerNames();
|
|
const status = await this.docker.getStatus(containers.minio);
|
|
|
|
if (status === 'running') {
|
|
if (await this.docker.stop(containers.minio)) {
|
|
helpers.printMessage(' Stopped ✓', 'green');
|
|
} else {
|
|
helpers.printMessage(' Failed to stop', 'red');
|
|
}
|
|
} else {
|
|
helpers.printMessage(' Not running', 'yellow');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show service status
|
|
*/
|
|
public async showStatus(): Promise<void> {
|
|
helpers.printHeader('Service Status');
|
|
|
|
const config = this.config.getConfig();
|
|
const containers = this.config.getContainerNames();
|
|
|
|
helpers.printMessage(`Project: ${config.PROJECT_NAME}`, 'magenta');
|
|
console.log();
|
|
|
|
// MongoDB status
|
|
const mongoStatus = await this.docker.getStatus(containers.mongo);
|
|
switch (mongoStatus) {
|
|
case 'running':
|
|
helpers.printMessage('📦 MongoDB: 🟢 Running', 'green');
|
|
helpers.printMessage(` ├─ Container: ${containers.mongo}`, 'cyan');
|
|
helpers.printMessage(` └─ ${this.config.getMongoConnectionString()}`, 'cyan');
|
|
break;
|
|
case 'stopped':
|
|
helpers.printMessage('📦 MongoDB: 🟡 Stopped', 'yellow');
|
|
helpers.printMessage(` └─ Container: ${containers.mongo}`, 'cyan');
|
|
break;
|
|
case 'not_exists':
|
|
helpers.printMessage('📦 MongoDB: ⚪ Not installed', 'magenta');
|
|
break;
|
|
}
|
|
|
|
// MinIO status
|
|
const minioStatus = await this.docker.getStatus(containers.minio);
|
|
switch (minioStatus) {
|
|
case 'running':
|
|
helpers.printMessage('📦 S3/MinIO: 🟢 Running', 'green');
|
|
helpers.printMessage(` ├─ Container: ${containers.minio}`, 'cyan');
|
|
helpers.printMessage(` ├─ API: http://${config.S3_HOST}:${config.S3_PORT}`, 'cyan');
|
|
helpers.printMessage(` ├─ Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`, 'cyan');
|
|
helpers.printMessage(` └─ Bucket: ${config.S3_BUCKET}`, 'cyan');
|
|
break;
|
|
case 'stopped':
|
|
helpers.printMessage('📦 S3/MinIO: 🟡 Stopped', 'yellow');
|
|
helpers.printMessage(` └─ Container: ${containers.minio}`, 'cyan');
|
|
break;
|
|
case 'not_exists':
|
|
helpers.printMessage('📦 S3/MinIO: ⚪ Not installed', 'magenta');
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show configuration
|
|
*/
|
|
public async showConfig(): Promise<void> {
|
|
helpers.printHeader('Current Configuration');
|
|
|
|
const config = this.config.getConfig();
|
|
|
|
helpers.printMessage(`Project: ${config.PROJECT_NAME}`, 'magenta');
|
|
console.log();
|
|
|
|
helpers.printMessage('MongoDB:', 'yellow');
|
|
helpers.printMessage(` Host: ${config.MONGODB_HOST}:${config.MONGODB_PORT}`, undefined);
|
|
helpers.printMessage(` Database: ${config.MONGODB_NAME}`, undefined);
|
|
helpers.printMessage(` User: ${config.MONGODB_USER}`, undefined);
|
|
helpers.printMessage(' Password: ***', undefined);
|
|
helpers.printMessage(` Container: ${this.config.getContainerNames().mongo}`, undefined);
|
|
helpers.printMessage(` Data: ${this.config.getDataDirectories().mongo}`, undefined);
|
|
helpers.printMessage(` Connection: ${this.config.getMongoConnectionString()}`, 'blue');
|
|
|
|
console.log();
|
|
helpers.printMessage('S3/MinIO:', 'yellow');
|
|
helpers.printMessage(` Host: ${config.S3_HOST}`, undefined);
|
|
helpers.printMessage(` API Port: ${config.S3_PORT}`, undefined);
|
|
helpers.printMessage(` Console Port: ${config.S3_CONSOLE_PORT}`, undefined);
|
|
helpers.printMessage(` User: ${config.S3_USER}`, undefined);
|
|
helpers.printMessage(' Password: ***', undefined);
|
|
helpers.printMessage(` Bucket: ${config.S3_BUCKET}`, undefined);
|
|
helpers.printMessage(` Container: ${this.config.getContainerNames().minio}`, undefined);
|
|
helpers.printMessage(` Data: ${this.config.getDataDirectories().minio}`, undefined);
|
|
helpers.printMessage(` API URL: http://${config.S3_HOST}:${config.S3_PORT}`, 'blue');
|
|
helpers.printMessage(` Console URL: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`, 'blue');
|
|
}
|
|
|
|
/**
|
|
* Show MongoDB Compass connection string
|
|
*/
|
|
public async showCompassConnection(): Promise<void> {
|
|
helpers.printHeader('MongoDB Compass Connection');
|
|
|
|
const config = this.config.getConfig();
|
|
const networkIp = await helpers.getLocalNetworkIp();
|
|
|
|
const connectionString = `mongodb://${config.MONGODB_USER}:${config.MONGODB_PASS}@${networkIp}:${config.MONGODB_PORT}/${config.MONGODB_NAME}?authSource=admin`;
|
|
|
|
helpers.printMessage('MongoDB Compass is a GUI tool for MongoDB. To connect:', 'cyan');
|
|
console.log();
|
|
helpers.printMessage('1. Download MongoDB Compass from:', undefined);
|
|
helpers.printMessage(' https://www.mongodb.com/products/compass', 'blue');
|
|
console.log();
|
|
helpers.printMessage('2. Open Compass and paste this connection string:', undefined);
|
|
helpers.printMessage(` ${connectionString}`, 'green');
|
|
console.log();
|
|
helpers.printMessage('Connection Details:', 'yellow');
|
|
helpers.printMessage(` Network IP: ${networkIp}`, undefined);
|
|
helpers.printMessage(` Port: ${config.MONGODB_PORT}`, undefined);
|
|
helpers.printMessage(` Database: ${config.MONGODB_NAME}`, undefined);
|
|
helpers.printMessage(` Username: ${config.MONGODB_USER}`, undefined);
|
|
helpers.printMessage(` Auth Source: admin`, undefined);
|
|
}
|
|
|
|
/**
|
|
* Show logs for a service
|
|
*/
|
|
public async showLogs(service: string, lines: number = 20): Promise<void> {
|
|
const containers = this.config.getContainerNames();
|
|
|
|
switch (service) {
|
|
case 'mongo':
|
|
case 'mongodb':
|
|
if (await this.docker.isRunning(containers.mongo)) {
|
|
helpers.printHeader(`MongoDB Logs (last ${lines} lines)`);
|
|
const logs = await this.docker.logs(containers.mongo, lines);
|
|
console.log(logs);
|
|
} else {
|
|
helpers.printMessage('MongoDB container is not running', 'yellow');
|
|
}
|
|
break;
|
|
|
|
case 'minio':
|
|
case 's3':
|
|
if (await this.docker.isRunning(containers.minio)) {
|
|
helpers.printHeader(`S3/MinIO Logs (last ${lines} lines)`);
|
|
const logs = await this.docker.logs(containers.minio, lines);
|
|
console.log(logs);
|
|
} else {
|
|
helpers.printMessage('S3/MinIO container is not running', 'yellow');
|
|
}
|
|
break;
|
|
|
|
case 'all':
|
|
case '':
|
|
await this.showLogs('mongo', lines);
|
|
console.log();
|
|
await this.showLogs('minio', lines);
|
|
break;
|
|
|
|
default:
|
|
helpers.printMessage('Usage: gitzone services logs [mongo|s3|all] [lines]', 'yellow');
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove containers
|
|
*/
|
|
public async removeContainers(): Promise<void> {
|
|
const containers = this.config.getContainerNames();
|
|
let removed = false;
|
|
|
|
if (await this.docker.exists(containers.mongo)) {
|
|
if (await this.docker.remove(containers.mongo, true)) {
|
|
helpers.printMessage(' MongoDB container removed ✓', 'green');
|
|
removed = true;
|
|
}
|
|
}
|
|
|
|
if (await this.docker.exists(containers.minio)) {
|
|
if (await this.docker.remove(containers.minio, true)) {
|
|
helpers.printMessage(' S3/MinIO container removed ✓', 'green');
|
|
removed = true;
|
|
}
|
|
}
|
|
|
|
if (!removed) {
|
|
helpers.printMessage(' No containers to remove', 'yellow');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clean data directories
|
|
*/
|
|
public async cleanData(): Promise<void> {
|
|
const directories = this.config.getDataDirectories();
|
|
let cleaned = false;
|
|
|
|
if (await plugins.smartfile.fs.fileExists(directories.mongo)) {
|
|
await plugins.smartfile.fs.remove(directories.mongo);
|
|
helpers.printMessage(' MongoDB data removed ✓', 'green');
|
|
cleaned = true;
|
|
}
|
|
|
|
if (await plugins.smartfile.fs.fileExists(directories.minio)) {
|
|
await plugins.smartfile.fs.remove(directories.minio);
|
|
helpers.printMessage(' S3/MinIO data removed ✓', 'green');
|
|
cleaned = true;
|
|
}
|
|
|
|
if (!cleaned) {
|
|
helpers.printMessage(' No data to clean', 'yellow');
|
|
}
|
|
}
|
|
} |