Compare commits

..

6 Commits

Author SHA1 Message Date
cc37f70185 1.18.0
Some checks failed
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-08-16 08:47:39 +00:00
dbc1a1ba18 feat(services): Add Docker port mapping sync and reconfigure workflow for local services 2025-08-16 08:47:39 +00:00
ff57f8a322 1.17.5
Some checks failed
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-08-15 12:17:04 +00:00
968e67330d fix(services): Update S3 credentials naming and add S3_ENDPOINT/S3_USESSL support for improved MinIO integration 2025-08-15 12:17:04 +00:00
935ee20e83 1.17.4
Some checks failed
Default (tags) / security (push) Failing after 1s
Default (tags) / test (push) Failing after 1s
Default (tags) / release (push) Has been skipped
Default (tags) / metadata (push) Has been skipped
2025-08-15 11:05:50 +00:00
c205180991 fix(services): Update S3 credentials naming and add S3_ENDPOINT support for improved MinIO integration 2025-08-15 11:05:50 +00:00
7 changed files with 428 additions and 31 deletions

View File

@@ -1,5 +1,34 @@
# Changelog # Changelog
## 2025-08-16 - 1.18.0 - feat(services)
Add Docker port mapping sync and reconfigure workflow for local services
- Add getPortMappings to DockerContainer to extract port bindings from docker inspect output
- Sync existing container port mappings into .nogit/env.json when loading/creating service configuration
- Validate and automatically update ports only when containers are not present; preserve container ports when containers exist
- Recreate containers automatically if detected container port mappings differ from configuration (MongoDB and MinIO)
- Add reconfigure method and new CLI command to reassign ports and optionally restart services
- Improve status output to show configured ports and port availability information
- Minor helpers and imports updated (DockerContainer injected into ServiceConfiguration)
- Add .claude/settings.local.json (local permissions config) to repository
## 2025-08-15 - 1.17.5 - fix(services)
Update S3 credentials naming and add S3_ENDPOINT/S3_USESSL support for improved MinIO integration
- Replaced S3_USER/S3_PASS with S3_ACCESSKEY/S3_SECRETKEY in ServiceConfiguration
- Added S3_ENDPOINT field with automatic protocol selection based on S3_USESSL
- Introduced S3_USESSL boolean field for SSL/TLS configuration
- Updated ServiceManager logging to display new S3_USESSL configuration
- Added .claude/settings.local.json for local permission settings
## 2025-08-15 - 1.17.4 - fix(services)
Update S3 credentials naming and add S3_ENDPOINT/S3_USESSL support for improved MinIO integration
- Replaced S3_USER/S3_PASS with S3_ACCESSKEY/S3_SECRETKEY in ServiceConfiguration
- Added S3_ENDPOINT field with automatic protocol selection based on S3_USESSL
- Added S3_USESSL boolean field for SSL/TLS configuration support
- Updated ServiceManager to use new credential names in container setup and logging
## 2025-08-15 - 1.17.3 - fix(serviceconfig) ## 2025-08-15 - 1.17.3 - fix(serviceconfig)
Update service configuration to include dynamic MongoDB connection string and add local permissions settings Update service configuration to include dynamic MongoDB connection string and add local permissions settings

View File

