feat: Implement platform service providers for MinIO and MongoDB

- Added base interface and abstract class for platform service providers.
- Created MinIOProvider class for S3-compatible storage with deployment, provisioning, and deprovisioning functionalities.
- Implemented MongoDBProvider class for MongoDB service with similar capabilities.
- Introduced error handling utilities for better error management.
- Developed TokensComponent for managing registry tokens in the UI, including creation, deletion, and display of tokens.
This commit is contained in:
2025-11-25 04:20:19 +00:00
parent 9aa6906ca5
commit 8ebd677478
28 changed files with 3462 additions and 490 deletions

View File

@@ -4,10 +4,11 @@
* Orchestrates service deployment: Docker + Nginx + DNS + SSL
*/
import type { IService, IServiceDeployOptions } from '../types.ts';
import type { IService, IServiceDeployOptions, IPlatformRequirements } from '../types.ts';
import { logger } from '../logging.ts';
import { OneboxDatabase } from './database.ts';
import { OneboxDockerManager } from './docker.ts';
import type { PlatformServicesManager } from './platform-services/index.ts';
export class OneboxServicesManager {
private oneboxRef: any; // Will be Onebox instance
@@ -34,13 +35,9 @@ export class OneboxServicesManager {
}
// Handle Onebox Registry setup
let registryToken: string | undefined;
let imageToPull: string;
if (options.useOneboxRegistry) {
// Generate registry token
registryToken = await this.oneboxRef.registry.createServiceToken(options.name);
// Use onebox registry image name
const tag = options.registryImageTag || 'latest';
imageToPull = this.oneboxRef.registry.getImageName(options.name, tag);
@@ -49,6 +46,15 @@ export class OneboxServicesManager {
imageToPull = options.image;
}
// Build platform requirements
const platformRequirements: IPlatformRequirements | undefined =
(options.enableMongoDB || options.enableS3)
? {
mongodb: options.enableMongoDB,
s3: options.enableS3,
}
: undefined;
// Create service record in database
const service = await this.database.createService({
name: options.name,
@@ -63,18 +69,46 @@ export class OneboxServicesManager {
// Onebox Registry fields
useOneboxRegistry: options.useOneboxRegistry,
registryRepository: options.useOneboxRegistry ? options.name : undefined,
registryToken: registryToken,
registryImageTag: options.registryImageTag || 'latest',
autoUpdateOnPush: options.autoUpdateOnPush,
// Platform requirements
platformRequirements,
});
// Provision platform resources if needed
let platformEnvVars: Record<string, string> = {};
if (platformRequirements) {
try {
logger.info(`Provisioning platform resources for service '${options.name}'...`);
const platformServices = this.oneboxRef.platformServices as PlatformServicesManager;
platformEnvVars = await platformServices.provisionForService(service);
logger.success(`Platform resources provisioned for service '${options.name}'`);
} catch (error) {
logger.error(`Failed to provision platform resources: ${error.message}`);
// Clean up the service record on failure
this.database.deleteService(service.id!);
throw error;
}
}
// Merge platform env vars with user-specified env vars (user vars take precedence)
const mergedEnvVars = { ...platformEnvVars, ...(options.envVars || {}) };
// Update service with merged env vars
if (Object.keys(platformEnvVars).length > 0) {
this.database.updateService(service.id!, { envVars: mergedEnvVars });
}
// Get updated service with merged env vars
const serviceWithEnvVars = this.database.getServiceByName(options.name)!;
// Pull image (skip if using onebox registry - image might not exist yet)
if (!options.useOneboxRegistry) {
await this.docker.pullImage(imageToPull, options.registry);
}
// Create container
const containerID = await this.docker.createContainer(service);
// Create container (uses the updated service with merged env vars)
const containerID = await this.docker.createContainer(serviceWithEnvVars);
// Update service with container ID
this.database.updateService(service.id!, {
@@ -293,6 +327,19 @@ export class OneboxServicesManager {
// as they might be used by other services or need manual cleanup
}
// Cleanup platform resources (MongoDB databases, S3 buckets, etc.)
if (service.platformRequirements) {
try {
logger.info(`Cleaning up platform resources for service '${name}'...`);
const platformServices = this.oneboxRef.platformServices as PlatformServicesManager;
await platformServices.cleanupForService(service.id!);
logger.success(`Platform resources cleaned up for service '${name}'`);
} catch (error) {
logger.warn(`Failed to cleanup platform resources: ${error.message}`);
// Continue with service deletion even if cleanup fails
}
}
// Remove from database
this.database.deleteService(service.id!);
@@ -392,6 +439,28 @@ export class OneboxServicesManager {
}
}
/**
* Get platform resources for a service
*/
async getServicePlatformResources(name: string) {
try {
const service = this.database.getServiceByName(name);
if (!service) {
throw new Error(`Service not found: ${name}`);
}
if (!service.platformRequirements) {
return [];
}
const platformServices = this.oneboxRef.platformServices as PlatformServicesManager;
return await platformServices.getResourcesForService(service.id!);
} catch (error) {
logger.error(`Failed to get platform resources for service ${name}: ${error.message}`);
return [];
}
}
/**
* Get service status
*/