@@ -1,7 +1,7 @@
{ {
"name": "@git.zone/cli", "name": "@git.zone/cli",
"private": false, "private": false,
"version": "1.17.3", "version": "1.18.0",
"description": "A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.", "description": "A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.",
"main": "dist_ts/index.ts", "main": "dist_ts/index.ts",
"typings": "dist_ts/index.d.ts", "typings": "dist_ts/index.d.ts",

View File

@@ -3,6 +3,6 @@
*/ */
export const commitinfo = { export const commitinfo = {
name: '@git.zone/cli', name: '@git.zone/cli',
version: '1.17.3', version: '1.18.0',
description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.' description: 'A comprehensive CLI tool for enhancing and managing local development workflows with gitzone utilities, focusing on project setup, version control, code formatting, and template management.'
} }

View File

@@ -215,7 +215,7 @@ export class DockerContainer {
*/ */
public async inspect(containerName: string): Promise<any> { public async inspect(containerName: string): Promise<any> {
try { try {
const result = await this.smartshell.exec(`docker inspect ${containerName}`); const result = await this.smartshell.exec(`docker inspect ${containerName} 2>/dev/null`);
if (result.exitCode === 0) { if (result.exitCode === 0) {
return JSON.parse(result.stdout); return JSON.parse(result.stdout);
} }
@@ -224,4 +224,38 @@ export class DockerContainer {
return null; return null;
} }
} }
/**
* Get port mappings for a container
*/
public async getPortMappings(containerName: string): Promise<{ [key: string]: string } | null> {
try {
// Use docker inspect without format to get full JSON, then extract PortBindings
const result = await this.smartshell.exec(`docker inspect ${containerName} 2>/dev/null`);
if (result.exitCode === 0 && result.stdout) {
const inspectData = JSON.parse(result.stdout);
if (inspectData && inspectData[0] && inspectData[0].HostConfig && inspectData[0].HostConfig.PortBindings) {
const portBindings = inspectData[0].HostConfig.PortBindings;
const mappings: { [key: string]: string } = {};
// Convert Docker's port binding format to simple host:container mapping
for (const [containerPort, hostBindings] of Object.entries(portBindings)) {
if (Array.isArray(hostBindings) && hostBindings.length > 0) {
const hostPort = (hostBindings[0] as any).HostPort;
if (hostPort) {
mappings[containerPort.replace('/tcp', '').replace('/udp', '')] = hostPort;
}
}
}
return mappings;
}
}
return null;
} catch (error) {
// Silently fail - container might not exist
return null;
}
}
} }

View File

@@ -1,6 +1,7 @@
import * as plugins from './mod.plugins.js'; import * as plugins from './mod.plugins.js';
import * as helpers from './helpers.js'; import * as helpers from './helpers.js';
import { logger } from '../gitzone.logging.js'; import { logger } from '../gitzone.logging.js';
import { DockerContainer } from './classes.dockercontainer.js';
export interface IServiceConfig { export interface IServiceConfig {
PROJECT_NAME: string; PROJECT_NAME: string;
@@ -13,17 +14,21 @@ export interface IServiceConfig {
S3_HOST: string; S3_HOST: string;
S3_PORT: string; S3_PORT: string;
S3_CONSOLE_PORT: string; S3_CONSOLE_PORT: string;
S3_USER: string; S3_ACCESSKEY: string;
S3_PASS: string; S3_SECRETKEY: string;
S3_BUCKET: string; S3_BUCKET: string;
S3_ENDPOINT: string;
S3_USESSL: boolean;
} }
export class ServiceConfiguration { export class ServiceConfiguration {
private configPath: string; private configPath: string;
private config: IServiceConfig; private config: IServiceConfig;
private docker: DockerContainer;
constructor() { constructor() {
this.configPath = plugins.path.join(process.cwd(), '.nogit', 'env.json'); this.configPath = plugins.path.join(process.cwd(), '.nogit', 'env.json');
this.docker = new DockerContainer();
} }
/** /**
@@ -39,6 +44,9 @@ export class ServiceConfiguration {
await this.createDefaultConfig(); await this.createDefaultConfig();
} }
// Sync ports from existing Docker containers if they exist
await this.syncPortsFromDocker();
return this.config; return this.config;
} }
@@ -101,6 +109,8 @@ export class ServiceConfiguration {
const mongoHost = 'localhost'; const mongoHost = 'localhost';
const mongoName = projectName; const mongoName = projectName;
const mongoPortStr = mongoPort.toString(); const mongoPortStr = mongoPort.toString();
const s3Host = 'localhost';
const s3PortStr = s3Port.toString();
this.config = { this.config = {
PROJECT_NAME: projectName, PROJECT_NAME: projectName,
@@ -110,12 +120,14 @@ export class ServiceConfiguration {
MONGODB_USER: mongoUser, MONGODB_USER: mongoUser,
MONGODB_PASS: mongoPass, MONGODB_PASS: mongoPass,
MONGODB_URL: `mongodb://${mongoUser}:${mongoPass}@${mongoHost}:${mongoPortStr}/${mongoName}?authSource=admin`, MONGODB_URL: `mongodb://${mongoUser}:${mongoPass}@${mongoHost}:${mongoPortStr}/${mongoName}?authSource=admin`,
S3_HOST: 'localhost', S3_HOST: s3Host,
S3_PORT: s3Port.toString(), S3_PORT: s3PortStr,
S3_CONSOLE_PORT: s3ConsolePort.toString(), S3_CONSOLE_PORT: s3ConsolePort.toString(),
S3_USER: 'defaultadmin', S3_ACCESSKEY: 'defaultadmin',
S3_PASS: 'defaultpass', S3_SECRETKEY: 'defaultpass',
S3_BUCKET: `${projectName}-documents` S3_BUCKET: `${projectName}-documents`,
S3_ENDPOINT: `http://${s3Host}:${s3PortStr}`,
S3_USESSL: false
}; };
await this.saveConfig(); await this.saveConfig();
@@ -206,15 +218,15 @@ export class ServiceConfiguration {
updated = true; updated = true;
} }
if (!this.config.S3_USER) { if (!this.config.S3_ACCESSKEY) {
this.config.S3_USER = 'defaultadmin'; this.config.S3_ACCESSKEY = 'defaultadmin';
fieldsAdded.push('S3_USER'); fieldsAdded.push('S3_ACCESSKEY');
updated = true; updated = true;
} }
if (!this.config.S3_PASS) { if (!this.config.S3_SECRETKEY) {
this.config.S3_PASS = 'defaultpass'; this.config.S3_SECRETKEY = 'defaultpass';
fieldsAdded.push('S3_PASS'); fieldsAdded.push('S3_SECRETKEY');
updated = true; updated = true;
} }
@@ -224,6 +236,21 @@ export class ServiceConfiguration {
updated = true; updated = true;
} }
if (!this.config.S3_USESSL) {
this.config.S3_USESSL = false;
fieldsAdded.push('S3_USESSL');
updated = true;
}
// Always update S3_ENDPOINT based on current settings
const oldEndpoint = this.config.S3_ENDPOINT;
const protocol = this.config.S3_USESSL ? 'https' : 'http';
this.config.S3_ENDPOINT = `${protocol}://${this.config.S3_HOST}:${this.config.S3_PORT}`;
if (oldEndpoint !== this.config.S3_ENDPOINT) {
fieldsAdded.push('S3_ENDPOINT');
updated = true;
}
if (updated) { if (updated) {
await this.saveConfig(); await this.saveConfig();
logger.log('ok', `✅ Added missing fields: ${fieldsAdded.join(', ')}`); logger.log('ok', `✅ Added missing fields: ${fieldsAdded.join(', ')}`);
@@ -259,4 +286,147 @@ export class ServiceConfiguration {
minio: plugins.path.join(process.cwd(), '.nogit', 'miniodata') minio: plugins.path.join(process.cwd(), '.nogit', 'miniodata')
}; };
} }
/**
* Sync port configuration from existing Docker containers
*/
private async syncPortsFromDocker(): Promise<void> {
const containers = this.getContainerNames();
let updated = false;
// Check MongoDB container
const mongoStatus = await this.docker.getStatus(containers.mongo);
if (mongoStatus !== 'not_exists') {
const portMappings = await this.docker.getPortMappings(containers.mongo);
if (portMappings && portMappings['27017']) {
const dockerPort = portMappings['27017'];
if (this.config.MONGODB_PORT !== dockerPort) {
this.config.MONGODB_PORT = dockerPort;
updated = true;
}
}
}
// Check MinIO container
const minioStatus = await this.docker.getStatus(containers.minio);
if (minioStatus !== 'not_exists') {
const portMappings = await this.docker.getPortMappings(containers.minio);
if (portMappings) {
if (portMappings['9000']) {
const dockerPort = portMappings['9000'];
if (this.config.S3_PORT !== dockerPort) {
this.config.S3_PORT = dockerPort;
updated = true;
}
}
if (portMappings['9001']) {
const dockerPort = portMappings['9001'];
if (this.config.S3_CONSOLE_PORT !== dockerPort) {
this.config.S3_CONSOLE_PORT = dockerPort;
updated = true;
}
}
}
}
if (updated) {
// Update derived fields
this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`;
const protocol = this.config.S3_USESSL ? 'https' : 'http';
this.config.S3_ENDPOINT = `${protocol}://${this.config.S3_HOST}:${this.config.S3_PORT}`;
await this.saveConfig();
}
}
/**
* Validate and update ports if they're not available
*/
public async validateAndUpdatePorts(): Promise<boolean> {
let updated = false;
const containers = this.getContainerNames();
// Check if containers exist - if they do, ports are fine
const mongoExists = await this.docker.exists(containers.mongo);
const minioExists = await this.docker.exists(containers.minio);
// Only check port availability if containers don't exist
if (!mongoExists) {
const mongoPort = parseInt(this.config.MONGODB_PORT);
if (!(await helpers.isPortAvailable(mongoPort))) {
logger.log('note', `⚠️ MongoDB port ${mongoPort} is in use, finding new port...`);
const newPort = await helpers.getRandomAvailablePort();
this.config.MONGODB_PORT = newPort.toString();
logger.log('ok', `✅ New MongoDB port: ${newPort}`);
updated = true;
}
}
if (!minioExists) {
const s3Port = parseInt(this.config.S3_PORT);
const s3ConsolePort = parseInt(this.config.S3_CONSOLE_PORT);
if (!(await helpers.isPortAvailable(s3Port))) {
logger.log('note', `⚠️ S3 API port ${s3Port} is in use, finding new port...`);
const newPort = await helpers.getRandomAvailablePort();
this.config.S3_PORT = newPort.toString();
logger.log('ok', `✅ New S3 API port: ${newPort}`);
updated = true;
}
if (!(await helpers.isPortAvailable(s3ConsolePort))) {
logger.log('note', `⚠️ S3 Console port ${s3ConsolePort} is in use, finding new port...`);
let newPort = parseInt(this.config.S3_PORT) + 1;
while (!(await helpers.isPortAvailable(newPort))) {
newPort++;
}
this.config.S3_CONSOLE_PORT = newPort.toString();
logger.log('ok', `✅ New S3 Console port: ${newPort}`);
updated = true;
}
}
if (updated) {
// Update derived fields
this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`;
const protocol = this.config.S3_USESSL ? 'https' : 'http';
this.config.S3_ENDPOINT = `${protocol}://${this.config.S3_HOST}:${this.config.S3_PORT}`;
await this.saveConfig();
}
return updated;
}
/**
* Force reconfigure all ports with new available ones
*/
public async reconfigurePorts(): Promise<void> {
logger.log('note', '🔄 Finding new available ports...');
const mongoPort = await helpers.getRandomAvailablePort();
const s3Port = await helpers.getRandomAvailablePort();
let s3ConsolePort = s3Port + 1;
// Ensure console port is also available
while (!(await helpers.isPortAvailable(s3ConsolePort))) {
s3ConsolePort++;
}
this.config.MONGODB_PORT = mongoPort.toString();
this.config.S3_PORT = s3Port.toString();
this.config.S3_CONSOLE_PORT = s3ConsolePort.toString();
// Update derived fields
this.config.MONGODB_URL = `mongodb://${this.config.MONGODB_USER}:${this.config.MONGODB_PASS}@${this.config.MONGODB_HOST}:${this.config.MONGODB_PORT}/${this.config.MONGODB_NAME}?authSource=admin`;
const protocol = this.config.S3_USESSL ? 'https' : 'http';
this.config.S3_ENDPOINT = `${protocol}://${this.config.S3_HOST}:${this.config.S3_PORT}`;
await this.saveConfig();
logger.log('ok', '✅ New port configuration:');
logger.log('info', ` 📍 MongoDB: ${mongoPort}`);
logger.log('info', ` 📍 S3 API: ${s3Port}`);
logger.log('info', ` 📍 S3 Console: ${s3ConsolePort}`);
}
} }

View File

@@ -26,6 +26,9 @@ export class ServiceManager {
// Load or create configuration // Load or create configuration
await this.config.loadOrCreate(); await this.config.loadOrCreate();
logger.log('info', `📋 Project: ${this.config.getConfig().PROJECT_NAME}`); logger.log('info', `📋 Project: ${this.config.getConfig().PROJECT_NAME}`);
// Validate and update ports if needed
await this.config.validateAndUpdatePorts();
} }
/** /**
@@ -49,11 +52,43 @@ export class ServiceManager {
break; break;
case 'stopped': case 'stopped':
// Check if port mapping matches config
const mongoPortMappings = await this.docker.getPortMappings(containers.mongo);
if (mongoPortMappings && mongoPortMappings['27017'] !== config.MONGODB_PORT) {
logger.log('note', ' Port configuration changed, recreating container...');
await this.docker.remove(containers.mongo, true);
// Fall through to create new container
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',
command: '--bind_ip_all'
});
if (success) {
logger.log('ok', ' Recreated with new port ✓');
} else {
logger.log('error', ' Failed to recreate container');
}
} else {
// Ports match, just start the container
if (await this.docker.start(containers.mongo)) { if (await this.docker.start(containers.mongo)) {
logger.log('ok', ' Started ✓'); logger.log('ok', ' Started ✓');
} else { } else {
logger.log('error', ' Failed to start'); logger.log('error', ' Failed to start');
} }
}
break; break;
case 'not_exists': case 'not_exists':
@@ -116,11 +151,61 @@ export class ServiceManager {
break; break;
case 'stopped': case 'stopped':
// Check if port mapping matches config
const minioPortMappings = await this.docker.getPortMappings(containers.minio);
if (minioPortMappings &&
(minioPortMappings['9000'] !== config.S3_PORT ||
minioPortMappings['9001'] !== config.S3_CONSOLE_PORT)) {
logger.log('note', ' Port configuration changed, recreating container...');
await this.docker.remove(containers.minio, true);
// Fall through to create new container
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_ACCESSKEY,
MINIO_ROOT_PASSWORD: config.S3_SECRETKEY
},
restart: 'unless-stopped',
command: 'server /data --console-address ":9001"'
});
if (success) {
logger.log('ok', ' Recreated with new ports ✓');
// 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_ACCESSKEY} ${config.S3_SECRETKEY}`
);
await this.docker.exec(
containers.minio,
`mc mb local/${config.S3_BUCKET}`
);
logger.log('ok', ` Bucket '${config.S3_BUCKET}' created ✓`);
} else {
logger.log('error', ' Failed to recreate container');
}
} else {
// Ports match, just start the container
if (await this.docker.start(containers.minio)) { if (await this.docker.start(containers.minio)) {
logger.log('ok', ' Started ✓'); logger.log('ok', ' Started ✓');
} else { } else {
logger.log('error', ' Failed to start'); logger.log('error', ' Failed to start');
} }
}
break; break;
case 'not_exists': case 'not_exists':
@@ -137,8 +222,8 @@ export class ServiceManager {
[directories.minio]: '/data' [directories.minio]: '/data'
}, },
environment: { environment: {
MINIO_ROOT_USER: config.S3_USER, MINIO_ROOT_USER: config.S3_ACCESSKEY,
MINIO_ROOT_PASSWORD: config.S3_PASS MINIO_ROOT_PASSWORD: config.S3_SECRETKEY
}, },
restart: 'unless-stopped', restart: 'unless-stopped',
command: 'server /data --console-address ":9001"' command: 'server /data --console-address ":9001"'
@@ -153,7 +238,7 @@ export class ServiceManager {
// Create default bucket // Create default bucket
await this.docker.exec( await this.docker.exec(
containers.minio, containers.minio,
`mc alias set local http://localhost:9000 ${config.S3_USER} ${config.S3_PASS}` `mc alias set local http://localhost:9000 ${config.S3_ACCESSKEY} ${config.S3_SECRETKEY}`
); );
await this.docker.exec( await this.docker.exec(
@@ -172,7 +257,7 @@ export class ServiceManager {
logger.log('info', ` Port: ${config.S3_PORT}`); logger.log('info', ` Port: ${config.S3_PORT}`);
logger.log('info', ` Bucket: ${config.S3_BUCKET}`); logger.log('info', ` Bucket: ${config.S3_BUCKET}`);
logger.log('info', ` API: http://${config.S3_HOST}:${config.S3_PORT}`); logger.log('info', ` API: http://${config.S3_HOST}:${config.S3_PORT}`);
logger.log('info', ` Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT} (login: ${config.S3_USER}/***)`); logger.log('info', ` Console: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT} (login: ${config.S3_ACCESSKEY}/***)`);
} }
/** /**
@@ -233,6 +318,7 @@ export class ServiceManager {
case 'running': case 'running':
logger.log('ok', '📦 MongoDB: 🟢 Running'); logger.log('ok', '📦 MongoDB: 🟢 Running');
logger.log('info', ` ├─ Container: ${containers.mongo}`); logger.log('info', ` ├─ Container: ${containers.mongo}`);
logger.log('info', ` ├─ Port: ${config.MONGODB_PORT}`);
logger.log('info', ` ├─ Connection: ${this.config.getMongoConnectionString()}`); logger.log('info', ` ├─ Connection: ${this.config.getMongoConnectionString()}`);
// Show Compass connection string // Show Compass connection string
@@ -242,10 +328,19 @@ export class ServiceManager {
break; break;
case 'stopped': case 'stopped':
logger.log('note', '📦 MongoDB: 🟡 Stopped'); logger.log('note', '📦 MongoDB: 🟡 Stopped');
logger.log('info', ` ─ Container: ${containers.mongo}`); logger.log('info', ` ─ Container: ${containers.mongo}`);
logger.log('info', ` └─ Port: ${config.MONGODB_PORT}`);
break; break;
case 'not_exists': case 'not_exists':
logger.log('info', '📦 MongoDB: ⚪ Not installed'); logger.log('info', '📦 MongoDB: ⚪ Not installed');
// Check port availability
const mongoPort = parseInt(config.MONGODB_PORT);
const mongoAvailable = await helpers.isPortAvailable(mongoPort);
if (!mongoAvailable) {
logger.log('error', ` └─ ⚠️ Port ${mongoPort} is in use by another process`);
} else {
logger.log('info', ` └─ Port ${mongoPort} is available`);
}
break; break;
} }
@@ -261,10 +356,33 @@ export class ServiceManager {
break; break;
case 'stopped': case 'stopped':
logger.log('note', '📦 S3/MinIO: 🟡 Stopped'); logger.log('note', '📦 S3/MinIO: 🟡 Stopped');
logger.log('info', ` ─ Container: ${containers.minio}`); logger.log('info', ` ─ Container: ${containers.minio}`);
logger.log('info', ` ├─ API Port: ${config.S3_PORT}`);
logger.log('info', ` └─ Console Port: ${config.S3_CONSOLE_PORT}`);
break; break;
case 'not_exists': case 'not_exists':
logger.log('info', '📦 S3/MinIO: ⚪ Not installed'); logger.log('info', '📦 S3/MinIO: ⚪ Not installed');
// Check port availability
const s3Port = parseInt(config.S3_PORT);
const s3ConsolePort = parseInt(config.S3_CONSOLE_PORT);
const s3Available = await helpers.isPortAvailable(s3Port);
const consoleAvailable = await helpers.isPortAvailable(s3ConsolePort);
if (!s3Available || !consoleAvailable) {
if (!s3Available) {
logger.log('error', ` ├─ ⚠️ API Port ${s3Port} is in use`);
} else {
logger.log('info', ` ├─ API Port ${s3Port} is available`);
}
if (!consoleAvailable) {
logger.log('error', ` └─ ⚠️ Console Port ${s3ConsolePort} is in use`);
} else {
logger.log('info', ` └─ Console Port ${s3ConsolePort} is available`);
}
} else {
logger.log('info', ` ├─ API Port ${s3Port} is available`);
logger.log('info', ` └─ Console Port ${s3ConsolePort} is available`);
}
break; break;
} }
} }
@@ -294,12 +412,13 @@ export class ServiceManager {
logger.log('info', ` Host: ${config.S3_HOST}`); logger.log('info', ` Host: ${config.S3_HOST}`);
logger.log('info', ` API Port: ${config.S3_PORT}`); logger.log('info', ` API Port: ${config.S3_PORT}`);
logger.log('info', ` Console Port: ${config.S3_CONSOLE_PORT}`); logger.log('info', ` Console Port: ${config.S3_CONSOLE_PORT}`);
logger.log('info', ` User: ${config.S3_USER}`); logger.log('info', ` Access Key: ${config.S3_ACCESSKEY}`);
logger.log('info', ' Password: ***'); logger.log('info', ' Secret Key: ***');
logger.log('info', ` Bucket: ${config.S3_BUCKET}`); logger.log('info', ` Bucket: ${config.S3_BUCKET}`);
logger.log('info', ` Use SSL: ${config.S3_USESSL}`);
logger.log('info', ` Container: ${this.config.getContainerNames().minio}`); logger.log('info', ` Container: ${this.config.getContainerNames().minio}`);
logger.log('info', ` Data: ${this.config.getDataDirectories().minio}`); logger.log('info', ` Data: ${this.config.getDataDirectories().minio}`);
logger.log('info', ` API URL: http://${config.S3_HOST}:${config.S3_PORT}`); logger.log('info', ` Endpoint: ${config.S3_ENDPOINT}`);
logger.log('info', ` Console URL: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`); logger.log('info', ` Console URL: http://${config.S3_HOST}:${config.S3_CONSOLE_PORT}`);
} }
@@ -421,4 +540,44 @@ export class ServiceManager {
logger.log('note', ' No data to clean'); logger.log('note', ' No data to clean');
} }
} }
/**
* Reconfigure services with new ports
*/
public async reconfigure(): Promise<void> {
helpers.printHeader('Reconfiguring Services');
const containers = this.config.getContainerNames();
// Stop existing containers
logger.log('note', '🛑 Stopping existing containers...');
if (await this.docker.exists(containers.mongo)) {
await this.docker.stop(containers.mongo);
logger.log('ok', ' MongoDB stopped ✓');
}
if (await this.docker.exists(containers.minio)) {
await this.docker.stop(containers.minio);
logger.log('ok', ' S3/MinIO stopped ✓');
}
// Reconfigure ports
await this.config.reconfigurePorts();
// Ask if user wants to restart services
const smartinteract = new plugins.smartinteract.SmartInteract();
const response = await smartinteract.askQuestion({
name: 'restart',
type: 'confirm',
message: 'Do you want to start services with new ports?',
default: true
});
if (response.value) {
console.log();
await this.startMongoDB();
await this.startMinIO();
}
}
} }

View File

@@ -48,6 +48,10 @@ export const run = async (argvArg: any) => {
await handleClean(serviceManager); await handleClean(serviceManager);
break; break;
case 'reconfigure':
await serviceManager.reconfigure();
break;
case 'help': case 'help':
default: default:
showHelp(); showHelp();
@@ -195,6 +199,7 @@ function showHelp() {
logger.log('info', ' config Show current configuration'); logger.log('info', ' config Show current configuration');
logger.log('info', ' compass Show MongoDB Compass connection string'); logger.log('info', ' compass Show MongoDB Compass connection string');
logger.log('info', ' logs [service] Show logs (mongo|s3|all) [lines]'); logger.log('info', ' logs [service] Show logs (mongo|s3|all) [lines]');
logger.log('info', ' reconfigure Reassign ports and restart services');
logger.log('info', ' remove Remove all containers'); logger.log('info', ' remove Remove all containers');
logger.log('info', ' clean Remove all containers and data ⚠️'); logger.log('info', ' clean Remove all containers and data ⚠️');
logger.log('info', ' help Show this help message'); logger.log('info', ' help Show this help message');